diff --git a/api/.vscode/launch.json b/api/.vscode/launch.json index b1ea7a0..e441918 100644 --- a/api/.vscode/launch.json +++ b/api/.vscode/launch.json @@ -24,6 +24,8 @@ "-g postgres://FashionAdmin:123456@10.8.30.166:5432/POMS", "-k 10.8.30.72:29092,10.8.30.73:29092,10.8.30.74:29092", "-e http://10.8.30.60:9200", + "-c https://camundatest.anxinyun.cn", + "-r fs-workflow", // "-e http://10.8.30.60:5601", "--iotaProxy http://10.8.30.157:17007", // diff --git a/api/app/lib/controllers/form/index.js b/api/app/lib/controllers/form/index.js new file mode 100644 index 0000000..9c17fb2 --- /dev/null +++ b/api/app/lib/controllers/form/index.js @@ -0,0 +1,113 @@ +'use strict'; +// const moment = require('moment'); +// const CamundaApi = require('../../utils/camunda-api'); + +//运维相关的待办事项 +async function getUnfinished (ctx) { + const { models } = ctx.fs.dc + const { clickHouse } = ctx.app.fs + const userInfo = ctx.fs.api.userInfo; + // const { camundaUserId } =ctx.fs.api + const assignee='fsUser'+userInfo.pepUserId + const BeforeAssignUser='fsBeforeAssignUser'+userInfo.pepUserId + const AfterAssignUser='fsAfterAssignUser'+userInfo.pepUserId + + try{ + let all=await clickHouse.camWorkflow.query(` + SELECT DISTINCT * + FROM ( + SELECT * + FROM ( + SELECT DISTINCT RES.* + FROM act_hi_taskinst RES, act_hi_procinst PRO + WHERE 1 = 1 + AND RES.end_time_ IS NULL + AND 1 = 1 + AND RES.assignee_ = '${assignee}' + AND RES.proc_inst_id_ = PRO.proc_inst_id_ + AND PRO.business_key_ in ('160','159') + ) RES + UNION ALL + SELECT * + FROM ( + SELECT DISTINCT RES.* + FROM act_hi_taskinst RES + WHERE 1 = 1 + AND RES.end_time_ IS NULL + AND 1 = 1 + AND RES.id_ IN ( + SELECT id_ + FROM act_hi_varinst VAR + WHERE name_ IN ('${BeforeAssignUser}','${AfterAssignUser}') + AND var_type_ IS NOT NULL + AND var_type_ = 'string' + AND text_ IS NOT NULL + AND text_ = 'pending' + ) + ) RES + ) AS res; +`).toPromise() +const procinstIds = [...new Set(all.map(e => e.proc_inst_id_))]; + // 获取流程实例变量 + if(all && all.length > 0){ + let procinstsVariables = await ctx.app.camunda.request.post(encodeURI(`/engine-rest/history/variable-instance`), { + processInstanceIdIn: procinstIds + }) + let data = { list: all, procinstsVariables: procinstsVariables, keywords: null, userInfo: userInfo, userId: userInfo.pepUserId }; + ctx.body = { count: countFilters(data) } + }else { + ctx.body = { count: 0 }; + } + ctx.status = 200 + }catch(error){ + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); + ctx.status = 400; + ctx.body = { + message: typeof error == 'string' ? error : undefined + } + } +} + +function countFilters(data) { + let totalCount = 0; + // let searchKeywords = data.keywords ? data.keywords.toLowerCase() : null; + let keywordsFlag = false; + data.list.map(e => { + let curVariables = data.procinstsVariables.body && data.procinstsVariables.body.filter(item => item.processInstanceId === e.processInstanceId); + keywordsFlag = false; + const isAssignee = e.assignee === `fsUser${data.userId}`; + if (isAssignee) { + //当前节点任务的办理人是自己才会过滤是否有前后加签 + const fsAfterAssignUnNum = curVariables.find(v => (v.name == 'fsAfterAssignUnNum' && e.id == v.taskId)) ? true : false; + const fsBeforeAssignUnNum = curVariables.find(v => (v.name == 'fsBeforeAssignUnNum' && e.id == v.taskId)) ? curVariables.find(v => (v.name == 'fsBeforeAssignUnNum' && e.id == v.taskId)) : false; + //需要过滤一下前后加签,如果是当前用户的任务但是操作过前后加签不显示代办任务里 + if (fsBeforeAssignUnNum) { + //存在前加签判断是否前加签的人员已经处理完了 + if (fsBeforeAssignUnNum.value === 0) { keywordsFlag = true; }; + } else { + //判断是否存在后加签,有后加签就不显示当前用户的待办任务 + if (!fsAfterAssignUnNum) { keywordsFlag = true; } + } + } else { + keywordsFlag = true; + } + if (keywordsFlag) { + //暂未用到关键词传参 + // if (searchKeywords) { + // const fsFormItemName = curVariables.find(t => t.name == 'fsFormItemName') ? curVariables.find(t => t.name == 'fsFormItemName').value : ''; + // const fsEmisApplyUserName = curVariables.find(t => t.name == 'fsEmisApplyUserName') ? curVariables.find(t => t.name == 'fsEmisApplyUserName').value : ''; + // if (!((fsFormItemName && fsFormItemName.toLowerCase().includes(searchKeywords)) || (fsEmisApplyUserName.includes(searchKeywords)) + // )) { + // totalCount++; + // } + // } else { + totalCount++; + // } + } + }); + return totalCount; +} + +module.exports = { + getUnfinished +}; \ No newline at end of file diff --git a/api/app/lib/index.js b/api/app/lib/index.js index d668b4e..b8c4758 100644 --- a/api/app/lib/index.js +++ b/api/app/lib/index.js @@ -6,6 +6,7 @@ const utils = require('./utils') const routes = require('./routes'); const redisConnect = require('./service/redis') const socketConect = require('./service/socket') +const camundarest = require('./middlewares/camunda-rest'); const mqttVideoServer = require('./service/mqttServer') const paasRequest = require('./service/paasRequest'); const es = require('./service/es'); @@ -22,6 +23,7 @@ module.exports.entry = function (app, router, opts) { app.fs.utils = app.fs.utils || {}; app.fs.api.authAttr = app.fs.api.authAttr || {}; app.fs.api.logAttr = app.fs.api.logAttr || {}; + // 顺序固定 ↓ redisConnect(app, opts) @@ -46,11 +48,14 @@ module.exports.entry = function (app, router, opts) { // 鉴权中间件 router.use(authenticator(app, opts)); - + //camundarest + router.use(camundarest(app, router, opts.camundarest)); // 日志记录 // router.use(apiLog(app, opts)); router = routes(app, router, opts); + + }; module.exports.models = function (dc) { // dc = { orm: Sequelize对象, ORM: Sequelize, models: {} } diff --git a/api/app/lib/middlewares/authenticator.js b/api/app/lib/middlewares/authenticator.js index 90000bf..111a906 100644 --- a/api/app/lib/middlewares/authenticator.js +++ b/api/app/lib/middlewares/authenticator.js @@ -98,6 +98,8 @@ let authorizeToken = async function (ctx, token) { ctx.fs.api.userInfo = pomsUser; ctx.fs.api.pepUserId = userInfo.id; ctx.fs.api.pepUserInfo = userInfo; + ctx.fs.api.camundaUserId = `fsUser${userInfo.id}`; + ctx.fs.api.password = `workflow-${userInfo.id}`; ctx.fs.api.token = token; } } catch (err) { diff --git a/api/app/lib/middlewares/camunda-rest.js b/api/app/lib/middlewares/camunda-rest.js new file mode 100644 index 0000000..41f2f32 --- /dev/null +++ b/api/app/lib/middlewares/camunda-rest.js @@ -0,0 +1,71 @@ +'use strict'; + +const request = require('superagent'); + +function factory(app, router, opts) { + return async function (ctx, next) { + const apiRoot = `${opts.host}/${opts.root}`; + + const username = ctx.fs.api.camundaUserId ? ctx.fs.api.camundaUserId : "admin"; + const password = ctx.fs.api.password ? ctx.fs.api.password : "fs-workflow"; + + // console.log('[camunda-rest] ctx.fs.api:', JSON.stringify(ctx.fs.api)) + console.log('[camunda-rest] ctx.fs.api.camundaUserId:', ctx.fs.api.camundaUserId) + const req = { + get: (url, query) => { + return request + .get(`${apiRoot}${url}`) + .query(query) + .auth(username, password); + }, + post: (url, data, query, userId) => { + if(url.indexOf('engine-rest/task') != -1 && url.indexOf('variables') != -1) { + console.log(` + \n批量转办\n + url ${apiRoot}${url}\n + query ${query}\n + auth + username ${userId && `fsUser${userId}` || username}\n + pwd ${userId && `workflow-${userId}` || password}\n + data ${JSON.stringify(data)} + `) + } + + + return request + .post(`${apiRoot}${url}`) + .query(query) + .auth(userId && `fsUser${userId}` || username, + userId && `workflow-${userId}` || password) + .set('Content-Type', 'application/json') + .send(data); + }, + + put: (url, data, userId) => { + return request + .put(`${apiRoot}${url}`) + .auth(userId && `fsUser${userId}` || username, + userId && `workflow-${userId}` || password) + .set('Content-Type', 'application/json') + .send(data); + }, + + delete: (url, userId) => { + return request + .del(`${apiRoot}${url}`) + .auth(userId && `fsUser${userId}` || username, + userId && `workflow-${userId}` || password); + }, + deploy: (url, file) => { + return request.post(`${apiRoot}${url}`).auth(username, password).attach('file', file); + } + }; + + app.camunda = app.camunda || {}; + app.camunda.request = req; + + await next(); + }; +} + +module.exports = factory; diff --git a/api/app/lib/routes/form/index.js b/api/app/lib/routes/form/index.js new file mode 100644 index 0000000..14f5f18 --- /dev/null +++ b/api/app/lib/routes/form/index.js @@ -0,0 +1,10 @@ +'use strict'; + + +const form = require('../../controllers/form'); + +module.exports = function (app, router, opts) { + app.fs.api.logAttr['GET/unfinished'] = { content: '表单待办事项', visible: true }; + router.get('/unfinished', form.getUnfinished); + +}; \ No newline at end of file diff --git a/api/app/lib/utils/index.js b/api/app/lib/utils/index.js index 19d9745..11e0649 100644 --- a/api/app/lib/utils/index.js +++ b/api/app/lib/utils/index.js @@ -6,6 +6,7 @@ const fs = require('fs'); module.exports = async function (app, opts) { fs.readdirSync(__dirname).forEach((filename) => { if (!['index.js'].some(f => filename == f)) { + console.log('filename',filename) const utils = require(`./${filename}`)(app, opts) console.log(`载入 ${filename} 工具集成功`); app.fs.utils = { diff --git a/api/config.js b/api/config.js index 6e665a6..fccf72c 100644 --- a/api/config.js +++ b/api/config.js @@ -13,7 +13,8 @@ args.option(['g', 'pg'], 'postgre 服务 URL'); args.option(['f', 'fileHost'], '文件中心本地化存储: WebApi 服务器地址(必填), 该服务器提供文件上传Web服务'); args.option(['k', 'kafka'], 'kafka 服务 URL'); args.option(['e', 'es'], 'es 服务 URL'); - +args.option(['c', 'camundaHost'], 'camunda rest host'); +args.option(['r', 'camundaRoot'], 'camunda rest root'); args.option('iotaProxy', '以太代理') args.option('redisHost', 'redisHost'); @@ -64,6 +65,9 @@ const flags = args.parse(process.argv); const POMS_DB = process.env.POMS_DB || flags.pg; const LOCAL_SVR_ORIGIN = process.env.LOCAL_SVR_ORIGIN || flags.fileHost; +//项企 +const FS_CAMUNDA_HOST = process.env.CAMUNDA_HOST || flags.camundaHost; +const FS_CAMUNDA_ROOT = process.env.CAMUNDA_ROOT || flags.camundaRoot; // kafka const ANXINCLOUD_KAFKA_BROKERS = process.env.ANXINCLOUD_KAFKA_BROKERS || flags.kafka; @@ -130,8 +134,10 @@ const ES_PLATFORM_NAME = process.env.ES_PLATFORM_NAME || flags.esPlatformName || 'anxincloud' || 'anxinyun'; const ANXINCLOUD_ES_NODES_REST = process.env.ANXINCLOUD_ES_NODES_REST || flags.es; - +// //business_key +// const BUSINESS_KEY=process.env.BUSINESS_KEY||['160','161'] if ( + !FS_CAMUNDA_HOST || !FS_CAMUNDA_ROOT || !POMS_DB || !IOTA_REDIS_SERVER_HOST || !IOTA_REDIS_SERVER_PORT || !ANXINCLOUD_KAFKA_BROKERS @@ -152,6 +158,7 @@ if ( process.exit(-1); } + const product = { port: flags.port || 8080, staticDirs: ['static'], @@ -171,6 +178,11 @@ const product = { entry: require('./app').entry, opts: { dev, + // BUSINESS_KEY, + camundarest: { + host: FS_CAMUNDA_HOST, + root: FS_CAMUNDA_ROOT + }, exclude: [ // "*", { p: '/attachments/:p', o: 'POST' }, diff --git a/web/config.js b/web/config.js index 8ac8a60..ce7d83e 100644 --- a/web/config.js +++ b/web/config.js @@ -35,7 +35,7 @@ args.option('qnbkt', 'qiniuBucket'); args.option('qndmn', 'qiniuDomain'); const flags = args.parse(process.argv); - +console.log('flags111',flags) const API_URL = process.env.API_URL || flags.apiUrl; const API_POMS_URL = process.env.API_POMS_URL || flags.apiPomsUrl; const API_EMIS_URL = process.env.API_EMIS_URL || flags.apiEmisUrl; @@ -119,6 +119,7 @@ const product = { pomsNotebook: POMS_NOTEBOOK, dcWeb: DC_WEB, staticRoot: './client', + qiniu: { fetchUrl: '/_file-server', domain: ANXINCLOUD_QINIU_DOMAIN_QNDMN_RESOURCE