Browse Source

运维项目的单数据源

dev
巴林闲侠 2 years ago
parent
commit
5f9a36518a
  1. 53
      api/app/lib/controllers/workOrder/index.js
  2. 4
      api/app/lib/routes/workOrder/index.js
  3. BIN
      web/client/assets/images/fs-logo.png
  4. 5
      web/client/src/components/index.js
  5. 32
      web/client/src/components/workflow/index.jsx
  6. 166
      web/client/src/components/workflow/view.jsx
  7. 1
      web/client/src/layout/actions/global.js
  8. 2
      web/client/src/layout/reducers/global.js
  9. 9
      web/client/src/sections/workOrder/containers/jobOrder.jsx
  10. 7
      web/config.js
  11. 2
      web/package.json
  12. 3
      web/routes/attachment/index.js

53
api/app/lib/controllers/workOrder/index.js

@ -34,6 +34,57 @@ async function getEnabledWorkflowProcess (ctx) {
} }
} }
async function basicDataAllProject (ctx) {
try {
const { models } = ctx.fs.dc;
const proRes = await models.ProjectCorrelation.findAndCountAll({
where: {
del: false,
},
order: [['updateTime', 'desc']],
})
let pepProjectIds = new Set()
for (let p of proRes.rows) {
if (p.pepProjectId) {
pepProjectIds.add(p.pepProjectId)
}
}
const pepProjectRes = pepProjectIds.size ?
await clickHouse.projectManage.query(
`
SELECT
t_pim_project.id AS id,
t_pim_project.project_name AS project_name,
t_pim_project.isdelete AS isdelete
FROM t_pim_project
WHERE id IN (${[...pepProjectIds].join(',')}, -1)
`
).toPromise() :
[]
const list = proRes.map(p => {
const corPro = pepProjectRes.find(pp => pp.id == p.pepProjectId) || {}
return {
value: p.id,
label: corPro.project_name || p.name,
disabled: corPro.isdelete == 1
}
})
ctx.status = 200;
ctx.body = list
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: error`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
module.exports = { module.exports = {
getEnabledWorkflowProcess getEnabledWorkflowProcess,
basicDataAllProject
}; };

4
api/app/lib/routes/workOrder/index.js

@ -5,4 +5,8 @@ const workOrder = require('../../controllers/workOrder');
module.exports = function (app, router, opts) { module.exports = function (app, router, opts) {
app.fs.api.logAttr['GET/workflow/process/enabled'] = { content: '获取工作流可用表单', visible: true }; app.fs.api.logAttr['GET/workflow/process/enabled'] = { content: '获取工作流可用表单', visible: true };
router.get('/workflow/process/enabled', workOrder.getEnabledWorkflowProcess); router.get('/workflow/process/enabled', workOrder.getEnabledWorkflowProcess);
// 单一数据源
app.fs.api.logAttr['GET/basic-data/workflow/single/allProject'] = { content: '查询所有项目', visible: false };
router.get('/basic-data/workflow/single/allProject', workOrder.basicDataAllProject);
}; };

BIN
web/client/assets/images/fs-logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

5
web/client/src/components/index.js

@ -6,7 +6,7 @@ import { SkeletonScreen } from './skeletonScreen'
import OutHidden from './outHidden' import OutHidden from './outHidden'
import Uploads from './Uploads/index' import Uploads from './Uploads/index'
import WorkflowModal from './workflow'; import WorkflowModal from './workflow';
import WorkFlowViewModal from './workflow/view'
export { export {
SimpleFileDownButton, SimpleFileDownButton,
ReminderBox, ReminderBox,
@ -14,5 +14,6 @@ export {
SkeletonScreen, SkeletonScreen,
OutHidden, OutHidden,
Uploads, Uploads,
WorkflowModal WorkflowModal,
WorkFlowViewModal
}; };

32
web/client/src/components/workflow/index.jsx

@ -14,10 +14,9 @@ import './index.less'
const { confirm } = Modal; const { confirm } = Modal;
const WorkFlowModal = (props) => { const WorkFlowModal = (props) => {
const { successCallBack = () => { }, title, visible, clientHeight, postData, processId, user, dispatch, webEmis } = props; const { successCallBack = () => { }, title, visible, clientHeight, postData, processId, user, dispatch, webEmis, webOa } = props;
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [ifShowMessage, setIfShowMessage] = useState(true); const [ifShowMessage, setIfShowMessage] = useState(true);
const [webUrl, setWebUrl] = useState(null);
const [customVisible, setCustomVisible] = useState(false); const [customVisible, setCustomVisible] = useState(false);
const [draftId, setDraftId] = useState(); const [draftId, setDraftId] = useState();
const iframeRef = React.createRef(); const iframeRef = React.createRef();
@ -47,11 +46,9 @@ const WorkFlowModal = (props) => {
} }
const handelApprovalCenter = (activeKey) => { const handelApprovalCenter = (activeKey) => {
RouteRequest.get(RouteTable.getWebUrl + `?sys=emisWebUrl`).then(res => { if (webOa) {
if (res.url) { window.open(webOa + "/approval/center?activeKey=" + activeKey);
window.open(res.url + "/approval/center?activeKey=" + activeKey); }
}
});
} }
const handelOk = () => { const handelOk = () => {
@ -112,31 +109,22 @@ const WorkFlowModal = (props) => {
} }
//message //message
window.addEventListener('message', receiveMessageFromIndex, false); window.addEventListener('message', receiveMessageFromIndex, false);
//webURL
if (!webUrl) {
RouteRequest.get(RouteTable.getEmisWebUrl).then(res => {
if (res.url) {
setWebUrl(res.url);
}
});
}
}, []) }, [])
console.log(webEmis, processId);
return ( return (
<div> <div>
<Modal <Modal
fullScreen fullScreen
visible={visible} visible={visible}
width={'100%'} width={'100%'}
// style={{ top: 0, left: 0, padding: 0, maxWidth: '100%' }}
// bodyStyle={{ paddingLeft: 32, paddingRight: 32, margin: 0, backgroundColor: '#FAFAFA', height: '100%', overflowY: 'auto' }}
title={''} title={''}
closable={false} closable={false}
hasCancel={false} hasCancel={false}
footer={null} footer={null}
wrapClassName='process_modal_wrap' wrapClassName='process_modal_wrap'
onCancel={showConfirm} onCancel={showConfirm}
destroyOnClose
> >
<Row> <Row>
<div className='workflow-body'> <div className='workflow-body'>
@ -152,7 +140,7 @@ const WorkFlowModal = (props) => {
<Spin <Spin
spinning={loading} spinning={loading}
> >
{webUrl && processId ? <iframe {webEmis && processId ? <iframe
id='workflowFrame' id='workflowFrame'
onLoad={() => { onLoad={() => {
let frameWin = document.getElementById('workflowFrame'); let frameWin = document.getElementById('workflowFrame');
@ -161,7 +149,7 @@ const WorkFlowModal = (props) => {
}} }}
allowTransparency="true" allowTransparency="true"
ref={iframeRef} ref={iframeRef}
src={`${webUrl}/process/${processId}/apply?token=${user.token}`} src={`${webEmis}/process/${processId}/apply?token=${user.token}`}
width={'100%'} width={'100%'}
style={{ height: '100vh' }} style={{ height: '100vh' }}
frameBorder="0" frameBorder="0"
@ -189,11 +177,11 @@ const WorkFlowModal = (props) => {
function mapStateToProps (state) { function mapStateToProps (state) {
const { auth, global } = state; const { auth, global } = state;
console.log(global);
return { return {
user: auth.user, user: auth.user,
clientHeight: global.clientHeight, clientHeight: global.clientHeight,
webEmis: global.webEmis webEmis: global.webEmis,
webOa: global.webOa
} }
} }

166
web/client/src/components/workflow/view.jsx

@ -2,109 +2,95 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
// import { Modal, Spin, message, Row } from 'antd'; import { Modal, Spin, Row } from '@douyinfe/semi-ui';
import { RouteTable } from '../../utils/webapi';
import { RouteRequest } from '@peace/utils';
import { useState } from 'react'; import { useState } from 'react';
import { useEffect } from 'react'; import { IconClose } from '@douyinfe/semi-icons';
import { CloseCircleFilled } from '@ant-design/icons';
import './index.less' import './index.less'
const { confirm } = Modal; const { confirm } = Modal;
const WorkFlowViewModal = (props) => { const WorkFlowViewModal = (props) => {
// const { successCallBack, title, visible, clientHeight, postData, processId, user } = props; const { visible, clientHeight, postData, processId, user, webEmis, webOa } = props;
// const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
// const [ifShowMessage, setIfShowMessage] = useState(true); const [ifShowMessage, setIfShowMessage] = useState(true);
// const [webUrl, setWebUrl] = useState(null); const iframeRef = React.createRef();
// const iframeRef = React.createRef();
// const handelCancel = () => { const handelCancel = () => {
// const { onCancel } = props; const { onCancel } = props;
// onCancel && onCancel(); onCancel && onCancel();
// setLoading(false); setLoading(false);
// } }
// const showConfirm = () => { const showConfirm = () => {
// confirm({ confirm({
// title: '?', title: '确定关闭此表单吗?',
// onOk() { onOk () {
// handelCancel() handelCancel()
// }, },
// onCancel() { }, onCancel () { },
// }); });
// } }
// useEffect(() => { return (
// if (!webUrl) { <div>
// RouteRequest.get(RouteTable.getEmisWebUrl).then(res => { <Modal
// if (res.url) { fullScreen
// setWebUrl(res.url); visible={visible}
// } width={'100%'}
// }); title={''}
// } closable={false}
// }, []) footer={null}
const bodyStyle = { paddingLeft: 32, paddingRight: 32, margin: 0, backgroundColor: '#FAFAFA', height: '100%', overflowY: 'auto' } wrapClassName='process_modal_wrap'
return ( onCancel={showConfirm}
<div> >
{/* <Modal <Row>
visible={visible} <div className='workflow-body'>
width={'100%'} <div id="processHeader" className='workflow-body-header'>
style={{ top: 0, left: 0, padding: 0, maxWidth: '100%' }} <img src='/assets/images/fs-logo.png' />
bodyStyle={bodyStyle} <span className='workflow-body-header_title'>
title={''} <span className='workflow-body-header_title_shu'>|</span>
closable={false} <span className='workflow-body-header_title_zi'>让世间万物拥有感知服务人类社会于美好</span>
footer={null} </span>
wrapClassName='process_modal_wrap' <IconClose className="workflow-body-header_closeIcon" onClick={showConfirm} />
onCancel={showConfirm} </div>
destroyOnClose <div className='workflow-body-form'>
> <Spin
<Row> spinning={loading}
<div className='workflow-body'> >
<div id="processHeader" className='workflow-body-header'> {webEmis && processId ? <iframe
<img src='/assets/images/fs-logo.png' /> id='workflowViewFrame'
<span className='workflow-body-header_title'> name='workflowViewFrame'
<span className='workflow-body-header_title_shu'>|</span> onLoad={() => {
<span className='workflow-body-header_title_zi'>让世间万物拥有感知服务人类社会于美好</span> let frameWin = document.getElementById('workflowViewFrame');
</span> frameWin.contentWindow.postMessage(JSON.stringify(postData), '*');
<CloseCircleFilled className="workflow-body-header_closeIcon" onClick={showConfirm} /> setLoading(false);
</div> }}
<div className='workflow-body-form'> allowTransparency="true"
<Spin ref={iframeRef}
spinning={loading} src={`${webEmis}/process/my-apply?token=${user.token}&processInstanceId=${processId}&type=oaleader`}
> width={'100%'}
{webUrl && processId ? <iframe style={{ height: '100vh' }}
id='workflowViewFrame' frameBorder="0"
name='workflowViewFrame' ></iframe> : ''}
onLoad={() => { </Spin>
let frameWin = document.getElementById('workflowViewFrame'); </div>
frameWin.contentWindow.postMessage(JSON.stringify(postData), '*'); </div>
setLoading(false); </Row>
}}
allowTransparency="true"
ref={iframeRef}
src={`${webUrl}/process/my-apply?token=${user.token}&processInstanceId=${processId}&type=oaleader`}
width={'100%'}
style={{ height: '100vh' }}
frameBorder="0"
></iframe> : ''}
</Spin>
</div>
</div>
</Row>
</Modal > */} </Modal >
</div> </div>
) )
} }
function mapStateToProps(state) { function mapStateToProps (state) {
const { auth, global } = state; const { auth, global } = state;
return { return {
user: auth.user, user: auth.user,
clientHeight: global.clientHeight, clientHeight: global.clientHeight,
} webEmis: global.webEmis,
webOa: global.webOa
}
} }
export default connect(mapStateToProps)(WorkFlowViewModal); export default connect(mapStateToProps)(WorkFlowViewModal);

1
web/client/src/layout/actions/global.js

@ -49,6 +49,7 @@ export function initApiRoot () {
dcWeb: res.dcWeb, dcWeb: res.dcWeb,
qiniu: res.qiniu, qiniu: res.qiniu,
webEmis: res.webEmis, webEmis: res.webEmis,
webOa: res.webOa,
} }
}) })
}); });

2
web/client/src/layout/reducers/global.js

@ -50,6 +50,8 @@ function global (state = {
pomsNotebook: payload.pomsNotebook, pomsNotebook: payload.pomsNotebook,
dcWeb: payload.dcWeb, dcWeb: payload.dcWeb,
qiniu: payload.qiniu, qiniu: payload.qiniu,
webEmis: payload.webEmis,
webOa: payload.webOa,
}).toJS(); }).toJS();
case PEPPROJECTID: case PEPPROJECTID:
return Immutable.fromJS(state).merge({ return Immutable.fromJS(state).merge({

9
web/client/src/sections/workOrder/containers/jobOrder.jsx

@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import moment from 'moment'; import moment from 'moment';
import { WorkflowModal } from "$components" import { WorkflowModal, WorkFlowViewModal } from "$components"
import { EmisRequest, EmisApiTable } from "$utils" import { EmisRequest, EmisApiTable } from "$utils"
import { Card, Notification, Space, Button } from '@douyinfe/semi-ui'; import { Card, Notification, Space, Button } from '@douyinfe/semi-ui';
import { IconArticle } from '@douyinfe/semi-icons'; import { IconArticle } from '@douyinfe/semi-icons';
@ -27,6 +27,7 @@ const JobOrder = (props) => {
workflowProcess.map(p => { workflowProcess.map(p => {
return ( return (
<Card <Card
key={p.id}
className='work-order-card' className='work-order-card'
style={{ gridColumn: `span 1`, cursor: 'pointer' }} style={{ gridColumn: `span 1`, cursor: 'pointer' }}
footerLine={true} footerLine={true}
@ -71,12 +72,16 @@ const JobOrder = (props) => {
) )
}) })
} }
<WorkflowModal {/* <WorkflowModal
visible={workflowModalVisible} visible={workflowModalVisible}
title={''} title={''}
processId={launchProcessId} processId={launchProcessId}
onCancel={() => { setWorkflowModalVisible(false) }} onCancel={() => { setWorkflowModalVisible(false) }}
successCallBack={() => { setWorkflowModalVisible(false) }} successCallBack={() => { setWorkflowModalVisible(false) }}
/> */}
<WorkFlowViewModal
visible={workflowModalVisible}
processId={launchProcessId}
/> />
</div> </div>
) )

7
web/config.js

@ -15,7 +15,8 @@ args.option(['u', 'api-url'], 'webapi的URL');
args.option('apiPomsUrl', 'webapi的URL 外网可访问'); args.option('apiPomsUrl', 'webapi的URL 外网可访问');
args.option('apiAnxinyunUrl', '安心云 api'); args.option('apiAnxinyunUrl', '安心云 api');
args.option('apiEmisUrl', '企业管理 api'); args.option('apiEmisUrl', '企业管理 api');
args.option('webEmisUrl', '企业管理 web'); args.option('webEmisUrl', '统一认证 web - 统一认证 配置表单的');
args.option('webOaUrl', 'OA web - 项企填表单的');
args.option('iotVcmpWeb', 'IOT 视频服务'); args.option('iotVcmpWeb', 'IOT 视频服务');
args.option('pomsMonitor', '运维监控 web'); args.option('pomsMonitor', '运维监控 web');
args.option('pomsKubesphere', 'kubesphere web'); args.option('pomsKubesphere', 'kubesphere web');
@ -39,6 +40,7 @@ const API_URL = process.env.API_URL || flags.apiUrl;
const API_POMS_URL = process.env.API_POMS_URL || flags.apiPomsUrl; const API_POMS_URL = process.env.API_POMS_URL || flags.apiPomsUrl;
const API_EMIS_URL = process.env.API_EMIS_URL || flags.apiEmisUrl; const API_EMIS_URL = process.env.API_EMIS_URL || flags.apiEmisUrl;
const WEB_EMIS_URL = process.env.WEB_EMIS_URL || flags.webEmisUrl; const WEB_EMIS_URL = process.env.WEB_EMIS_URL || flags.webEmisUrl;
const WEB_OA_URL = process.env.WEB_OA_URL || flags.webOaUrl;
const API_ANXINYUN_URL = process.env.API_ANXINYUN_URL || flags.apiAnxinyunUrl; const API_ANXINYUN_URL = process.env.API_ANXINYUN_URL || flags.apiAnxinyunUrl;
const IOT_VIDEO_WEB = process.env.IOT_VIDEO_WEB || flags.iotVcmpWeb; const IOT_VIDEO_WEB = process.env.IOT_VIDEO_WEB || flags.iotVcmpWeb;
const POMS_MONITOR = process.env.POMS_MONITOR || flags.pomsMonitor; const POMS_MONITOR = process.env.POMS_MONITOR || flags.pomsMonitor;
@ -59,7 +61,7 @@ const ANXINCLOUD_QINIU_DOMAIN_QNDMN_RESOURCE = process.env.ANXINCLOUD_QINIU_DOMA
if ( if (
!API_URL !API_URL
|| !API_EMIS_URL || !WEB_EMIS_URL || !API_EMIS_URL || !WEB_EMIS_URL || !WEB_OA_URL
|| !API_ANXINYUN_URL || !API_ANXINYUN_URL
|| !POMS_MONITOR || !DC_WEB || !POMS_MONITOR || !DC_WEB
|| !ANXINCLOUD_QINIU_AK || !ANXINCLOUD_QINIU_SK || !ANXINCLOUD_QINIU_BUCKET_RESOURCE || !ANXINCLOUD_QINIU_DOMAIN_QNDMN_RESOURCE || !IOT_VIDEO_WEB) { || !ANXINCLOUD_QINIU_AK || !ANXINCLOUD_QINIU_SK || !ANXINCLOUD_QINIU_BUCKET_RESOURCE || !ANXINCLOUD_QINIU_DOMAIN_QNDMN_RESOURCE || !IOT_VIDEO_WEB) {
@ -106,6 +108,7 @@ const product = {
opts: { opts: {
apiUrl: API_POMS_URL, apiUrl: API_POMS_URL,
webEmis: WEB_EMIS_URL, webEmis: WEB_EMIS_URL,
webOa: WEB_OA_URL,
iotVcmpWeb: IOT_VIDEO_WEB, iotVcmpWeb: IOT_VIDEO_WEB,
pomsMonitor: POMS_MONITOR, pomsMonitor: POMS_MONITOR,
pomsKubesphere: POMS_KUBESPHERE, pomsKubesphere: POMS_KUBESPHERE,

2
web/package.json

@ -7,7 +7,7 @@
"test": "mocha", "test": "mocha",
"start-vite": "cross-env NODE_ENV=developmentVite npm run start-params", "start-vite": "cross-env NODE_ENV=developmentVite npm run start-params",
"start": "cross-env NODE_ENV=development npm run start-params", "start": "cross-env NODE_ENV=development npm run start-params",
"start-params": "node server -p 5600 -u http://localhost:4600 --apiPomsUrl http://localhost:4600 --apiAnxinyunUrl http://10.8.30.112:4100 --apiEmisUrl http://10.8.30.161:1111 --webEmisUrl http://10.8.30.161:1111 --qnak 5XrM4wEB9YU6RQwT64sPzzE6cYFKZgssdP5Kj3uu --qnsk w6j2ixR_i-aelc6I7S3HotKIX-ukMzcKmDfH6-M5 --qnbkt anxinyun-test --qndmn http://test.resources.anxinyun.cn --iotVcmpWeb https://mediaconsole.ngaiot.com --pomsMonitor http://monitor.anxinyun.cn/goto/PaEDLE84z?orgId=1 --pomsKubesphere https://k8sadmin.anxinyun.cn/ --pomsAmbari https://ambari.anxinyun.cn/ --pomsKowl https://kafka.anxinyun.cn/ --pomsPghero https://pghero.anxinyun.cn/ --pomsEs https://esc.anxinyun.cn/ --pomsNotebook https://inotebook.anxinyun.cn/ --dcWeb https://fsiot-oamss.anxinyun.cn", "start-params": "node server -p 5600 -u http://localhost:4600 --apiPomsUrl http://localhost:4600 --apiAnxinyunUrl http://10.8.30.112:4100 --apiEmisUrl http://10.8.30.161:1111 --webEmisUrl http://10.8.30.161:1112 --webOaUrl http://10.8.30.161:8668 --qnak 5XrM4wEB9YU6RQwT64sPzzE6cYFKZgssdP5Kj3uu --qnsk w6j2ixR_i-aelc6I7S3HotKIX-ukMzcKmDfH6-M5 --qnbkt anxinyun-test --qndmn http://test.resources.anxinyun.cn --iotVcmpWeb https://mediaconsole.ngaiot.com --pomsMonitor http://monitor.anxinyun.cn/goto/PaEDLE84z?orgId=1 --pomsKubesphere https://k8sadmin.anxinyun.cn/ --pomsAmbari https://ambari.anxinyun.cn/ --pomsKowl https://kafka.anxinyun.cn/ --pomsPghero https://pghero.anxinyun.cn/ --pomsEs https://esc.anxinyun.cn/ --pomsNotebook https://inotebook.anxinyun.cn/ --dcWeb https://fsiot-oamss.anxinyun.cn",
"deploy": "export NODE_ENV=production&& npm run build && node server", "deploy": "export NODE_ENV=production&& npm run build && node server",
"build-dev": "cross-env NODE_ENV=development&&webpack --config webpack.config.js", "build-dev": "cross-env NODE_ENV=development&&webpack --config webpack.config.js",
"build": "cross-env NODE_ENV=production&&webpack --config webpack.config.prod.js" "build": "cross-env NODE_ENV=production&&webpack --config webpack.config.prod.js"

3
web/routes/attachment/index.js

@ -19,7 +19,7 @@ module.exports = {
entry: function (app, router, opts) { entry: function (app, router, opts) {
const getApiRoot = async function (ctx) { const getApiRoot = async function (ctx) {
const { apiUrl, iotVcmpWeb, pomsMonitor, pomsKubesphere, pomsAmbari, pomsKowl, pomsPghero, pomsEs, pomsNotebook, dcWeb, qiniu, webEmis, } = opts; const { apiUrl, iotVcmpWeb, pomsMonitor, pomsKubesphere, pomsAmbari, pomsKowl, pomsPghero, pomsEs, pomsNotebook, dcWeb, qiniu, webEmis, webOa } = opts;
ctx.status = 200; ctx.status = 200;
ctx.body = { ctx.body = {
@ -35,6 +35,7 @@ module.exports = {
dcWeb: dcWeb, dcWeb: dcWeb,
qiniu: qiniu, qiniu: qiniu,
webEmis, webEmis,
webOa,
}; };
}; };

Loading…
Cancel
Save