diff --git a/api/.vscode/launch.json b/api/.vscode/launch.json index 2217519..e901f66 100644 --- a/api/.vscode/launch.json +++ b/api/.vscode/launch.json @@ -16,6 +16,7 @@ "-p 4400", // 研发 "-g postgres://FashionAdmin:123456@10.8.30.39:5432/GovernmentDataResourceCenter", + // "-g postgres://FashionAdmin:123456@10.8.30.156:5432/gdrcenter", "-b http://10.8.30.160:8085" ] }, diff --git a/web/client/assets/files/common/1687849649468_5.jpg b/web/client/assets/files/common/1687849649468_5.jpg new file mode 100644 index 0000000..900b37d Binary files /dev/null and b/web/client/assets/files/common/1687849649468_5.jpg differ diff --git a/web/client/assets/files/common/1687849663076_2.jpg b/web/client/assets/files/common/1687849663076_2.jpg new file mode 100644 index 0000000..3f96826 Binary files /dev/null and b/web/client/assets/files/common/1687849663076_2.jpg differ diff --git a/web/client/assets/files/common/1687849677583_2.jpg b/web/client/assets/files/common/1687849677583_2.jpg new file mode 100644 index 0000000..3f96826 Binary files /dev/null and b/web/client/assets/files/common/1687849677583_2.jpg differ diff --git a/web/client/src/app.js b/web/client/src/app.js index 60017ea..29ed713 100644 --- a/web/client/src/app.js +++ b/web/client/src/app.js @@ -12,6 +12,7 @@ import memberManagement from './sections/memberManagement'; import dataQuality from './sections/dataQuality'; import safetySpecification from './sections/safetySpecification'; import backups from './sections/backups'; +import dataService from './sections/dataService'; const App = props => { const { projectName } = props @@ -31,6 +32,7 @@ const App = props => { resourceRetrieval, dataQuality, safetySpecification, + dataService, memberManagement, backups ]} diff --git a/web/client/src/sections/dataQuality/components/ruleModal.js b/web/client/src/sections/dataQuality/components/ruleModal.js index 1e01922..e32c758 100644 --- a/web/client/src/sections/dataQuality/components/ruleModal.js +++ b/web/client/src/sections/dataQuality/components/ruleModal.js @@ -5,7 +5,7 @@ import { v4 as uuidv4 } from 'uuid' import { Tabs, Form, Input, DatePicker, Button, Modal, Radio, Select, TreeSelect } from 'antd'; const { TextArea } = Input; -const { Option, OptGroup } = Select; +const { TreeNode } = TreeSelect; function RuleModal ({ loading, parent, user, actions, dispatch, close, success, treeList, editData }) { const { dataQuality } = actions @@ -13,15 +13,23 @@ function RuleModal ({ loading, parent, user, actions, dispatch, close, success, const [query, setQuery] = useState({ page: 0, limit: 10 }); const [proTableList, setProTableList] = useState({ rows: [], count: 0 }); const [approve, setApprove] = useState() - + const [ruleBasis, setRuleBasis] = useState() const [form] = Form.useForm(); useEffect(() => { - + }, []) - + let recursive = (data) => { + let title = [] + data?.map(v => { + title.push( + {recursive(v.children)} + ) + }) + return title + } return <> @@ -30,7 +38,7 @@ function RuleModal ({ loading, parent, user, actions, dispatch, close, success, form.validateFields().then(v => { // console.log(v); dispatch(dataQuality.postBusinessRules({ - ...v, id: editData?.id + ...v, id: editData?.id, ruleBasis: ruleBasis })).then(res => { if (res.success) { close() @@ -52,7 +60,7 @@ function RuleModal ({ loading, parent, user, actions, dispatch, close, success, autoComplete="off" labelCol={{ span: 4 }} wrapperCol={{ span: 20 }} > - + @@ -75,16 +83,26 @@ function RuleModal ({ loading, parent, user, actions, dispatch, close, success, width: 300, }} // value={} - dropdownStyle={{ - maxHeight: 300, - overflow: 'auto', - }} + // dropdownStyle={{ + // maxHeight: 300, + // overflow: 'auto', + // }} placeholder="" allowClear treeDefaultExpandAll - // onChange={onChange} - treeData={treeList || []} - /> + onChange={(label, extra) => { + // console.log(label, extra); + }} + onSearch={v => { + // console.log(v); + }} + onSelect={(value, node, extra) => { + setRuleBasis(node.key) + }} + // treeData={treeList || []} + > + {treeList?.length && recursive(treeList)} + diff --git a/web/client/src/sections/dataQuality/containers/documentLibrary.js b/web/client/src/sections/dataQuality/containers/documentLibrary.js index b207704..1516cc8 100644 --- a/web/client/src/sections/dataQuality/containers/documentLibrary.js +++ b/web/client/src/sections/dataQuality/containers/documentLibrary.js @@ -74,7 +74,7 @@ function Approve ({ loading, clientHeight, actions, dispatch, }) { 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) + 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 }) @@ -83,16 +83,23 @@ function Approve ({ loading, clientHeight, actions, dispatch, }) { const zip = new JSZip() let result = [] + let date = moment().add(8, 'hours').utc(); + let year = date.year(); + let month = date.month(); + let day = date.date(); + let hours = date.hours(); + let minutes = date.minutes(); + let seconds = date.seconds(); fileUrl.map(d => { let url = d?.url?.replace(/\\/g, '/') let promise = getFileBlob(url).then((res) => { - zip.file(d.name, res, { binary: true }) + zip.file(d.name, res, { binary: true, date: new Date(Date.UTC(year, month, day, hours, minutes, seconds)) }) }) result.push(promise) }) Promise.all(result).then(() => { zip.generateAsync({ type: "blob" }).then((res) => { - saveAs(res, `标准文档.zip`) + saveAs(res, `标准文档.zip`); }) }) } diff --git a/web/client/src/sections/dataService/actions/documentLibrary.js b/web/client/src/sections/dataService/actions/documentLibrary.js new file mode 100644 index 0000000..b8af1d1 --- /dev/null +++ b/web/client/src/sections/dataService/actions/documentLibrary.js @@ -0,0 +1,78 @@ +'use strict'; + +import { basicAction } from '@peace/utils' +import { ApiTable } from '$utils' + +export function getStandardDocFolders (query = {}) { + return dispatch => basicAction({ + type: 'get', + query, + dispatch: dispatch, + actionType: 'GET_STANDARD_DOC_FOLDERS', + url: `${ApiTable.standardDocFolders}`, + msg: { error: '获取标准文档目录列表失败' }, + reducer: { name: '' } + }); +} + + +export function postStandardDocFolders (data = {}) { + return dispatch => basicAction({ + type: 'post', + data, + dispatch: dispatch, + actionType: 'POST_STANDARD_DOC_FOLDERS', + url: `${ApiTable.standardDocFolders}`, + msg: { option: '标准文档目录新增' }, + reducer: { name: '' } + }); +} + +export function postStandardDocs (data = {}) { + return dispatch => basicAction({ + type: 'post', + data, + dispatch: dispatch, + actionType: 'POST_STANDARD_DOCS', + url: `${ApiTable.standardDocs}`, + msg: { option: '新增标准文档' }, + reducer: { name: '' } + }); +} + +export function getStandardDocs (query = {}) { + return dispatch => basicAction({ + type: 'get', + query, + dispatch: dispatch, + actionType: 'GET_STANDARD_DOCS', + url: `${ApiTable.standardDocs}`, + msg: { error: '获取标准文档列表失败' }, + reducer: { name: '' } + }); +} + +export function postFolderFile (data) { + return dispatch => basicAction({ + type: 'post', + data, + dispatch: dispatch, + actionType: 'POST_FOLDER_FILE', + url: ApiTable.postFolderFile, + msg: { option: '删除文件夹或文件' }, + reducer: { name: '' } + }); +} + +export function fetchFiles (data = {}) { + return dispatch => basicAction({ + type: 'post', + data, + dispatch: dispatch, + actionType: 'POST_FETCH_FILES', + url: `${ApiTable.fetchFiles}`, + msg: { error: '获取文件夹下文件失败' }, + reducer: { name: '' } + }); +} + diff --git a/web/client/src/sections/dataService/actions/example.js b/web/client/src/sections/dataService/actions/example.js new file mode 100644 index 0000000..6b3c25d --- /dev/null +++ b/web/client/src/sections/dataService/actions/example.js @@ -0,0 +1,15 @@ +'use strict'; + +import { basicAction } from '@peace/utils' +import { ApiTable } from '$utils' + +// export function getMembers(orgId) { +// return dispatch => basicAction({ +// type: 'get', +// dispatch: dispatch, +// actionType: 'GET_MEMBERS', +// url: `${ApiTable.getEnterprisesMembers.replace('{enterpriseId}', orgId)}`, +// msg: { error: '获取用户列表失败' }, +// reducer: { name: 'members' } +// }); +// } diff --git a/web/client/src/sections/dataService/actions/index.js b/web/client/src/sections/dataService/actions/index.js new file mode 100644 index 0000000..bb9a933 --- /dev/null +++ b/web/client/src/sections/dataService/actions/index.js @@ -0,0 +1,11 @@ +'use strict'; + +import * as example from './example' +import * as documentLibrary from './documentLibrary' +import * as ruleLibrary from './ruleLibrary' + +export default { + ...example, + ...documentLibrary, + ...ruleLibrary, +} \ No newline at end of file diff --git a/web/client/src/sections/dataService/actions/ruleLibrary.js b/web/client/src/sections/dataService/actions/ruleLibrary.js new file mode 100644 index 0000000..b3182d5 --- /dev/null +++ b/web/client/src/sections/dataService/actions/ruleLibrary.js @@ -0,0 +1,52 @@ +'use strict'; + +import { basicAction } from '@peace/utils' +import { ApiTable } from '$utils' + +export function postBusinessRules (data = {}) { + let reminder = data?.id ? '修改业务规则' : '新增业务规则' + return dispatch => basicAction({ + type: 'post', + data, + dispatch: dispatch, + actionType: 'POST_BUSINESS_RULES', + url: `${ApiTable.businessRules}`, + msg: { option: reminder }, + reducer: { name: '' } + }); +} + +export function getBusinessRules (query = {}) { + return dispatch => basicAction({ + type: 'get', + query, + dispatch: dispatch, + actionType: 'GET_BUSINESS_RULES', + url: `${ApiTable.businessRules}`, + msg: { error: '查询业务规则列表失败' }, + reducer: { name: '' } + }); +} + +export function delBusinessRules (id) { + return dispatch => basicAction({ + type: 'del', + dispatch: dispatch, + actionType: 'del_BUSINESS_RULES', + url: `${ApiTable.delBusinessRules.replace('{id}', id)}`, + msg: { option: '删除业务规则' }, + reducer: { name: '' } + }); +} + +export function getRegularBasis (query = {}) { + return dispatch => basicAction({ + type: 'get', + query, + dispatch: dispatch, + actionType: 'GET_REGULAR_BASIS', + url: `${ApiTable.regularBasis}`, + msg: { error: '查询规则依据列表失败' }, + reducer: { name: '' } + }); +} diff --git a/web/client/src/sections/dataService/components/fileModal.js b/web/client/src/sections/dataService/components/fileModal.js new file mode 100644 index 0000000..54356a6 --- /dev/null +++ b/web/client/src/sections/dataService/components/fileModal.js @@ -0,0 +1,118 @@ +import React, { useEffect, useState } from 'react' +import { connect } from 'react-redux'; +import moment from 'moment'; +import { UploadLocal } from '$components'; + + +import { Tabs, Form, Input, DatePicker, Button, Modal, Select, Tag } from 'antd'; + + +function FileModal ({ loading, parent, user, actions, editData = {}, dispatch, close, success,remove }) { + + const { dataQuality } = actions + const [tabsKey, setTabsKey] = useState("stay") + const [query, setQuery] = useState({ page: 0, limit: 10 }); + const [proTableList, setProTableList] = useState({ rows: [], count: 0 }); + const [approve, setApprove] = useState() + + const [form] = Form.useForm(); + const [editUrl, setEditUrl] = useState([]); + useEffect(() => { + + }, []) + + + + 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([]) + } + } + + return <> + { + form.validateFields().then(v => { + dispatch(dataQuality.postStandardDocs({ + ...v, + path: v?.files[0]?.url, docName: v?.files[0]?.name, + folder: parent || null, + })).then(res => { + if (res.success) { + close() + success() + } + }) + }) + }} + onCancel={() => { + if (form.getFieldValue('files') && form.getFieldValue('files').length) { + remove(form.getFieldValue('files')[0]?.url) + } + close() + }} + > +
{ + + }} + autoComplete="off" + labelCol={{ span: 4 }} wrapperCol={{ span: 20 }} + > + + + + + + + + 文件大小不超过40MB,开放资源包含多个文件,建议将文件进行压缩,形成压缩包再上传 + 支持的文件格式:jpg,png,gif,txt,doc,docx,pdf,xsl,xlsx,zip,rar + +
+
+ + +} +function mapStateToProps (state) { + const { global, auth, resourceCatalog } = state; + return { + user: auth.user, + actions: global.actions, + clientHeight: global.clientHeight, + // resourceCatalog: resourceCatalog?.data || [], + // isRequesting: resourceCatalog.isRequesting + }; +} +export default connect(mapStateToProps)(FileModal) \ No newline at end of file diff --git a/web/client/src/sections/dataService/components/groupModal.js b/web/client/src/sections/dataService/components/groupModal.js new file mode 100644 index 0000000..4024fa6 --- /dev/null +++ b/web/client/src/sections/dataService/components/groupModal.js @@ -0,0 +1,66 @@ +import React, { useEffect, useState } from 'react' +import { connect } from 'react-redux'; +import moment from 'moment'; +import { v4 as uuidv4 } from 'uuid' + +import { Tabs, Form, Input, DatePicker, Button, Modal, Radio } from 'antd'; + + +function GroupModal ({ loading, parent, user, actions, dispatch, close, success, }) { + + const { dataQuality } = actions + + const [form] = Form.useForm(); + useEffect(() => { + + }, []) + + + + + return <> + { + form.validateFields().then(v => { + dispatch(dataQuality.postStandardDocFolders({ + ...v, + parent: parent || null, + })).then(res => { + if (res.success) { + close() + success() + } + }) + }) + }} + onCancel={() => { + close() + }} + > +
{ + + }} + autoComplete="off" + > + + + +
+
+ + +} +function mapStateToProps (state) { + const { global, auth, resourceCatalog } = state; + return { + user: auth.user, + actions: global.actions, + clientHeight: global.clientHeight, + // resourceCatalog: resourceCatalog?.data || [], + // isRequesting: resourceCatalog.isRequesting + }; +} +export default connect(mapStateToProps)(GroupModal) \ No newline at end of file diff --git a/web/client/src/sections/dataService/components/ruleModal.js b/web/client/src/sections/dataService/components/ruleModal.js new file mode 100644 index 0000000..1e01922 --- /dev/null +++ b/web/client/src/sections/dataService/components/ruleModal.js @@ -0,0 +1,104 @@ +import React, { useEffect, useState } from 'react' +import { connect } from 'react-redux'; +import moment from 'moment'; +import { v4 as uuidv4 } from 'uuid' + +import { Tabs, Form, Input, DatePicker, Button, Modal, Radio, Select, TreeSelect } from 'antd'; +const { TextArea } = Input; +const { Option, OptGroup } = Select; +function RuleModal ({ loading, parent, user, actions, dispatch, close, success, treeList, editData }) { + + const { dataQuality } = actions + const [tabsKey, setTabsKey] = useState("stay") + const [query, setQuery] = useState({ page: 0, limit: 10 }); + const [proTableList, setProTableList] = useState({ rows: [], count: 0 }); + const [approve, setApprove] = useState() + + const [form] = Form.useForm(); + useEffect(() => { + + }, []) + + + + + + + return <> + { + form.validateFields().then(v => { + // console.log(v); + dispatch(dataQuality.postBusinessRules({ + ...v, id: editData?.id + })).then(res => { + if (res.success) { + close() + success() + } + }) + }) + }} + onCancel={() => { + close() + }} + > +
{ + + }} + autoComplete="off" + labelCol={{ span: 4 }} wrapperCol={{ span: 20 }} + > + + + + +