|
|
@@ -0,0 +1,364 @@
|
|
|
+import * as React from 'react';
|
|
|
+import { generatePath, useParams, useLocation } from 'react-router-dom';
|
|
|
+import { observer } from 'mobx-react';
|
|
|
+
|
|
|
+import config, { getHeaders } from '@/apis/config';
|
|
|
+
|
|
|
+import {
|
|
|
+ Button,
|
|
|
+ Table,
|
|
|
+ TableColumnsType,
|
|
|
+ Modal,
|
|
|
+ TablePaginationConfig,
|
|
|
+ Upload,
|
|
|
+ UploadProps,
|
|
|
+ message,
|
|
|
+ Spin
|
|
|
+} from 'antd';
|
|
|
+import { EditOutlined, DeleteOutlined, InboxOutlined, PlusOutlined, ArrowLeftOutlined } from '@ant-design/icons';
|
|
|
+import InfoModal from './components/InfoModal';
|
|
|
+import InfoModalSetting from './components/InfoModalSetting';
|
|
|
+import router from '@/router';
|
|
|
+import { Record } from './types';
|
|
|
+import dayjs from 'dayjs';
|
|
|
+import axios from 'axios';
|
|
|
+import LocalStorage from '@/LocalStorage';
|
|
|
+import store from './store';
|
|
|
+import './style.less';
|
|
|
+
|
|
|
+const { Dragger } = Upload;
|
|
|
+interface Props{
|
|
|
+ drawerItem: any;
|
|
|
+}
|
|
|
+
|
|
|
+const KnowledgeLibInfo : React.FC<Props> = ({drawerItem}:Props) => {
|
|
|
+ const params = {
|
|
|
+ knowledgeId: drawerItem.value,
|
|
|
+ ...drawerItem,
|
|
|
+ }
|
|
|
+
|
|
|
+ const {
|
|
|
+ state,
|
|
|
+ init,
|
|
|
+ onClickModify,
|
|
|
+ onClickDelete,
|
|
|
+ onChangePagination,
|
|
|
+ onClickDocumentDetail,
|
|
|
+ infoModalOnClickConfirm,
|
|
|
+ infoModalOnClickCancel,
|
|
|
+ infoModalSettingOnClickConfirm,
|
|
|
+ infoModalSettingOnClickCancel,
|
|
|
+ onClickSettings,
|
|
|
+ reset
|
|
|
+ } = store;
|
|
|
+ const {
|
|
|
+ knowledge_id,
|
|
|
+ listLoading,
|
|
|
+ page,
|
|
|
+ list,
|
|
|
+ infoModalOpen,
|
|
|
+ infoModalId,
|
|
|
+ infoModalSettingOpen,
|
|
|
+ infoModalSettingId,
|
|
|
+ knowledgeDetail,
|
|
|
+ } = state;
|
|
|
+ const location = useLocation();
|
|
|
+ const [ uploadLoading, setUploadLoading ] = React.useState( false );
|
|
|
+
|
|
|
+
|
|
|
+ const [ fileList, setFileList ] = React.useState<any[]>( [] );
|
|
|
+ const [ uploading, setUploading ] = React.useState( false );
|
|
|
+
|
|
|
+ const [ sListFlag, setSListFlag ] = React.useState<boolean>();
|
|
|
+ const [ cUpdateFlag, setCUpdateFlag ] = React.useState<boolean>();
|
|
|
+ const [ detailFlag, setDetailFlag ] = React.useState<boolean>();
|
|
|
+ const [ deleteFlag, setDeleteFlag ] = React.useState<boolean>();
|
|
|
+ const [ createFlag, setCreateFlag ] = React.useState<boolean>();
|
|
|
+ const [userInfoAll, setUserInfoAll] = React.useState<any>({});
|
|
|
+
|
|
|
+ const props : UploadProps = {
|
|
|
+ name: 'files',
|
|
|
+ multiple: true,
|
|
|
+ action: '/api/deepseek/api/uploadDocument/' + params.knowledgeId,
|
|
|
+ headers: getHeaders(),
|
|
|
+ beforeUpload( file, fileList ) {
|
|
|
+ setUploadLoading( true );
|
|
|
+ // const allowedExtensions = ['md', 'txt', 'pdf', 'jpg', 'png', 'jpeg', 'docx', 'xlsx', 'pptx', 'eml', 'csv', 'tar', 'gz', 'bz2', 'zip', 'rar', 'jar'];
|
|
|
+
|
|
|
+ const allowedExtensions = [ 'txt', 'pdf', 'jpg', 'png', 'jpeg', 'doc', 'docx', 'ppt', 'pptx' ];
|
|
|
+
|
|
|
+ // 检查文件类型
|
|
|
+ for ( const file of fileList ) {
|
|
|
+ const fileExt = file.name.split( '.' ).pop()?.toLowerCase();
|
|
|
+ if ( !fileExt || !allowedExtensions.includes( fileExt ) ) {
|
|
|
+ message.error( `不支持 ${ fileExt } 格式的文件上传` );
|
|
|
+ setUploadLoading( false );
|
|
|
+ return Upload.LIST_IGNORE;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查文件大小
|
|
|
+ let totalSize = 0;
|
|
|
+ for ( const file of fileList ) {
|
|
|
+ const fileExt = file.name.split( '.' ).pop()?.toLowerCase();
|
|
|
+ const fileSizeMB = file.size / 1024 / 1024;
|
|
|
+
|
|
|
+ if ( fileSizeMB > 30 ) {
|
|
|
+ message.error( '单个文件不能大于30M' );
|
|
|
+ setUploadLoading( false );
|
|
|
+ return Upload.LIST_IGNORE;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( [ 'jpg', 'png', 'jpeg' ].includes( fileExt! ) && fileSizeMB > 5 ) {
|
|
|
+ message.error( '单张图片不能大于5M' );
|
|
|
+ setUploadLoading( false );
|
|
|
+ return Upload.LIST_IGNORE;
|
|
|
+ }
|
|
|
+
|
|
|
+ totalSize += fileSizeMB;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( totalSize > 125 ) {
|
|
|
+ message.error( '文件总大小超过125M' );
|
|
|
+ setUploadLoading( false );
|
|
|
+ return Upload.LIST_IGNORE;
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+ onChange( info ) {
|
|
|
+ const { status } = info.file;
|
|
|
+
|
|
|
+ if ( status !== 'uploading' ) {
|
|
|
+ console.log( status, 'status--uploading' );
|
|
|
+ }
|
|
|
+ if ( status === 'done' ) {
|
|
|
+ console.log( status, 'status--done' );
|
|
|
+ console.info( info.file.response, 'info.file.response.data' );
|
|
|
+ if ( info.file.response.code === 200 && info.file.response.data === 1 ) {
|
|
|
+ message.success( `${ info.file.name } file uploaded successfully.` );
|
|
|
+ init( params.knowledgeId );
|
|
|
+ }
|
|
|
+ setUploadLoading( false );
|
|
|
+ } else if ( status === 'error' ) {
|
|
|
+ console.log( status, 'status--error' );
|
|
|
+ message.error( `${ info.file.name } file upload failed.` );
|
|
|
+ setUploadLoading( false );
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onDrop( e ) {
|
|
|
+ console.log( 'Dropped files', e.dataTransfer.files );
|
|
|
+ },
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleUpload = async () => {
|
|
|
+ if ( fileList.length === 0 ) return;
|
|
|
+
|
|
|
+ setUploading( true );
|
|
|
+ const formData = new FormData();
|
|
|
+
|
|
|
+ // 添加所有文件
|
|
|
+ fileList.forEach( file => {
|
|
|
+ if ( file.originFileObj ) {
|
|
|
+ formData.append( 'files', file.originFileObj );
|
|
|
+ }
|
|
|
+ } );
|
|
|
+
|
|
|
+ try {
|
|
|
+ const res = await axios.post( '/api/deepseek/api/uploadDocument/' + params.knowledgeId, formData, {
|
|
|
+ headers: { 'Content-Type': 'multipart/form-data' }
|
|
|
+ } );
|
|
|
+
|
|
|
+ message.success( `${ fileList.length }个文件上传成功` );
|
|
|
+ setFileList( [] );
|
|
|
+ } catch ( err ) {
|
|
|
+ message.error( '上传失败' );
|
|
|
+ } finally {
|
|
|
+ setUploading( false );
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ React.useEffect( () => {
|
|
|
+ init( params.knowledgeId );
|
|
|
+ const cList = LocalStorage.getStatusFlag( 'deepseek:slice:list' );
|
|
|
+ setSListFlag( cList );
|
|
|
+ const cDetail = LocalStorage.getStatusFlag( 'deepseek:config:update' );
|
|
|
+ setCUpdateFlag( cDetail );
|
|
|
+ const detail = LocalStorage.getStatusFlag( 'deepseek:document:detail' );
|
|
|
+ setDetailFlag( detail );
|
|
|
+ const deleteF = LocalStorage.getStatusFlag( 'deepseek:document:delete' );
|
|
|
+ setDeleteFlag( deleteF );
|
|
|
+ const createF = LocalStorage.getStatusFlag( 'deepseek:document:create' );
|
|
|
+ setCreateFlag( createF );
|
|
|
+ setUserInfoAll(LocalStorage.getUserInfo());
|
|
|
+ return () => reset();
|
|
|
+ }, [params.knowledgeId] );
|
|
|
+
|
|
|
+ const columns : TableColumnsType<Record> = [
|
|
|
+ {
|
|
|
+ title: '序号',
|
|
|
+ dataIndex: 'index',
|
|
|
+ width: 80,
|
|
|
+ render: ( text, record, index ) => {
|
|
|
+ return index + 1;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '文件名',
|
|
|
+ dataIndex: 'name',
|
|
|
+ width: 300,
|
|
|
+ sorter: (a, b) => a.name.localeCompare(b.name),
|
|
|
+ render: ( text, record ) => {
|
|
|
+ return (
|
|
|
+ `${ text }`
|
|
|
+ )
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '文件大小',
|
|
|
+ dataIndex: 'length',
|
|
|
+ width: 100,
|
|
|
+ render: ( text ) => {
|
|
|
+ if ( text ) {
|
|
|
+ const size = ( text / 1024 / 1024 ).toFixed( 2 );
|
|
|
+ return `${ size } M`;
|
|
|
+ } else {
|
|
|
+ return '--'
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '字符数量',
|
|
|
+ dataIndex: 'wordNum',
|
|
|
+ width: 100,
|
|
|
+ render: ( text ) => {
|
|
|
+ if ( text ) {
|
|
|
+ return `${ text }`;
|
|
|
+ } else {
|
|
|
+ return '--'
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '分段',
|
|
|
+ dataIndex: 'sliceTotal',
|
|
|
+ width: 100,
|
|
|
+ render: ( text ) => {
|
|
|
+ if ( text ) {
|
|
|
+ return `${ text }`;
|
|
|
+ } else {
|
|
|
+ return '--';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '上传时间',
|
|
|
+ dataIndex: 'createTime',
|
|
|
+ width: 180,
|
|
|
+ render: ( text ) => {
|
|
|
+ if ( text ) {
|
|
|
+ return dayjs( text ).format( 'YYYY-MM-DD HH:mm:ss' );
|
|
|
+ } else {
|
|
|
+ return '--';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '更新时间',
|
|
|
+ dataIndex: 'updateTime',
|
|
|
+ width: 180,
|
|
|
+ render: ( text ) => {
|
|
|
+ if ( text ) {
|
|
|
+ return dayjs( text ).format( 'YYYY-MM-DD HH:mm:ss' );
|
|
|
+ } else {
|
|
|
+ return '--';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '操作',
|
|
|
+ dataIndex: 'operation',
|
|
|
+ width: 80,
|
|
|
+ fixed: 'right',
|
|
|
+ render: ( text, record:any ) => {
|
|
|
+ return (
|
|
|
+ <>
|
|
|
+ {
|
|
|
+ <a
|
|
|
+ style={ { marginRight: 16 } }
|
|
|
+ onClick={ () => {
|
|
|
+ // window.location= record.url
|
|
|
+ window.open(`${record.url}`, '_blank');
|
|
|
+ // window.open(`https://10.1.28.14:9000/deepseek-doc/%E6%95%B0%E5%AD%97%E9%A1%B9%E7%9B%AE%E7%AE%A1%E7%90%86%E5%B9%B3%E5%8F%B0%E7%94%A8%E6%88%B7%E6%93%8D%E4%BD%9C%E6%89%8B%E5%86%8C_%E9%83%A8%E5%88%863.pdf`, '_blank');
|
|
|
+ } }
|
|
|
+ >
|
|
|
+ 查看
|
|
|
+ </a>
|
|
|
+ }
|
|
|
+ </>
|
|
|
+ )
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ];
|
|
|
+
|
|
|
+ const paginationConfig : TablePaginationConfig = {
|
|
|
+ // 显示数据总量
|
|
|
+ showTotal: ( total : number ) => {
|
|
|
+ return `共 ${ total } 条`;
|
|
|
+ },
|
|
|
+ // 展示分页条数切换
|
|
|
+ showSizeChanger: true,
|
|
|
+ // 指定每页显示条数
|
|
|
+ pageSizeOptions: [ '10', '20', '50', '100' ],
|
|
|
+ // 快速跳转至某页
|
|
|
+ showQuickJumper: true,
|
|
|
+ current: page.page,
|
|
|
+ pageSize: page.size,
|
|
|
+ total: page.total,
|
|
|
+ onChange: async ( page, pageSize ) => {
|
|
|
+ await onChangePagination( page, pageSize );
|
|
|
+ },
|
|
|
+ };
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div className='knowledgeLibInfo'>
|
|
|
+ <Spin spinning={ uploadLoading || listLoading }>
|
|
|
+ {
|
|
|
+ <>
|
|
|
+ <div className='knowledgeLibInfo-table'>
|
|
|
+ <Table
|
|
|
+ scroll={ { x: 'max-content' } }
|
|
|
+ rowKey={ ( record ) => record.documentId }
|
|
|
+ loading={ listLoading }
|
|
|
+ columns={ columns }
|
|
|
+ dataSource={ list }
|
|
|
+ pagination={ paginationConfig }
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {
|
|
|
+ infoModalOpen &&
|
|
|
+ <InfoModal
|
|
|
+ id={ infoModalId }
|
|
|
+ open={ infoModalOpen }
|
|
|
+ onClickConfirm={ infoModalOnClickConfirm }
|
|
|
+ onClickCancel={ infoModalOnClickCancel }
|
|
|
+ />
|
|
|
+ }
|
|
|
+
|
|
|
+ {
|
|
|
+ infoModalSettingOpen &&
|
|
|
+ <InfoModalSetting
|
|
|
+ id={ infoModalSettingId }
|
|
|
+ open={ infoModalSettingOpen }
|
|
|
+ onClickConfirm={ infoModalSettingOnClickConfirm }
|
|
|
+ onClickCancel={ infoModalSettingOnClickCancel }
|
|
|
+ />
|
|
|
+ }
|
|
|
+ </>
|
|
|
+ }
|
|
|
+ </Spin>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+export default observer( KnowledgeLibInfo );
|