451 lines
13 KiB
TypeScript
451 lines
13 KiB
TypeScript
import { Button, Input, message, Modal, Radio, Space, Table, TableProps } from 'antd';
|
||
import React, { useEffect, useState } from 'react';
|
||
import { GetResourceListApi, DelResourceItemApi, GetDetailApi } from '../../api/textbook';
|
||
import styles from './resource.module.less';
|
||
import { TableRowSelection } from 'antd/es/table/interface';
|
||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||
import LoadingPage from '../loading';
|
||
import { BackBartment } from '../../compenents';
|
||
import { useTranslation } from 'react-i18next';
|
||
|
||
import { DeleteOutlined, UploadOutlined } from '@ant-design/icons';
|
||
import CreateResourceModal from './compenents/Resource/CreateResourceModal';
|
||
|
||
interface ResourceBase {
|
||
id: number | null | string | undefined; // 资源id
|
||
typeId: number; // 分类Id
|
||
bookId: 0;
|
||
chapterId: 0;
|
||
name: string;
|
||
type: string;
|
||
ext: string;
|
||
size: 0;
|
||
duration: 0;
|
||
url: string;
|
||
cover: string;
|
||
status: 0;
|
||
creator: string;
|
||
updater: string;
|
||
createTime: string;
|
||
updateTime: string;
|
||
tenantId: string;
|
||
}
|
||
|
||
// 列表展示
|
||
interface ResourceDataType extends ResourceBase {
|
||
index?: number;
|
||
}
|
||
// 分页查询
|
||
interface ResourceResData {
|
||
data: {
|
||
records: ResourceDataType[];
|
||
total: number;
|
||
};
|
||
}
|
||
|
||
const ResourcePage = () => {
|
||
const navigate = useNavigate();
|
||
const { t } = useTranslation();
|
||
const [searchParams] = useSearchParams();
|
||
const title = searchParams.get('title');
|
||
const { bookId } = useParams();
|
||
const [isEdit, setIsEdit] = useState(false); // 是否编辑模式
|
||
const [editId, setEditId] = useState<number>(0);
|
||
const [isAddModalOpen, setIsAddModalOpen] = useState<boolean>(false);
|
||
const [confirmLoading, setConfirmLoading] = useState(false);
|
||
const [modalVisible, setModalVisible] = useState(false);
|
||
const [isConfirmModalOpen, setIsConfirmModalOpen] = useState(false);
|
||
const [selectedId, setSelectedId] = useState<number | string | null>(null);
|
||
const [selectedIdList, setSelectedIdList] = useState<string[]>([]);
|
||
const [resource, setResource] = useState<ResourceBase[]>([]);
|
||
const [resourceTotal, setResourceTotal] = useState<number>(0);
|
||
const [type, setType] = useState<number>(0);
|
||
const [page, setPage] = useState<number>(1);
|
||
const [pageSize, setPageSize] = useState<number>(10);
|
||
const [sortOrder, setSortOrder] = useState<string>('');
|
||
const [sortField, setSortField] = useState<string>('');
|
||
const [searchData, setSearchData] = useState<string>('');
|
||
const [refresh, setRefresh] = useState(false);
|
||
const [pageLoading, setPageLoading] = useState<boolean>(false);
|
||
|
||
const TypeOptions = [
|
||
{ label: t('textbook.resource.typeList.all'), value: 0, color: '#f3f4f6' },
|
||
{ label: t('textbook.resource.typeList.video'), value: 1, color: '#dbeafe' },
|
||
{ label: t('textbook.resource.typeList.img'), value: 2, color: '#dcfce7' },
|
||
{ label: t('textbook.resource.typeList.doc'), value: 3, color: '#fef9c3' },
|
||
{ label: t('textbook.resource.typeList.audio'), value: 4, color: '#f3e8ff' },
|
||
{ label: t('textbook.resource.typeList.other'), value: 5, color: '#f3f4f6' },
|
||
];
|
||
// 排序字段/**/
|
||
/* name
|
||
size createTime这三个*/
|
||
// 列表数据
|
||
const columns: TableProps<ResourceBase>['columns'] = [
|
||
{
|
||
title: t('textbook.resource.title1'),
|
||
dataIndex: 'softNo',
|
||
align: 'left',
|
||
width: 300,
|
||
sorter: true,
|
||
},
|
||
{
|
||
title: t('textbook.resource.title2'),
|
||
dataIndex: 'softwareName',
|
||
align: 'left',
|
||
},
|
||
|
||
{
|
||
title: t('textbook.resource.title3'),
|
||
dataIndex: 'company',
|
||
ellipsis: true,
|
||
sorter: true,
|
||
},
|
||
{
|
||
title: t('textbook.resource.title4'),
|
||
dataIndex: 'version',
|
||
align: 'left',
|
||
ellipsis: true,
|
||
width: 140,
|
||
sorter: true,
|
||
},
|
||
{
|
||
title: t('textbook.resource.title5'),
|
||
// align: 'center',
|
||
render: (_, record) => (
|
||
<Space
|
||
size="middle"
|
||
style={{ display: 'flex', justifyContent: 'space-around', alignItems: 'center' }}
|
||
>
|
||
<a
|
||
key="pre"
|
||
onClick={() => {
|
||
console.log('预览');
|
||
}}
|
||
>
|
||
{/*<EyeOutlined />*/}
|
||
{t('commen.preview')}
|
||
</a>
|
||
<a
|
||
key={'edit'}
|
||
//@ts-ignore
|
||
onClick={() => {
|
||
getDetail(Number(record.id));
|
||
}}
|
||
>
|
||
{t('commen.edit')}
|
||
</a>
|
||
<a
|
||
key={'del'}
|
||
className="b-link c-red"
|
||
onClick={() => showDeleteConfirm(Number(record.id))}
|
||
>
|
||
{/*<DeleteOutlined />*/}
|
||
{t('commen.del')}
|
||
</a>
|
||
</Space>
|
||
),
|
||
},
|
||
];
|
||
|
||
// @ts-ignore
|
||
const getResourceList = async () => {
|
||
try {
|
||
const res = (await GetResourceListApi(
|
||
page,
|
||
pageSize,
|
||
type,
|
||
searchData,
|
||
sortOrder,
|
||
sortField
|
||
)) as ResourceResData;
|
||
if (res && 'data' in res && 'records' in res.data) {
|
||
setResource(res.data.records);
|
||
setResourceTotal(res.data.total);
|
||
} else {
|
||
console.warn('接口返回数据结构异常:', res);
|
||
setResource([]); // 设置为空数组防止崩溃
|
||
}
|
||
} catch (error) {
|
||
console.error('获取列表失败:', error);
|
||
}
|
||
};
|
||
|
||
const resetVirtualList = async () => {
|
||
try {
|
||
const res = (await GetResourceListApi(1, 10, null, null, null, null)) as ResourceResData;
|
||
if (res && 'data' in res && 'records' in res.data) {
|
||
setResource(res.data.records || []);
|
||
setResourceTotal(res.data.total);
|
||
} else {
|
||
console.warn('接口返回数据结构异常:', res);
|
||
setResource([]); // 设置为空数组防止崩溃
|
||
}
|
||
} catch (error) {
|
||
console.error('获取列表失败:', error);
|
||
}
|
||
};
|
||
|
||
const getDetail = async (id: number) => {
|
||
try {
|
||
const res = (await GetDetailApi(id)) as VirtualResDetail | undefined;
|
||
if (!res || !res.data) {
|
||
message.error('获取详情失败');
|
||
return;
|
||
}
|
||
setIsEdit(true);
|
||
//@ts-ignore
|
||
setItemDetailData(res.data);
|
||
setSelectedId(res.data.id);
|
||
// 打开弹窗
|
||
setIsAddModalOpen(true);
|
||
} catch (error) {
|
||
message.error('获取详情失败');
|
||
setPageLoading(false);
|
||
console.error('获取详情失败:', error);
|
||
}
|
||
};
|
||
|
||
const showDeleteConfirm = (id: number) => {
|
||
setSelectedId(id);
|
||
setModalVisible(true);
|
||
};
|
||
|
||
const handleDeleteItem = async () => {
|
||
if (selectedId === null) return;
|
||
setConfirmLoading(true);
|
||
try {
|
||
await DelResourceItemApi(selectedId.toString());
|
||
message.success('删除成功');
|
||
// @ts-ignore
|
||
await getVirtualList();
|
||
} catch (error) {
|
||
message.error('删除失败');
|
||
console.error('删除失败:', error);
|
||
} finally {
|
||
setConfirmLoading(false);
|
||
setModalVisible(false);
|
||
setSelectedId(null);
|
||
}
|
||
};
|
||
|
||
//弹窗取消
|
||
|
||
const showAddSoftModal = () => {
|
||
setIsEdit(false); // 设置为新增模式
|
||
setSelectedId(null); // 清除选中 ID
|
||
setIsAddModalOpen(true);
|
||
};
|
||
const handleCancelDeleteItem = () => {
|
||
setModalVisible(false);
|
||
};
|
||
const handleCancelDeleteItems = () => {
|
||
setIsConfirmModalOpen(false);
|
||
};
|
||
const handleReset = () => {
|
||
setPage(1);
|
||
setPageSize(10);
|
||
setType(0);
|
||
setSelectedIdList([]);
|
||
setSearchData('');
|
||
resetVirtualList();
|
||
};
|
||
// 批量删除
|
||
const handleDeleteItems = () => {
|
||
toDeleteSoftwareList();
|
||
};
|
||
|
||
const toDeleteSoftwareList = async () => {
|
||
try {
|
||
const selectedIdListString = selectedIdList.join(',');
|
||
const res = await DelResourceItemApi(selectedIdListString);
|
||
message.success('删除成功');
|
||
// @ts-ignore
|
||
await getVirtualList();
|
||
} catch (error) {
|
||
message.error('删除失败');
|
||
console.error('删除失败:', error);
|
||
} finally {
|
||
setConfirmLoading(false);
|
||
setIsConfirmModalOpen(false);
|
||
setSelectedId(null);
|
||
setSelectedIdList([]);
|
||
}
|
||
};
|
||
|
||
const handleAddCancel = () => {
|
||
setIsAddModalOpen(false);
|
||
setIsEdit(false);
|
||
setSelectedId(null);
|
||
setType(0);
|
||
};
|
||
|
||
useEffect(() => {
|
||
setResource([]);
|
||
getResourceList();
|
||
}, [refresh, page, pageSize, type, searchData]);
|
||
|
||
const onSelectChange = (newSelectedRowKeys: any[]) => {
|
||
setSelectedIdList(newSelectedRowKeys);
|
||
};
|
||
|
||
const canDelete = selectedIdList.length > 0;
|
||
const rowSelection: TableRowSelection<ResourceBase> = {
|
||
selectedRowKeys: selectedIdList,
|
||
onChange: onSelectChange,
|
||
};
|
||
|
||
useEffect(() => {
|
||
getResourceList();
|
||
}, [page, pageSize, type, sortOrder, sortField, searchData]);
|
||
|
||
const handleTableChange = (
|
||
pagination: { current: number; pageSize: number },
|
||
filters: any,
|
||
sorter: { field: string; order: string }
|
||
) => {
|
||
// 统一处理分页
|
||
// if (pagination.current !== page || pagination.pageSize !== pageSize) {
|
||
setPage(pagination.current);
|
||
setPageSize(pagination.pageSize);
|
||
// }
|
||
// 处理排序
|
||
if (sorter && sorter.field) {
|
||
const sortField = sorter.field as string;
|
||
const sortOrder =
|
||
sorter.order === 'ascend' ? 'asc' : sorter.order === 'descend' ? 'desc' : '';
|
||
console.log('排序字段:', sortField, '排序方向:', sortOrder);
|
||
}
|
||
};
|
||
|
||
return (
|
||
<>
|
||
<div className={styles.container}>
|
||
{pageLoading && <LoadingPage />}
|
||
<BackBartment title={`${t('textbook.resource.pageTitle')}`} />
|
||
<div className={styles.mainBox}>
|
||
<div className={styles.title}>教材名称: {title}</div>
|
||
<div className={styles.search}>
|
||
<div className={styles.types}>
|
||
<div className={styles.typeTitle}>{t('textbook.resource.type')}:</div>
|
||
<Radio.Group
|
||
optionType="button"
|
||
buttonStyle={'solid'}
|
||
defaultValue={0}
|
||
value={type}
|
||
onChange={(e) => {
|
||
console.log(e.target.value, 'data');
|
||
setType(e.target.value);
|
||
}}
|
||
style={{
|
||
display: 'flex',
|
||
height: 40,
|
||
borderRadius: 16,
|
||
gap: 8,
|
||
}}
|
||
>
|
||
{TypeOptions.map((option) => {
|
||
return (
|
||
<Radio.Button
|
||
key={option.value}
|
||
value={option.value}
|
||
style={{
|
||
borderRadius: '16px',
|
||
border: '1px solid #d9d9d9',
|
||
}}
|
||
>
|
||
{option.label}
|
||
</Radio.Button>
|
||
);
|
||
})}
|
||
</Radio.Group>
|
||
</div>
|
||
|
||
<div className={styles.btns}>
|
||
<Input
|
||
placeholder={t('textbook.resource.searchPlaceholder')}
|
||
style={{ marginRight: 15, width: 360 }}
|
||
value={searchData}
|
||
allowClear
|
||
onChange={(e) => setSearchData(e.target.value)}
|
||
/>
|
||
|
||
<Button type="primary" onClick={getResourceList}>
|
||
{t('commen.search')}
|
||
</Button>
|
||
<Button
|
||
variant="outlined"
|
||
style={{ marginRight: 15, marginLeft: 15 }}
|
||
onClick={handleReset}
|
||
>
|
||
{t('commen.reset')}
|
||
</Button>
|
||
<Button type="primary" style={{ marginRight: 15 }} onClick={showAddSoftModal}>
|
||
<UploadOutlined />
|
||
{t('textbook.resource.upload')}
|
||
</Button>
|
||
<Button
|
||
variant="outlined"
|
||
style={{ marginRight: 15 }}
|
||
disabled={!canDelete}
|
||
onClick={() => setIsConfirmModalOpen(true)}
|
||
>
|
||
<DeleteOutlined /> {t('commen.moreDel')}
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
|
||
<Table<ResourceBase>
|
||
rowSelection={rowSelection}
|
||
columns={columns}
|
||
dataSource={resource}
|
||
// @ts-ignore
|
||
rowKey={(record) => record.id}
|
||
pagination={{
|
||
pageSize: pageSize,
|
||
current: page,
|
||
total: resourceTotal,
|
||
showSizeChanger: true,
|
||
align: 'start',
|
||
showTotal: (total) => `共 ${resourceTotal} 条记录`,
|
||
}}
|
||
// @ts-ignore
|
||
onChange={handleTableChange}
|
||
/>
|
||
</div>
|
||
</div>
|
||
{isAddModalOpen && (
|
||
<CreateResourceModal
|
||
isEdit={isEdit}
|
||
isOpen={isAddModalOpen}
|
||
onCancel={handleAddCancel}
|
||
resourceId={editId}
|
||
bookId={bookId}
|
||
typeOptions={TypeOptions}
|
||
></CreateResourceModal>
|
||
)}
|
||
|
||
{/*删除确认*/}
|
||
<Modal
|
||
title="确认删除"
|
||
open={modalVisible}
|
||
onOk={handleDeleteItem}
|
||
onCancel={handleCancelDeleteItem}
|
||
confirmLoading={confirmLoading}
|
||
>
|
||
<p>确定要删除这个软件吗?</p>
|
||
</Modal>
|
||
{/*多个删除确认*/}
|
||
<Modal
|
||
title="确认删除"
|
||
open={isConfirmModalOpen}
|
||
onOk={handleDeleteItems}
|
||
onCancel={handleCancelDeleteItems}
|
||
confirmLoading={confirmLoading}
|
||
>
|
||
<p>确定要删除这些软件吗?</p>
|
||
</Modal>
|
||
</>
|
||
);
|
||
};
|
||
export default ResourcePage;
|