Browse Source

fix 待办打不开

dev
巴林闲侠 2 years ago
parent
commit
e8cd12bb75
  1. 2
      api/.vscode/launch.json
  2. 5
      api/app/lib/schedule/index.js
  3. 63
      api/app/lib/schedule/workorder_statistics.js
  4. 106
      api/app/lib/utils/parseProcessData.js
  5. 9
      api/config.js
  6. 99
      web/client/src/sections/analysis/containers/workorderData.jsx
  7. 9
      web/client/src/sections/analysis/routes.js

2
api/.vscode/launch.json

@ -26,7 +26,6 @@
"--redisPort 6379",
"--apMergeDeVeAnxinProjectId 1,2,3",
"--axyApiUrl http://127.0.0.1:4100",
"--apiEmisUrl http://10.8.30.112:14000",
//
// "--apiEmisUrl http://10.8.30.161:1111",
// "--apiEmisUrl http://10.8.30.161:31111/",
@ -71,6 +70,7 @@
"--clickHouseVcmp video_access_dev",
"--clickHouseDataAlarm default",
"--clickHouseIot iota",
"--clickHouseCamworkflow camworkflow",
"--confirmAlarmAnxinUserId 1",
"--vcmpAppId 5048b08d-c449-4d7f-b1ec-f741012aefe8",
"--vcmpAppSecret 5ba8c0ab-9fbd-4f07-9817-c48017c3cbad",

5
api/app/lib/schedule/index.js

