Browse Source

(*)培训资料库:公司培训资料删除功能

master
周沫沫历险记 2 years ago
parent
commit
8fdbb7176f
  1. 82
      api/app/lib/controllers/resourceRepository/index.js
  2. 11
      api/app/lib/routes/resourceRepository/index.js
  3. 24
      web/client/src/sections/humanAffairs/actions/resourceRepository.js
  4. 6
      web/client/src/sections/humanAffairs/components/resourceRepository/folder-model.jsx
  5. 51
      web/client/src/sections/humanAffairs/components/resourceRepository/upload-modal.jsx
  6. 58
      web/client/src/sections/humanAffairs/containers/resourceRepository.jsx
  7. 3
      web/client/src/utils/webapi.js

82
api/app/lib/controllers/resourceRepository/index.js

@ -136,24 +136,27 @@ async function getResourceFileList(ctx, next) {
findObj.limit = Number(limit);
findObj.offset = Number(offset);
}
if (departmentName) {
const where = {
departmentName: departmentName
if ("公司培训资料" == type) {
findObj.where = { fileName: { $not: null } };
if (departmentName) {
findObj.where.departmentName = departmentName;
}
if (trainDate) {
//todo
// where.trainDate = trainDate
}
findObj.where = where;
}
if ("公司培训资料" == type) {
if (findObj.where) {
findObj.where.fileName = { $not: null };
} else {
findObj.where = { fileName: { $not: null } };
findObj.where.trainDate = trainDate;
}
rlst = await models.TrainingInformation.findAndCountAll(findObj);
} else {
if (departmentName) {
const where = {
departmentName: departmentName
}
if (trainDate) {
//todo
where.trainDate = trainDate
}
findObj.where = where;
}
rlst = await models.DeptTraining.findAndCountAll(findObj);
}
} else {
@ -246,11 +249,62 @@ async function delResourceClassify(ctx) {
ctx.body = { message: err.message || '新增培训资源储备库文件夹失败' }
}
}
//新增公司培训资料文件
async function postResourceFile(ctx) {
const transaction = await ctx.fs.dc.orm.transaction();
try {
const { fileList, currentSelect } = ctx.request.body;
const { models } = ctx.fs.dc;
const files = fileList && fileList.length && fileList.filter(f => f.fileName && f.fileType && f.fileSize && f.attachPath);
const splitArr = currentSelect.split("/");
if (files.length && splitArr.length == 3 && "公司培训资料" == splitArr[0]) {
const dataToSave = files.map(r => {
return {
...r,
departmentName: splitArr[1],
trainDate: splitArr[2],
updateDate: moment()
}
});
await models.TrainingInformation.bulkCreate(dataToSave, { transaction });
} else {
ctx.throw("新增公司培训资料文件内容不合法,请检查");
}
await transaction.commit();
ctx.status = 204;
} catch (err) {
await transaction.rollback();
ctx.status = 400;
ctx.body = { message: err.message || '新增公司培训资料文件失败' }
}
}
//删除公司培训资料文件
async function delResourceFile(ctx) {
const transaction = await ctx.fs.dc.orm.transaction();
try {
const { id } = ctx.params;
const { models } = ctx.fs.dc;
const old = await models.TrainingInformation.findOne({ where: { id: id } });
if (old) {
await models.TrainingInformation.destroy({ where: { id: id }, transaction });
}
await transaction.commit();
ctx.status = 204;
} catch (err) {
await transaction.rollback();
ctx.status = 400;
ctx.body = { message: err.message || '删除培训资源储备库文件夹失败' }
}
}
module.exports = {
getResourceClassify,
getResourceFileList,
postResourceClassify,
putResourceClassify,
delResourceClassify
delResourceClassify,
postResourceFile,
delResourceFile
}

11
api/app/lib/routes/resourceRepository/index.js

@ -15,8 +15,15 @@ module.exports = function (app, router, opts) {
app.fs.api.logAttr['PUT/train/trainFiles/resourceRepository/classify'] = { content: '编辑培训资源储备库文件夹', visible: true };
router.put('/train/trainFiles/resourceRepository/classify', resourceRepository.putResourceClassify);
app.fs.api.logAttr['DELETE/train/trainFiles/resourceRepository/classify'] = { content: '删除培训资源储备库文件夹', visible: true };
router.delete('/train/trainFiles/resourceRepository/classify', resourceRepository.delResourceClassify);
app.fs.api.logAttr['POST/train/trainFiles/resourceRepository/file'] = { content: '新增公司培训资料文件', visible: true };
router.post('/train/trainFiles/resourceRepository/file', resourceRepository.postResourceFile);
app.fs.api.logAttr['DELETE/train/trainFiles/resourceRepository/file/:id'] = { content: '删除公司培训资料文件', visible: true };
router.delete('/train/trainFiles/resourceRepository/file/:id', resourceRepository.delResourceFile);
};

24
web/client/src/sections/humanAffairs/actions/resourceRepository.js

@ -58,4 +58,26 @@ export function delResourceClassify(query) {
url: `${ApiTable.delResourceClassify}`,
msg: { option: "删除" },
});
}
}
export function postResourceFile(data) {
return (dispatch) =>
basicAction({
type: "post",
dispatch: dispatch,
data,
actionType: "POST_RESOURCE_FILE",
url: `${ApiTable.postResourceFile}`,
msg: { option: "上传" },
});
}
export function delResourceFile(id) {
return (dispatch) =>
basicAction({
type: "del",
dispatch: dispatch,
actionType: "DEL_RESOURCE_FILE",
url: ApiTable.delResourceFile.replace("{id}", id),
msg: { option: "删除" },
});
}

