Browse Source

文件下载

master
wenlele 1 year ago
parent
commit
bb274ecb2b
  1. 62
      api/app/lib/controllers/dataQuality/index.js
  2. 11
      api/app/lib/controllers/safetySpecification/index.js
  3. 5
      api/app/lib/routes/dataQuality/index.js
  4. 3
      api/package.json
  5. BIN
      web/client/assets/files/common/1687322895851_3.jpg
  6. BIN
      web/client/assets/files/common/1687322905542_2.jpg
  7. BIN
      web/client/assets/files/common/1687654158463_1.jpg
  8. BIN
      web/client/assets/files/common/1687657483581_2.jpg
  9. 12
      web/client/src/sections/dataQuality/actions/documentLibrary.js
  10. 95
      web/client/src/sections/dataQuality/containers/documentLibrary.js
  11. 12
      web/client/src/sections/safetySpecification/actions/specificationLibrary.js
  12. 66
      web/client/src/sections/safetySpecification/containers/specificationLibrary.js
  13. 4
      web/client/src/utils/webapi.js
  14. 3
      web/package.json
  15. 59
      web/routes/attachment/index.js

62
api/app/lib/controllers/dataQuality/index.js

@ -72,16 +72,18 @@ function getStandardDocFolders (opts) {
function postStandardDocFolders (opts) {
return async function (ctx, next) {
let message = '标准文档目录新增失败'
try {
const models = ctx.fs.dc.models;
const { name, parent } = ctx.request.body;
let findOne = await models.StandardDocFolder.findOne({ where: { name, parent: parent || null } })
if (findOne) {
message = '文件夹名重复'
throw ''
}
await models.StandardDocFolder.create({
name, parent, createAt: moment().format('YYYY-MM-DD HH:mm:ss')
@ -91,7 +93,7 @@ function postStandardDocFolders (opts) {
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = { message: '标准文档目录新增失败' }
ctx.body = { message: message }
}
}
}
@ -100,12 +102,16 @@ function postStandardDocFolders (opts) {
// 新增标准文档
function postStandardDocs (opts) {
return async function (ctx, next) {
let message = '新增标准文档失败'
try {
const models = ctx.fs.dc.models;
const { docName, standardType, tags, folder, path } = ctx.request.body;
let findOne = await models.StandardDoc.findOne({ where: { docName, folder: folder || null } })
if (findOne) {
message = '同一目录下文件名重复'
throw ''
}
await models.StandardDoc.create({
docName, standardType, tags, folder, path, createAt: moment().format('YYYY-MM-DD HH:mm:ss')
@ -115,7 +121,7 @@ function postStandardDocs (opts) {
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = { message: '新增标准文档失败' }
ctx.body = { message: message }
}
}
}
@ -390,6 +396,43 @@ function postFolderFile (opts) {
}
}
function fetchFiles (opts) {
return async function (ctx, next) {
try {
const models = ctx.fs.dc.models;
const { folderId } = ctx.request.body;
let fileAll = await models.StandardDoc.findAll({})
let folderAll = await models.StandardDocFolder.findAll({})
const recursive = (id) => {
let levelId = []
folderAll.map(d => {
if (id.includes(d.parent)) {
levelId.push(d.id)
folderId.push(d.id)
}
})
if (levelId.length > 0) {
recursive(levelId)
}
}
recursive(folderId)
let res = fileAll.filter(s => folderId.includes(s.folder)).map(x => ({ name: x.docName, url: x.path }))
ctx.status = 200;
ctx.body = res;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = { message: '获取文件夹下文件失败' }
}
}
}
module.exports = {
getStandardDocFolders,
postStandardDocFolders,
@ -399,5 +442,6 @@ module.exports = {
getBusinessRules,
delBusinessRules,
getRegularBasis,
postFolderFile
postFolderFile,
fetchFiles
}

11
api/app/lib/controllers/safetySpecification/index.js

@ -64,13 +64,18 @@ function delSpecifications (opts) {
// 新增标准文档
function postSpecifications (opts) {
return async function (ctx, next) {
let message = '新增数据安全规范失败'
try {
const models = ctx.fs.dc.models;
const { fileName, tags, path } = ctx.request.body;
let findOne = await models.DataSecuritySpecification.findOne({ where: { fileName } })
if (findOne) {
message = '文件名重复'
throw ''
}
await models.DataSecuritySpecification.create({
fileName, tags, path, createAt: moment().format('YYYY-MM-DD HH:mm:ss')
})
@ -79,7 +84,7 @@ function postSpecifications (opts) {
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = { message: '新增数据安全规范失败' }
ctx.body = { message: message }
}
}
}

5
api/app/lib/routes/dataQuality/index.js

@ -19,7 +19,7 @@ module.exports = function (app, router, opts, AuthCode) {
app.fs.api.logAttr['POST/postFolderFile'] = { content: '删除文件夹或文件', visible: true };
router.post('/postFolderFile', model.postFolderFile(opts))
app.fs.api.logAttr['POST/business-rules'] = { content: '新增/修改业务规则', visible: true };
router.post('/business-rules', model.postBusinessRules(opts))
@ -31,4 +31,7 @@ module.exports = function (app, router, opts, AuthCode) {
app.fs.api.logAttr['GET/regular-basis'] = { content: '查询规则依据列表', visible: true };
router.get('/regular-basis', model.getRegularBasis(opts));
app.fs.api.logAttr['POST/fetchFiles'] = { content: '获取文件夹下文件', visible: true };
router.post('/fetchFiles', model.fetchFiles(opts));
};

3
api/package.json

@ -21,9 +21,10 @@
"clickhouse": "^2.6.0",
"crypto-js": "^4.0.0",
"diskinfo": "0.0.3",
"file-saver": "^2.0.2",
"file-saver": "^2.0.5",
"fs-web-server-scaffold": "^2.0.2",
"ioredis": "^5.0.4",
"jszip": "^3.10.1",
"kafka-node": "^2.2.3",
"koa-convert": "^1.2.0",
"koa-proxy": "^0.9.0",

BIN
web/client/assets/files/common/1687322895851_3.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

BIN
web/client/assets/files/common/1687322905542_2.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

BIN
web/client/assets/files/common/1687654158463_1.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

BIN
web/client/assets/files/common/1687657483581_2.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

12
web/client/src/sections/dataQuality/actions/documentLibrary.js

@ -64,3 +64,15 @@ export function postFolderFile (data) {
});
}
export function fetchFiles (data = {}) {
return dispatch => basicAction({
type: 'post',
data,
dispatch: dispatch,
actionType: 'POST_FETCH_FILES',
url: `${ApiTable.fetchFiles}`,
msg: { error: '获取文件夹下文件失败' },
reducer: { name: '' }
});
}

95
web/client/src/sections/dataQuality/containers/documentLibrary.js

@ -9,7 +9,8 @@ import { RouteTable } from '$utils'
import { Tabs, Form, Input, Space, Button, Table, Breadcrumb, message, Popconfirm } from 'antd';
const { Search } = Input;
import { CreditCardFilled, FilePdfOutlined } from '@ant-design/icons';
import { agent } from 'superagent';
import JSZip from 'jszip'
import { saveAs } from 'file-saver'
let clicks = 0
function Approve ({ loading, clientHeight, actions, dispatch, }) {
@ -50,6 +51,53 @@ function Approve ({ loading, clientHeight, actions, dispatch, }) {
}
const getFileBlob = (url) => {
return new Promise((resolve, reject) => {
let request = new XMLHttpRequest()
request.responseType = "blob"
request.open("GET", url, true)
request.onload = (res) => {
if (res.target.status == 200) {
resolve(res.target.response)
} else {
reject(res)
}
}
request.send()
})
}
function packBulk ({ fileUrl }) {
let name = []
fileUrl.forEach(d => {
if (name.filter(f => d.name == f.name)?.length) {
name.filter(f => d.name == f.name)?.forEach(s => {
s.number = s.number + 1
d.name = d.name.slice(0, d.name.lastIndexOf(".")) + '(' + s.number + ')' + d.name.slice(d.name.lastIndexOf("."), d.name.length)
})
} else {
name.push({ name: d.name, number: 0 })
}
})
const zip = new JSZip()
let result = []
fileUrl.map(d => {
let url = d?.url?.replace(/\\/g, '/')
let promise = getFileBlob(url).then((res) => {
zip.file(d.name, res, { binary: true })
})
result.push(promise)
})
Promise.all(result).then(() => {
zip.generateAsync({ type: "blob" }).then((res) => {
saveAs(res, `${111}.zip`)
})
})
}
return <>
@ -77,12 +125,46 @@ function Approve ({ loading, clientHeight, actions, dispatch, }) {
<Button type="primary" onClick={() => {
setFileModal(true)
}}>上传</Button>
<Button type="primary" onClick={() => {
// let fileUrlList = fileData.filter(d => fileId.current.includes(d.id))?.map(s => s.path)
// console.log(fileUrlList);
<Button type="primary" onClick={async () => {
let fileUrl = []
if (fileId.current.length > 0) {
if (folderId.current.length > 0) {
await dispatch(dataQuality.fetchFiles({ folderId: folderId.current })).then(res => {
if (res.success) {
res.payload.data?.map(s => fileUrl.push(s))
}
})
}
fileData?.map(d => {
if (fileId.current.includes(d.id)) {
fileUrl.push({ url: d.path, name: d.docName })
}
})
console.log(fileUrl);
packBulk({ fileUrl: fileUrl })
} else {
if (folderId.current.length > 0) {
await dispatch(dataQuality.fetchFiles({ folderId: folderId.current })).then(res => {
if (res.success) {
if (res.payload.data?.length > 0) {
res.payload.data?.map(s => fileUrl.push(s))
} else {
message.warning({
duration: 1,
content: '所选文件夹没有文件',
});
}
}
})
} else {
message.warning({
duration: 1,
content: '未选择文件夹或文件',
});
}
packBulk({ fileUrl: fileUrl })
}
}}>下载</Button>
<Popconfirm
@ -153,6 +235,7 @@ function Approve ({ loading, clientHeight, actions, dispatch, }) {
setFileIds([])
folderId.current = []
setFolderIds([])
setCheckAll(false)
}}>{s.name}</Breadcrumb.Item>
)
})

12
web/client/src/sections/safetySpecification/actions/specificationLibrary.js

@ -38,3 +38,15 @@ export function delSpecifications (id) {
reducer: { name: '' }
});
}
export function packBulk (data = {}) {
return dispatch => basicAction({
type: 'post',
data,
dispatch: dispatch,
actionType: 'POST_PACKBULK',
url: `${ApiTable.packBulk}`,
msg: { option: '批量下载' },
reducer: { name: '' }
});
}

66
web/client/src/sections/safetySpecification/containers/specificationLibrary.js

@ -5,13 +5,12 @@ import { RouteRequest } from '@peace/utils';
import { RouteTable } from '$utils'
import SimpleBar from 'simplebar-react';
import FileModal from '../components/fileModal';
import { Tabs, Form, Input, Space, Button, Table, Checkbox, message, Pagination } from 'antd';
import { Input, Space, Button, message, Pagination } from 'antd';
const { Search } = Input;
import { CreditCardFilled, FilePdfOutlined } from '@ant-design/icons';
import { agent } from 'superagent';
const CheckboxGroup = Checkbox.Group;
import { FilePdfOutlined } from '@ant-design/icons';
import JSZip from 'jszip'
import { savAes } from 'file-saver'
import { saveAs } from 'file-saver'
function SpecificationLibrary ({ loading, clientHeight, actions, dispatch, }) {
@ -40,7 +39,44 @@ function SpecificationLibrary ({ loading, clientHeight, actions, dispatch, }) {
}
})
}
const getFileBlob = (url) => {
return new Promise((resolve, reject) => {
let request = new XMLHttpRequest()
request.responseType = "blob"
request.open("GET", url, true)
request.onload = (res) => {
if (res.target.status == 200) {
resolve(res.target.response)
} else {
reject(res)
}
}
request.send()
})
}
function packBulk ({ fileUrl, folderId }) {
const zip = new JSZip()
let result = []
fileUrl.map(d => {
let url = d?.url?.replace(/\\/g, '/')
let promise = getFileBlob(url).then((res) => {
zip.file(d.name, res, { binary: true })
})
result.push(promise)
})
Promise.all(result).then(() => {
zip.generateAsync({ type: "blob" }).then((res) => {
saveAs(res, `${111}.zip`)
})
})
}
return <>
@ -61,11 +97,17 @@ function SpecificationLibrary ({ loading, clientHeight, actions, dispatch, }) {
setFileModal(true)
}}>上传</Button>
<Button type="primary" onClick={() => {
// let fileUrlList = fileData?.data?.filter(d => fileId.current.includes(d.id))?.map(s => s.path)
// RouteRequest.post(RouteTable.packBulk, { fileUrl: fileUrlList });
if (fileId.current.length > 0) {
let fileUrlList = fileData?.data?.filter(d => fileId.current.includes(d.id))?.map(s => ({
url: s.path, name: s.fileName
})) || []
packBulk({ fileUrl: fileUrlList })
} else {
message.warning({
duration: 1,
content: '未选择文件',
});
}
}}>下载</Button>
<Button type="primary" onClick={() => {
if (fileId.current?.length) {
@ -80,7 +122,7 @@ function SpecificationLibrary ({ loading, clientHeight, actions, dispatch, }) {
url.map(d => {
RouteRequest.delete(RouteTable.cleanUpUploadTrash, { url: d });
})
resourceData({ page: 0, limit: 20 })
resourceData({ page: 0, limit: 20, keyword: keyword })
fileId.current = []
setFileIds([])
setFileIds(false)

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

@ -92,11 +92,11 @@ export const ApiTable = {
businessRules: 'business-rules',
delBusinessRules: 'business-rules/{id}',
regularBasis: 'regular-basis',
fetchFiles: 'fetchFiles',
//数据安全规范上传
specifications: 'data-security/specifications',
delSpecifications: 'data-security/specifications/{fileIds}',
packBulk: 'packBulk',
//元数据检索
searchMetadata: "meta/data/search",
@ -111,8 +111,6 @@ export const ApiTable = {
export const RouteTable = {
fileUpload: '/_upload/new',
cleanUpUploadTrash: '/_upload/cleanup',
packBulk: '/packBulk/{}',
};
const resultHandler = (resolve, reject) => (err, res) => {

3
web/package.json

@ -94,6 +94,7 @@
"superagent": "^6.1.0",
"uuid": "^8.3.1",
"webpack-dev-server": "^3.11.2",
"xlsx": "^0.16.9"
"xlsx": "^0.16.9",
"xmlhttprequest": "^1.8.0"
}
}

59
web/routes/attachment/index.js

@ -5,7 +5,6 @@ const path = require('path')
const fs = require('fs');
const OSS = require('ali-oss');
const uuid = require('uuid');
const JSZip = require('jszip');
const UploadPath = {
project: ['.txt', '.dwg', '.doc', '.docx', '.xls', '.xlsx', ".csv", '.pdf', '.pptx', '.png', '.jpg', '.svg', '.rar', '.zip', '.jpeg', '.mp4'],
@ -230,63 +229,6 @@ module.exports = {
}
}
const getFileBlob = (url) => {
return new Promise((resolve, reject) => {
let request = new XMLHttpRequest()
request.open("GET", url, true)
request.responseType = "blob"
request.onload = (res) => {
if (res.target.status == 200) {
resolve(res.target.response)
} else {
reject(res)
}
}
request.send()
})
}
const packBulk = async (ctx) => {
console.log(11111,);
try {
const { fileUrl, folderId } = parse(ctx.req)
const zip = new JSZip()
let result = []
let files = []
console.log(22,fileUrl);
fileUrl.map(a => {
let url = path.join(__dirname, '../../', './client', a);
files.push({ url, name: 111 })
})
for (let i in files) {
let promise = getFileBlob(files[i].url).then((res) => {
let format = files[i].url.substring(files[i].url.lastIndexOf("."), files[i].url.length)
zip.file(files[i].name + format, res, { binary: true })
})
result.push(promise)
console.log(77, promise);
}
console.log(33,);
Promise.all(result).then(() => {
zip.generateAsync({ type: "blob" }).then((res) => {
console.log(55,);
saveAs(res, `${111}.zip`)
})
})
console.log(44,);
ctx.status = 200;
ctx.body = {};
} catch (error) {
ctx.status = 400;
ctx.fs.logger.error(error);
ctx.body = { err: 'download error.' };
}
}
router.use(download_);
router.post('/_upload/new', upload);
@ -294,6 +236,5 @@ module.exports = {
router.post('/_upload/attachments/ali/:p', uploadAliOSS);
router.get('/_download/attachments/ali', downloadFromAli);
router.post('/_upload/attachments/:p', upload_);
router.post('/packBulk/:p', packBulk);
}
};

Loading…
Cancel
Save