resource mock data show
This commit is contained in:
parent
0d5781d07a
commit
e0b27ad257
@ -104,7 +104,7 @@ export function GetResourceListApi(
|
||||
|
||||
//删除+ 批量删除
|
||||
export function DelResourceItemApi(idList: string) {
|
||||
return client.destroy(`/backend/v1/jc/softwareInfo?idList=${idList}`);
|
||||
return client.destroy(`/backend/v1/jc/resource/delIds?idList=${idList}`);
|
||||
}
|
||||
|
||||
//根据id查详情
|
||||
@ -258,8 +258,7 @@ export function AddResourceItemApi(
|
||||
txtDesc: string,
|
||||
extension: string,
|
||||
size: number,
|
||||
path: string,
|
||||
chapterId?: string
|
||||
path: string
|
||||
) {
|
||||
return client.post(`/jc/resource`, {
|
||||
bookId,
|
||||
@ -269,6 +268,27 @@ export function AddResourceItemApi(
|
||||
extension,
|
||||
size,
|
||||
path,
|
||||
chapterId,
|
||||
});
|
||||
}
|
||||
|
||||
export function UpdateResourceItemApi(
|
||||
editId: number,
|
||||
bookId: number,
|
||||
name: string,
|
||||
knowledgeCode: string,
|
||||
txtDesc: string,
|
||||
extension: string,
|
||||
size: number,
|
||||
path: string
|
||||
) {
|
||||
return client.put(`/jc/resource`, {
|
||||
id: editId,
|
||||
bookId,
|
||||
name,
|
||||
knowledgeCode,
|
||||
txtDesc,
|
||||
extension,
|
||||
size,
|
||||
path,
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,8 +1,13 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Modal, Form, Input, message, Spin, Select } from 'antd';
|
||||
import { Modal, Form, Input, message, Spin, Select, SelectProps } from 'antd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import TextArea from 'antd/es/input/TextArea';
|
||||
import { AddResourceItemApi } from '../../../../api/textbook';
|
||||
import {
|
||||
AddResourceItemApi,
|
||||
GetDetailApi,
|
||||
getKnowledgeListApi,
|
||||
UpdateResourceItemApi,
|
||||
} from '../../../../api/textbook';
|
||||
import { DraggerUpload } from '../Upload/DraggerUpload';
|
||||
|
||||
interface ModalPropsType {
|
||||
@ -13,18 +18,95 @@ interface ModalPropsType {
|
||||
resourceId: number;
|
||||
}
|
||||
|
||||
interface Option {
|
||||
value: string | number;
|
||||
title: string;
|
||||
children?: Option[];
|
||||
}
|
||||
const defaultData = [
|
||||
{
|
||||
createTime: '2025-11-29 16:37:08',
|
||||
updateTime: '2025-12-02 15:42:09',
|
||||
creator: null,
|
||||
updater: null,
|
||||
tenantId: '-1',
|
||||
id: 1,
|
||||
bookId: 46,
|
||||
parentId: 0,
|
||||
name: '高等数学基础',
|
||||
knowledgeCode: 'MATH001',
|
||||
desc: '高等数学的基础知识点,包含极限、导数、积分等',
|
||||
level: 1,
|
||||
type: '基础',
|
||||
isReal: '1',
|
||||
orderNum: 1,
|
||||
extraJson: null,
|
||||
children: null,
|
||||
},
|
||||
{
|
||||
createTime: '2025-11-29 16:37:08',
|
||||
updateTime: '2025-12-02 15:42:09',
|
||||
creator: null,
|
||||
updater: null,
|
||||
tenantId: '-1',
|
||||
id: 2,
|
||||
bookId: 46,
|
||||
parentId: 1,
|
||||
name: '极限与连续',
|
||||
knowledgeCode: 'MATH001001',
|
||||
desc: '函数极限的定义与性质,连续函数的特征',
|
||||
level: 2,
|
||||
type: '基础',
|
||||
isReal: '1',
|
||||
orderNum: 1,
|
||||
extraJson: null,
|
||||
children: null,
|
||||
},
|
||||
{
|
||||
createTime: '2025-11-29 16:37:08',
|
||||
updateTime: '2025-12-02 15:42:09',
|
||||
creator: null,
|
||||
updater: null,
|
||||
tenantId: '-1',
|
||||
id: 3,
|
||||
bookId: 46,
|
||||
parentId: 1,
|
||||
name: '导数与微分',
|
||||
knowledgeCode: 'MATH001002',
|
||||
desc: '导数的定义、计算方法及应用',
|
||||
level: 2,
|
||||
type: '基础',
|
||||
isReal: '1',
|
||||
orderNum: 2,
|
||||
extraJson: null,
|
||||
children: null,
|
||||
},
|
||||
{
|
||||
createTime: '2025-11-29 16:37:08',
|
||||
updateTime: '2025-12-02 15:42:09',
|
||||
creator: null,
|
||||
updater: null,
|
||||
tenantId: '-1',
|
||||
id: 4,
|
||||
bookId: 46,
|
||||
parentId: 1,
|
||||
name: '积分学',
|
||||
knowledgeCode: 'MATH001003',
|
||||
desc: '不定积分与定积分的计算方法',
|
||||
level: 2,
|
||||
type: '基础',
|
||||
isReal: '1',
|
||||
orderNum: 3,
|
||||
extraJson: null,
|
||||
children: null,
|
||||
},
|
||||
];
|
||||
const CreateResourceModal = (props: ModalPropsType) => {
|
||||
const { t } = useTranslation();
|
||||
const { isOpen, onCancel, bookId, resourceId, isEdit } = props;
|
||||
const [form] = Form.useForm();
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [spinInit, setSpinInit] = useState(false);
|
||||
const [knowledgeOption, setKnowledgeOption] = useState<Option[]>([]);
|
||||
const [spinInit, setSpinInit] = useState<boolean>(false);
|
||||
const [knowledgeOption, setKnowledgeOption] = useState<
|
||||
{
|
||||
label: string;
|
||||
value: number;
|
||||
}[]
|
||||
>([]);
|
||||
const [fileSize, setFileSize] = useState<number>(0);
|
||||
const [fileName, setFileName] = useState<string>('');
|
||||
const [filePath, setFilePath] = useState<string>('');
|
||||
@ -36,77 +118,87 @@ const CreateResourceModal = (props: ModalPropsType) => {
|
||||
if (isEdit && resourceId) {
|
||||
getDetail();
|
||||
} else {
|
||||
form.resetFields();
|
||||
setSpinInit(false);
|
||||
form.setFieldsValue({
|
||||
type: '视频',
|
||||
});
|
||||
}
|
||||
}, [isEdit, resourceId]);
|
||||
|
||||
/* useEffect(() => {
|
||||
getChapterTreeData();
|
||||
}, []);*/
|
||||
useEffect(() => {
|
||||
getKnowledgeOptionData();
|
||||
}, []);
|
||||
|
||||
/* const getKnowledgeOptionData = () => {
|
||||
GetChapterTreeApi({ bookId }).then((res: any) => {
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
form.resetFields();
|
||||
setFileName('');
|
||||
setFilePath('');
|
||||
setFileSize(0);
|
||||
setKnowledgeCode('');
|
||||
};
|
||||
}, []);
|
||||
|
||||
const getKnowledgeOptionData = () => {
|
||||
getKnowledgeListApi(bookId).then((res: any) => {
|
||||
const resData: any = res.data;
|
||||
// console.log(resData, '>>>');
|
||||
setKnowledgeOption(resData);
|
||||
const knowledgeOption: { label: string; value: number }[] = defaultData.map(
|
||||
(item: { name: string; id: number }) => ({
|
||||
label: `${item.name}`, // 如:"极限与连续 (基础)" (${item.type})
|
||||
value: item.id,
|
||||
})
|
||||
);
|
||||
setKnowledgeOption(knowledgeOption);
|
||||
});
|
||||
};*/
|
||||
};
|
||||
|
||||
const getDetail = () => {
|
||||
setSpinInit(false);
|
||||
GetDetailApi(resourceId)
|
||||
.then((res: any) => {
|
||||
if (!res || !res.data) {
|
||||
message.error('获取详情失败');
|
||||
setSpinInit(false);
|
||||
return;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
message.error('获取详情失败');
|
||||
setSpinInit(false);
|
||||
console.error('获取详情失败:', err);
|
||||
});
|
||||
};
|
||||
|
||||
const onFinish = (values: any) => {
|
||||
console.log('表单提交:', values);
|
||||
|
||||
const { name = '', txtDesc = '', chapterId = '' } = values;
|
||||
|
||||
const { name = '', txtDesc = '', knowledgeCode = '' } = values;
|
||||
try {
|
||||
if (isEdit) {
|
||||
/*UpdateTextbookApi(
|
||||
editId,
|
||||
values.title,
|
||||
thumb,
|
||||
values.short_desc,
|
||||
values.author,
|
||||
values.major,
|
||||
dep_ids,
|
||||
group_ids,
|
||||
user_ids,
|
||||
values.publish_time,
|
||||
values.publish_unit,
|
||||
values.create_time,
|
||||
values.isbn
|
||||
)
|
||||
.then((res: any) => {
|
||||
setLoading(false);
|
||||
message.success(t('commen.saveSuccess'));
|
||||
onCancel();
|
||||
})
|
||||
.catch((e) => {
|
||||
setLoading(false);
|
||||
});*/
|
||||
} else {
|
||||
AddResourceItemApi(
|
||||
UpdateResourceItemApi(
|
||||
resourceId,
|
||||
bookId,
|
||||
name,
|
||||
knowledgeCode,
|
||||
txtDesc,
|
||||
fileExtension,
|
||||
fileSize,
|
||||
filePath,
|
||||
chapterId
|
||||
filePath
|
||||
)
|
||||
.then((res: any) => {
|
||||
setLoading(false);
|
||||
setSpinInit(false);
|
||||
message.success(t('commen.saveSuccess'));
|
||||
onCancel();
|
||||
})
|
||||
.catch((e) => {
|
||||
setLoading(false);
|
||||
setSpinInit(false);
|
||||
});
|
||||
} else {
|
||||
console.log(bookId, name, knowledgeCode, txtDesc, fileExtension, fileSize, filePath);
|
||||
AddResourceItemApi(bookId, name, knowledgeCode, txtDesc, fileExtension, fileSize, filePath)
|
||||
.then((res: any) => {
|
||||
setSpinInit(false);
|
||||
message.success(t('commen.saveSuccess'));
|
||||
onCancel();
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log(e, 'error');
|
||||
setSpinInit(false);
|
||||
});
|
||||
}
|
||||
onCancel();
|
||||
@ -117,6 +209,7 @@ const CreateResourceModal = (props: ModalPropsType) => {
|
||||
|
||||
const handleSelectChange = (e: any) => {
|
||||
console.log(e, '>>.select e');
|
||||
setKnowledgeCode(e.join(','));
|
||||
};
|
||||
|
||||
const onFinishFailed = (errorInfo: any) => {
|
||||
@ -160,14 +253,6 @@ const CreateResourceModal = (props: ModalPropsType) => {
|
||||
>
|
||||
<TextArea allowClear placeholder={t('textbook.resource.descPlaceholder')} />
|
||||
</Form.Item>
|
||||
|
||||
{/* <Dragger {...uploadProps}>
|
||||
<p className="ant-upload-drag-icon">
|
||||
<InboxOutlined />
|
||||
</p>
|
||||
<p className="ant-upload-text">{t('textbook.resource.uploadTips')}</p>
|
||||
<p className="ant-upload-hint">{t('textbook.resource.uploadTips2')}</p>
|
||||
</Dragger>*/}
|
||||
<Form.Item
|
||||
name="path"
|
||||
label={t('textbook.resource.upload')}
|
||||
@ -215,15 +300,20 @@ const CreateResourceModal = (props: ModalPropsType) => {
|
||||
<Form.Item
|
||||
name="knowledge"
|
||||
label={t('textbook.resource.knowledgeId')}
|
||||
rules={[{ required: true, message: t('textbook.resource.konwledgePlaceholder') }]}
|
||||
rules={[{ required: true, message: t('textbook.resource.knowledgePlaceholder') }]}
|
||||
>
|
||||
<Select
|
||||
mode="multiple"
|
||||
placeholder="Please select"
|
||||
defaultValue={[]}
|
||||
placeholder={t('textbook.resource.knowledgePlaceholder')}
|
||||
defaultValue={knowledgeCode ? [knowledgeCode] : []}
|
||||
onChange={handleSelectChange}
|
||||
style={{ width: '100%' }}
|
||||
options={knowledgeOption}
|
||||
showSearch
|
||||
//@ts-ignore
|
||||
filterOption={(input: string, option: { label: string; value: number }) =>
|
||||
(option?.label ?? '')?.toLowerCase().includes(input.toLowerCase())
|
||||
}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
|
||||
@ -2,7 +2,7 @@ import { useEffect, useState, useRef } from 'react';
|
||||
import { Upload, message, Progress, List, Button, Space } from 'antd';
|
||||
import { InboxOutlined, CloseOutlined, FileOutlined } from '@ant-design/icons';
|
||||
import type { UploadProps } from 'antd';
|
||||
import { getTenant, getToken } from '../../../../utils';
|
||||
import { formatFileSize, getTenant, getToken } from '../../../../utils';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import config from '../../../../js/config';
|
||||
|
||||
@ -92,7 +92,6 @@ export const DraggerUpload = (props: IProps) => {
|
||||
// 检查文件类型(仅对其他类型做限制)
|
||||
const checkFileType = (file: File): boolean => {
|
||||
if (typeId && typeId !== 5) return true;
|
||||
|
||||
const extension = getFileExtension(file.name);
|
||||
const restrictedExtensions = [
|
||||
'mp4',
|
||||
@ -119,7 +118,6 @@ export const DraggerUpload = (props: IProps) => {
|
||||
message.error(t('textbook.resource.restrictedFileType'));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
@ -285,19 +283,13 @@ export const DraggerUpload = (props: IProps) => {
|
||||
return false;
|
||||
}
|
||||
|
||||
return checkFileType(file);
|
||||
if (typeId) {
|
||||
checkFileType(file);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
// 格式化文件大小
|
||||
const formatFileSize = (bytes: number) => {
|
||||
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 getStatusInfo = (status: UploadFileItem['status']) => {
|
||||
switch (status) {
|
||||
|
||||
@ -25,14 +25,15 @@
|
||||
justify-content: space-between;
|
||||
margin-bottom: 16px;
|
||||
.btns{
|
||||
width: 70%;
|
||||
width: 56%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: end;
|
||||
align-items: baseline;
|
||||
}
|
||||
.types{
|
||||
width: 30%;
|
||||
min-width: 475px;
|
||||
width: 44%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: start;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Button, Input, message, Modal, Radio, Space, Table, TableProps } from 'antd';
|
||||
import { Button, Image, Input, message, Modal, Radio, Space, Table, TableProps, Tag } from 'antd';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { GetResourceListApi, DelResourceItemApi, GetDetailApi } from '../../api/textbook';
|
||||
import styles from './resource.module.less';
|
||||
@ -7,28 +7,54 @@ 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';
|
||||
const MusicSvg: React.FC = () => (
|
||||
<svg
|
||||
className="icon"
|
||||
viewBox="0 0 1024 1024"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="30"
|
||||
height="30"
|
||||
>
|
||||
<path
|
||||
d="M320 192 1024 0 1024 64 1024 192 1024 736C1024 824.352 923.712 896 800 896 676.288 896 576 824.352 576 736 576 647.648 676.288 576 800 576 834.368 576 866.912 581.536 896 591.392L896 261.824 448 384 448 864C448 952.352 347.712 1024 224 1024 100.288 1024 0 952.352 0 864 0 775.648 100.288 704 224 704 258.368 704 290.912 709.536 320 719.392L320 384 320 192Z"
|
||||
fill="#628eee"
|
||||
></path>
|
||||
</svg>
|
||||
);
|
||||
import {
|
||||
DeleteOutlined,
|
||||
EyeOutlined,
|
||||
FileTextFilled,
|
||||
FileTextTwoTone,
|
||||
FileUnknownTwoTone,
|
||||
PlayCircleOutlined,
|
||||
UploadOutlined,
|
||||
VideoCameraFilled,
|
||||
} from '@ant-design/icons';
|
||||
import CreateResourceModal from './compenents/Resource/CreateResourceModal';
|
||||
import { dateFormatNoTime, formatFileSize } from '../../utils';
|
||||
import defaultThumb1 from '../../assets/thumb/thumb1.png';
|
||||
|
||||
interface ResourceBase {
|
||||
id: number | null | string | undefined; // 资源id
|
||||
typeId: number; // 分类Id
|
||||
id: string; // 资源id
|
||||
typeId?: number | string; // 分类Id
|
||||
bookId: 0;
|
||||
chapterId: 0;
|
||||
chapterId?: 0;
|
||||
chapterTitle?: string;
|
||||
name: string;
|
||||
type: string;
|
||||
ext: string;
|
||||
ext?: string;
|
||||
size: 0;
|
||||
duration: 0;
|
||||
duration?: 0;
|
||||
url: string;
|
||||
cover: string;
|
||||
status: 0;
|
||||
creator: string;
|
||||
updater: string;
|
||||
cover?: string;
|
||||
status?: 0;
|
||||
creator?: string;
|
||||
updater?: string;
|
||||
createTime: string;
|
||||
updateTime: string;
|
||||
tenantId: string;
|
||||
updateTime?: string;
|
||||
tenantId?: string;
|
||||
}
|
||||
|
||||
// 列表展示
|
||||
@ -51,6 +77,8 @@ const ResourcePage = () => {
|
||||
const { bookId } = useParams();
|
||||
const [isEdit, setIsEdit] = useState(false); // 是否编辑模式
|
||||
const [editId, setEditId] = useState<number>(0);
|
||||
const [itemDetailData, setItemDetailData] = useState<ResourceBase>();
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [isAddModalOpen, setIsAddModalOpen] = useState<boolean>(false);
|
||||
const [confirmLoading, setConfirmLoading] = useState(false);
|
||||
const [modalVisible, setModalVisible] = useState(false);
|
||||
@ -76,136 +104,218 @@ const ResourcePage = () => {
|
||||
{ label: t('textbook.resource.typeList.audio'), value: 4, color: '#f3e8ff' },
|
||||
{ label: t('textbook.resource.typeList.other'), value: 5, color: '#f3f4f6' },
|
||||
];
|
||||
const bgColors = ['#dbeafe', '#dcfce7', '#fef9c3', '#f3e8ff', '#f3f4f6'];
|
||||
const fontColors = ['#4649c1', '#1a6838', '#98692b', '#6e26aa', '#434b57'];
|
||||
|
||||
// 排序字段/**/
|
||||
/* name
|
||||
size createTime这三个*/
|
||||
// 列表数据
|
||||
const columns: TableProps<ResourceBase>['columns'] = [
|
||||
const demoData = [
|
||||
{
|
||||
title: t('textbook.resource.title1'),
|
||||
dataIndex: 'softNo',
|
||||
align: 'left',
|
||||
width: 300,
|
||||
sorter: true,
|
||||
key: '1',
|
||||
id: '1',
|
||||
name: '课程介绍视频.mp4',
|
||||
chapterTitle: '第1章 课程概述 - 1.1 课程简介',
|
||||
type: '视频',
|
||||
typeId: '1',
|
||||
createTime: '2024-01-15',
|
||||
size: 12500000, // 用于排序的数值
|
||||
},
|
||||
{
|
||||
title: t('textbook.resource.title2'),
|
||||
dataIndex: 'softwareName',
|
||||
align: 'left',
|
||||
},
|
||||
key: '2',
|
||||
id: '2',
|
||||
|
||||
{
|
||||
title: t('textbook.resource.title3'),
|
||||
dataIndex: 'company',
|
||||
ellipsis: true,
|
||||
sorter: true,
|
||||
name: '课程大纲图.jpg',
|
||||
chapterTitle: '第1章 课程概述 - 1.1 课程简介',
|
||||
type: '图片',
|
||||
typeId: '2',
|
||||
url: '',
|
||||
createTime: '2024-01-10',
|
||||
size: 2400000,
|
||||
},
|
||||
{
|
||||
title: t('textbook.resource.title4'),
|
||||
dataIndex: 'version',
|
||||
align: 'left',
|
||||
ellipsis: true,
|
||||
width: 140,
|
||||
sorter: true,
|
||||
id: '3',
|
||||
key: '3',
|
||||
name: '第一套练习题.pdf',
|
||||
chapterTitle: '第1章 课程概述',
|
||||
type: '文档',
|
||||
typeId: '3',
|
||||
|
||||
createTime: '2024-01-12',
|
||||
size: 1800000,
|
||||
},
|
||||
{
|
||||
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>
|
||||
),
|
||||
id: '4',
|
||||
key: '4',
|
||||
name: '课程导入音频.mp3',
|
||||
chapterTitle: '第1章 课程概述 - 1.1 课程简介',
|
||||
type: '音频',
|
||||
typeId: '4',
|
||||
|
||||
createTime: '2024-01-14',
|
||||
size: 5200000,
|
||||
},
|
||||
];
|
||||
|
||||
// @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);
|
||||
const columns: TableProps<ResourceBase>['columns'] = [
|
||||
{
|
||||
title: t('textbook.resource.title1'),
|
||||
dataIndex: 'name',
|
||||
align: 'left',
|
||||
width: 500,
|
||||
sorter: true,
|
||||
render: (name: string, record) => (
|
||||
<div className="d-flex">
|
||||
<div
|
||||
style={{
|
||||
width: 58,
|
||||
height: 58,
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderRadius: '6px',
|
||||
background: '#f3f4f6',
|
||||
textAlign: 'center',
|
||||
marginRight: 15,
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
{record.typeId == '1' && (
|
||||
<VideoCameraFilled style={{ fontSize: 30, color: '#628eee' }} />
|
||||
)}{' '}
|
||||
{record.typeId == '2' && (
|
||||
<Image
|
||||
src={record.url}
|
||||
width={58}
|
||||
height={58}
|
||||
preview={false}
|
||||
fallback={defaultThumb1}
|
||||
/>
|
||||
)}
|
||||
{record.typeId == '3' && <FileTextFilled style={{ fontSize: 30, color: '#628eee' }} />}
|
||||
{record.typeId == '4' && <MusicSvg />}
|
||||
{record.typeId == '5' && (
|
||||
<FileUnknownTwoTone style={{ fontSize: 30, color: '#628eee' }} />
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ fontWeight: 'bold', fontSize: '14px', marginBottom: '4px' }}>{name}</div>
|
||||
<div style={{ color: '#666', fontSize: '12px' }}>{record?.chapterTitle}</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t('textbook.resource.title2'),
|
||||
dataIndex: 'typeId',
|
||||
key: 'typeId',
|
||||
align: 'center',
|
||||
width: 100,
|
||||
render: (typeId: number, record) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
borderRadius: '20px',
|
||||
width: 60,
|
||||
height: 30,
|
||||
lineHeight: '30px',
|
||||
backgroundColor: bgColors[Number(typeId) - 1],
|
||||
color: fontColors[Number(typeId) - 1],
|
||||
}}
|
||||
>
|
||||
{record.type}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('textbook.resource.title3'),
|
||||
dataIndex: 'size',
|
||||
ellipsis: true,
|
||||
sorter: true,
|
||||
key: 'size',
|
||||
width: 150,
|
||||
align: 'center',
|
||||
render: (size) => <span style={{ fontWeight: 500 }}>{formatFileSize(size)}</span>,
|
||||
},
|
||||
{
|
||||
title: t('textbook.resource.title4'),
|
||||
align: 'left',
|
||||
ellipsis: true,
|
||||
width: 180,
|
||||
sorter: true,
|
||||
dataIndex: 'createTime',
|
||||
key: 'createTime',
|
||||
render: (createTime: string) => {
|
||||
return <span style={{ color: 'gray' }}>{dateFormatNoTime(createTime)}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('textbook.resource.title5'),
|
||||
align: 'center',
|
||||
width: 240,
|
||||
render: (_, record) => {
|
||||
return (
|
||||
<Space
|
||||
size="middle"
|
||||
style={{ display: 'flex', justifyContent: 'space-around', alignItems: 'center' }}
|
||||
>
|
||||
<a
|
||||
key="pre"
|
||||
onClick={() => {
|
||||
console.log('预览');
|
||||
}}
|
||||
>
|
||||
{t('commen.preview')}
|
||||
</a>
|
||||
<a
|
||||
key={'edit'}
|
||||
onClick={() => {
|
||||
setEditId(Number(record.id));
|
||||
setIsAddModalOpen(true);
|
||||
}}
|
||||
>
|
||||
{t('commen.edit')}
|
||||
</a>
|
||||
<a key={'del'} className="b-link c-red" onClick={() => showDeleteConfirm(record.id)}>
|
||||
{/*<DeleteOutlined />*/}
|
||||
{t('commen.del')}
|
||||
</a>
|
||||
</Space>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const getResourceList = () => {
|
||||
GetResourceListApi(page, pageSize, type, sortOrder, sortField, searchData)
|
||||
.then((res: any) => {
|
||||
// @ts-ignore
|
||||
setResource(demoData);
|
||||
setResourceTotal(demoData.length);
|
||||
setResourceTotal(res.data.total);
|
||||
} else {
|
||||
console.warn('接口返回数据结构异常:', res);
|
||||
setResource([]); // 设置为空数组防止崩溃
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取列表失败:', error);
|
||||
}
|
||||
setLoading(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
setLoading(false);
|
||||
setResource([]);
|
||||
});
|
||||
};
|
||||
|
||||
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) {
|
||||
const resetVirtualList = () => {
|
||||
GetResourceListApi(1, 10, null, null, null, null)
|
||||
.then((res: any) => {
|
||||
setResource(res.data.records || []);
|
||||
setResourceTotal(res.data.total);
|
||||
} else {
|
||||
console.warn('接口返回数据结构异常:', res);
|
||||
setResource([]); // 设置为空数组防止崩溃
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取列表失败:', error);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.warn('接口返回数据结构异常:', error);
|
||||
setResource([]);
|
||||
});
|
||||
};
|
||||
|
||||
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) => {
|
||||
const showDeleteConfirm = (id: string) => {
|
||||
setSelectedId(id);
|
||||
setModalVisible(true);
|
||||
};
|
||||
@ -213,31 +323,33 @@ const ResourcePage = () => {
|
||||
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);
|
||||
}
|
||||
DelResourceItemApi(selectedId.toString())
|
||||
.then(() => {
|
||||
message.success('删除成功');
|
||||
getResourceList();
|
||||
setConfirmLoading(false);
|
||||
setModalVisible(false);
|
||||
setSelectedId(null);
|
||||
})
|
||||
.catch((err) => {
|
||||
setConfirmLoading(false);
|
||||
setModalVisible(false);
|
||||
setSelectedId(null);
|
||||
message.error('删除失败');
|
||||
console.error('删除失败:', err);
|
||||
});
|
||||
};
|
||||
|
||||
//弹窗取消
|
||||
|
||||
const showAddSoftModal = () => {
|
||||
setIsEdit(false); // 设置为新增模式
|
||||
setSelectedId(null); // 清除选中 ID
|
||||
setIsEdit(false);
|
||||
setSelectedId(null);
|
||||
setIsAddModalOpen(true);
|
||||
};
|
||||
|
||||
const handleCancelDeleteItem = () => {
|
||||
setModalVisible(false);
|
||||
};
|
||||
|
||||
const handleCancelDeleteItems = () => {
|
||||
setIsConfirmModalOpen(false);
|
||||
};
|
||||
@ -247,6 +359,8 @@ const ResourcePage = () => {
|
||||
setType(0);
|
||||
setSelectedIdList([]);
|
||||
setSearchData('');
|
||||
setSortOrder('');
|
||||
setSortField('');
|
||||
resetVirtualList();
|
||||
};
|
||||
// 批量删除
|
||||
@ -254,22 +368,25 @@ const ResourcePage = () => {
|
||||
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 toDeleteSoftwareList = () => {
|
||||
const selectedIdListString = selectedIdList.join(',');
|
||||
DelResourceItemApi(selectedIdListString)
|
||||
.then(() => {
|
||||
message.success('删除成功');
|
||||
setConfirmLoading(false);
|
||||
setIsConfirmModalOpen(false);
|
||||
setSelectedId(null);
|
||||
setSelectedIdList([]);
|
||||
getResourceList();
|
||||
})
|
||||
.catch((err) => {
|
||||
message.error('删除失败');
|
||||
console.error('删除失败:', err);
|
||||
setConfirmLoading(false);
|
||||
setIsConfirmModalOpen(false);
|
||||
setSelectedId(null);
|
||||
setSelectedIdList([]);
|
||||
});
|
||||
};
|
||||
|
||||
const handleAddCancel = () => {
|
||||
@ -282,7 +399,7 @@ const ResourcePage = () => {
|
||||
useEffect(() => {
|
||||
setResource([]);
|
||||
getResourceList();
|
||||
}, [refresh, page, pageSize, type, searchData]);
|
||||
}, [refresh, page, pageSize, type, sortOrder, sortField]);
|
||||
|
||||
const onSelectChange = (newSelectedRowKeys: any[]) => {
|
||||
setSelectedIdList(newSelectedRowKeys);
|
||||
@ -294,26 +411,21 @@ const ResourcePage = () => {
|
||||
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' : '';
|
||||
const sField = sorter.field as string;
|
||||
const sOrder = sorter.order === 'ascend' ? 'asc' : sorter.order === 'descend' ? 'desc' : '';
|
||||
console.log('排序字段:', sortField, '排序方向:', sortOrder);
|
||||
setSortField(sField);
|
||||
setSortOrder(sOrder);
|
||||
}
|
||||
};
|
||||
|
||||
@ -363,7 +475,7 @@ const ResourcePage = () => {
|
||||
<div className={styles.btns}>
|
||||
<Input
|
||||
placeholder={t('textbook.resource.searchPlaceholder')}
|
||||
style={{ marginRight: 15, width: 360 }}
|
||||
style={{ marginRight: 15, width: 220 }}
|
||||
value={searchData}
|
||||
allowClear
|
||||
onChange={(e) => setSearchData(e.target.value)}
|
||||
@ -405,8 +517,8 @@ const ResourcePage = () => {
|
||||
current: page,
|
||||
total: resourceTotal,
|
||||
showSizeChanger: true,
|
||||
align: 'start',
|
||||
showTotal: (total) => `共 ${resourceTotal} 条记录`,
|
||||
align: 'end',
|
||||
showTotal: () => `共 ${resourceTotal} 条记录`,
|
||||
}}
|
||||
// @ts-ignore
|
||||
onChange={handleTableChange}
|
||||
@ -431,7 +543,7 @@ const ResourcePage = () => {
|
||||
onCancel={handleCancelDeleteItem}
|
||||
confirmLoading={confirmLoading}
|
||||
>
|
||||
<p>确定要删除这个软件吗?</p>
|
||||
<p>确定要删除这条信息吗?</p>
|
||||
</Modal>
|
||||
{/*多个删除确认*/}
|
||||
<Modal
|
||||
@ -441,7 +553,7 @@ const ResourcePage = () => {
|
||||
onCancel={handleCancelDeleteItems}
|
||||
confirmLoading={confirmLoading}
|
||||
>
|
||||
<p>确定要删除这些软件吗?</p>
|
||||
<p>确定要删除这些信息吗?</p>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
|
||||
@ -408,3 +408,16 @@ export const dataURLtoBlob = (dataurl: string): Blob => {
|
||||
export const getFileExtension = (filename: string): string => {
|
||||
return filename.slice(((filename.lastIndexOf('.') - 1) >>> 0) + 2);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取文件大小
|
||||
*/
|
||||
|
||||
// 格式化文件大小
|
||||
export const formatFileSize = (bytes: number) => {
|
||||
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];
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user