6
web/client/src/sections/humanAffairs/components/resourceRepository/folder-model.jsx

@ -11,7 +11,10 @@ const FolderModal = (props) => {
if (val && '' == val.trim()) {
return '不可以为空';
} else
if (val.length > 20) {
if (RegExp(/\//).exec(val)) {
return '不可以包含"/"特殊字符';
}
else if (val.length > 20) {
return '最大20字符';
} else {
if (oldData.children) {
@ -43,7 +46,6 @@ const FolderModal = (props) => {
return '';
}
const handleOk = () => {
form.current.validate().then((values) => {
if (!add) {
values.oldDepName = departmentName;

51
web/client/src/sections/humanAffairs/components/resourceRepository/upload-modal.jsx

@ -0,0 +1,51 @@
import React, { useRef, useState } from 'react';
import { Modal, Form, Button, Toast } from '@douyinfe/semi-ui';
import { IconUpload } from '@douyinfe/semi-icons';
const ResourceUploadModal = (props) => {
const { apiRoot, user, onCancel, onOk } = props;
const form = useRef();
const handleOk = () => {
form.current.validate().then((values) => {
onOk(values);
});
}
return (<Modal
title={"上传文件"}
visible={true}
maskClosable={false}
onOk={handleOk}
onCancel={onCancel}>
<Form
getFormApi={(formApi) => (form.current = formApi)}
labelPosition={'left'}
labelAlign={'right'}
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
>
<Form.Upload
field='attachPath'
label='文件上传'
action={apiRoot + '/attachments/resourceRepository?token=' + user.token}
maxSize={204800}
limit={5}
accept='.doc,.docx,.xls,.xlsx,.pdf,.pptx,.zip,.rar,.7z'
onAcceptInvalid={(files) => { Toast.error(`仅支持文件、压缩包类型`) }}
onSizeError={(file, fileList) => Toast.error(`${file.name} 超过200M`)}
onExceed={(fileList) => { Toast.error(`一次最多上传5个文件`) }}
rules={[{ required: true, message: '请上传文件' }]}
>
<Button icon={<IconUpload />} theme="light">
点击上传
</Button>
</Form.Upload>
<p>支持文件类型.doc,.docx,.xls,.xlsx,.pdf,.pptx
支持压缩包类型ziprar7z
文件大小一个不能超过200M一次最多上传5个文件
</p>
</Form>
</Modal >
)
}
export default ResourceUploadModal

58
web/client/src/sections/humanAffairs/containers/resourceRepository.jsx

@ -1,18 +1,24 @@
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 } from '@douyinfe/semi-ui';
import { IconSearch, IconEditStroked, IconMinusCircleStroked, IconPlusCircleStroked } from '@douyinfe/semi-icons';
import { getResourceClassify, getResourceFileList, postResourceClassify, putResourceClassify, delResourceClassify } from '../actions/resourceRepository';
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 '../style.less';
const ResourceRepository = (props) => {
const { dispatch, clientHeight, resourceClassify, resourceFilelist, isRequesting } = 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 ref = useRef();
useEffect(() => {
@ -40,9 +46,18 @@ const ResourceRepository = (props) => {
{
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>
<a href={'/_file-server/' + record.attachPath + '?filename=' + encodeURIComponent(record.fileName + record.fileType)}>下载</a>
<a onClick={() => handleDelFile(record.id)}>删除</a>
</Space>
</div>
}
}
];
@ -97,7 +112,13 @@ const ResourceRepository = (props) => {
});
}
}
const handleDelFile = (id) => {
dispatch(delResourceFile(id)).then(res => {
if (res.success) {
getFile(currentSelect);
}
})
}
const handleDel = (key) => {
const arr = key.split('/');
const query = {
@ -113,6 +134,26 @@ const ResourceRepository = (props) => {
}
});
}
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 getFile = (e) => {
const arr = e.split("/");
const query = { type: arr[0] };
@ -187,7 +228,7 @@ const ResourceRepository = (props) => {
<Row type="flex" justify="space-around" align="middle">
<Col span={18}>
<Space>
{currentSelect && currentSelect.includes("部门培训资料") ? null : <Button theme='solid' type='primary' >上传文件</Button>}
{currentSelect && currentSelect.includes("部门培训资料") ? null : <Button theme='solid' type='primary' onClick={() => { setUploadModalVisiable(true) }} >上传文件</Button>}
<span className="path-lable"><strong>当前文件夹{currentSelect}</strong></span>
</Space>
</Col>
@ -211,6 +252,14 @@ const ResourceRepository = (props) => {
onCancel={() => { setModelVisiable(false) }}
/> : null
}
{uploadModalVisiable ?
<ResourceUploadModal
apiRoot={apiRoot}
user={user}
onOk={handleUploadOk}
onCancel={() => { setUploadModalVisiable(false) }}
/> : null
}
</div>
</>
)
@ -221,6 +270,7 @@ function mapStateToProps(state) {
return {
user: auth.user,
actions: global.actions,
apiRoot: global.apiRoot,
clientHeight: global.clientHeight,
resourceClassify: resourceClassify.data || [],
resourceFilelist: resourceFilelist.data && resourceFilelist.data,

3
web/client/src/utils/webapi.js

@ -54,6 +54,9 @@ export const ApiTable = {
putResourceClassify: 'train/trainFiles/resourceRepository/classify',
delResourceClassify: 'train/trainFiles/resourceRepository/classify',
getResourceFileList: 'train/trainFiles/resourceRepository/fileList',
postResourceFile: 'train/trainFiles/resourceRepository/file',
delResourceFile: 'train/trainFiles/resourceRepository/file/{id}'
};
export const RouteTable = {

Loading…
Cancel
Save