You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
364 lines
17 KiB
364 lines
17 KiB
import React, { useEffect, useState, useRef } from 'react';
|
|
import { connect } from 'react-redux';
|
|
import moment from 'moment';
|
|
import { Button, Col, Row, Input, Tree, Table, Space, Tooltip, Spin, Popconfirm, Pagination, DatePicker } from '@douyinfe/semi-ui';
|
|
import { IconSearch, IconEditStroked, IconMinusCircleStroked, IconPlusCircleStroked } from '@douyinfe/semi-icons';
|
|
import {
|
|
getResourceFileList, postResourceFile, delResourceFile,
|
|
getResourceClassify, postResourceClassify, putResourceClassify, delResourceClassify
|
|
} from '../actions/resourceRepository';
|
|
import FolderModal from '../components/resourceRepository/folder-model';
|
|
import ResourceUploadModal from '../components/resourceRepository/upload-modal';
|
|
import { isAuthorized } from '$utils'
|
|
import '../style.less';
|
|
|
|
const ResourceRepository = (props) => {
|
|
const { dispatch, clientHeight, apiRoot, user, resourceClassify, resourceFilelist, isRequesting } = props;
|
|
const [treeData, setTreeData] = useState([]);
|
|
const [currentSelect, setCurrentSelect] = useState("公司培训资料");
|
|
const [defaultExpandedKey, setDefaultExpandedKey] = useState();
|
|
const [modelVisiable, setModelVisiable] = useState(false);
|
|
const [modalData, setModalData] = useState();
|
|
const [uploadModalVisiable, setUploadModalVisiable] = useState(false);
|
|
const [paginationQuery, setPaginatioQuery] = useState({ limit: 10, page: 0 }); //页码信息
|
|
const [keyword, setKeyword] = useState();//文件名称过滤
|
|
const [dataRange, setDataRange] = useState();//更新时间过滤
|
|
const ref = useRef();
|
|
|
|
useEffect(() => {
|
|
getClassify();
|
|
}, [])
|
|
|
|
const style = {
|
|
width: 260,
|
|
height: clientHeight - 294,
|
|
border: '1px solid var(--semi-color-border)'
|
|
};
|
|
const columns = [
|
|
{
|
|
title: '文件类型',
|
|
dataIndex: 'fileType',
|
|
},
|
|
{
|
|
title: '文件名称',
|
|
dataIndex: 'fileName',
|
|
},
|
|
{
|
|
title: '大小',
|
|
dataIndex: 'fileSize',
|
|
},
|
|
{
|
|
title: '更新时间',
|
|
dataIndex: 'updateDate',
|
|
render: (text) => text && moment(text).format('YYYY-MM-DD HH:mm:ss') || '-'
|
|
}, {
|
|
title: '操作',
|
|
dataIndex: 'action',
|
|
render: (text, record) => {
|
|
return <div style={{ color: "#1890FF" }}>
|
|
<Space>
|
|
{
|
|
isAuthorized('DOWNLOADTRAININGMATERIALS') ? <a href={'/_file-server/' + record.attachPath + '?filename=' + encodeURIComponent(record.fileName + record.fileType)}>下载</a> : ''
|
|
}
|
|
|
|
{
|
|
isAuthorized('DELETETRAININGMATERIALS')?currentSelect.includes("公司培训资料") &&
|
|
<Popconfirm
|
|
style={{ minWidth: "max-content" }}
|
|
title="提示"
|
|
content="确认删除该文件?"
|
|
onConfirm={() => { handleDelFile(record.id) }}
|
|
position={"leftBottom"}
|
|
>
|
|
<a style={{ cursor: 'pointer' }}>删除</a>
|
|
</Popconfirm>:''
|
|
}
|
|
</Space>
|
|
</div>
|
|
}
|
|
}
|
|
];
|
|
|
|
const renderLabel = (label, data) => {
|
|
const child = data.children ? true : false;
|
|
const key = data.key.split('/');
|
|
return (<div>
|
|
<Tooltip content={label}><span >{label.length > 7 ? label.substring(0, 7) + '...' : label}</span></Tooltip>
|
|
{true == data.operation ?
|
|
<span className='tree-icon'>
|
|
<IconEditStroked size='default' onClick={() => handleFolderClick(child ? '编辑' : '编辑子', !child, key[1], key[2] || undefined)} />
|
|
<Popconfirm
|
|
title="确定是否要删除?"
|
|
content="该文件夹下的所有子文件/附件将永久删除,请慎重!"
|
|
onConfirm={() => handleDel(data.key)}
|
|
// onCancel={onCancel}
|
|
>
|
|
<IconMinusCircleStroked size='default' />
|
|
</Popconfirm>
|
|
|
|
{child ?
|
|
<IconPlusCircleStroked
|
|
size='default'
|
|
onClick={() => handleFolderClick('新建子', true, label, undefined)}
|
|
/> : ''}
|
|
</span>
|
|
: ''}
|
|
</div>)
|
|
};
|
|
const handleFolderClick = (title, childFolder, departmentName, trainDate) => {
|
|
setModelVisiable(true);
|
|
setModalData({ title, childFolder, departmentName, trainDate });
|
|
}
|
|
const handleSelect = (e) => {
|
|
setCurrentSelect(e);
|
|
setPaginatioQuery({ limit: 10, page: 0 });
|
|
setKeyword(null);
|
|
setDataRange(null);
|
|
getFile(e, { limit: 10, page: 0 }, { restSearch: true });
|
|
}
|
|
const handleDataToSave = (add, body) => {
|
|
setDefaultExpandedKey([]);
|
|
if (add) {
|
|
dispatch(postResourceClassify(body)).then(res => {
|
|
if (res.success) {
|
|
getClassify();
|
|
setModelVisiable(false);
|
|
}
|
|
});
|
|
} else {
|
|
dispatch(putResourceClassify(body)).then(res => {
|
|
if (res.success) {
|
|
getClassify();
|
|
setModelVisiable(false);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
const handleDelFile = (id) => {
|
|
dispatch(delResourceFile(id)).then(res => {
|
|
if (res.success) {
|
|
getFile(currentSelect, { limit: 10, page: 0 }, { restSearch: true });
|
|
|
|
}
|
|
})
|
|
}
|
|
const handleDel = (key) => {
|
|
const arr = key.split('/');
|
|
const query = {
|
|
departmentName: arr[1]
|
|
}
|
|
if (arr.length == 3) {
|
|
query.trainDate = arr[2];
|
|
}
|
|
dispatch(delResourceClassify(query)).then(res => {
|
|
if (res.success) {
|
|
getClassify();
|
|
setModelVisiable(false);
|
|
}
|
|
});
|
|
}
|
|
const handleUploadOk = (data) => {
|
|
const fileList = data.attachPath && data.attachPath.length && data.attachPath.filter(d => "success" == d.status).map(d => {
|
|
const { name, size, response } = d;
|
|
const { uploaded } = response || {};
|
|
let index = name.lastIndexOf('.');
|
|
return {
|
|
fileType: name.substring(index),
|
|
fileName: name.substring(0, index),
|
|
fileSize: size,
|
|
attachPath: uploaded
|
|
}
|
|
});
|
|
dispatch(postResourceFile({ fileList, currentSelect })).then(res => {
|
|
if (res.success) {
|
|
getFile(currentSelect);
|
|
setUploadModalVisiable(false);
|
|
}
|
|
})
|
|
|
|
}
|
|
const handleSearch = () => {
|
|
setPaginatioQuery({ limit: 10, page: 0 });
|
|
getFile(null, { limit: 10, page: 0 });
|
|
}
|
|
const getFile = (e, pagination, opt) => {
|
|
const arr = e ? e.split("/") : currentSelect.split("/");
|
|
const query = pagination ? { ...pagination, type: arr[0] } : { ...paginationQuery, type: arr[0] };
|
|
if (opt && opt.restSearch) {
|
|
//选中树节点重置
|
|
setPaginatioQuery({ limit: 10, page: 0 });
|
|
setKeyword(null);
|
|
setDataRange(null);
|
|
} else {
|
|
if (keyword) { query.keyword = keyword; }
|
|
if (dataRange) {
|
|
query.startTime = moment(dataRange[0]).format('YYYY-MM-DD HH:mm:ss');
|
|
query.endTime = moment(dataRange[1]).format('YYYY-MM-DD HH:mm:ss');
|
|
}
|
|
}
|
|
if (arr[1]) { query.departmentName = arr[1]; }
|
|
if (arr[2]) { query.trainDate = arr[2]; }
|
|
|
|
dispatch(getResourceFileList(query));
|
|
}
|
|
const getClassify = () => {
|
|
dispatch(getResourceClassify()).then(res => {
|
|
const { success, payload } = res;
|
|
if (success) {
|
|
let defaultKey = "";
|
|
if (payload.data.length) {
|
|
if (payload.data[0].children && payload.data[0].children.length) {
|
|
defaultKey = payload.data[0].children[0].key;
|
|
setDefaultExpandedKey([payload.data[0].key, payload.data[0].children[0].key]);
|
|
} else {
|
|
defaultKey = payload.data[0].key;
|
|
setDefaultExpandedKey([payload.data[0].key]);
|
|
}
|
|
}
|
|
setCurrentSelect(defaultKey);
|
|
setTreeData(payload.data);
|
|
getFile(defaultKey);
|
|
}
|
|
});
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<div style={{ padding: '0px 12px' }}>
|
|
<div style={{ display: 'flex' }}>
|
|
<div style={{ color: 'rgba(0,0,0,0.45)', fontSize: 14 }}>培训</div>
|
|
<div style={{ color: 'rgba(0,0,0,0.45)', fontSize: 14, margin: '0px 8px' }}>/</div>
|
|
<div style={{ color: 'rgba(0,0,0,0.45)', fontSize: 14 }}>培训档案</div>
|
|
<div style={{ color: '#033C9A', fontSize: 14, margin: '0px 8px' }}>/</div>
|
|
<div style={{ color: '#033C9A', fontSize: 14 }}>培训资源储存库</div>
|
|
</div>
|
|
<div style={{ background: '#FFFFFF', boxShadow: '0px 0px 12px 2px rgba(220,222,224,0.2)', borderRadius: 2, padding: '20px', marginTop: 12 }}>
|
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
|
<div style={{ display: 'flex', alignItems: 'baseline' }}>
|
|
<div style={{ width: 0, height: 20, borderLeft: '3px solid #0F7EFB', borderTop: '3px solid transparent', borderBottom: '3px solid transparent' }}></div>
|
|
<div style={{ fontFamily: "YouSheBiaoTiHei", fontSize: 24, color: '#033C9A', marginLeft: 8 }}>培训资源储存库</div>
|
|
<div style={{ marginLeft: 6, fontSize: 12, color: '#969799', fontFamily: "DINExp", }}>RESOURCE REPOSITORY</div>
|
|
</div>
|
|
</div>
|
|
<Spin spinning={isRequesting}>
|
|
<Row className='resourceRepository'>
|
|
{/* 左侧 */}
|
|
<Col className='left' span={6}>
|
|
{
|
|
isAuthorized('FOLDERMANAGEMENT') ? <Button theme='solid' type='primary' onClick={() => handleFolderClick("新建", false)}>新建文件夹</Button> : ''
|
|
}
|
|
<Button theme='solid' type='primary' onClick={() => handleFolderClick("新建", false)}>新建文件夹</Button>
|
|
<br />
|
|
<Input suffix={<IconSearch />} showClear onChange={v => ref.current.search(v)} placeholder="请输入"></Input>
|
|
<Tree
|
|
ref={ref}
|
|
defaultExpandAll={true}
|
|
treeData={treeData}
|
|
style={style}
|
|
value={[currentSelect]}
|
|
expandedKeys={defaultExpandedKey}
|
|
filterTreeNode={true}
|
|
searchRender={false}
|
|
directory={true}
|
|
showFilteredOnly={true}
|
|
renderLabel={renderLabel}
|
|
onExpand={(e) => setDefaultExpandedKey(e)}
|
|
onSelect={handleSelect}
|
|
/>
|
|
</Col>
|
|
{/* 右侧内容 */}
|
|
<Col span={18} className='right'>
|
|
<Row> <span className="path-lable"><strong>当前文件夹:{currentSelect}</strong></span></Row>
|
|
<Row className='search'>
|
|
<Space>
|
|
{isAuthorized('UPLOADTRAININGMATERIALS') ? currentSelect && currentSelect.includes("公司培训资料") && currentSelect.split("/").length == 3 ?
|
|
<Button theme='solid' type='primary' onClick={() => { setUploadModalVisiable(true) }} >上传文件</Button>
|
|
: null : ''}
|
|
<span className='search-label'>关键字</span>
|
|
<Input
|
|
style={{ width: 160 }}
|
|
// suffix={<IconSearch />}
|
|
showClear
|
|
placeholder="文件名称"
|
|
value={keyword}
|
|
onChange={(value) => { setKeyword(value) }}
|
|
></Input>
|
|
<span className='search-label'>更新时间范围</span>
|
|
<DatePicker
|
|
style={{ width: 350 }}
|
|
value={dataRange}
|
|
type="dateTimeRange"
|
|
density="compact"
|
|
onChange={(data) => { setDataRange(data) }}
|
|
onClear={() => { setDataRange(null) }}
|
|
/>
|
|
<Button theme='solid' type='primary' style={{ width: 80, borderRadius: 2, height: 32, background: '#DBECFF', color: '#005ABD' }}
|
|
onClick={() => handleSearch()}
|
|
>查询</Button>
|
|
</Space>
|
|
</Row>
|
|
<Table
|
|
columns={columns}
|
|
dataSource={resourceFilelist && resourceFilelist.rows || []}
|
|
pagination={false} />
|
|
<div style={{
|
|
display: "flex",
|
|
justifyContent: "space-between",
|
|
padding: "20px 20px",
|
|
}}>
|
|
<div></div>
|
|
<div style={{ display: 'flex', }}>
|
|
<span style={{ lineHeight: "30px", fontSize: 13, color: 'rgba(0,90,189,0.8)' }}>
|
|
共{resourceFilelist && resourceFilelist.count}条信息
|
|
</span>
|
|
<Pagination
|
|
total={resourceFilelist && resourceFilelist.count}
|
|
showSizeChanger
|
|
currentPage={paginationQuery.page + 1}
|
|
pageSizeOpts={[10, 20, 30, 40]}
|
|
onChange={(currentPage, pageSize) => {
|
|
setPaginatioQuery({ limit: pageSize, page: currentPage - 1 });
|
|
getFile(currentSelect, { limit: pageSize, page: currentPage - 1 });
|
|
}}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</Col>
|
|
</Row>
|
|
</Spin>
|
|
</div>
|
|
{modelVisiable ?
|
|
<FolderModal
|
|
oldData={resourceClassify && resourceClassify.find(r => '公司培训资料' == r.label)}
|
|
modalData={modalData}
|
|
onOk={handleDataToSave}
|
|
onCancel={() => { setModelVisiable(false) }}
|
|
/> : null
|
|
}
|
|
{uploadModalVisiable ?
|
|
<ResourceUploadModal
|
|
apiRoot={apiRoot}
|
|
user={user}
|
|
onOk={handleUploadOk}
|
|
onCancel={() => { setUploadModalVisiable(false) }}
|
|
/> : null
|
|
}
|
|
</div>
|
|
</>
|
|
)
|
|
}
|
|
|
|
function mapStateToProps(state) {
|
|
const { auth, global, resourceClassify, resourceFilelist } = state;
|
|
return {
|
|
user: auth.user,
|
|
actions: global.actions,
|
|
apiRoot: global.apiRoot,
|
|
clientHeight: global.clientHeight,
|
|
resourceClassify: resourceClassify.data || [],
|
|
resourceFilelist: resourceFilelist.data && resourceFilelist.data,
|
|
isRequesting: resourceClassify.isRequesting || resourceFilelist.isRequesting
|
|
};
|
|
}
|
|
|
|
export default connect(mapStateToProps)(ResourceRepository);
|
|
|