17 changed files with 1604 additions and 143 deletions
			
			
		| @ -0,0 +1,339 @@ | |||||
|  | 'use strict'; | ||||
|  | 
 | ||||
|  | import React, { Component } from 'react'; | ||||
|  | import { connect } from 'react-redux'; | ||||
|  | import { Spin, Upload, message, Modal, Card, Button } from 'antd'; | ||||
|  | import moment from 'moment'; | ||||
|  | import { PlusOutlined, UploadOutlined, CloseOutlined } from '@ant-design/icons'; | ||||
|  | import { RouteRequest } from '@peace/utils'; | ||||
|  | import { RouteTable } from '$utils' | ||||
|  | const { confirm } = Modal; | ||||
|  | class Uploads extends Component { | ||||
|  |     constructor(props) { | ||||
|  |         super(props); | ||||
|  |         this.state = { | ||||
|  |             fileUploading: false, | ||||
|  |             fileList: [], | ||||
|  |             curPreviewPic: '', | ||||
|  |             delPicIng: false, | ||||
|  |             removeFilesList: [] | ||||
|  |         }; | ||||
|  |     } | ||||
|  |     dealName = (uploaded) => { | ||||
|  |         let realName = uploaded.split('/')[2] | ||||
|  |         let x1 = realName.split('.') | ||||
|  |         let x2 = x1[0].split('_') | ||||
|  |         let showName = `${x2[0]}.${x1[1]}` | ||||
|  |         return showName | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     // setFileList = (value) => {
 | ||||
|  |     //     let defaultFileList = [];
 | ||||
|  |     //     defaultFileList = value.map((u, index) => {
 | ||||
|  |     //         let fileUrl = `${this.ApiRoot}/${u.url}`;
 | ||||
|  |     //         return {
 | ||||
|  |     //             uid: -index - 1,
 | ||||
|  |     //             name: this.dealName(u.url),
 | ||||
|  |     //             status: 'done',
 | ||||
|  |     //             storageUrl: u.url,
 | ||||
|  |     //             url: fileUrl
 | ||||
|  |     //         };
 | ||||
|  |     //     });
 | ||||
|  |     //     onChange(defaultFileList)
 | ||||
|  |     //     this.setState({
 | ||||
|  |     //         fileList: defaultFileList
 | ||||
|  |     //     });
 | ||||
|  |     // };
 | ||||
|  | 
 | ||||
|  |     componentDidMount() { | ||||
|  |         const { value } = this.props; | ||||
|  |         if (value) { | ||||
|  |             // this.setState(value);
 | ||||
|  |             this.setState({ fileList: value }) | ||||
|  | 
 | ||||
|  |         } | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     componentWillReceiveProps(np) { | ||||
|  |         const { dispatch, value: thisEditData, onChange } = this.props; | ||||
|  |         const { value: nextEditData } = np; | ||||
|  | 
 | ||||
|  |         const setFileList = () => { | ||||
|  |             let defaultFileList = []; | ||||
|  |             defaultFileList = nextEditData.map((u, index) => { | ||||
|  |                 let fileUrl = u.filename; | ||||
|  |                 return { | ||||
|  |                     uid: -index - 1, | ||||
|  |                     name: u.name, | ||||
|  |                     status: 'done', | ||||
|  |                     storageUrl: u.filename, | ||||
|  |                     url: fileUrl, | ||||
|  |                     size: u.size || -1 | ||||
|  |                 }; | ||||
|  |             }); | ||||
|  |             this.setState({ | ||||
|  |                 fileList: defaultFileList | ||||
|  |             }); | ||||
|  |         }; | ||||
|  | 
 | ||||
|  |         if (nextEditData && nextEditData.length) { | ||||
|  |             if (!thisEditData || !this.state.fileList.length) { | ||||
|  |                 setFileList(); | ||||
|  |             } else if (nextEditData.length != thisEditData.length) { | ||||
|  |                 setFileList(); | ||||
|  |             } else { | ||||
|  |                 let repeat = true; | ||||
|  |                 for (let i = 0; i < thisEditData.length; i++) { | ||||
|  |                     if (thisEditData[i] != nextEditData[i]) { | ||||
|  |                         repeat = false; | ||||
|  |                         break; | ||||
|  |                     } | ||||
|  |                 } | ||||
|  |                 if (!repeat) { | ||||
|  |                     setFileList(); | ||||
|  |                 } | ||||
|  |             } | ||||
|  |         } | ||||
|  |         // else{
 | ||||
|  |         //     this.setState({
 | ||||
|  |         //         fileList:[],
 | ||||
|  |         //     })
 | ||||
|  |         // }
 | ||||
|  |     } | ||||
|  |     //删除文件
 | ||||
|  |     deleteFile(file) { | ||||
|  |         if (file.url) { | ||||
|  |             RouteRequest.delete(RouteTable.cleanUpUploadTrash, { url: file.url }); | ||||
|  |         }; | ||||
|  |     } | ||||
|  |     handleOk = (that, file, fileList, curPreviewPic, removeFilesList) => { | ||||
|  |         let nextFileList = []; | ||||
|  |         fileList.map((f, i) => { | ||||
|  |             if (f.uid != file.uid) { | ||||
|  |                 nextFileList.push(f); | ||||
|  |             } | ||||
|  |         }); | ||||
|  |         that.deleteFile(file); | ||||
|  |         let nextRemoveFiles = removeFilesList.concat([file.storageUrl]); | ||||
|  |         if (curPreviewPic == file.url) { | ||||
|  |             that.setState({ | ||||
|  |                 curPreviewPic: '' | ||||
|  |             }); | ||||
|  |         } | ||||
|  |         that.props.onChange(nextFileList); | ||||
|  |         that.setState({ | ||||
|  |             fileList: nextFileList, | ||||
|  |             removeFilesList: nextRemoveFiles | ||||
|  |         }); | ||||
|  |     } | ||||
|  |     render() { | ||||
|  |         const UploadPath = { | ||||
|  |             project: ['txt', 'dwg', 'doc', 'docx', 'xls', 'xlsx', 'pdf', 'png', 'jpg', 'rar', 'zip'], | ||||
|  |             report: ['doc', 'docx', 'xls', 'xlsx', 'pdf'], | ||||
|  |             data: ['txt', 'xls', 'xlsx'], | ||||
|  |             image: ['png', 'jpg', 'svg', 'jpeg'], | ||||
|  |             three: ['js'], | ||||
|  |             video: ['mp4'] | ||||
|  |         }; | ||||
|  |         /** | ||||
|  |          * uploadType 【string】 主要区别文件上传路径 以及类型 以 web/routes/attachment/index.js 中 UploadPath 的 key 值为准;默认 project; | ||||
|  |          * disabled 【boolean】 上传是否可用 | ||||
|  |          * maxFilesNum 【number】 最大上传数量 | ||||
|  |          * fileTypes 【array[string]】 可允许上传的文件类型; | ||||
|  |          * maxFileSize 【number】 单个文件最大大小 M | ||||
|  |          * listType 【antd】 upload 组件的属性 | ||||
|  |          * onChange 【function】 文件数量变化时候回调 返回文件 | ||||
|  |          * value 【array[obj]】 编辑数据 [{url:'xxx', [size:999]}] | ||||
|  |          * onStateChange 【function】 文件状态改变回调函数 上传中 return { uploading:true/false } | ||||
|  |          */ | ||||
|  |         const { | ||||
|  |             uploadType, | ||||
|  |             disabled, | ||||
|  |             maxFilesNum, | ||||
|  |             fileTypes, | ||||
|  |             maxFileSize, | ||||
|  |             listType, | ||||
|  |             onChange, | ||||
|  |             value, | ||||
|  |             showUploadList, | ||||
|  |             onStateChange, | ||||
|  |             addNew | ||||
|  |         } = this.props; | ||||
|  |         const { fileList, curPreviewPic, delPicIng, removeFilesList } = this.state; | ||||
|  |         const that = this; | ||||
|  |         let uploadType_ = uploadType || 'project'; | ||||
|  |         let maxFilesNum_ = maxFilesNum || 1; | ||||
|  |         let defaultFileTypes = fileTypes || UploadPath[uploadType_]; | ||||
|  |         const uploadProps = { | ||||
|  |             name: 'checkFile_', | ||||
|  |             multiple: false, | ||||
|  |             showUploadList: showUploadList || true, | ||||
|  |             action: "/_upload/new?type=project", | ||||
|  |             listType: listType || 'text', | ||||
|  |             disabled: disabled, | ||||
|  |             beforeUpload: (file) => { | ||||
|  |                 if (fileList.length >= maxFilesNum_) { | ||||
|  |                     message.warning(`最多选择${maxFilesNum_}个文件上传`); | ||||
|  |                     return false; | ||||
|  |                 } | ||||
|  |                 if (file.name.length > 60) { | ||||
|  |                     message.warning(`文件名过长(大于60字符),请修改后上传`); | ||||
|  |                     return false; | ||||
|  |                 } | ||||
|  |                 const extNames = file.name.split('.'); | ||||
|  |                 var reg = /^[\.\s\u4e00-\u9fa5a-zA-Z0-9_-]{0,}$/; | ||||
|  |                 // if (!reg.exec(file.name)) {
 | ||||
|  |                 //     message.warning(`文件名包含除字母、汉字、数字、中划线、下划线之外的字符,请修改后上传`);
 | ||||
|  |                 //     return false;
 | ||||
|  |                 // }
 | ||||
|  |                 let isDAE = false; | ||||
|  |                 if (extNames.length > 0) { | ||||
|  |                     let fileType = extNames[extNames.length - 1].toLowerCase(); | ||||
|  |                     isDAE = defaultFileTypes.some((f) => f == fileType); | ||||
|  |                 } | ||||
|  |                 if (!isDAE) { | ||||
|  |                     message.error(`只能上传 ${defaultFileTypes.join()} 格式的文件!`); | ||||
|  |                     return false; | ||||
|  |                 } | ||||
|  |                 const isLt = file.size / 1024 / 1024 < (maxFileSize || 3); | ||||
|  |                 if (!isLt) { | ||||
|  |                     message.error(`文件必须小于${maxFileSize || 3}MB!`); | ||||
|  |                     return false; | ||||
|  |                 } | ||||
|  |                 this.setState({ | ||||
|  |                     fileUploading: true | ||||
|  |                 }); | ||||
|  |                 if (onStateChange) { | ||||
|  |                     onStateChange({ uploading: true }); | ||||
|  |                 } | ||||
|  |             }, | ||||
|  |             onChange(info) { | ||||
|  |                 const status = info.file.status; | ||||
|  |                 if (status === 'uploading') { | ||||
|  |                     that.setState({ | ||||
|  |                         fileList: info.fileList | ||||
|  |                     }); | ||||
|  |                 } | ||||
|  |                 if (status === 'done') { | ||||
|  |                     let { filename } = info.file.response; | ||||
|  |                     let size = info.file.size; | ||||
|  |                     let nextFileList = fileList; | ||||
|  |                     nextFileList[nextFileList.length - 1] = { | ||||
|  |                         uid: -moment().unix(), | ||||
|  |                         name: info.file.name, | ||||
|  |                         status: 'done', | ||||
|  |                         storageUrl: filename, | ||||
|  |                         url: filename, | ||||
|  |                         size: size | ||||
|  |                     }; | ||||
|  |                     onChange(nextFileList); | ||||
|  |                     that.setState({ | ||||
|  |                         fileUploading: false, | ||||
|  |                         fileList: nextFileList | ||||
|  |                     }); | ||||
|  |                     if (onStateChange) { | ||||
|  |                         onStateChange({ uploading: false }); | ||||
|  |                     } | ||||
|  |                 } else if (status === 'error') { | ||||
|  |                     that.setState({ | ||||
|  |                         fileUploading: false | ||||
|  |                     }); | ||||
|  |                     message.error(`${info.file.name} 上传失败,请重试`); | ||||
|  |                     if (onStateChange) { | ||||
|  |                         onStateChange({ uploading: false }); | ||||
|  |                     } | ||||
|  |                 } | ||||
|  |             }, | ||||
|  |             onRemove(file) { | ||||
|  |                 // if (confirm('请确认是否删除此文件?删除后将不可恢复!') === true) {
 | ||||
|  |                 if (addNew) { | ||||
|  |                     that.handleOk(that, file, fileList, curPreviewPic, removeFilesList); | ||||
|  |                 } else { | ||||
|  |                     confirm({ | ||||
|  |                         title: '请确认是否删除此文件?删除后将不可恢复!', | ||||
|  |                         onOk() { | ||||
|  |                             that.handleOk(that, file, fileList, curPreviewPic, removeFilesList); | ||||
|  |                         }, | ||||
|  |                         onCancel() { }, | ||||
|  |                     }); | ||||
|  |                 } | ||||
|  |             }, | ||||
|  |             onPreview(file) { | ||||
|  |                 let filePostfix = file.url.split('.').pop(); | ||||
|  |                 filePostfix = filePostfix.toLowerCase(); | ||||
|  |                 if (UploadPath.image.some((img) => img == filePostfix)) { | ||||
|  |                     that.setState({ | ||||
|  |                         curPreviewPic: file.url | ||||
|  |                     }); | ||||
|  |                 } else { | ||||
|  |                     message.warn('仅支持图片预览'); | ||||
|  |                 } | ||||
|  |             } | ||||
|  |         }; | ||||
|  | 
 | ||||
|  |         let fileList_ = fileList | ||||
|  |         // .map(f => {
 | ||||
|  |         //     if (f.storageUrl) {
 | ||||
|  |         //         let realName = f.storageUrl.split('/').pop()
 | ||||
|  |         //         if (f.name != realName) {
 | ||||
|  |         //             f.name = realName
 | ||||
|  |         //         }
 | ||||
|  |         //     }
 | ||||
|  |         //     return f
 | ||||
|  |         // })
 | ||||
|  | 
 | ||||
|  |         return ( | ||||
|  |             <div> | ||||
|  |                 <Spin spinning={delPicIng}> | ||||
|  |                     <Upload {...uploadProps} fileList={fileList_}> | ||||
|  |                         { | ||||
|  |                             disabled ? ( | ||||
|  |                                 '' | ||||
|  |                             ) : | ||||
|  |                                 listType == 'picture-card' ? | ||||
|  |                                     ( | ||||
|  |                                         fileList.length >= maxFilesNum_ ? null : ( | ||||
|  |                                             <div style={{}}> | ||||
|  |                                                 <PlusOutlined /> | ||||
|  |                                                 <div>上传图片</div> | ||||
|  |                                             </div> | ||||
|  |                                         ) | ||||
|  |                                     ) : ( | ||||
|  |                                         <Button disabled={fileList.length >= maxFilesNum_} icon={<UploadOutlined />}>  文件上传 </Button> | ||||
|  |                                     ) | ||||
|  |                         } | ||||
|  |                     </Upload> | ||||
|  |                     { | ||||
|  |                         curPreviewPic ? ( | ||||
|  |                             <Card | ||||
|  |                                 bodyStyle={{ | ||||
|  |                                     padding: 8 | ||||
|  |                                 }} | ||||
|  |                             > | ||||
|  |                                 <div style={{ marginBottom: 8 }} > | ||||
|  |                                     <span>文件预览</span> | ||||
|  |                                     <span | ||||
|  |                                         style={{ float: 'right' }} | ||||
|  |                                         onClick={() => { this.setState({ curPreviewPic: '' }); }} | ||||
|  |                                     > | ||||
|  |                                         <CloseOutlined style={{ fontSize: 20 }} /> | ||||
|  |                                     </span> | ||||
|  |                                 </div> | ||||
|  |                                 <img style={{ width: '100%' }} src={curPreviewPic}></img> | ||||
|  |                             </Card> | ||||
|  |                         ) : '' | ||||
|  |                     } | ||||
|  |                 </Spin> | ||||
|  |             </div> | ||||
|  |         ); | ||||
|  |     } | ||||
|  | } | ||||
|  | 
 | ||||
|  | function mapStateToProps(state) { | ||||
|  |     const { auth } = state | ||||
|  |     return { | ||||
|  |         user: auth.user | ||||
|  |     }; | ||||
|  | } | ||||
|  | 
 | ||||
|  | export default connect(mapStateToProps)(Uploads); | ||||
| @ -0,0 +1,174 @@ | |||||
|  | import React, { useEffect, useState } from 'react'; | ||||
|  | import { Modal, Input, Form, Select, InputNumber, Tooltip, Tag, message } from 'antd'; | ||||
|  | import { UploadLocal } from '$components'; | ||||
|  | const { TextArea } = Input; | ||||
|  | const MetadataFileModal = (props) => { | ||||
|  |     const { onConfirm, onCancel, editData, metadataModels } = props; | ||||
|  |     const [form] = Form.useForm(); | ||||
|  |     const [editUrl, setEditUrl] = useState([]); | ||||
|  |     useEffect(() => { | ||||
|  |     }, []); | ||||
|  |     const handleOk = () => { | ||||
|  |         form.validateFields().then(values => { | ||||
|  |             if (onConfirm) { | ||||
|  |                 let dataSave = JSON.parse(JSON.stringify(values)); | ||||
|  |                 dataSave.attributesParam = {}; | ||||
|  |                 metadataModels.map(m => { | ||||
|  |                     dataSave.attributesParam[m.attributeCode] = values[m.attributeCode]; | ||||
|  |                     delete dataSave[m.attributeCode]; | ||||
|  |                 }) | ||||
|  |                 onConfirm(dataSave); | ||||
|  |             } | ||||
|  |         }) | ||||
|  |     } | ||||
|  |     const validatorNull = (rule, value, getFieldValue, validateFields, label) => { | ||||
|  |         if (!value || !value.trim().length) { | ||||
|  |             return Promise.reject(new Error(`${label}不可空字符串`)); | ||||
|  |         } | ||||
|  |         return Promise.resolve(); | ||||
|  |     } | ||||
|  |     const renderModelItems = () => { | ||||
|  |         const items = metadataModels.filter(mm => mm.modelType === '文件').map(m => { | ||||
|  |             if (m.control === '文本框') { | ||||
|  |                 const rules = [{ required: !m.nullable, message: '' }] | ||||
|  |                 if (!m.nullable) { | ||||
|  |                     rules.push(({ getFieldValue, validateFields }) => ({ | ||||
|  |                         validator(_, value) { return validatorNull(_, value, getFieldValue, validateFields, m.attributeName) } | ||||
|  |                     })) | ||||
|  |                     rules.push({ max: m.length, message: `${m.attributeName}不超过${m.length}个字符` }) | ||||
|  |                 } | ||||
|  |                 return <Form.Item | ||||
|  |                     label={m.attributeName.length > 10 ? <Tooltip title={m.attributeName}> | ||||
|  |                         {m.attributeName.substring(0, 10) + '...'} | ||||
|  |                     </Tooltip> : m.attributeName} | ||||
|  |                     name={m.attributeCode} | ||||
|  |                     rules={rules}> | ||||
|  |                     <Input style={{ width: '90%' }} placeholder={`请输入${m.attributeName}`} /> | ||||
|  |                 </Form.Item> | ||||
|  |             } else if (m.control === '数字输入框') { | ||||
|  |                 const rules = [{ required: !m.nullable, message: `${m.attributeName}不可空` }] | ||||
|  |                 let maxValue = ''; | ||||
|  |                 let length = m.length; | ||||
|  |                 if (length) { | ||||
|  |                     while (length > 0) { | ||||
|  |                         maxValue += '9' | ||||
|  |                         length--; | ||||
|  |                     } | ||||
|  |                 } | ||||
|  |                 return <Form.Item | ||||
|  |                     label={m.attributeName.length > 10 ? <Tooltip title={m.attributeName}> | ||||
|  |                         {m.attributeName.substring(0, 10) + '...'} | ||||
|  |                     </Tooltip> : m.attributeName} | ||||
|  |                     name={m.attributeCode} | ||||
|  |                     rules={rules}> | ||||
|  |                     <InputNumber min={0} max={maxValue ? parseInt(maxValue) : 0} precision={0} style={{ width: '90%' }} placeholder={`请输入${m.attributeName}`} /> | ||||
|  |                 </Form.Item> | ||||
|  |             } else { | ||||
|  |                 return <Form.Item | ||||
|  |                     label={m.attributeName.length > 10 ? <Tooltip title={m.attributeName}> | ||||
|  |                         {m.attributeName.substring(0, 10) + '...'} | ||||
|  |                     </Tooltip> : m.attributeName} | ||||
|  |                     name={m.attributeCode} | ||||
|  |                     rules={[{ required: !m.nullable, message: `${m.attributeName}不可空` }]}> | ||||
|  |                     <Select | ||||
|  |                         placeholder={`请选择${m.attributeName}`} | ||||
|  |                         style={{ width: '90%' }} | ||||
|  |                         showSearch | ||||
|  |                         optionFilterProp='children' | ||||
|  |                         getPopupContainer={triggerNode => triggerNode.parentNode} | ||||
|  |                         filterOption={(input, option) => option.props.children | ||||
|  |                             .toLowerCase().indexOf(input.toLowerCase()) >= 0} | ||||
|  |                     > | ||||
|  |                         <Select.Option value={'是'} key={'是'}>是</Select.Option> | ||||
|  |                         <Select.Option value={'否'} key={'否'}>否</Select.Option> | ||||
|  |                     </Select> | ||||
|  |                 </Form.Item > | ||||
|  |             } | ||||
|  |         }) | ||||
|  |         return items; | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     const vsjunct = (params) => { | ||||
|  |         if (params.length) { | ||||
|  |             let appendix = [] | ||||
|  |             for (let p of params) { | ||||
|  |                 appendix.push({ | ||||
|  |                     fName: p.name, | ||||
|  |                     size: p.size, | ||||
|  |                     fileSize: p.size, | ||||
|  |                     storageUrl: p.storageUrl,//必须有storageUrl
 | ||||
|  |                 }) | ||||
|  |             } | ||||
|  |             setEditUrl(appendix) | ||||
|  |         } else { | ||||
|  |             setEditUrl([]) | ||||
|  |         } | ||||
|  |     } | ||||
|  |     const handleCancel = () => { | ||||
|  |         if (editData.add) { | ||||
|  |             if (form.getFieldValue('files') && form.getFieldValue('files').length) { | ||||
|  |                 onCancel(form.getFieldValue('files')[0]); | ||||
|  |             } else { | ||||
|  |                 onCancel(null); | ||||
|  |             } | ||||
|  |         } else { | ||||
|  |             if (!(form.getFieldValue('files') && form.getFieldValue('files').length)) { | ||||
|  |                 message.warning('文件已被删除,可重新编辑上传'); | ||||
|  |                 onCancel(null, editData.record.id); | ||||
|  |             } else { | ||||
|  |                 if (!editData.record.files.length) { | ||||
|  |                     message.warning('文件需确定提交,才进行入库存储'); | ||||
|  |                     onCancel(form.getFieldValue('files')[0]); | ||||
|  |                 } else { | ||||
|  |                     onCancel(null); | ||||
|  |                 } | ||||
|  |             } | ||||
|  |         } | ||||
|  |     } | ||||
|  |     return ( | ||||
|  |         <Modal title={editData.title} open={true} destroyOnClose | ||||
|  |             okText='确定' width={800} | ||||
|  |             onOk={() => handleOk(null)} | ||||
|  |             onCancel={() => handleCancel()}> | ||||
|  |             <Form form={form} labelCol={{ span: 6 }} wrapperCol={{ span: 18 }} initialValues={editData.record || {}}> | ||||
|  |                 <Form.Item | ||||
|  |                     label='文件名称' | ||||
|  |                     name='name' | ||||
|  |                     rules={[{ required: true, message: '' }, { max: 50, message: `文件名称不超过50个字符` }, | ||||
|  |                     ({ getFieldValue, validateFields }) => ({ | ||||
|  |                         validator(_, value) { return validatorNull(_, value, getFieldValue, validateFields, '文件名称') } | ||||
|  |                     })]}> | ||||
|  |                     <Input style={{ width: '90%' }} placeholder={`请输入文件名称`} /> | ||||
|  |                 </Form.Item> | ||||
|  |                 <Form.Item | ||||
|  |                     label='文件描述' | ||||
|  |                     name='description' | ||||
|  |                     rules={[{ max: 255, message: `文件描述不超过255个字符` }]}> | ||||
|  |                     <TextArea rows={4} style={{ width: '90%' }} placeholder={`请输入文件描述`} /> | ||||
|  |                 </Form.Item> | ||||
|  |                 <Form.Item | ||||
|  |                     label='文件' | ||||
|  |                     name='files' | ||||
|  |                     rules={[{ required: true, message: '文件不可为空' }]}> | ||||
|  |                     <UploadLocal | ||||
|  |                         addNew={editData.add || !editData.record.files.length} | ||||
|  |                         isLocal={true} | ||||
|  |                         maxFilesNum={1} | ||||
|  |                         maxFileSize={40} | ||||
|  |                         onChange={vsjunct} | ||||
|  |                         fileTypes={["jpg", "png", "gif", "txt", "doc", "docx", "pdf", "xls", "xlsx", "zip", "rar"]} | ||||
|  |                         value={editUrl} | ||||
|  |                         defaultValue={editUrl} | ||||
|  |                         fileList={editData.record.files || []} | ||||
|  |                     /> | ||||
|  |                 </Form.Item> | ||||
|  |                 <Form.Item style={{ paddingLeft: 190 }}> | ||||
|  |                     <Tag color="orange">文件大小不超过40MB,开放资源包含多个文件,建议将文件进行压缩,形成压缩包再上传</Tag> | ||||
|  |                     <Tag color="orange">支持的文件格式:jpg,png,gif,txt,doc,docx,pdf,xsl,xlsx,zip,rar</Tag> | ||||
|  |                 </Form.Item> | ||||
|  |                 {renderModelItems()} | ||||
|  |             </Form> | ||||
|  |         </Modal > | ||||
|  |     ) | ||||
|  | } | ||||
|  | export default MetadataFileModal; | ||||
| @ -0,0 +1,53 @@ | |||||
|  | import React, { useEffect, useState } from 'react'; | ||||
|  | import { Modal, Input, Form } from 'antd'; | ||||
|  | const { TextArea } = Input; | ||||
|  | const MetadataResourceModal = (props) => { | ||||
|  |     const { onConfirm, onCancel, editData } = props; | ||||
|  |     const [form] = Form.useForm(); | ||||
|  |     useEffect(() => { | ||||
|  |     }, []); | ||||
|  |     const handleOk = () => { | ||||
|  |         form.validateFields().then(values => { | ||||
|  |             if (onConfirm) { | ||||
|  |                 onConfirm({ ...editData.record, ...values }); | ||||
|  |             } | ||||
|  |         }) | ||||
|  |     } | ||||
|  |     const validatorNull = (rule, value, getFieldValue, validateFields, label) => { | ||||
|  |         if (!value || !value.trim().length) { | ||||
|  |             return Promise.reject(new Error(`${label}不可空字符串`)); | ||||
|  |         } | ||||
|  |         return Promise.resolve(); | ||||
|  |     } | ||||
|  |     return ( | ||||
|  |         <Modal title={'申请资源'} open={true} destroyOnClose | ||||
|  |             okText='确定' width={800} | ||||
|  |             onOk={() => handleOk(null)} | ||||
|  |             onCancel={onCancel}> | ||||
|  |             <Form form={form} labelCol={{ span: 6 }} wrapperCol={{ span: 18 }} initialValues={editData.record || {}}> | ||||
|  |                 <Form.Item | ||||
|  |                     label='资源名称' | ||||
|  |                     name='resourceName' | ||||
|  |                     rules={[{ required: true, message: '资源名称不可空' }]}> | ||||
|  |                     <Input disabled style={{ width: '90%' }} /> | ||||
|  |                 </Form.Item> | ||||
|  |                 <Form.Item | ||||
|  |                     label='申请人' | ||||
|  |                     name='applyByName' | ||||
|  |                     rules={[{ required: true, message: '申请人不可空' }]}> | ||||
|  |                     <Input disabled style={{ width: '90%' }} /> | ||||
|  |                 </Form.Item> | ||||
|  |                 <Form.Item | ||||
|  |                     label='需求描述' | ||||
|  |                     name='requirements' | ||||
|  |                     rules={[{ required: true, message: '' }, { max: 255, message: `需求描述不超过255个字符` }, | ||||
|  |                     ({ getFieldValue, validateFields }) => ({ | ||||
|  |                         validator(_, value) { return validatorNull(_, value, getFieldValue, validateFields, '需求描述') } | ||||
|  |                     })]}> | ||||
|  |                     <TextArea rows={4} style={{ width: '90%' }} placeholder={`请输入需求描述`} /> | ||||
|  |                 </Form.Item> | ||||
|  |             </Form> | ||||
|  |         </Modal > | ||||
|  |     ) | ||||
|  | } | ||||
|  | export default MetadataResourceModal; | ||||
| @ -0,0 +1,79 @@ | |||||
|  | import React, { useEffect, useState } from 'react'; | ||||
|  | import { Modal, Form, Select, } from 'antd'; | ||||
|  | const MetadataDatabaseTagModal = (props) => { | ||||
|  |     const { onConfirm, onCancel, editData, tagList } = props; | ||||
|  |     const [form] = Form.useForm(); | ||||
|  |     const [tagSet, setTagSet] = useState(editData.record.tagSet || []); | ||||
|  |     useEffect(() => { | ||||
|  |     }, []); | ||||
|  |     const handleOk = () => { | ||||
|  |         form.validateFields().then(values => { | ||||
|  |             if (onConfirm) { | ||||
|  |                 onConfirm({ ...values }); | ||||
|  |             } | ||||
|  |         }) | ||||
|  |     } | ||||
|  |     const renderTagItems = () => { | ||||
|  |         let tags = []; | ||||
|  |         if (tagSet.length) { | ||||
|  |             tagList.map(t => { | ||||
|  |                 if (tagSet.includes(t.tagSetId)) { | ||||
|  |                     t.tags.map(t => { | ||||
|  |                         tags.push(<Select.Option value={t.id} key={`tag-${t.id}`}>{t.name}</Select.Option>) | ||||
|  |                     }) | ||||
|  |                 } | ||||
|  |             }); | ||||
|  |         } | ||||
|  |         return tags; | ||||
|  |     } | ||||
|  |     return ( | ||||
|  |         <Modal title={'打标'} open={true} destroyOnClose | ||||
|  |             okText='确定' width={800} | ||||
|  |             onOk={() => handleOk(null)} | ||||
|  |             onCancel={onCancel}> | ||||
|  |             <Form form={form} labelCol={{ span: 6 }} wrapperCol={{ span: 18 }} initialValues={editData.record}> | ||||
|  |                 <Form.Item | ||||
|  |                     label="标签集" | ||||
|  |                     name='tagSet' | ||||
|  |                     rules={[{ required: true, message: '请选择标签集' }]}> | ||||
|  |                     <Select | ||||
|  |                         maxTagCount={5} | ||||
|  |                         placeholder='请选择标签集' | ||||
|  |                         style={{ width: '90%' }} | ||||
|  |                         showSearch | ||||
|  |                         optionFilterProp='children' | ||||
|  |                         getPopupContainer={triggerNode => triggerNode.parentNode} | ||||
|  |                         filterOption={(input, option) => option.props.children | ||||
|  |                             .toLowerCase().indexOf(input.toLowerCase()) >= 0} | ||||
|  |                         onChange={value => { | ||||
|  |                             setTagSet(value) | ||||
|  |                             form.setFieldValue('tags', []); | ||||
|  |                         }} | ||||
|  |                         mode="multiple" | ||||
|  |                     > | ||||
|  |                         {tagList.map(t => <Select.Option value={t.tagSetId} key={`tagSet-${t.tagSetId}`}>{t.tagSetName}</Select.Option>)} | ||||
|  |                     </Select> | ||||
|  |                 </Form.Item> | ||||
|  |                 <Form.Item | ||||
|  |                     label="标签" | ||||
|  |                     name='tags' | ||||
|  |                     rules={[{ required: true, message: '请选择标签' }]}> | ||||
|  |                     <Select | ||||
|  |                         maxTagCount={5} | ||||
|  |                         placeholder='请选择标签' | ||||
|  |                         style={{ width: '90%' }} | ||||
|  |                         showSearch | ||||
|  |                         optionFilterProp='children' | ||||
|  |                         getPopupContainer={triggerNode => triggerNode.parentNode} | ||||
|  |                         filterOption={(input, option) => option.props.children | ||||
|  |                             .toLowerCase().indexOf(input.toLowerCase()) >= 0} | ||||
|  |                         mode="multiple" | ||||
|  |                     > | ||||
|  |                         {renderTagItems()} | ||||
|  |                     </Select> | ||||
|  |                 </Form.Item> | ||||
|  |             </Form> | ||||
|  |         </Modal > | ||||
|  |     ) | ||||
|  | } | ||||
|  | export default MetadataDatabaseTagModal; | ||||
| @ -1,105 +1,410 @@ | |||||
| import React, { useEffect, useState } from 'react'; | import React, { useEffect, useState } from 'react'; | ||||
| import { connect } from 'react-redux'; | import { connect } from 'react-redux'; | ||||
| import { Spin, Table, Popconfirm } from 'antd'; | import { Spin, Table, Popconfirm, Button, Input } from 'antd'; | ||||
|  | import { ButtonGroup } from '$components'; | ||||
| import moment from 'moment'; | import moment from 'moment'; | ||||
|  | import FileSaver from 'file-saver'; | ||||
|  | import MetadataFileModal from '../components/metadataFileModal'; | ||||
|  | import MetadataTagModal from '../components/metadataTagModal'; | ||||
|  | import MetadataResourceModal from '../components/metadataResourceModal'; | ||||
|  | import { RouteRequest } from '@peace/utils'; | ||||
|  | import { RouteTable } from '$utils' | ||||
| 
 | 
 | ||||
| const FilesTable = (props) => { | const FilesTable = (props) => { | ||||
|     const { user, dispatch, actions, clientHeight, resourceCatalogId, isRequesting } = props; |     const { user, dispatch, actions, clientHeight, resourceCatalogId, resourceCatalogKey, | ||||
|  |         isRequesting, metadataModels, tagList, metadataResourceApplications } = props; | ||||
|     const { metadataManagement } = actions; |     const { metadataManagement } = actions; | ||||
|     const [resourceCatalogData, setResourceCatalogData] = useState([]); |     const SortValues = { 'ascend': 'asc', 'descend': 'desc' }; | ||||
|     const [limit, setLimit] = useState(10) |     const [tableData, setTableData] = useState([]); | ||||
|     const [offset, setOffset] = useState(0) |     const [tableDataCount, setTableDataCount] = useState(0);//Table数据
 | ||||
|  |     const [updateAtSort, setUpdateAtSort] = useState('descend'); | ||||
|  |     const [keywords, setKeywords] = useState(''); | ||||
|  |     const [limit, setLimit] = useState(10); | ||||
|  |     const [currentPage, setCurrentPage] = useState(1); | ||||
|  |     const [selectedRowKeys, setSelectedRowKeys] = useState([]); | ||||
|  |     const [selectedRows, setSelectedRows] = useState([]); | ||||
|  |     const [modalVisible, setModalVisible] = useState(false); | ||||
|  |     const [editData, setEditData] = useState({}); | ||||
|  |     const [tagModalVisible, setTagModalVisible] = useState(false); | ||||
|  |     const [editTagData, setEditTagData] = useState({}); | ||||
|  |     const [resourceModalVisible, setResourceModalVisible] = useState(false); | ||||
|  |     const [editResourceData, setEditResourceData] = useState({}); | ||||
| 
 | 
 | ||||
|     useEffect(() => { |     useEffect(() => { | ||||
|         initData(resourceCatalogId); |         dispatch(metadataManagement.getTagList()); | ||||
|     }, []); |         setUpdateAtSort('descend'); | ||||
|  |         initData({ limit, offset: currentPage - 1, orderDirection: SortValues[updateAtSort] }); | ||||
|  |     }, [resourceCatalogId]); | ||||
| 
 | 
 | ||||
|     const initData = (resourceCatalogId) => { |     const initData = (query = {}) => { | ||||
|         dispatch(metadataManagement.getMetadataFiles({ catalog: resourceCatalogId, limit, offset })).then(res => { |         dispatch(metadataManagement.getMetadataFiles({ catalog: resourceCatalogId, keywords, orderBy: 'updateAt', ...query })).then(res => { | ||||
|             const { data } = res.payload; |  | ||||
|             if (res.success) { |             if (res.success) { | ||||
|  |                 setTableData(res.payload.data.rows); | ||||
|  |                 setTableDataCount(res.payload.data.count); | ||||
|  |                 let resourceNames = []; | ||||
|  |                 res.payload.data.rows.map(r => { | ||||
|  |                     resourceNames.push(r.name); | ||||
|  |                 }) | ||||
|  |                 if (resourceNames.length) | ||||
|  |                     dispatch(metadataManagement.getMetadataResourceApplications({ resourceNames: resourceNames.join(','), type: '文件' })) | ||||
|  |             } | ||||
| 
 | 
 | ||||
|  |         }) | ||||
|  |     } | ||||
|  |     const onEdit = (record) => { | ||||
|  |         dispatch(metadataManagement.getMetadataModels({ modelTypes: '文件' })).then(res => { | ||||
|  |             if (res.success) { | ||||
|  |                 setEditData({ | ||||
|  |                     title: '修改文件元数据', record: { | ||||
|  |                         ...record, ...record.attributesParam, | ||||
|  |                         files: record.fileName ? [{ | ||||
|  |                             url: "\\assets\\files\\common\\" + record.fileName, name: record.fileName.split('_').pop() | ||||
|  |                         }] : [] | ||||
|  |                     } | ||||
|  |                 }); | ||||
|  |                 setModalVisible(true); | ||||
|             } |             } | ||||
|         }) |         }) | ||||
|     } |     } | ||||
|     const onEdit = (record) => { } |     const confirmDelete = (record) => { | ||||
|     const confirmDelete = (id) => { } |         dispatch(metadataManagement.delMetadataFiles(record.id)).then(res => { | ||||
|     const marking = (id) => { } |             if (res.success) { | ||||
|     const applyResources = (id) => { } |                 onSearch(); setModalVisible(false); | ||||
|     const columns = [{ |                 deleteFile({ url: "\\assets\\files\\common\\" + record.fileName }) | ||||
|         title: '文件名称', |             } | ||||
|         dataIndex: 'name', |         }); | ||||
|         key: 'name', |     } | ||||
|         width: '20%' |     //删除文件
 | ||||
|     }, { |     const deleteFile = (file) => { | ||||
|         title: '文件描述', |         if (file.url) { | ||||
|         dataIndex: 'description', |             RouteRequest.delete(RouteTable.cleanUpUploadTrash, { url: file.url }); | ||||
|         key: 'description', |         }; | ||||
|         width: '20%' |     } | ||||
|     }, { |     const marking = (id) => { | ||||
|         title: '文件类型', |         dispatch(metadataManagement.getTagMetadata(id, 'file')).then(res => { | ||||
|         dataIndex: 'type', |             if (res.success) { | ||||
|         key: 'type', |                 const obj = { tagSet: [], tags: [], id: id }; | ||||
|         width: '20%' |                 if (res.payload.data.length) { | ||||
|     }, { |                     obj.tagSet = res.payload.data.map(d => d.tagSet); | ||||
|         title: '标签', |                     obj.tags = res.payload.data.map(d => d.id); | ||||
|         dataIndex: 'tags', |                 } | ||||
|         key: 'tags', |                 setEditTagData({ record: obj }); | ||||
|         width: '20%' |                 setTagModalVisible(true); | ||||
|     }, { |             } | ||||
|         title: '大小', |         }) | ||||
|         dataIndex: 'size', |     } | ||||
|         key: 'size', |     const onConfirmTag = (values) => { | ||||
|         width: '20%' |         dispatch(metadataManagement.postTagMetadata({ file: editTagData.record.id, ...values })).then(res => { | ||||
|     }, { |             if (res.success) { | ||||
|         title: '创建者', |                 onSearch(); setTagModalVisible(false); | ||||
|         dataIndex: 'createBy', |             } | ||||
|         key: 'createBy', |         }); | ||||
|         width: '10%', |     } | ||||
|     }, { |     const applyResources = (record) => { | ||||
|         title: '修改时间', |         setEditResourceData({ record: { resourceName: record.name, applyBy: user.id, applyByName: user.name, resourceType: '文件' } }); | ||||
|         dataIndex: 'updateAt', |         setResourceModalVisible(true); | ||||
|         key: 'updateAt', |     } | ||||
|         width: '20%', | 
 | ||||
|         render: (text, record, index) => { |     const onConfirmResource = (values) => { | ||||
|             return text ? moment(text).format('YYYY-MM-DD HH:mm') : '' |         dispatch(metadataManagement.postMetadataResourceApplications(values)).then(res => { | ||||
|         } |             if (res.success) { | ||||
|     }, { |                 onSearch(); setResourceModalVisible(false); | ||||
|         title: '操作', |             } | ||||
|         dataIndex: 'action', |         }); | ||||
|         width: '20%', |     } | ||||
|         render: (text, record) => { |     const onTableChange = (pagination, filters, sorter) => { | ||||
|             return <div> |         let limit = Number.parseInt(pagination.pageSize); | ||||
|                 <a onClick={() => onEdit(record)}>编辑</a> |         let offset = Number.parseInt(pagination.current) - 1; | ||||
|                    |         setCurrentPage(pagination.current); | ||||
|                 <Popconfirm |         setLimit(limit); | ||||
|                     title="是否确认删除该元数据?若确认删除则关联的数据将一并删除!" |         let query = { offset, limit, orderDirection: SortValues[updateAtSort] }; | ||||
|                     onConfirm={() => confirmDelete(record.id)} |         if (sorter.columnKey === 'updateAt') { | ||||
|                 > <a>删除</a></Popconfirm> |             query.orderDirection = SortValues[sorter.order]; | ||||
|                    |             setUpdateAtSort(sorter.order); | ||||
|                 <a onClick={() => marking(record.id)}>打标</a> |  | ||||
|                    |  | ||||
|                 <a onClick={() => applyResources(record.id)}>申请资源</a> |  | ||||
|             </div> |  | ||||
|         } |         } | ||||
|     }]; |         setSelectedRowKeys([]); | ||||
|  |         setSelectedRows([]); | ||||
|  |         initData(query); | ||||
|  |     } | ||||
| 
 | 
 | ||||
|  |     const getfilesize = (size) => { | ||||
|  |         if (!size) | ||||
|  |             return "0K"; | ||||
|  |         var num = 1024.00; //byte
 | ||||
|  |         if (size < num) | ||||
|  |             return size + "B"; | ||||
|  |         if (size < Math.pow(num, 2)) | ||||
|  |             return (size / num).toFixed(2) + "KB"; //kb
 | ||||
|  |         if (size < Math.pow(num, 3)) | ||||
|  |             return (size / Math.pow(num, 2)).toFixed(2) + "M"; //M
 | ||||
|  |         if (size < Math.pow(num, 4)) | ||||
|  |             return (size / Math.pow(num, 3)).toFixed(2) + "G"; //G
 | ||||
|  |         return (size / Math.pow(num, 4)).toFixed(2) + "T"; //T
 | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     const columns = [ | ||||
|  |         { | ||||
|  |             title: '文件名称', | ||||
|  |             dataIndex: 'name', | ||||
|  |             key: 'name', | ||||
|  |             width: '16%', | ||||
|  |             ellipsis: true | ||||
|  |         }, { | ||||
|  |             title: '文件描述', | ||||
|  |             dataIndex: 'description', | ||||
|  |             key: 'description', | ||||
|  |             width: '29%', | ||||
|  |             ellipsis: true | ||||
|  |         }, { | ||||
|  |             title: '文件类型', | ||||
|  |             dataIndex: 'type', | ||||
|  |             key: 'type', | ||||
|  |             width: '10%', | ||||
|  |             render: (text, record) => { | ||||
|  |                 if (record.fileName) | ||||
|  |                     return <span>{text}</span> | ||||
|  |                 else | ||||
|  |                     return '' | ||||
|  |             } | ||||
|  |         }, { | ||||
|  |             title: '标签', | ||||
|  |             dataIndex: 'tags', | ||||
|  |             key: 'tags', | ||||
|  |             width: '18%', | ||||
|  |             ellipsis: true, | ||||
|  |             render: (text, record, index) => { | ||||
|  |                 let tagName = record.tagFiles.map(tagSet => tagSet.tag.name); | ||||
|  |                 return tagName.join(','); | ||||
|  |             } | ||||
|  |         }, { | ||||
|  |             title: '大小', | ||||
|  |             dataIndex: 'size', | ||||
|  |             key: 'size', | ||||
|  |             width: '10%', | ||||
|  |             render: (text, record) => { | ||||
|  |                 if (record.fileName) | ||||
|  |                     return <span>{getfilesize(text)}</span> | ||||
|  |                 else | ||||
|  |                     return '' | ||||
|  |             } | ||||
|  |         }, { | ||||
|  |             title: '修改时间', | ||||
|  |             dataIndex: 'updateAt', | ||||
|  |             key: 'updateAt', | ||||
|  |             width: '18%', | ||||
|  |             sortOrder: updateAtSort, | ||||
|  |             sorter: (a, b) => moment(a.updateAt).valueOf() - moment(b.updateAt).valueOf(), | ||||
|  |             sortDirections: ['descend', 'ascend', 'descend'], | ||||
|  |             render: (text, record, index) => { | ||||
|  |                 return text && moment(text).format('YYYY-MM-DD HH:mm:ss') || '' | ||||
|  |             } | ||||
|  |         }, { | ||||
|  |             title: '操作', | ||||
|  |             dataIndex: 'action', | ||||
|  |             width: '8%', | ||||
|  |             render: (text, record) => { | ||||
|  |                 let resourceApplicationsRecords = metadataResourceApplications.filter(ra => | ||||
|  |                     ra.applyBy == user.id && ra.resourceName === record.name); | ||||
|  |                 return <ButtonGroup> | ||||
|  |                     <a style={{ marginLeft: 10 }} onClick={() => onEdit(record)}>编辑</a> | ||||
|  |                     <Popconfirm | ||||
|  |                         title="是否确认删除该元数据?" | ||||
|  |                         onConfirm={() => confirmDelete(record)} | ||||
|  |                     > <a style={{ marginLeft: 10 }}>删除</a></Popconfirm> | ||||
|  |                     <a style={{ marginLeft: 10 }} onClick={() => marking(record.id)}>打标</a> | ||||
|  |                     {resourceApplicationsRecords.length === 0 ? | ||||
|  |                         <a style={{ marginLeft: 10 }} onClick={() => applyResources(record)}>申请资源</a> : | ||||
|  |                         <span style={{ marginLeft: 10, color: "#c0c0c0" }} title='已存在资源申请'>申请资源</span>} | ||||
|  |                 </ButtonGroup> | ||||
|  |             } | ||||
|  |         }]; | ||||
|  | 
 | ||||
|  |     const onSearch = () => { | ||||
|  |         setSelectedRowKeys([]); | ||||
|  |         setSelectedRows([]); | ||||
|  |         setCurrentPage(1); | ||||
|  |         initData({ limit, offset: 0, orderDirection: SortValues[updateAtSort] }); | ||||
|  |     } | ||||
|  |     const handleExport = (isAll = false) => { | ||||
|  |         let tableHeader = `<tr>`; | ||||
|  |         columns.filter(c => c.dataIndex != 'action').map(c => { tableHeader += `<th><div>${c.title}</div></th>`; }); | ||||
|  |         tableHeader += '</tr>'; | ||||
|  |         if (isAll) { | ||||
|  |             dispatch(metadataManagement.getMetadataFiles({ catalog: resourceCatalogId })).then(res => { | ||||
|  |                 if (res.success) { | ||||
|  |                     handleExportTable(tableHeader, res.payload.data.rows, isAll); | ||||
|  |                 } | ||||
|  |             }) | ||||
|  |         } else { | ||||
|  |             let data = [] | ||||
|  |             if (updateAtSort === 'descend') { | ||||
|  |                 data = selectedRows.sort((a, b) => moment(b.updateAt).valueOf() - moment(a.updateAt).valueOf()); | ||||
|  |             } else { | ||||
|  |                 data = selectedRows.sort((a, b) => moment(a.updateAt).valueOf() - moment(b.updateAt).valueOf()); | ||||
|  |             } | ||||
|  |             handleExportTable(tableHeader, data); | ||||
|  |         } | ||||
|  |     } | ||||
|  |     const handleExportTable = (tableHeader, contentData, isAll = false) => { | ||||
|  |         let tableContent = ''; | ||||
|  |         contentData.map(cd => { | ||||
|  |             tableContent += `<tr>`; | ||||
|  |             tableContent += `<th style="font-weight:600"><div>${cd.name}</div></th>`; | ||||
|  |             tableContent += `<th style="font-weight:600"><div>${cd.description}</div></th>`; | ||||
|  |             tableContent += `<th style="font-weight:600"><div>${cd.type}</div></th>`; | ||||
|  |             let tagName = cd.tagFiles.map(tagSet => tagSet.tag.name); | ||||
|  |             tableContent += `<th style="font-weight:600"><div>${tagName.join(',')}</div></th>`; | ||||
|  |             tableContent += `<th style="font-weight:600"><div>${cd.size}</div></th>`; | ||||
|  |             tableContent += `<th style="font-weight:600"><div>${moment(cd.updateAt).format('YYYY-MM-DD HH:mm:ss')}</div></th>`; | ||||
|  |             tableContent += `</tr>`; | ||||
|  |         }) | ||||
|  |         let exportTable = `\uFEFF<table border="1">
 | ||||
|  |             ${tableHeader} | ||||
|  |             ${tableContent} | ||||
|  |         </table>`; | ||||
|  |         let tempStr = new Blob([exportTable], { type: 'text/plain;charset=utf-8' }); | ||||
|  |         FileSaver.saveAs(tempStr, `文件元数据导出.xls`); | ||||
|  |     } | ||||
|  |     //新建、修改
 | ||||
|  |     const onConfirm = (values) => { | ||||
|  |         let obj = {} | ||||
|  |         if (editData.add) { | ||||
|  |             obj = { createBy: user.id, catalog: resourceCatalogId, catalogKey: resourceCatalogKey, ...values } | ||||
|  |             if (values.files && values.files.length) { | ||||
|  |                 obj.type = values.files[0].name.split('.').pop(); | ||||
|  |                 obj.size = values.files[0].size; | ||||
|  |                 obj.fileName = values.files[0].url.split('\\').pop(); | ||||
|  |             } | ||||
|  |             dispatch(metadataManagement.postMetadataFiles(obj)).then(res => { | ||||
|  |                 if (res.success) { | ||||
|  |                     onSearch(); setModalVisible(false); | ||||
|  |                 } | ||||
|  |             }); | ||||
|  |         } else { | ||||
|  |             obj = { catalog: resourceCatalogId, catalogKey: resourceCatalogKey, ...values } | ||||
|  |             if (values.files && values.files.length) { | ||||
|  |                 obj.type = values.files[0].name.split('.').pop(); | ||||
|  |                 if (values.files[0].size) { | ||||
|  |                     obj.size = values.files[0].size; | ||||
|  |                 } | ||||
|  |                 obj.fileName = values.files[0].url.split('\\').pop(); | ||||
|  |             } | ||||
|  |             dispatch(metadataManagement.putMetadataFiles(editData.record.id, obj)).then(res => { | ||||
|  |                 if (res.success) { | ||||
|  |                     onSearch(); setModalVisible(false); | ||||
|  |                 } | ||||
|  |             }); | ||||
|  |         } | ||||
|  |     } | ||||
|     return <Spin spinning={isRequesting}> |     return <Spin spinning={isRequesting}> | ||||
|         <Table scroll={{ y: clientHeight - 320 }} |         <div style={{ marginBottom: 16 }}> | ||||
|             rowKey='filesId' |             <Button type='primary' onClick={() => { | ||||
|  |                 dispatch(metadataManagement.getMetadataModels({ modelTypes: '文件' })).then(res => { | ||||
|  |                     if (res.success) { | ||||
|  |                         setEditData({ add: true, title: '新建文件元数据', record: {} }); | ||||
|  |                         setModalVisible(true); | ||||
|  |                     } | ||||
|  |                 }) | ||||
|  |             }}>新建</Button> | ||||
|  |             { | ||||
|  |                 tableDataCount == 0 ? <Button disabled={tableDataCount == 0} style={{ marginLeft: 16 }} onClick={() => handleExport()}>导出</Button> : | ||||
|  |                     selectedRowKeys && selectedRowKeys.length ? | ||||
|  |                         <Button disabled={tableDataCount == 0} style={{ marginLeft: 16 }} onClick={() => handleExport()}>导出</Button> | ||||
|  |                         : <Popconfirm title={'是否导出全部?'} onConfirm={() => handleExport(true)} okText="确定" cancelText="取消"> | ||||
|  |                             <Button disabled={tableDataCount == 0} style={{ marginLeft: 16 }}> 导出</Button> | ||||
|  |                         </Popconfirm> | ||||
|  |             } | ||||
|  |             <Button type='primary' style={{ marginLeft: 16, float: 'right' }} onClick={onSearch}>查询</Button> | ||||
|  |             <Input style={{ width: 220, float: 'right' }} placeholder="输入名称/类型" | ||||
|  |                 allowClear onPressEnter={onSearch} onChange={e => setKeywords(e.target.value || '')} /> | ||||
|  |         </div > | ||||
|  |         <Table | ||||
|  |             scroll={{ y: clientHeight - 320 }} | ||||
|  |             rowKey='id' | ||||
|             columns={columns} |             columns={columns} | ||||
|             dataSource={[]}> |             dataSource={tableData} | ||||
|  |             onChange={onTableChange} | ||||
|  |             pagination={{ | ||||
|  |                 current: currentPage, | ||||
|  |                 pageSize: limit, | ||||
|  |                 total: tableDataCount, | ||||
|  |                 showSizeChanger: true, | ||||
|  |                 // showQuickJumper: true,
 | ||||
|  |                 showTotal: (total) => { return <span style={{ fontSize: 15 }}>{`共${Math.ceil(total / limit)}页,${total}项`}</span> }, | ||||
|  |                 onShowSizeChange: (currentPage, pageSize) => { | ||||
|  |                     setCurrentPage(currentPage); | ||||
|  |                     setLimit(pageSize); | ||||
|  |                 }, | ||||
|  |                 onChange: (page, pageSize) => { | ||||
|  |                     setSelectedRowKeys([]); | ||||
|  |                     setSelectedRows([]); | ||||
|  |                     setCurrentPage(page); | ||||
|  |                     setLimit(pageSize); | ||||
|  |                     let queryParams = { | ||||
|  |                         orderDirection: SortValues[updateAtSort], | ||||
|  |                         page: page - 1, | ||||
|  |                         size: pageSize | ||||
|  |                     }; | ||||
|  |                     initData(queryParams); | ||||
|  |                 } | ||||
|  |             }} | ||||
|  |             rowSelection={{ | ||||
|  |                 onChange: (selectedRowKeys, selectedRows) => { | ||||
|  |                     setSelectedRowKeys(selectedRowKeys) | ||||
|  |                     setSelectedRows(selectedRows); | ||||
|  |                 }, | ||||
|  |                 selectedRowKeys: selectedRowKeys | ||||
|  |             }} | ||||
|  |         > | ||||
|         </Table> |         </Table> | ||||
|     </Spin> |         { | ||||
| 
 |             modalVisible ? | ||||
|  |                 <MetadataFileModal | ||||
|  |                     metadataModels={metadataModels.filter(m => m.modelType === '文件')} | ||||
|  |                     editData={editData} | ||||
|  |                     onCancel={(file, updateId) => { | ||||
|  |                         setModalVisible(false) | ||||
|  |                         if (file) | ||||
|  |                             deleteFile(file); | ||||
|  |                         if (updateId) { | ||||
|  |                             dispatch(metadataManagement.putMetadataFiles(updateId, {}, true)).then(res => { | ||||
|  |                                 if (res.success) { | ||||
|  |                                     onSearch(); setModalVisible(false); | ||||
|  |                                 } | ||||
|  |                             }); | ||||
|  |                         } | ||||
|  |                     }} | ||||
|  |                     onConfirm={onConfirm} /> : '' | ||||
|  |         } | ||||
|  |         { | ||||
|  |             tagModalVisible ? | ||||
|  |                 <MetadataTagModal | ||||
|  |                     tagList={tagList} | ||||
|  |                     editData={editTagData} | ||||
|  |                     onCancel={() => setTagModalVisible(false)} | ||||
|  |                     onConfirm={onConfirmTag} /> : '' | ||||
|  |         } | ||||
|  |         { | ||||
|  |             resourceModalVisible ? | ||||
|  |                 <MetadataResourceModal | ||||
|  |                     editData={editResourceData} | ||||
|  |                     onCancel={() => setResourceModalVisible(false)} | ||||
|  |                     onConfirm={onConfirmResource} /> : '' | ||||
|  |         } | ||||
|  |     </Spin > | ||||
| } | } | ||||
| function mapStateToProps(state) { | function mapStateToProps(state) { | ||||
|     const { global, auth, metadataFiles } = state; |     const { global, auth, metadataDatabases, metadataModels, tagList, tagMetadata, metadataResourceApplications } = state; | ||||
|     return { |     return { | ||||
|         user: auth.user, |         user: auth.user, | ||||
|         actions: global.actions, |         actions: global.actions, | ||||
|         clientHeight: global.clientHeight, |         clientHeight: global.clientHeight, | ||||
|         isRequesting: metadataFiles.isRequesting |         isRequesting: metadataDatabases.isRequesting || metadataModels.isRequesting || tagList.isRequesting | ||||
|  |             || tagMetadata.isRequesting || metadataResourceApplications.isRequesting, | ||||
|  |         metadataModels: metadataModels.data, | ||||
|  |         tagList: tagList.data || [], | ||||
|  |         tagMetadata: tagMetadata.data || [], | ||||
|  |         metadataResourceApplications: metadataResourceApplications.data || [] | ||||
|     }; |     }; | ||||
| } | } | ||||
| export default connect(mapStateToProps)(FilesTable) | export default connect(mapStateToProps)(FilesTable) | ||||
					Loading…
					
					
				
		Reference in new issue