@ -7,8 +7,11 @@ const nodeSchedule = require('node-schedule');
module.exports = async function (app, opts) {
const scheduleInit = ({
interval, immediate, proRun,
interval, immediate, proRun, disabled
}, callback) => {
if (disabled) {
return;
}
if (proRun && opts.dev) {
return;
}

63
api/app/lib/schedule/workorder_statistics.js

@ -0,0 +1,63 @@
const moment = require('moment')
let isDev = false
// let isDev = true
module.exports = function (app, opts) {
const workorderStatistics = app.fs.scheduleInit(
{
interval: '24 */1 * * * *',
immediate: isDev,
proRun: !isDev,
disabled: true
},
async () => {
try {
const { models, ORM: sequelize } = app.fs.dc
const { apMergeDeVeAnxinProjectId = '' } = opts
const { clickHouse } = app.fs
const { database: camWorkflow } = clickHouse.camWorkflow.opts.config
const { parseProcessData } = app.fs.utils
const attendanceRes = await clickHouse.pepEmis.query(
`
SELECT
story.id AS historyId,
story.apply_user AS pepUserId,
story.form_data AS formData,
story.submit_form_data AS submitFormData,
fform.form_schema AS formSchema,
fprocess.name AS processName,
procin.state_ AS state,
fform.id AS formId,
fversion.id AS versionId,
fgroup.name AS groupName
FROM
workflow_process_history AS story
INNER JOIN workflow_process_version AS fversion
ON fversion.id = story.version_id
INNER JOIN workflow_process_form AS fform
ON fform.id = fversion.form_id
INNER JOIN workflow_process AS fprocess
ON fprocess.id = fform.process_id
INNER JOIN workflow_group AS fgroup
ON fgroup.id = fprocess.group_id
AND fgroup.name = '运维中台表单'
INNER JOIN ${camWorkflow}.act_hi_procinst AS procin
ON procin.id_ = story.procinst_id
${existOvertimeCount || existVacateCount ?
`WHERE story.create_at > '2023-03-16 00:00:00'`
: ''}
`
).toPromise()
} catch (error) {
console.error(error);
}
}
)
return {
workorderStatistics,
}
}

106
api/app/lib/utils/parseProcessData.js

@ -0,0 +1,106 @@
'use strict';
const schemaRecursionObj = (obj, target, schemaPath) => {
let schemaPath_ = JSON.parse(JSON.stringify(schemaPath))
if (obj.properties) {
for (let prKey in obj.properties) {
if (obj.properties[prKey].title == target) {
schemaPath_.push({
prKey,
...obj.properties[prKey]
})
return schemaPath_
}
const hasProperties = obj.properties[prKey].properties
const isGroup = obj.properties[prKey].type == 'array' && obj.properties[prKey].title == '分组'
if (hasProperties || isGroup) {
schemaPath_.push({
prKey,
...obj.properties[prKey],
isGroup: isGroup,
})
schemaPath_ = schemaRecursionObj(
isGroup ?
obj.properties[prKey].items
: obj.properties[prKey],
target,
schemaPath_
)
if (!schemaPath_) {
return []
}
if (schemaPath_.length > schemaPath.length) {
return schemaPath_
}
}
}
} else {
return schemaPath_
}
}
const dataRecursionObj = (dataObj, index, needData, lastKeyObj, nd) => {
const keyObj = needData[nd].schemaPath[index]
if (dataObj.hasOwnProperty(keyObj.prKey)) {
if (lastKeyObj.prKey == keyObj.prKey) {
let gotValue = dataObj[keyObj.prKey]
if (keyObj.enum && !needData[nd].fromDataSource) {
let vIndex = keyObj.enum.findIndex(ke => ke == gotValue)
gotValue = keyObj.enumNames[vIndex]
}
return gotValue
} else {
if (keyObj.isGroup) {
for (let item of dataObj[keyObj.prKey]) {
const gotValue = dataRecursionObj(item, index + 1, needData, lastKeyObj, nd)
if (gotValue) {
return gotValue
}
}
} else {
return dataRecursionObj(dataObj[keyObj.prKey], index + 1, needData, lastKeyObj, nd)
}
}
}
}
const getData = (applyDetail, needData) => {
for (let nd in needData) {
if (needData[nd].noProcess) {
continue
}
needData[nd].schemaPath = schemaRecursionObj(applyDetail.formSchema.jsonSchema, needData[nd]['keyWord'], [])
if (needData[nd].schemaPath && needData[nd].schemaPath.length) {
const lastKeyObj = needData[nd].schemaPath[
needData[nd].schemaPath.length - 1
]
needData[nd].value = dataRecursionObj(applyDetail.formData, 0, needData, lastKeyObj, nd)
} else {
// 记录错误 关键数据没找到
}
}
}
module.exports = function (app, opts) {
const parseProcessData = (applyDetail, pomsNeedData = {
title: {
keyWord: '标题',
},
pomsProjectId: {
keyWord: '关联项目',
fromDataSource: true
},
expectTime: {
keyWord: '期望完成时间'
}
}) => {
let needData = JSON.parse(JSON.stringify(pomsNeedData))
getData(applyDetail, needData)
return needData
}
return {
parseProcessData
}
}

9
api/config.js

@ -46,6 +46,7 @@ args.option('clickHouseProjectManage', 'clickHouse 项目管理数据库名称')
args.option('clickHouseVcmp', 'clickHouse 视频平台数据库名称');
args.option('clickHouseDataAlarm', 'clickHouse 视频平台数据告警库名称');
args.option('clickHouseIot', 'clickHouse IOT平台设备信息库名称');
args.option('clickHouseCamworkflow', 'clickHouse 工作流数据库名称');
args.option('confirmAlarmAnxinUserId', '确认告警时保存到 ES 的安心云的用户的 id');
@ -104,6 +105,7 @@ const CLICKHOUST_PROJECT_MANAGE = process.env.CLICKHOUST_PROJECT_MANAGE || flags
const CLICKHOUST_VCMP = process.env.CLICKHOUST_VCMP || flags.clickHouseVcmp
const CLICKHOUST_DATA_ALARM = process.env.CLICKHOUST_DATA_ALARM || flags.clickHouseDataAlarm
const CLICKHOUST_IOT = process.env.CLICKHOUST_IOT || flags.clickHouseIot
const CLICKHOUST_CAM_WORKFLOW = process.env.CLICKHOUST_CAM_WORKFLOW || flags.clickHouseCamworkflow
const CONFIRM_ALARM_ANXIN_USER_ID = process.env.CONFIRM_ALARM_ANXIN_USER_ID || flags.confirmAlarmAnxinUserId
@ -125,6 +127,7 @@ if (
|| !QINIU_DOMAIN_QNDMN_RESOURCE || !QINIU_BUCKET_RESOURCE || !QINIU_AK || !QINIU_SK
|| !CLICKHOUST_URL || !CLICKHOUST_PORT
|| !CLICKHOUST_ANXINCLOUD || !CLICKHOUST_PEP_EMIS || !CLICKHOUST_PROJECT_MANAGE || !CLICKHOUST_VCMP || !CLICKHOUST_DATA_ALARM || !CLICKHOUST_IOT
// || !CLICKHOUST_CAM_WORKFLOW
|| !CONFIRM_ALARM_ANXIN_USER_ID
|| !VCMP_APP_ID || !VCMP_APP_SECRET
) {
@ -248,7 +251,11 @@ const product = {
}, {
name: 'iot',
db: CLICKHOUST_IOT
}
},
{
name: 'camWorkflow',
db: CLICKHOUST_CAM_WORKFLOW
},
]
}
}

