From 3798154ac8b2335d290dd556dd40c23d258addaf Mon Sep 17 00:00:00 2001 From: wenlele Date: Thu, 18 May 2023 11:15:02 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=B8=8A=E4=BC=A0=E5=BF=85?= =?UTF-8?q?=E5=A1=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/app/lib/controllers/means/index.js | 5 +- .../sections/means/components/fileModal.jsx | 4 +- .../means/containers/devOpsStandard.jsx | 527 +++++++++++++++++- .../means/containers/faultInformation.jsx | 527 +++++++++++++++++- .../means/containers/projectMeans.jsx | 40 +- .../sections/means/containers/repairFQA.jsx | 523 ++++++++++++++++- 6 files changed, 1580 insertions(+), 46 deletions(-) diff --git a/api/app/lib/controllers/means/index.js b/api/app/lib/controllers/means/index.js index ec83b08..4447e4c 100644 --- a/api/app/lib/controllers/means/index.js +++ b/api/app/lib/controllers/means/index.js @@ -43,12 +43,15 @@ async function addEditFile (ctx, next) { async function fileList (ctx, next) { try { const models = ctx.fs.dc.models; - const { projectId, limit, page } = ctx.query; + const { projectId, type } = ctx.query; let options = { where: {}, } if (projectId) { options.where.projectId = projectId } + if (type) { + options.where.type = type + } let res = await models.ProjectFolder.findAll(options) diff --git a/web/client/src/sections/means/components/fileModal.jsx b/web/client/src/sections/means/components/fileModal.jsx index a94300f..3c6d896 100644 --- a/web/client/src/sections/means/components/fileModal.jsx +++ b/web/client/src/sections/means/components/fileModal.jsx @@ -5,7 +5,7 @@ import { IconAlertCircle } from '@douyinfe/semi-icons'; function FileModal (props) { - const { close, success, dispatch, actions, editData, pepProjectId, higherFile } = props; + const { close, success, dispatch, actions, editData, pepProjectId, higherFile ,type} = props; const { means } = actions; const form = useRef();//表单 @@ -24,7 +24,7 @@ function FileModal (props) { projectId: pepProjectId, fileName: v.fileName, higherFileId: editData?.higherFileId || v.higherFileId || null, - type: 1 + type })).then(v => { if (v.success) { close() diff --git a/web/client/src/sections/means/containers/devOpsStandard.jsx b/web/client/src/sections/means/containers/devOpsStandard.jsx index 8abf95c..5a55621 100644 --- a/web/client/src/sections/means/containers/devOpsStandard.jsx +++ b/web/client/src/sections/means/containers/devOpsStandard.jsx @@ -1,22 +1,525 @@ -import React, { useEffect } from 'react'; +import React, { useEffect, useState, useMemo } from 'react'; import { connect } from 'react-redux'; +import { Input, Button, Tree, Modal, Table, Upload, Pagination, Popconfirm } from '@douyinfe/semi-ui'; +import { IconDeleteStroked, IconEditStroked, IconUpload, IconAlertCircle } from '@douyinfe/semi-icons'; +import SimpleBar from 'simplebar-react'; +import FileModal from '../components/fileModal'; +import moment from 'moment'; +import './style.less' -const Server = (props) => { - const { dispatch, actions, user, loading, socket } = props +const Rest = (props) => { + const { dispatch, actions, user, qiniu, loading, clientHeight, overallProjectId } = props + const { install, means } = actions + const [pomsList, setPomsList] = useState([]); //项目 + const [showPomsList, setShowPomsList] = useState([]); //项目 + const [pepProjectId, setPepProjectId] = useState() //项目id + const [projectSearch, setProjectSearch] = useState() //项目搜索 + const [isFileModal, setIsFileModal] = useState(false) //添加文件弹窗 + const [editData, setEditData] = useState({}) //编辑参数 + const [treeData, settreeData] = useState([]); //文件夹列表 + const [higherFile, setHigherFile] = useState([]); //上级文件夹 + const [fileId, setFileId] = useState(); //文件夹id + const [uploadModal, setUploadModal] = useState(false) //上传弹窗 + const [uploadData, setUploadData] = useState({}) + const [dataSource, setDataSource] = useState([]) //表格数据 + const [query, setQuery] = useState({ limit: 10, page: 0 }) + const [count, setCount] = useState(0) + const [videoModalV, setVideoModalV] = useState(false); + const [videoUrl, setvideoUrl] = useState(null); + const [hint, setHint] = useState(false); + + useEffect(() => { + dispatch(install.getProjectPoms({ global: 1 })).then((res => { + if (res.success) { + let data = res.payload.data?.rows?.filter(v => v.pepProjectIsDelete !== 1)?.map(v => ({ pepProjectId: v.id, pepProjectName: v.pepProjectName || v.name })) + setPomsList(data) + setShowPomsList(data) + setPepProjectId(data[0]?.pepProjectId) + fileList(data[0]?.pepProjectId) + } + })) }, []) + useEffect(() => { + let data + if (overallProjectId) { + data = pomsList?.filter(v => (v.pepProjectName?.indexOf(projectSearch) != -1 && v.pepProjectId == overallProjectId)) + } else { + data = pomsList?.filter(v => v.pepProjectName?.indexOf(projectSearch) != -1) + } + setShowPomsList(data) + setPepProjectId(data[0]?.pepProjectId) + fileList(data[0]?.pepProjectId) + }, [projectSearch]) + + useEffect(() => { + setProjectSearch('') + let data + if (overallProjectId) { + data = pomsList?.filter(v => v.pepProjectId == overallProjectId) + } else { + data = pomsList + } + setShowPomsList(data) + setPepProjectId(data[0]?.pepProjectId) + fileList(data[0]?.pepProjectId) + }, [overallProjectId]) + + useEffect(() => { + if (fileId) { + filfolderFileListe() + setQuery({ limit: 10, page: 0 }) + } + }, [fileId]) + + const fileList = (id) => { + dispatch(means.fileList({ projectId: id, type: 4 })).then((res => { + if (res.success) { + let data = res.payload.data + let oneLevel = res.payload.data?.filter(f => !f.higherFileId) || [] + settreeData(listErgodic(oneLevel, data)) + setHigherFile(data?.map(d => ({ name: d.fileName, value: d.id }))) + } + })) + } + + + + const filfolderFileListe = (params) => { + let fileIds = [] + const treeDataList = (data, value) => { + data?.map(c => { + if (c.key == fileId || value) { + fileIds.push(c.key) + if (c.children?.length) { + treeDataList(c.children, true) + } + } else if (c.children?.length) { + treeDataList(c.children) + } + }) + } + treeDataList(treeData) + let datas = params || query + dispatch(means.folderFileList({ fileId: JSON.stringify(fileIds), ...datas })).then((res => { + if (res.success) { + setDataSource(res.payload.data?.rows || []) + setCount(res.payload.data?.count) + } + })) + } + + const listErgodic = (level, datas) => { + let data = [] + level.map(v => { + let list = { + value: v.id, + key: v.id, + } + let childrenList = datas?.filter(c => c.higherFileId == list.value) + if (childrenList?.length) { + list.children = listErgodic(childrenList, datas) + } + let fileData + dispatch(means.folderFileList({ fileId: JSON.stringify([v.id]) })).then((res => { + if (res.success) { + fileData = res.payload.data?.rows?.length + } + })) + list.label =
+
{v.fileName}
+ { + setIsFileModal(true) + setEditData({ id: v.id, fileName: v.fileName, higherFileId: v.higherFileId }) + }} /> + { + if (!fileData || !list?.children?.length) { + dispatch(means.delFile(v.id)).then((res => { + if (res.success) { + fileList(pepProjectId) + } + })) + } + }} + // onCancel={onCancel} + > + + + +
+ + data.push(list) + }) + return data + } + + + const column = [ + { + title: '文件名', + dataIndex: 'name', + key: 'name', + render: (text) => text?.length > 30 ?
{text.slice(0, 30)}...
: text + }, + { + title: '文件大小', + dataIndex: 'size', + key: 'size', + render: (text) => { + let show = '--' + if (text < 1048576) { + show = (text / 1024).toFixed(1) + ' KB' + } else { + show = (text / 1048576).toFixed(1) + ' MB' + } + return show + } + }, + { + title: '上传时间', + dataIndex: 'uploadTime', + key: 'uploadTime', + render: (text) => text ? moment(text).format("YYYY-MM-DD HH:mm:ss") : '--' + }, + { + title: '操作', + key: 'operation', + dataIndex: 'operation', + render: (_, r) => { + return
+ + + {(r.url?.indexOf("txt") !== -1 || r.url?.indexOf("rar") !== -1 || r.url?.indexOf("zip") !== -1) ? "" + : + + } + + + +
+ } + }, + ] + const data = [ + { + key: '1', + name: 'John Brown', + age: 32, + address: 'New York No. 1 Lake Park', + tags: ['nice', 'developer'], + }, + { + key: '2', + name: 'Jim Green', + age: 42, + address: 'London No. 1 Lake Park', + tags: ['loser'], + }, + { + key: '3', + name: 'Joe Black', + age: 32, + address: 'Sydney No. 1 Lake Park', + tags: ['cool', 'teacher'], + }, + ]; + + const preview = (url) => { + let link = encodeURI(`${qiniu}/${url}`) + if (url.indexOf("pdf") !== -1) { + window.open(link) + } else if (url.indexOf("png") !== -1 || url.indexOf("jpg") !== -1) { + setVideoModalV(true) + setvideoUrl(link) + } else { + window.open(`https://view.officeapps.live.com/op/view.aspx?src=${link}`) + } + } return ( - <> -
- + //
+
+ +
+ setProjectSearch(v)} /> + + {showPomsList?.map(v => { + return
{ + setPepProjectId(v.pepProjectId) + fileList(v.pepProjectId) + }}> + +
{v.pepProjectName}
+ +
+ })} +
+
+ +
+ {/* 文件夹———树 */} +
+ + {/* 添加文件弹窗 */} + {isFileModal ? + { + setIsFileModal(false) + setEditData({}) + }} + success={() => { + fileList(pepProjectId) + }} + /> : "" + } + + { + setFileId(selectedKey) + }} + /> + + +
+ {/* 表格 */} +
+
+ +
当前文件夹:{higherFile?.filter(c => c.value == fileId)[0]?.name ||
请选择文件夹
}
+ {uploadModal ? + { + if (uploadData?.name) { + dispatch(means.addFile({ ...uploadData, fileId: fileId })).then(v => { + if (v.success) { + setUploadModal(false) + filfolderFileListe({ limit: 10, page: 0 }) + setQuery({ limit: 10, page: 0 }) + setUploadData({}) + setHint(false) + } + }) + } else { + setHint(true) + } + }} + width={607} + onCancel={() => { + setUploadModal(false) + setHint(false) + setUploadData({}) + }} + > +
+
文件*
+ { + setUploadData({}) + }} + onSuccess={(responseBody, file) => { + + setUploadData({ + name: file.name, + size: file.size, + url: responseBody?.uploaded, + uploadTime: moment().format("YYYY-MM-DD HH:mm:ss") + }) + }} + > + + +
+ {hint && !uploadData?.name &&
请上传文件
} +
: "" + + } +
+ + + 暂无告警数据 + + } + onRow={(record, index) => { + if (index % 1 === 0) { + return { style: { background: '#FAFCFF' } } + } + }} + // rowSelection={{ + // // selectedRowKeys: selected || [], + // getCheckboxProps: record => ({ + // // disabled: record.confirmTime ? true : false, + // // name: record.name, + // }), + // onSelect: (record, selected) => { + // // console.log(`select row: ${selected}`, record); + // }, + // // onSelectAll: (selected, selectedRows) => { + // // console.log(`select all rows: ${selected}`, selectedRows); + // // }, + // onChange: (selectedRowKeys, selectedRows) => { + // // console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows); + // // setSelected(selectedRows?.map(v => v.id)) + // }, + // }} + /> + + + {count > 0 ?
+ + 共{count}个文件 + + { + setQuery({ limit: pageSize, page: currentPage - 1 }); + filfolderFileListe({ limit: pageSize, page: currentPage - 1 }) + }} + /> +
: ""} + {/*
+
+
勾选{selected.length}条问题
+ + +
+ {count > 0 ?
+ + 共{count}个问题 + + { + setQuery({ limit: pageSize, page: currentPage - 1 }); + }} + /> +
: ""} + +
*/} + - + { + videoModalV ? + { + setVideoModalV(false) + setvideoUrl('') + }} width={400} + footer={null}> + +
+ +
+
+ : '' + } + + // ) } @@ -24,11 +527,13 @@ function mapStateToProps (state) { const { auth, global, members, webSocket } = state; return { // loading: members.isRequesting, - // user: auth.user, - // actions: global.actions, - // members: members.data, + user: auth.user, + actions: global.actions, + overallProjectId: global.pepProjectId, // socket: webSocket.socket + clientHeight: global.clientHeight, + qiniu: global.qiniu?.domain }; } -export default connect(mapStateToProps)(Server); +export default connect(mapStateToProps)(Rest); diff --git a/web/client/src/sections/means/containers/faultInformation.jsx b/web/client/src/sections/means/containers/faultInformation.jsx index c116207..397b959 100644 --- a/web/client/src/sections/means/containers/faultInformation.jsx +++ b/web/client/src/sections/means/containers/faultInformation.jsx @@ -1,22 +1,525 @@ -import React, { useEffect } from 'react'; +import React, { useEffect, useState, useMemo } from 'react'; import { connect } from 'react-redux'; +import { Input, Button, Tree, Modal, Table, Upload, Pagination, Popconfirm } from '@douyinfe/semi-ui'; +import { IconDeleteStroked, IconEditStroked, IconUpload, IconAlertCircle } from '@douyinfe/semi-icons'; +import SimpleBar from 'simplebar-react'; +import FileModal from '../components/fileModal'; +import moment from 'moment'; +import './style.less' -const SetControl = (props) => { - const { dispatch, actions, user, loading, socket } = props +const Rest = (props) => { + const { dispatch, actions, user, qiniu, loading, clientHeight, overallProjectId } = props + const { install, means } = actions + const [pomsList, setPomsList] = useState([]); //项目 + const [showPomsList, setShowPomsList] = useState([]); //项目 + const [pepProjectId, setPepProjectId] = useState() //项目id + const [projectSearch, setProjectSearch] = useState() //项目搜索 + const [isFileModal, setIsFileModal] = useState(false) //添加文件弹窗 + const [editData, setEditData] = useState({}) //编辑参数 + const [treeData, settreeData] = useState([]); //文件夹列表 + const [higherFile, setHigherFile] = useState([]); //上级文件夹 + const [fileId, setFileId] = useState(); //文件夹id + const [uploadModal, setUploadModal] = useState(false) //上传弹窗 + const [uploadData, setUploadData] = useState({}) + const [dataSource, setDataSource] = useState([]) //表格数据 + const [query, setQuery] = useState({ limit: 10, page: 0 }) + const [count, setCount] = useState(0) + const [videoModalV, setVideoModalV] = useState(false); + const [videoUrl, setvideoUrl] = useState(null); + const [hint, setHint] = useState(false); + + useEffect(() => { + dispatch(install.getProjectPoms({ global: 1 })).then((res => { + if (res.success) { + let data = res.payload.data?.rows?.filter(v => v.pepProjectIsDelete !== 1)?.map(v => ({ pepProjectId: v.id, pepProjectName: v.pepProjectName || v.name })) + setPomsList(data) + setShowPomsList(data) + setPepProjectId(data[0]?.pepProjectId) + fileList(data[0]?.pepProjectId) + } + })) }, []) + useEffect(() => { + let data + if (overallProjectId) { + data = pomsList?.filter(v => (v.pepProjectName?.indexOf(projectSearch) != -1 && v.pepProjectId == overallProjectId)) + } else { + data = pomsList?.filter(v => v.pepProjectName?.indexOf(projectSearch) != -1) + } + setShowPomsList(data) + setPepProjectId(data[0]?.pepProjectId) + fileList(data[0]?.pepProjectId) + }, [projectSearch]) + + useEffect(() => { + setProjectSearch('') + let data + if (overallProjectId) { + data = pomsList?.filter(v => v.pepProjectId == overallProjectId) + } else { + data = pomsList + } + setShowPomsList(data) + setPepProjectId(data[0]?.pepProjectId) + fileList(data[0]?.pepProjectId) + }, [overallProjectId]) + + useEffect(() => { + if (fileId) { + filfolderFileListe() + setQuery({ limit: 10, page: 0 }) + } + }, [fileId]) + + const fileList = (id) => { + dispatch(means.fileList({ projectId: id, type: 3 })).then((res => { + if (res.success) { + let data = res.payload.data + let oneLevel = res.payload.data?.filter(f => !f.higherFileId) || [] + settreeData(listErgodic(oneLevel, data)) + setHigherFile(data?.map(d => ({ name: d.fileName, value: d.id }))) + } + })) + } + + + + const filfolderFileListe = (params) => { + let fileIds = [] + const treeDataList = (data, value) => { + data?.map(c => { + if (c.key == fileId || value) { + fileIds.push(c.key) + if (c.children?.length) { + treeDataList(c.children, true) + } + } else if (c.children?.length) { + treeDataList(c.children) + } + }) + } + treeDataList(treeData) + let datas = params || query + dispatch(means.folderFileList({ fileId: JSON.stringify(fileIds), ...datas })).then((res => { + if (res.success) { + setDataSource(res.payload.data?.rows || []) + setCount(res.payload.data?.count) + } + })) + } + + const listErgodic = (level, datas) => { + let data = [] + level.map(v => { + let list = { + value: v.id, + key: v.id, + } + let childrenList = datas?.filter(c => c.higherFileId == list.value) + if (childrenList?.length) { + list.children = listErgodic(childrenList, datas) + } + let fileData + dispatch(means.folderFileList({ fileId: JSON.stringify([v.id]) })).then((res => { + if (res.success) { + fileData = res.payload.data?.rows?.length + } + })) + list.label =
+
{v.fileName}
+ { + setIsFileModal(true) + setEditData({ id: v.id, fileName: v.fileName, higherFileId: v.higherFileId }) + }} /> + { + if (!fileData || !list?.children?.length) { + dispatch(means.delFile(v.id)).then((res => { + if (res.success) { + fileList(pepProjectId) + } + })) + } + }} + // onCancel={onCancel} + > + + + +
+ + data.push(list) + }) + return data + } + + + const column = [ + { + title: '文件名', + dataIndex: 'name', + key: 'name', + render: (text) => text?.length > 30 ?
{text.slice(0, 30)}...
: text + }, + { + title: '文件大小', + dataIndex: 'size', + key: 'size', + render: (text) => { + let show = '--' + if (text < 1048576) { + show = (text / 1024).toFixed(1) + ' KB' + } else { + show = (text / 1048576).toFixed(1) + ' MB' + } + return show + } + }, + { + title: '上传时间', + dataIndex: 'uploadTime', + key: 'uploadTime', + render: (text) => text ? moment(text).format("YYYY-MM-DD HH:mm:ss") : '--' + }, + { + title: '操作', + key: 'operation', + dataIndex: 'operation', + render: (_, r) => { + return + } + }, + ] + const data = [ + { + key: '1', + name: 'John Brown', + age: 32, + address: 'New York No. 1 Lake Park', + tags: ['nice', 'developer'], + }, + { + key: '2', + name: 'Jim Green', + age: 42, + address: 'London No. 1 Lake Park', + tags: ['loser'], + }, + { + key: '3', + name: 'Joe Black', + age: 32, + address: 'Sydney No. 1 Lake Park', + tags: ['cool', 'teacher'], + }, + ]; + + const preview = (url) => { + let link = encodeURI(`${qiniu}/${url}`) + if (url.indexOf("pdf") !== -1) { + window.open(link) + } else if (url.indexOf("png") !== -1 || url.indexOf("jpg") !== -1) { + setVideoModalV(true) + setvideoUrl(link) + } else { + window.open(`https://view.officeapps.live.com/op/view.aspx?src=${link}`) + } + } return ( - <> -
- + //
+
+ +
+ setProjectSearch(v)} /> + + {showPomsList?.map(v => { + return
{ + setPepProjectId(v.pepProjectId) + fileList(v.pepProjectId) + }}> + +
{v.pepProjectName}
+ +
+ })} +
+
+ +
+ {/* 文件夹———树 */} +
+ + {/* 添加文件弹窗 */} + {isFileModal ? + { + setIsFileModal(false) + setEditData({}) + }} + success={() => { + fileList(pepProjectId) + }} + /> : "" + } + + { + setFileId(selectedKey) + }} + /> + + +
+ {/* 表格 */} +
+
+ +
当前文件夹:{higherFile?.filter(c => c.value == fileId)[0]?.name ||
请选择文件夹
}
+ {uploadModal ? + { + if (uploadData?.name) { + dispatch(means.addFile({ ...uploadData, fileId: fileId })).then(v => { + if (v.success) { + setUploadModal(false) + filfolderFileListe({ limit: 10, page: 0 }) + setQuery({ limit: 10, page: 0 }) + setUploadData({}) + setHint(false) + } + }) + } else { + setHint(true) + } + }} + width={607} + onCancel={() => { + setUploadModal(false) + setHint(false) + setUploadData({}) + }} + > +
+
文件*
+ { + setUploadData({}) + }} + onSuccess={(responseBody, file) => { + + setUploadData({ + name: file.name, + size: file.size, + url: responseBody?.uploaded, + uploadTime: moment().format("YYYY-MM-DD HH:mm:ss") + }) + }} + > + + +
+ {hint && !uploadData?.name &&
请上传文件
} +
: "" + + } +
+ +
+ 暂无告警数据 + + } + onRow={(record, index) => { + if (index % 1 === 0) { + return { style: { background: '#FAFCFF' } } + } + }} + // rowSelection={{ + // // selectedRowKeys: selected || [], + // getCheckboxProps: record => ({ + // // disabled: record.confirmTime ? true : false, + // // name: record.name, + // }), + // onSelect: (record, selected) => { + // // console.log(`select row: ${selected}`, record); + // }, + // // onSelectAll: (selected, selectedRows) => { + // // console.log(`select all rows: ${selected}`, selectedRows); + // // }, + // onChange: (selectedRowKeys, selectedRows) => { + // // console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows); + // // setSelected(selectedRows?.map(v => v.id)) + // }, + // }} + /> + + + {count > 0 ?
+ + 共{count}个文件 + + { + setQuery({ limit: pageSize, page: currentPage - 1 }); + filfolderFileListe({ limit: pageSize, page: currentPage - 1 }) + }} + /> +
: ""} + {/*
+
+
勾选{selected.length}条问题
+ + +
+ {count > 0 ?
+ + 共{count}个问题 + + { + setQuery({ limit: pageSize, page: currentPage - 1 }); + }} + /> +
: ""} + +
*/} + - + { + videoModalV ? + { + setVideoModalV(false) + setvideoUrl('') + }} width={400} + footer={null}> + +
+ +
+
+ : '' + } + + // ) } @@ -24,11 +527,13 @@ function mapStateToProps (state) { const { auth, global, members, webSocket } = state; return { // loading: members.isRequesting, - // user: auth.user, - // actions: global.actions, - // members: members.data, + user: auth.user, + actions: global.actions, + overallProjectId: global.pepProjectId, // socket: webSocket.socket + clientHeight: global.clientHeight, + qiniu: global.qiniu?.domain }; } -export default connect(mapStateToProps)(SetControl); +export default connect(mapStateToProps)(Rest); diff --git a/web/client/src/sections/means/containers/projectMeans.jsx b/web/client/src/sections/means/containers/projectMeans.jsx index 59f0927..dc80dd6 100644 --- a/web/client/src/sections/means/containers/projectMeans.jsx +++ b/web/client/src/sections/means/containers/projectMeans.jsx @@ -1,7 +1,7 @@ import React, { useEffect, useState, useMemo } from 'react'; import { connect } from 'react-redux'; import { Input, Button, Tree, Modal, Table, Upload, Pagination, Popconfirm } from '@douyinfe/semi-ui'; -import { IconDeleteStroked, IconEditStroked, IconUpload } from '@douyinfe/semi-icons'; +import { IconDeleteStroked, IconEditStroked, IconUpload, IconAlertCircle } from '@douyinfe/semi-icons'; import SimpleBar from 'simplebar-react'; import FileModal from '../components/fileModal'; import moment from 'moment'; @@ -28,6 +28,7 @@ const Rest = (props) => { const [count, setCount] = useState(0) const [videoModalV, setVideoModalV] = useState(false); const [videoUrl, setvideoUrl] = useState(null); + const [hint, setHint] = useState(false); @@ -71,13 +72,13 @@ const Rest = (props) => { useEffect(() => { if (fileId) { - filfolderFileListe() + setQuery({ limit: 10, page: 0 }) } }, [fileId]) const fileList = (id) => { - dispatch(means.fileList({ projectId: id })).then((res => { + dispatch(means.fileList({ projectId: id, type: 1 })).then((res => { if (res.success) { let data = res.payload.data let oneLevel = res.payload.data?.filter(f => !f.higherFileId) || [] @@ -203,6 +204,7 @@ const Rest = (props) => { dispatch(means.delfolderFile(r.id)).then((res => { if (res.success) { filfolderFileListe({ limit: 10, page: 0 }) + setQuery({ limit: 10, page: 0 }) } })) }} @@ -297,6 +299,7 @@ const Rest = (props) => { editData={editData} higherFile={higherFile} pepProjectId={pepProjectId} + type={1} close={() => { setIsFileModal(false) setEditData({}) @@ -338,28 +341,40 @@ const Rest = (props) => { cancelText="取消" visible={true} onOk={() => { - dispatch(means.addFile({ ...uploadData, fileId: fileId })).then(v => { - if (v.success) { - setUploadModal(false) - filfolderFileListe({ limit: 10, page: 0 }) - } - }) + if (uploadData?.name) { + dispatch(means.addFile({ ...uploadData, fileId: fileId })).then(v => { + if (v.success) { + setUploadModal(false) + filfolderFileListe({ limit: 10, page: 0 }) + setQuery({ limit: 10, page: 0 }) + setUploadData({}) + setHint(false) + } + }) + } else { + setHint(true) + } }} width={607} onCancel={() => { setUploadModal(false) + setHint(false) + setUploadData({}) }} > -
-
文件:
+
+
文件*
{ + setUploadData({}) + }} onSuccess={(responseBody, file) => { - console.log(11111, responseBody, file); + setUploadData({ name: file.name, size: file.size, @@ -373,6 +388,7 @@ const Rest = (props) => {
+ {hint && !uploadData?.name &&
请上传文件
} : "" } diff --git a/web/client/src/sections/means/containers/repairFQA.jsx b/web/client/src/sections/means/containers/repairFQA.jsx index 27f758a..87abd9b 100644 --- a/web/client/src/sections/means/containers/repairFQA.jsx +++ b/web/client/src/sections/means/containers/repairFQA.jsx @@ -1,22 +1,525 @@ -import React, { useEffect } from 'react'; +import React, { useEffect, useState, useMemo } from 'react'; import { connect } from 'react-redux'; +import { Input, Button, Tree, Modal, Table, Upload, Pagination, Popconfirm } from '@douyinfe/semi-ui'; +import { IconDeleteStroked, IconEditStroked, IconUpload, IconAlertCircle } from '@douyinfe/semi-icons'; +import SimpleBar from 'simplebar-react'; +import FileModal from '../components/fileModal'; +import moment from 'moment'; +import './style.less' const Rest = (props) => { - const { dispatch, actions, user, loading, socket } = props + const { dispatch, actions, user, qiniu, loading, clientHeight, overallProjectId } = props + const { install, means } = actions + const [pomsList, setPomsList] = useState([]); //项目 + const [showPomsList, setShowPomsList] = useState([]); //项目 + const [pepProjectId, setPepProjectId] = useState() //项目id + const [projectSearch, setProjectSearch] = useState() //项目搜索 + const [isFileModal, setIsFileModal] = useState(false) //添加文件弹窗 + const [editData, setEditData] = useState({}) //编辑参数 + const [treeData, settreeData] = useState([]); //文件夹列表 + const [higherFile, setHigherFile] = useState([]); //上级文件夹 + const [fileId, setFileId] = useState(); //文件夹id + const [uploadModal, setUploadModal] = useState(false) //上传弹窗 + const [uploadData, setUploadData] = useState({}) + const [dataSource, setDataSource] = useState([]) //表格数据 + const [query, setQuery] = useState({ limit: 10, page: 0 }) + const [count, setCount] = useState(0) + const [videoModalV, setVideoModalV] = useState(false); + const [videoUrl, setvideoUrl] = useState(null); + const [hint, setHint] = useState(false); + + useEffect(() => { + dispatch(install.getProjectPoms({ global: 1 })).then((res => { + if (res.success) { + let data = res.payload.data?.rows?.filter(v => v.pepProjectIsDelete !== 1)?.map(v => ({ pepProjectId: v.id, pepProjectName: v.pepProjectName || v.name })) + setPomsList(data) + setShowPomsList(data) + setPepProjectId(data[0]?.pepProjectId) + fileList(data[0]?.pepProjectId) + } + })) }, []) + useEffect(() => { + let data + if (overallProjectId) { + data = pomsList?.filter(v => (v.pepProjectName?.indexOf(projectSearch) != -1 && v.pepProjectId == overallProjectId)) + } else { + data = pomsList?.filter(v => v.pepProjectName?.indexOf(projectSearch) != -1) + } + setShowPomsList(data) + setPepProjectId(data[0]?.pepProjectId) + fileList(data[0]?.pepProjectId) + }, [projectSearch]) + + useEffect(() => { + setProjectSearch('') + let data + if (overallProjectId) { + data = pomsList?.filter(v => v.pepProjectId == overallProjectId) + } else { + data = pomsList + } + setShowPomsList(data) + setPepProjectId(data[0]?.pepProjectId) + fileList(data[0]?.pepProjectId) + }, [overallProjectId]) + + useEffect(() => { + if (fileId) { + filfolderFileListe() + setQuery({ limit: 10, page: 0 }) + } + }, [fileId]) + + const fileList = (id) => { + dispatch(means.fileList({ projectId: id, type: 2 })).then((res => { + if (res.success) { + let data = res.payload.data + let oneLevel = res.payload.data?.filter(f => !f.higherFileId) || [] + settreeData(listErgodic(oneLevel, data)) + setHigherFile(data?.map(d => ({ name: d.fileName, value: d.id }))) + } + })) + } + + + + const filfolderFileListe = (params) => { + let fileIds = [] + const treeDataList = (data, value) => { + data?.map(c => { + if (c.key == fileId || value) { + fileIds.push(c.key) + if (c.children?.length) { + treeDataList(c.children, true) + } + } else if (c.children?.length) { + treeDataList(c.children) + } + }) + } + treeDataList(treeData) + let datas = params || query + dispatch(means.folderFileList({ fileId: JSON.stringify(fileIds), ...datas })).then((res => { + if (res.success) { + setDataSource(res.payload.data?.rows || []) + setCount(res.payload.data?.count) + } + })) + } + + const listErgodic = (level, datas) => { + let data = [] + level.map(v => { + let list = { + value: v.id, + key: v.id, + } + let childrenList = datas?.filter(c => c.higherFileId == list.value) + if (childrenList?.length) { + list.children = listErgodic(childrenList, datas) + } + let fileData + dispatch(means.folderFileList({ fileId: JSON.stringify([v.id]) })).then((res => { + if (res.success) { + fileData = res.payload.data?.rows?.length + } + })) + list.label =
+
{v.fileName}
+ { + setIsFileModal(true) + setEditData({ id: v.id, fileName: v.fileName, higherFileId: v.higherFileId }) + }} /> + { + if (!fileData || !list?.children?.length) { + dispatch(means.delFile(v.id)).then((res => { + if (res.success) { + fileList(pepProjectId) + } + })) + } + }} + // onCancel={onCancel} + > + + + +
+ + data.push(list) + }) + return data + } + + + const column = [ + { + title: '文件名', + dataIndex: 'name', + key: 'name', + render: (text) => text?.length > 30 ?
{text.slice(0, 30)}...
: text + }, + { + title: '文件大小', + dataIndex: 'size', + key: 'size', + render: (text) => { + let show = '--' + if (text < 1048576) { + show = (text / 1024).toFixed(1) + ' KB' + } else { + show = (text / 1048576).toFixed(1) + ' MB' + } + return show + } + }, + { + title: '上传时间', + dataIndex: 'uploadTime', + key: 'uploadTime', + render: (text) => text ? moment(text).format("YYYY-MM-DD HH:mm:ss") : '--' + }, + { + title: '操作', + key: 'operation', + dataIndex: 'operation', + render: (_, r) => { + return
+ } + }, + ] + const data = [ + { + key: '1', + name: 'John Brown', + age: 32, + address: 'New York No. 1 Lake Park', + tags: ['nice', 'developer'], + }, + { + key: '2', + name: 'Jim Green', + age: 42, + address: 'London No. 1 Lake Park', + tags: ['loser'], + }, + { + key: '3', + name: 'Joe Black', + age: 32, + address: 'Sydney No. 1 Lake Park', + tags: ['cool', 'teacher'], + }, + ]; + + const preview = (url) => { + let link = encodeURI(`${qiniu}/${url}`) + if (url.indexOf("pdf") !== -1) { + window.open(link) + } else if (url.indexOf("png") !== -1 || url.indexOf("jpg") !== -1) { + setVideoModalV(true) + setvideoUrl(link) + } else { + window.open(`https://view.officeapps.live.com/op/view.aspx?src=${link}`) + } + } return ( - <> -
- + //
+
+ +
+ setProjectSearch(v)} /> + + {showPomsList?.map(v => { + return
{ + setPepProjectId(v.pepProjectId) + fileList(v.pepProjectId) + }}> + +
{v.pepProjectName}
+ +
+ })} +
+
+ +
+ {/* 文件夹———树 */} +
+ + {/* 添加文件弹窗 */} + {isFileModal ? + { + setIsFileModal(false) + setEditData({}) + }} + success={() => { + fileList(pepProjectId) + }} + /> : "" + } + + { + setFileId(selectedKey) + }} + /> + + +
+ {/* 表格 */} +
+
+ +
当前文件夹:{higherFile?.filter(c => c.value == fileId)[0]?.name ||
请选择文件夹
}
+ {uploadModal ? + { + if (uploadData?.name) { + dispatch(means.addFile({ ...uploadData, fileId: fileId })).then(v => { + if (v.success) { + setUploadModal(false) + filfolderFileListe({ limit: 10, page: 0 }) + setQuery({ limit: 10, page: 0 }) + setUploadData({}) + setHint(false) + } + }) + } else { + setHint(true) + } + }} + width={607} + onCancel={() => { + setUploadModal(false) + setHint(false) + setUploadData({}) + }} + > +
+
文件*
+ { + setUploadData({}) + }} + onSuccess={(responseBody, file) => { + + setUploadData({ + name: file.name, + size: file.size, + url: responseBody?.uploaded, + uploadTime: moment().format("YYYY-MM-DD HH:mm:ss") + }) + }} + > + + +
+ {hint && !uploadData?.name &&
请上传文件
} +
: "" + + } +
+ +
+ 暂无告警数据 + + } + onRow={(record, index) => { + if (index % 1 === 0) { + return { style: { background: '#FAFCFF' } } + } + }} + // rowSelection={{ + // // selectedRowKeys: selected || [], + // getCheckboxProps: record => ({ + // // disabled: record.confirmTime ? true : false, + // // name: record.name, + // }), + // onSelect: (record, selected) => { + // // console.log(`select row: ${selected}`, record); + // }, + // // onSelectAll: (selected, selectedRows) => { + // // console.log(`select all rows: ${selected}`, selectedRows); + // // }, + // onChange: (selectedRowKeys, selectedRows) => { + // // console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows); + // // setSelected(selectedRows?.map(v => v.id)) + // }, + // }} + /> + + + {count > 0 ?
+ + 共{count}个文件 + + { + setQuery({ limit: pageSize, page: currentPage - 1 }); + filfolderFileListe({ limit: pageSize, page: currentPage - 1 }) + }} + /> +
: ""} + {/*
+
+
勾选{selected.length}条问题
+ + +
+ {count > 0 ?
+ + 共{count}个问题 + + { + setQuery({ limit: pageSize, page: currentPage - 1 }); + }} + /> +
: ""} + +
*/} + - + { + videoModalV ? + { + setVideoModalV(false) + setvideoUrl('') + }} width={400} + footer={null}> + +
+ +
+
+ : '' + } + + // ) } @@ -24,10 +527,12 @@ function mapStateToProps (state) { const { auth, global, members, webSocket } = state; return { // loading: members.isRequesting, - // user: auth.user, - // actions: global.actions, - // members: members.data, + user: auth.user, + actions: global.actions, + overallProjectId: global.pepProjectId, // socket: webSocket.socket + clientHeight: global.clientHeight, + qiniu: global.qiniu?.domain }; }