WEB/src/pages/Woo/Media/index.tsx

168 lines
4.5 KiB
TypeScript

import { sitecontrollerAll } from '@/servers/api/site';
import { PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { request } from '@umijs/max';
import { App, Image, Select } from 'antd';
import React, { useEffect, useState } from 'react';
const MediaPage: React.FC = () => {
const { message } = App.useApp();
const [sites, setSites] = useState<any[]>([]);
const [selectedSiteId, setSelectedSiteId] = useState<number | undefined>();
const [mediaList, setMediaList] = useState<any[]>([]);
const [loading, setLoading] = useState(false);
const [pagination, setPagination] = useState({
current: 1,
pageSize: 20,
total: 0,
});
// Fetch sites
useEffect(() => {
const fetchSites = async () => {
try {
const res = await sitecontrollerAll();
if (res.success && res.data) {
setSites(res.data);
if (res.data.length > 0) {
setSelectedSiteId(res.data[0].id);
}
}
} catch (error) {
message.error('获取站点列表失败');
}
};
fetchSites();
}, []);
// Fetch media
const fetchMedia = async (siteId: number, page: number, pageSize: number) => {
setLoading(true);
try {
const res = await request('/media/list', {
params: { siteId, page, pageSize },
});
if (res.success) {
setMediaList(res.data.items || []);
setPagination({
current: page,
pageSize: pageSize,
total: res.data.total || 0,
});
} else {
message.error(res.message || '获取媒体库失败');
}
} catch (error) {
message.error('获取媒体库失败');
} finally {
setLoading(false);
}
};
useEffect(() => {
if (selectedSiteId) {
fetchMedia(selectedSiteId, 1, pagination.pageSize);
}
}, [selectedSiteId]);
const handlePageChange = (page: number, pageSize: number) => {
if (selectedSiteId) {
fetchMedia(selectedSiteId, page, pageSize);
}
};
const formatSize = (bytes: number) => {
if (!bytes) return '-';
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
};
const columns: ProColumns<any>[] = [
{
title: '展示',
dataIndex: 'source_url',
hideInSearch: true,
render: (_, record) => (
<Image
src={record.media_details?.sizes?.thumbnail?.source_url || record.source_url}
style={{ width: 60, height: 60, objectFit: 'contain', background: '#f0f0f0' }}
fallback="https://via.placeholder.com/60?text=No+Img"
/>
),
},
{
title: '名称',
dataIndex: ['title', 'rendered'],
copyable: true,
ellipsis: true,
width: 200,
},
{
title: '宽高',
dataIndex: 'media_details',
hideInSearch: true,
render: (_, record) => {
const width = record.media_details?.width;
const height = record.media_details?.height;
return width && height ? `${width} x ${height}` : '-';
},
},
{
title: '地址',
dataIndex: 'source_url',
copyable: true,
ellipsis: true,
hideInSearch: true,
},
{
title: '文件大小',
dataIndex: 'media_details',
hideInSearch: true,
render: (_, record) => formatSize(record.media_details?.filesize),
},
{
title: '素材类型',
dataIndex: 'mime_type',
width: 120,
},
];
return (
<PageContainer
header={{
title: '媒体库',
extra: [
<Select
key="site-select"
style={{ width: 200 }}
placeholder="选择站点"
value={selectedSiteId}
onChange={setSelectedSiteId}
options={sites.map(site => ({ label: site.name, value: site.id }))}
/>
]
}}
>
<ProTable
rowKey="id"
columns={columns}
dataSource={mediaList}
loading={loading}
search={false}
pagination={{
current: pagination.current,
pageSize: pagination.pageSize,
total: pagination.total,
onChange: handlePageChange,
showSizeChanger: true,
}}
options={false}
/>
</PageContainer>
);
};
export default MediaPage;