99
web/client/src/sections/analysis/containers/workorderData.jsx

@ -43,6 +43,7 @@ const WorkOrderData = (props) => {
nameGap: 20
},
legend: {},
tooltip: {},
grid: {
left: '3%',
right: '4%',
@ -61,9 +62,10 @@ const WorkOrderData = (props) => {
}, {
t: '工单完成情况分析',
echartOption: {
tooltip: {},
series: [
{
name: 'xx',
name: '工单完成率',
type: 'gauge',
progress: {
show: true
@ -77,10 +79,14 @@ const WorkOrderData = (props) => {
value: 50,
name: '工单完成率'
}
]
],
title: {
show: true,
offsetCenter: ["0", "100%"]
}
},
{
name: 'YY',
name: '延期数',
type: 'gauge',
progress: {
show: true
@ -94,7 +100,11 @@ const WorkOrderData = (props) => {
value: 50,
name: '延期数'
}
]
],
title: {
show: true,
offsetCenter: ["0", "100%"]
}
},
],
media: [
@ -111,10 +121,87 @@ const WorkOrderData = (props) => {
},
}, {
t: '工单处理分析',
echartOption: {},
echartOption: {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value',
name: "单位:个",
nameLocation: "end",
nameGap: 20
},
legend: {},
tooltip: {},
grid: {
left: '3%',
right: '4%',
bottom: '1%',
// top: '24%',
containLabel: true
},
series: [
{
data: [120, 200, 150, 80, 70, 110, 130],
type: 'bar',
name: '发起数'
},
{
data: [120, 200, 150, 80, 70, 110, 130],
type: 'bar',
name: '解决数'
}
]
},
}, {
t: '工单类型分析',
echartOption: {},
echartOption: {
tooltip: {},
series: [
{
name: '设备类型',
type: 'pie',
radius: '50%',
data: [
{ value: 1048, name: 'Search Engine' },
{ value: 735, name: 'Direct' },
{ value: 580, name: 'Email' },
{ value: 484, name: 'Union Ads' },
{ value: 300, name: 'Video Ads' }
],
label: {
}
},
{
name: '解决方案',
type: 'pie',
radius: '50%',
data: [
{ value: 1048, name: 'Search Engine' },
{ value: 735, name: 'Direct' },
{ value: 580, name: 'Email' },
{ value: 484, name: 'Union Ads' },
{ value: 300, name: 'Video Ads' }
],
label: {
}
},
],
media: [
{
query: { minAspectRatio: 1 },
option: {
series: [
{ center: ['25%', '50%'] },
{ center: ['75%', '50%'] }
]
}
},
]
},
},].map((c, idx) => (
<Card
key={idx}

9
web/client/src/sections/analysis/routes.js

@ -7,7 +7,8 @@ export default [{
key: 'analysis',
breadcrumb: '分析',
// 不设置 component 则面包屑禁止跳转
childRoutes: [{
childRoutes: [
{
path: '/problemAnalysis',
key: 'problemAnalysis',
breadcrumb: '问题分析',
@ -27,7 +28,8 @@ export default [{
component: OperationData,
breadcrumb: '运维数据',
}]
}, {
},
{
path: '/workorderAnalysis',
key: 'workorderAnalysis',
breadcrumb: '工单分析',
@ -37,6 +39,7 @@ export default [{
component: WorkorderData,
breadcrumb: '工单数据',
}]
}]
}
]
}
}];
Loading…
Cancel
Save