From ba5f3f8458f736791c5a1314550244c8cd2a6d2e Mon Sep 17 00:00:00 2001 From: wenlele Date: Tue, 13 Jun 2023 08:28:35 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B5=84=E6=BA=90=E6=B6=88=E8=B4=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controllers/resourceConsumption/index.js | 147 ++++++++++++++ api/app/lib/index.js | 3 +- .../lib/routes/resourceConsumption/index.js | 23 +++ .../resourceConsumption/actions/approve.js | 29 +++ .../resourceConsumption/actions/index.js | 4 +- .../components/approveModal.js | 94 +++++++++ .../resourceConsumption/containers/approve.js | 189 +++++++++++++++++- .../containers/myApplication.js | 136 ++++++++++++- web/client/src/utils/webapi.js | 5 +- 9 files changed, 619 insertions(+), 11 deletions(-) create mode 100644 api/app/lib/controllers/resourceConsumption/index.js create mode 100644 api/app/lib/routes/resourceConsumption/index.js create mode 100644 web/client/src/sections/resourceConsumption/actions/approve.js create mode 100644 web/client/src/sections/resourceConsumption/components/approveModal.js diff --git a/api/app/lib/controllers/resourceConsumption/index.js b/api/app/lib/controllers/resourceConsumption/index.js new file mode 100644 index 0000000..57280f9 --- /dev/null +++ b/api/app/lib/controllers/resourceConsumption/index.js @@ -0,0 +1,147 @@ +'use strict'; +const moment = require('moment') + +function getApproveList (opts) { + return async function (ctx, next) { + + const models = ctx.fs.dc.models; + const { page, limit, applyAt, approveState, resourceName, applyBy, applyById } = ctx.query; + + let errMsg = { message: '获取消费审批列表失败' } + try { + + let option = { + where: {}, + order: [["id", "desc"]], + distinct: true, + include: [{ + model: models.User, + attributes: ['id', 'name'] + },] + } + if (resourceName) { + option.where.resourceName = { $iLike: `%${resourceName}%` } + } + if (applyBy) { + option.include[0].where = { '$user.name$': { $iLike: `%${applyBy}%` } } + } + if (applyById) { + option.where.applyBy = applyById + } + + if (limit) { + option.limit = Number(limit) + } + if (page && limit) { + option.offset = Number(page) * Number(limit) + } + + if (approveState) { + option.where.approveState = approveState + } + + if (applyAt) { + option.where.applyAt = { + $between: [ + moment(applyAt).startOf('day').format('YYYY-MM-DD HH:mm:ss'), + moment(applyAt).endOf('day').format('YYYY-MM-DD HH:mm:ss') + ] + } + } + + + + const res = await models.ResourceConsumption.findAndCount(option); + ctx.status = 200; + ctx.body = res; + } catch (error) { + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); + ctx.status = 400; + ctx.body = errMsg + } + } +} + +// 新增模型 +function addModelManagement (opts) { + return async function (ctx, next) { + + const models = ctx.fs.dc.models; + try { + const { attributeName, attributeCode, modelType } = ctx.request.body + const checkName = await models.MetaModel.findOne({ where: { attributeName, modelType } }); + const checkCode = await models.MetaModel.findOne({ where: { attributeCode, modelType } }); + if (checkName || checkCode) { + ctx.status = 400; + ctx.body = { message: checkName ? '该属性名称已存在' : "该属性代码已存在" } + } else { + let rslt = ctx.request.body; + await models.MetaModel.create(Object.assign({}, rslt)) + ctx.status = 204; + ctx.body = { message: '新建模型成功' } + } + + } catch (error) { + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); + ctx.status = 400; + ctx.body = { message: '新建模型失败' } + } + } +} + +// 修改模型 +function postApprove (opts) { + return async function (ctx, next) { + + try { + const models = ctx.fs.dc.models; + + const data = ctx.request.body; + const { id } = data + + await models.ResourceConsumption.update( + data, + { where: { id: id, } } + ) + ctx.status = 204; + + } catch (error) { + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); + ctx.status = 400; + ctx.body = { message: '消费审批失败' } + } + } +} + +// 删除模型 +function deleteModelManagement (opts) { + return async function (ctx, next) { + + try { + const models = ctx.fs.dc.models; + const { id } = ctx.params; + await models.MetaModel.destroy({ + where: { + id: id + } + }) + ctx.status = 204; + ctx.body = { message: '删除模型成功' } + } catch (error) { + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); + ctx.status = 400; + ctx.body = { message: '删除模型失败' } + } + } +} + + + +module.exports = { + // getModelManagementList, + // addModelManagement, + // editModelManagement, + // deleteModelManagement, + getApproveList, + postApprove, +} \ No newline at end of file diff --git a/api/app/lib/index.js b/api/app/lib/index.js index 58c567e..1f86f45 100644 --- a/api/app/lib/index.js +++ b/api/app/lib/index.js @@ -56,7 +56,7 @@ module.exports.models = function (dc) { const { DataSource, AcquisitionTask, Adapter, User, MetadataDatabase, MetadataFile, MetadataRestapi, AcquisitionLog, ResourceCatalog, - BusinessMetadataDatabase, BusinessMetadataFile, BusinessMetadataRestapi + BusinessMetadataDatabase, BusinessMetadataFile, BusinessMetadataRestapi,ResourceConsumption } = dc.models; AcquisitionTask.belongsTo(DataSource, { foreignKey: 'dataSourceId', targetKey: 'id' }); @@ -85,4 +85,5 @@ module.exports.models = function (dc) { BusinessMetadataDatabase.belongsTo(User, { foreignKey: 'createBy', targetKey: 'id' }); BusinessMetadataFile.belongsTo(User, { foreignKey: 'createBy', targetKey: 'id' }); BusinessMetadataRestapi.belongsTo(User, { foreignKey: 'createBy', targetKey: 'id' }); + ResourceConsumption.belongsTo(User, { foreignKey: 'applyBy', targetKey: 'id' }); }; diff --git a/api/app/lib/routes/resourceConsumption/index.js b/api/app/lib/routes/resourceConsumption/index.js new file mode 100644 index 0000000..2252859 --- /dev/null +++ b/api/app/lib/routes/resourceConsumption/index.js @@ -0,0 +1,23 @@ +'use strict'; + +const model = require('../../controllers/resourceConsumption/index'); + +module.exports = function (app, router, opts, AuthCode) { + + // app.fs.api.logAttr['POST/meta/model'] = { content: '增加模型信息', visible: true }; + // router.post('/meta/model', model.addModelManagement(opts)) + + // 修改模型信息 + app.fs.api.logAttr['POST/resource/approve'] = { content: '消费审批', visible: true }; + router.post('/resource/approve', model.postApprove(opts)) + + // // 删除模型信息 + // app.fs.api.logAttr['DEL/meta/model/:id'] = { content: '删除模型信息', visible: true }; + // router.del('/meta/model/:id', model.deleteModelManagement(opts)) + + //获取模型信息列表 + app.fs.api.logAttr['GET/resource/approve'] = { content: '获取消费审批列表', visible: true }; + router.get('/resource/approve', model.getApproveList(opts)); + + +}; diff --git a/web/client/src/sections/resourceConsumption/actions/approve.js b/web/client/src/sections/resourceConsumption/actions/approve.js new file mode 100644 index 0000000..9f21dbd --- /dev/null +++ b/web/client/src/sections/resourceConsumption/actions/approve.js @@ -0,0 +1,29 @@ +'use strict'; + +import { basicAction } from '@peace/utils' +import { ApiTable } from '$utils' + +export function getApproveList (query = {}) { + return dispatch => basicAction({ + type: 'get', + query, + dispatch: dispatch, + actionType: 'GET_APPROVE_LIST', + url: `${ApiTable.approveList}`, + msg: { error: '获取资源消费列表失败' }, + reducer: { name: '' } + }); +} + + +export function postApprove (data = {}) { + return dispatch => basicAction({ + type: 'post', + data, + dispatch: dispatch, + actionType: 'POST_APPROVE', + url: `${ApiTable.approveList}`, + msg: { option: '资源审批' }, + reducer: { name: '' } + }); +} diff --git a/web/client/src/sections/resourceConsumption/actions/index.js b/web/client/src/sections/resourceConsumption/actions/index.js index 444af37..f233405 100644 --- a/web/client/src/sections/resourceConsumption/actions/index.js +++ b/web/client/src/sections/resourceConsumption/actions/index.js @@ -1,7 +1,9 @@ 'use strict'; import * as example from './example' +import * as approve from './approve' export default { - ...example, + ...example, + ...approve, } \ No newline at end of file diff --git a/web/client/src/sections/resourceConsumption/components/approveModal.js b/web/client/src/sections/resourceConsumption/components/approveModal.js new file mode 100644 index 0000000..4d01719 --- /dev/null +++ b/web/client/src/sections/resourceConsumption/components/approveModal.js @@ -0,0 +1,94 @@ +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 ApproveModal ({ loading, clientHeight, user, actions, dispatch, close, success, editData, }) { + + const { resourceConsumption } = 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(resourceConsumption.postApprove({ + id: editData?.id, ...v, + approveAt: moment().format('YYYY-MM-DD HH:mm:ss'), + approveBy: user?.id, + approveState: '已审批' + })).then(res => { + if (res.success) { + close() + success() + } + }) + }) + }} + onCancel={() => { + close() + }} + > +
{ + console.log(v); + if (v.approve) { + setApprove(v.approve) + } + // setFormData(v) + }} + autoComplete="off" + > + + + 同意 + 不同意 + + + {!approve || approve == 'false' ? + + + : ""} + {!approve || approve == 'true' ?
+ + + + +
: ""} +
+
+ + +} +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)(ApproveModal) \ No newline at end of file diff --git a/web/client/src/sections/resourceConsumption/containers/approve.js b/web/client/src/sections/resourceConsumption/containers/approve.js index d4a16fd..e2bd3c2 100644 --- a/web/client/src/sections/resourceConsumption/containers/approve.js +++ b/web/client/src/sections/resourceConsumption/containers/approve.js @@ -1,7 +1,188 @@ import React, { useEffect, useState } from 'react' +import { connect } from 'react-redux'; +import moment from 'moment'; +import ApproveModal from '../components/approveModal'; + + +import { Tabs, Form, Input, DatePicker, Button, Table } from 'antd'; +import { v1 } from 'uuid'; + + +function Approve ({ loading, clientHeight, actions, dispatch, }) { + + const { resourceConsumption } = actions + const [tabsKey, setTabsKey] = useState("stay") + const [query, setQuery] = useState({ page: 0, limit: 10 }); + const [proTableList, setProTableList] = useState({ rows: [], count: 0 }); + const [formData, setFormData] = useState({}) + const [approveModal, setApproveModal] = useState(false) + const [editData, setEditData] = useState({}) + const [column, setColumn] = useState([]) + + useEffect(() => { + resourceData() + }, []) + + + let resourceData = (params) => { + let data = params || query + dispatch(resourceConsumption.getApproveList({ approveState: tabsKey == 'stay' ? "审批中" : '已审批', ...formData, ...data, })).then(res => { + if (res.success) { + setProTableList(res.payload.data) + } + }) + } -function Approve (props) { - return <>数据消费审批 -} -export default Approve \ No newline at end of file + const columns = [{ + title: '资源名称', + dataIndex: 'resourceName', + }, { + title: '申请人', + dataIndex: 'applyBy', + render: (text, record) => record?.user?.name + }, { + title: '需求描述', + dataIndex: 'requirements', + }, { + title: '数据类型', + dataIndex: 'resourceType', + }, { + title: '令牌', + dataIndex: 'token', + render: (text, record) => text || '--' + }, { + title: '申请时间', + dataIndex: 'applyAt', + render: (text, record) => { + return moment(text).format('YYYY-MM-DD HH:mm:ss'); + }, + sorter: { + compare: (a, b) => moment(b?.applyAt).valueOf() - moment(a?.applyAt).valueOf(), + // multiple: 2, + }, + }, { + title: '审批意见', + dataIndex: 'result', + render: (text, record) => record?.token ? "审批通过" : "审批不通过" + }, { + title: '意见内容', + dataIndex: 'approveRemarks', + render: (text, record) => text || '--' + }, { + title: '审批时间', + dataIndex: 'approveAt', + render: (text, record) => { + return moment(text).format('YYYY-MM-DD HH:mm:ss'); + }, + sorter: { + compare: (a, b) => moment(b?.approveAt).valueOf() - moment(a?.approveAt).valueOf(), + // multiple: 2, + }, + }, { + title: '操作', + dataIndex: 'handle', + // ellipsis: true, + render: (text, record) => + }, + ]; + + useEffect(() => { + let data = [] + columns?.map(v => { + if (tabsKey == 'stay') { + if (v.dataIndex != 'token' + && v.dataIndex != 'result' + && v.dataIndex != 'approveRemarks' + && v.dataIndex != 'approveAt') { + data?.push(v) + } + + } else { + if (v.dataIndex != 'handle') { + data?.push(v) + } + } + }) + setColumn(data) + }, [tabsKey]) + + return <> + { + setTabsKey(key) + resourceData({ limit: 10, page: 0, approveState: key == 'stay' ? "审批中" : '已审批' }) + setQuery({ limit: 10, page: 0 }); + }} /> +
{ + + setFormData({ ...v, applyAt: v.applyAt ? moment(v.applyAt).format('YYYY-MM-DD HH:mm:ss') : "" }) + resourceData({ limit: 10, page: 0, ...v, applyAt: v.applyAt ? moment(v.applyAt).format('YYYY-MM-DD HH:mm:ss') : "" }) + setQuery({ limit: 10, page: 0 }); + console.log(v); + }} + autoComplete="off" + > + + + + + + + + + + + + +
+ + { return {`共${Math.ceil(total / query?.limit)}页,${total}项`} }, + onChange: (page, pageSize) => { + setQuery({ limit: pageSize, page: page - 1 }); + resourceData({ limit: pageSize, page: page - 1 }); + } + }} + /> + { + approveModal ? + { + setApproveModal(false); + setEditData({}) + }} + success={() => { + resourceData({ limit: 10, page: 0 }) + setQuery({ limit: 10, page: 0 }); + }} + /> : "" + } + + +} +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)(Approve) \ No newline at end of file diff --git a/web/client/src/sections/resourceConsumption/containers/myApplication.js b/web/client/src/sections/resourceConsumption/containers/myApplication.js index 6e17d56..57563a1 100644 --- a/web/client/src/sections/resourceConsumption/containers/myApplication.js +++ b/web/client/src/sections/resourceConsumption/containers/myApplication.js @@ -1,7 +1,135 @@ import React, { useEffect, useState } from 'react' +import { connect } from 'react-redux'; +import moment from 'moment'; +import ApproveModal from '../components/approveModal'; -function MyApplication (props) { - return <>我的数据消费申请 -} -export default MyApplication \ No newline at end of file +import { Tabs, Form, Input, DatePicker, Button, Table } from 'antd'; +import { v1 } from 'uuid'; + + +function MyApplication ({ loading, clientHeight, actions, dispatch, user }) { + + const { resourceConsumption } = actions + + const [query, setQuery] = useState({ page: 0, limit: 10 }); + const [proTableList, setProTableList] = useState({ rows: [], count: 0 }); + const [formData, setFormData] = useState({}) + + useEffect(() => { + resourceData() + }, []) + + + let resourceData = (params) => { + let data = params || query + dispatch(resourceConsumption.getApproveList({ applyById: user?.id, ...formData, ...data, })).then(res => { + if (res.success) { + setProTableList(res.payload.data) + } + }) + } + + + const columns = [{ + title: '资源名称', + dataIndex: 'resourceName', + }, { + title: '申请人', + dataIndex: 'applyBy', + render: (text, record) => record?.user?.name + }, { + title: '需求描述', + dataIndex: 'requirements', + }, { + title: '数据类型', + dataIndex: 'resourceType', + }, { + title: '令牌', + dataIndex: 'token', + render: (text, record) => text || '--' + }, { + title: '申请时间', + dataIndex: 'applyAt', + render: (text, record) => text && moment(text).format('YYYY-MM-DD HH:mm:ss') || '--', + sorter: { + compare: (a, b) => moment(b?.applyAt).valueOf() - moment(a?.applyAt).valueOf(), + // multiple: 2, + }, + }, { + title: '审批意见', + dataIndex: 'result', + render: (text, record) => record?.approveState == '审批中' ? record?.approveState : record?.approveState == '已审批' ? record?.token ? "审批通过" : "审批不通过" : "--" + }, { + title: '意见内容', + dataIndex: 'approveRemarks', + render: (text, record) => text || '--' + }, { + title: '审批时间', + dataIndex: 'approveAt', + render: (text, record) => text && moment(text).format('YYYY-MM-DD HH:mm:ss') || '--', + sorter: { + compare: (a, b) => moment(b?.approveAt).valueOf() - moment(a?.approveAt).valueOf(), + // multiple: 2, + }, + }]; + + + + return <> +
{ + + setFormData({ ...v, applyAt: v.applyAt ? moment(v.applyAt).format('YYYY-MM-DD HH:mm:ss') : "" }) + resourceData({ limit: 10, page: 0, ...v, applyAt: v.applyAt ? moment(v.applyAt).format('YYYY-MM-DD HH:mm:ss') : "" }) + setQuery({ limit: 10, page: 0 }); + console.log(v); + }} + autoComplete="off" + > + + + + + + + + + + + + + + +
{ return {`共${Math.ceil(total / query?.limit)}页,${total}项`} }, + onChange: (page, pageSize) => { + setQuery({ limit: pageSize, page: page - 1 }); + resourceData({ limit: pageSize, page: page - 1 }); + } + }} + /> + + +} +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)(MyApplication) diff --git a/web/client/src/utils/webapi.js b/web/client/src/utils/webapi.js index cbe1891..8556932 100644 --- a/web/client/src/utils/webapi.js +++ b/web/client/src/utils/webapi.js @@ -73,7 +73,10 @@ export const ApiTable = { runTask: 'run/acq/task', //采集日志 - getLogs: "meta/acq/logs" + getLogs: "meta/acq/logs", + + //资源消费 + approveList:'resource/approve' }; export const RouteTable = {