UNPKG

eme-flow

Version:

eme flow组件

1,269 lines (1,186 loc) 61.8 kB
/** * Created by cc on 2016/9/23 0023. * 未完成 : * 当节点CONTROLLER抛出异常时,页面依然进行渲染,且渲染错误时错误信息在界面上展示时可能引起脚本错误 * 即时是窗体,发生错误跳转到error时,仍然后退,而不是关闭页面.. */ 'use strict'; import fs from "fs"; import path from "path"; import ejs from "ejs"; import moment from "moment"; import T from "./util/toolkit"; import C from "./util/FlowController"; import SQL from "./sql/SQL"; import DAO from "./sql/dao"; import sqlMapper from "./resource/sql"; import consts from "./resource/consts"; import i18n from "./resource/i18n"; let readDir = T.P(fs.readdir); let readFile = T.P(fs.readFile); let unlink = T.P(fs.unlink); let writeFile = T.P(fs.writeFile); let renderFile = T.P(ejs.renderFile, ejs); let mkdir = T.P(fs.mkdir, fs); /** * 通过文件夹id获取文件夹下的文件名称 * ps : 文件夹下只能有一个文件 * @param id */ let getFileName = async function (id) { let apath = path.join(process.cwd(), `/script/${id}`); let files = await fs.existsSync(apath) === true && await readDir(apath); if (files && files.length > 0) return [path.join(apath, files[0]), files[0]]; return [0, 0]; }; /** * 将value保存为文件存放到id目录下,并以value的MD5命名;同时删掉旧文件 * @param id * @param value * @returns {*} */ let newFile = async function (id, oldName, value, isJs) { let apath = path.join(process.cwd(), '/script'); if (await fs.existsSync(apath) === false) await mkdir(apath); apath = path.join(apath, id); if (await fs.existsSync(apath) === false) await mkdir(apath); if (oldName !== 0) { await fs.existsSync(oldName) === true && await unlink(oldName); } let md5 = await T.md5(value); apath = path.join(apath, `${md5}.${isJs === true ? 'js' : 'ejs'}`); await writeFile(apath, value, 'utf8'); return apath; }; export default { /*初始化默认数据库*/ set: function (options) { DAO.set(options) }, /*获取流程列表*/ getFlowList: async function (req) { let sql = new SQL() .push(sqlMapper.getFlowSimplyInfo) .push(sqlMapper.getFlowCount) .jqGrid(req) .compile(); let connection = await DAO.get(); let result = await T.P(connection.query, connection)(sql); connection.release(); return { total: result[1][0].t, records: parseInt((result[1][0].t + (req.param('rows') - 0 + 1)) / req.param('rows')), rows: result[0] }; }, /** * 获取流程实例 * @param id */ getFlowInstance: async function (id, req) { let sql = new SQL() .push(sqlMapper.getInstanceSimplyInfo) .push(sqlMapper.getInstanceCount) .jqGrid(req) .and('flow_id = :flow_id') .set('flow_id', id) .compile(); let connection = await DAO.get(); let result = await T.P(connection.query, connection)(sql); connection.release(); return { total: result[1][0].t, records: req ? parseInt((result[1][0].t + (req.param('rows') - 0 + 1)) / req.param('rows')) : 0, rows: result[0] }; }, /** * 删除流程实例 * @param id */ delFlowInstance: async function (id) { let sql = new SQL() .push(sqlMapper.delInstanceByFlowid) .set('flow_id', id) .compile(); let connection = await DAO.get(); await T.P(connection.beginTransaction, connection); try { await T.P(connection.query, connection)(sql); await T.P(connection.commit, connection)(); } catch (e) { await T.P(connection.rollback, connection)(); sails.log.error(JSON.stringify(e)); throw T.error(211011); } finally { connection.release(); } return 0; }, /** * 删除流程 * @param id */ delFlow: async function (id) { let sql = new SQL() .push(sqlMapper.deleteFlow) .set('flow_id', id) .compile(); let connection = await DAO.get(); await T.P(connection.beginTransaction, connection); try { await T.P(connection.query, connection)(sql); await T.P(connection.commit, connection)(); } catch (e) { await T.P(connection.rollback, connection)(); sails.log.error(JSON.stringify(e)); throw T.error(211011); } finally { connection.release(); } return 0; }, /** * 获取流程for配置 * @param req flow_id */ getFlowConfig: async function (flow_id) { let sql = new SQL().push(sqlMapper.getFlow) .and('flow_id = :flow_id') .set('flow_id', flow_id) .compile(); let connection = await DAO.get(); let flow = await T.P(connection.query, connection)(sql); connection.release(); if (flow.length > 0) { return flow[0]; } }, /** * 根据编码获取流程 * @param flow_code * @returns {*} */ getFlowByCode: async function (flow_code) { let sql = new SQL().push(sqlMapper.getFlowSimplyInfo) .and('flow_code = :flow_code') .set('flow_code', flow_code) .compile(); let connection = await DAO.get(); let flow = await T.P(connection.query, connection)(sql); connection.release(); return flow; }, /** * 设置流程有效或者无效 * 同一个编码的只能有一个有效 * @param flow_code * @returns {*} */ updateFlowVliad: async function (flow_id, flow_valid) { let connection = await DAO.get(); let query = T.P(connection.query, connection); await T.P(connection.beginTransaction, connection); try { let sql = new SQL(); if (flow_valid == consts.FLOW_VALID_YES) { sql.push(sqlMapper.getFlowSimplyInfo) .and('flow_id = :flow_id') .set('flow_id', flow_id); let flow = await query(sql.compile()); if (flow.length === 0) { throw T.error(211007); } flow = flow[0]; sql.clear() .push(sqlMapper.updateFlowState) .and('flow_code = :flow_code') .set('flow_code', flow.flow_code) .set('flow_valid', consts.FLOW_VALID_NO); await query(sql.compile()); } sql.clear() .push(sqlMapper.updateFlowState) .and('flow_id = :flow_id') .set('flow_id', flow_id) .set('flow_valid', flow_valid); await query(sql.compile()); await T.P(connection.commit, connection)(); } catch (e) { sails.log.error(JSON.stringify(e)); await T.P(connection.rollback, connection)(); throw e; } finally { connection.release(); } }, /** * 查找最大版本号 * @param flow_code * @returns {*} */ getMaxVersionByCode: async function (flow_code) { let sql = new SQL().push(sqlMapper.getMaxVersionByCode) .set('flow_code', flow_code) .compile(); let connection = await DAO.get(); let version = await T.P(connection.query, connection)(sql); connection.release(); return version.length > 0 ? version[0].t : '1.0'; }, /** * 插入流程, 配置用 * @param req flow、node、action */ saveFlow: async function (data, mode) { let flow = data.flow; //数据检测 let flowByCode = await this.getFlowByCode(flow.flow_code); flowByCode.forEach(v => { if (v.flow_code === flow.flow_code && v.flow_version === flow.flow_version && v.flow_id !== flow.flow_id) { throw '数据重复,请修改版本号' } }); let instance = await this.getFlowInstance(flow.flow_id); if (instance.length > 0 && mode !== 'simply') { throw '存在实例,无法编辑' } let node = []; let action = []; for (let i in data.nodes) { node.push(data.nodes[i].flow); } for (let i in data.lines) { data.lines[i].flow && action.push(data.lines[i].flow); } flow.flow_struct = JSON.stringify(data); let connection = await DAO.get(); let query = T.P(connection.query, connection); await T.P(connection.beginTransaction, connection); try { let sql = new SQL() .push(sqlMapper.deleteFlow) .set('flow_id', flow.flow_id); await query(sql.compile()); if(flow.flow_valid === consts.FLOW_VALID_YES){ //其他版本改为无效 sql.clear() .push(sqlMapper.updateFlowState) .and('flow_code = :flow_code') .set('flow_code', flow.flow_code) .set('flow_valid', consts.FLOW_VALID_NO); await query(sql.compile()); } sql.clear().push(sqlMapper.insertNode); for (let i = 0; i < node.length; i++) { //page let script = []; //库 script.push(flow.flow_page_ware || ''); if (node[i].node_page_override) { script.push(node[i].node_page_override); } else { script.push(flow.flow_page); if (node[i].node_page_append) { script.push(node[i].node_page_append); } } node[i].page = script.join('\n'); node[i].page_md5 = await T.md5(node[i].page); //controller script.length = 0; script.push("'use strict';"); script.push(flow.flow_controller_ware || ''); script.push('module.exports = function(req , res , Flow , next){'); if (node[i].node_controller_override) { script.push(node[i].node_controller_override); } else { script.push(flow.flow_controller); if (node[i].node_controller_append) { script.push(node[i].node_controller_append); } } script.push('};'); node[i].controller = script.join('\n'); node[i].controller_md5 = await T.md5(node[i].controller); //controller-save script.length = 0; script.push("'use strict';"); script.push(flow.flow_controller_ware || ''); script.push('module.exports = function(req , res , Flow , next){'); if (node[i].node_controller_save) { script.push(node[i].node_controller_save || 'next();'); } script.push('};'); node[i].controller_save = script.join('\n'); node[i].controller_save_md5 = await T.md5(node[i].controller_save); //page-save script.length = 0; script.push('function(next){'); if (node[i].node_page_save) { script.push(node[i].node_page_save || 'next();'); } script.push('};'); node[i].page_save = script.join('\n'); node[i].page_save_md5 = await T.md5(node[i].page_save); //controller-del script.length = 0; script.push("'use strict';"); script.push(flow.flow_controller_ware || ''); script.push('module.exports = function(req , res , Flow , next){'); if (node[i].node_controller_save) { script.push(node[i].node_controller_del || ''); } script.push('};'); node[i].controller_del = script.join('\n'); node[i].controller_del_md5 = await T.md5(node[i].controller_del); //删掉没用的字段 delete node[i].node_page_append; delete node[i].node_page_override; delete node[i].node_controller_append; delete node[i].node_controller_override; delete node[i].node_controller_save; delete node[i].node_page_save; delete node[i].node_controller_del; sql.set('node', node[i]); await query(sql.compile()); } sql.clear().push(sqlMapper.insertAction); for (let i = 0; i < action.length; i++) { //page let script = []; script.push('function(next,comment){'); script.push(action[i].action_script || 'next();'); script.push('};'); action[i].page = script.join('\n'); action[i].page_md5 = await T.md5(action[i].page); //controller script.length = 0; script.push("'use strict';"); script.push(flow.flow_controller_ware || ''); script.push('module.exports = function(req , res , Flow , next){'); script.push(action[i].action_controller); script.push('};'); action[i].controller = script.join('\n'); action[i].controller_md5 = await T.md5(action[i].controller); delete action[i].action_controller; delete action[i].action_script; sql.set('action', action[i]); await query(sql.compile()); } //删掉没用的字段 delete flow.flow_page; delete flow.flow_controller; delete flow.flow_code_ware; delete flow.flow_page_ware; sql.clear() .push(sqlMapper.insertFlow) .set('flow_id', flow.flow_id) .set('flow', flow); await query(sql.compile()); await T.P(connection.commit, connection)(); } catch (e) { sails.log.error(JSON.stringify(e)); await T.P(connection.rollback, connection)(); throw e; } finally { connection.release(); } }, /** * 展示流程实例页面, * req.param 需要提供biz_id和instance_id和flow_code和flow_id选择一种方式 * from_page :在流程处理界面删除流程后跳转的地址 * @param req * @param res * @returns {*} */ showFlow: async function (req, res) { /*是否登陆*/ if (req.session.user === undefined) { throw T.error(211002); } let instance_id = req.param('instance_id'); let biz_id = req.param('biz_id'); let flow_code = req.param('flow_code'); let flow_id = req.param('flow_id'); let from_page = req.param('from_page'); let user = req.session.user; let data = { instance: 0, current_node: 0, last_record: 0, actions: 0, flow: 0 }; let sql = new SQL(); let connection = await DAO.get(); let query = T.P(connection.query, connection); /*根据流程实例id加载*/ if (instance_id !== undefined || biz_id !== undefined) { sql.clear() .push(sqlMapper.getInstanceSimplyInfo) .or('instance_id = :instance_id') .or('biz_id = :biz_id') .set('instance_id', instance_id) .set('biz_id', biz_id); /*流程实例信息*/ data.instance = await query(sql.compile()); if (data.instance.length !== 1) { throw T.error(211001); } data.instance = data.instance[0]; /*流程信息*/ sql.clear() .push(sqlMapper.getFlowSimplyInfo) .and('flow_id = :flow_id') .set('flow_id', data.instance.flow_id); data.flow = await query(sql.compile()); if (data.flow.length === 0) { connection.release(); throw T.error(211007); } data.flow = data.flow[0]; /*当前节点信息*/ sql.clear() .push(sqlMapper.getNodeSimplyInfo) .and('node_id = :current_node_id') .set('current_node_id', data.instance.current_node_id); data.current_node = await query(sql.compile()); if (data.current_node.length === 0) { connection.release(); throw T.error(211006); } data.current_node = data.current_node[0]; /*最新一步操作信息*/ sql.clear() .push(sqlMapper.getRecord) .and('action_record_id = :action_record_id') .set('action_record_id', data.instance.last_record_id); data.last_record = await query(sql.compile()); if (data.last_record.length === 0) { connection.release(); throw T.error(211008); } data.last_record = data.last_record[0]; } /*根据流程编码和版本号加载,当新建流程时*/ else if (flow_id !== undefined || flow_code !== undefined) { /* 流程信息 */ sql.clear(); if (flow_id !== undefined) { sql.push(sqlMapper.getFlowSimplyInfo) .and('flow_id = :flow_id') .set('flow_id', flow_id); } else { sql.push(sqlMapper.getFlowSimplyInfo) .and('flow_code = :flow_code') .and('flow_valid = :flow_valid') .set({flow_code: flow_code, flow_valid: consts.FLOW_VALID_YES}); } data.flow = await query(sql.compile()); if (data.flow.length !== 1) { connection.release(); throw T.error(211007); } data.flow = data.flow[0]; /*流程验证*/ /*是否有效*/ if (data.flow.flow_valid === consts.FLOW_VALID_NO) { connection.release(); throw T.error(211004); } /*开始节点信息*/ sql.clear() .push(sqlMapper.getNodeSimplyInfo) .and('flow_id = :flow_id') .and('node_type = :node_type') .set('flow_id', data.flow.flow_id) .set('node_type', consts.NODE_TYPE_START); data.current_node = await query(sql.compile()); if (data.current_node.length === 0) { connection.release(); throw T.error(211006); } data.current_node = data.current_node[0]; /*权限验证*/ /*开始节点指定操作人、开始节点指定操作人与当前登陆人不一样时 权限不足*/ if (data.current_node.node_userid && data.current_node.node_userid !== user.userid) { connection.release(); throw T.error(211003); } /*流程实例信息*/ data.instance = { instance_id: T.guid(2), current_node_id: data.current_node.node_id, flow_id: data.flow.flow_id, createorid: user.userid, createor: T.username(user), create_time: moment().format('YYYY/MM/DD HH:mm:ss'), instance_state: 0, last_record_id: 0 }; } if (data.flow === 0) { connection.release(); throw T.error(211001) } /*流程定义的、当前节点可进行的操作*/ /*当前登陆人和当前节点操作人id相同或者节点操作人为空时表示有权限操作 */ if (data.current_node.node_userid === user.userid || !data.current_node.node_userid) { if (data.instance.instance_state !== consts.INSTANCE_STATE_DISCARD) { //流程非废弃时,可进行常规操作 sql.clear() .push(sqlMapper.getActionSimplyInfo) .and('from_node_id = :current_node_id') .set('current_node_id', data.current_node.node_id) .order('action_order'); data.actions = await query(sql.compile()); for (let i = 0; i < data.actions.length; i++) { let action = data.actions[i] let actionMD5 = await getFileName(`${action.action_id}AS`); if (actionMD5[1] !== `${action.page_md5}.ejs`) { //需更新文件 //查询操作页面脚本 sql.clear() .push(sqlMapper.getActionPage) .and('action_id = :action_id') .set('action_id', action.action_id); let page = await query(sql.compile()); await newFile(`${action.action_id}AS`, actionMD5[0], page[0].page, false); action.script = page[0].page; } else { action.script = await readFile(actionMD5[0], 'utf8') } } /*当前节点是否允许回退*/ if (data.last_record !== 0 //有上一步 && data.current_node.node_allow_goback === consts.NODE_ALLOW_DISCARD_YES //允许回退 && (data.last_record.action_userid === user.userid)) { //上一步操作人=当前登陆人时 data.actions.push({ action_id: consts.ACTION_GOBACK_ID, action_code: consts.ACTION_GOBACK_CODE, action_name: i18n.GOBACK_ACTION_NAME, action_type: consts.ACTION_TYPE_GOBACK }); } /*当前节点是否允许废弃*/ if (data.current_node.node_allow_discard === consts.NODE_ALLOW_DISCARD_YES) { //允许废弃 data.actions.push({ action_id: consts.ACTION_DISCARD_ID, action_code: consts.ACTION_DISCARD_CODE, action_name: i18n.DISCARD_ACTION_NAME, action_type: consts.ACTION_TYPE_DISCARD }); } /*当前节点是否允许保存*/ if (data.current_node.node_allow_save === consts.NODE_ALLOW_SAVE_YES) { //允许保存 let action = { action_id: consts.ACTION_SAVE_ID, action_code: consts.ACTION_SAVE_CODE, action_name: i18n.SAVE_ACTION_NAME, action_type: consts.ACTION_TYPE_SAVE }; let actionMD5 = await getFileName(`${data.current_node.node_id}NPS`); if (actionMD5[1] !== `${action.page_save_md5}.ejs`) { //需更新文件 //保存页面脚本 sql.clear() .push(sqlMapper.getNodePageSave) .and('node_id = :node_id') .set('node_id', data.current_node.node_id); let page = await query(sql.compile()); await newFile(`${data.current_node.node_id}NPS`, actionMD5[0], page[0].page, false); action.script = page[0].page; } else { action.script = await readFile(actionMD5[0], 'utf8') } data.actions.push(action); } /*当前节点是否允许删除*/ if (data.current_node.node_allow_del === consts.NODE_ALLOW_DEL_YES) { //允许删除 data.actions.push({ action_id: consts.ACTION_DEL_ID, action_code: consts.ACTION_DEL_CODE, action_name: i18n.DEL_ACTION_NAME, action_type: consts.ACTION_TYPE_DEL }); } } else { //否则只能进行废弃还原操作 data.actions = [{ action_id: consts.ACTION_UN_DISCARD_ID, action_code: consts.ACTION_UN_DISCARD_CODE, action_name: i18n.UN_DISCARD_ACTION_NAME, action_type: consts.ACTION_TYPE_UN_DISCARD }]; } } /*后台脚本*/ let controllerMD5 = await getFileName(`${data.current_node.node_id}NC`); if (controllerMD5[1] !== `${data.current_node.controller_md5}.js`) { //需更新文件 //查询节点后台脚本 sql.clear() .push(sqlMapper.getNodeController) .and('node_id = :node_id') .set('node_id', data.current_node.node_id); let controller = await query(sql.compile()); controllerMD5[0] = await newFile(`${data.current_node.node_id}NC`, controllerMD5[0], controller[0].controller, true); } /*页面脚本*/ let pageMD5 = await getFileName(`${data.current_node.node_id}NP`); if (pageMD5[1] !== `${data.current_node.page_md5}.ejs`) { //需更新文件 //查询节点页面脚本 sql.clear() .push(sqlMapper.getNodePage) .and('node_id = :node_id') .set('node_id', data.current_node.node_id); let page = await query(sql.compile()); pageMD5[0] = await newFile(`${data.current_node.node_id}NP`, pageMD5[0], page[0].page, false); } //操作历史列表 sql.clear() .push(sqlMapper.getRecord) .and('instance_id = :instance_id') .set('instance_id', data.instance.instance_id) .order('action_time DESC'); let records = await query(sql.compile()); //释放sql connection.release(); //执行后台代码 let Flow = { node: 0, data: {}, goto: function (code) { this.node = code; return this; }, getInstance: function () { return data.instance; }, getCurrentNode: function () { return data.current_node; }, getLastRecord: function () { return data.last_record; }, getFlow: function () { return data.flow; }, getData: function (key) { return this.data[key]; }, setData: function (key, value) { this.data[key] = value; }, removeData: function (key) { delete this.data[key]; }, rollback: function () { }, setBiz: function (biz_id, biz_code) { } }; await T.P(require(controllerMD5[0]))(req, res, Flow); if (res.headersSent === false) { let reqs = req.allParams(); let session = req.session; Flow.data.Flow = data; Flow.data.req = reqs; Flow.data.session = session; Flow.data.sails = { config: sails.config }; let page = await renderFile(pageMD5[0], Flow.data, {cache: true}); res.ok({ page: page, Flow: { flow_instance: { instance_id: data.instance.instance_id, flow_id: data.instance.flow_id, current_node_id: data.instance.current_node_id, last_record_id: data.instance.last_record_id }, actions: data.actions, last_record: data.last_record, records: records, current_node: data.current_node, flow: data.flow, instance: data.instance }, req: reqs, session: session, from_page : from_page },'flow/doFlow'); } }, /** * 处理流程 * flow_instance对象 JSON对象或者JSON字符串 必有属性:instance_id、flow_id、current_node_id、last_record_id * flow_record对象 JSON对象或者JSON字符串 必有属性:action_id、action_type * @param req * @param res */ doFlow: async function (req, res) { /*是否登陆*/ if (req.session.user === undefined) { throw T.error(211002); } let user = req.session.user; let instance = req.param('flow_instance'); let record = req.param('flow_record'); if (typeof instance === 'string') instance = JSON.parse(instance); if (typeof record === 'string') record = JSON.parse(record); /* 参数合法性验证*/ if (instance === undefined //流程实例 || record === undefined //操作纪录 || instance.instance_id === undefined //流程实例id || instance.flow_id === undefined //流程id || instance.current_node_id === undefined //当前节点id || instance.last_record_id === undefined //上一步操作idxx || record.action_id === undefined //当前操作id || record.action_type === undefined //当前操作类型 ) { throw T.error(211009); } let sql = new SQL(); let connection = await DAO.get(); let query = T.P(connection.query, connection); /*流程合法性验证*/ sql.clear() .push(sqlMapper.getFlowSimplyInfo) .and('flow_id = :flow_id') .set('flow_id', instance.flow_id); let flow = await query(sql.compile()); if (flow.length === 0) { connection.release(); throw T.error(211007); } flow = flow[0]; /*流程实例合法性验证*/ /*防止多人操作、多界面操作、重复提交*/ sql.clear() .push(sqlMapper.getInstanceSimplyInfo) .and('instance_id = :instance_id') .set('instance_id', instance.instance_id); let instances = await query(sql.compile()); let last_record = 0; let current_node = 0; //无实例时的合法性验证 if (instances.length === 0) { //只有前台传回的实例的当前节点时开始节点,才合法 /*开始节点信息*/ sql.clear() .push(sqlMapper.getNodeSimplyInfo) .and('flow_id = :flow_id') .and('node_type = :node_type') .set('flow_id', instance.flow_id) .set('node_type', consts.NODE_TYPE_START); current_node = await query(sql.compile()); if (current_node.length === 0) { connection.release(); throw T.error(211006); } current_node = current_node[0]; if (current_node.node_id !== instance.current_node_id) { connection.release(); throw T.error(211005); } } //有实例时的合法性验证 else { //判断当前节点与提交的节点是否一致(防止多人操作) if (instance.current_node_id !== instances[0].current_node_id) { connection.release(); throw T.error(211005); } //最后一步的纪录id不一样,也不合法(防止多人操作) if (instance.last_record_id !== instances[0].last_record_id) { connection.release(); throw T.error(211005); } /*实例的上一步操作合法性验证*/ /*上一步的操作后节点id与当前节点id不一致,说明错误了*/ sql.clear() .push(sqlMapper.getRecord) .and('action_record_id = :action_record_id') .set('action_record_id', instances[0].last_record_id); last_record = await query(sql.compile()); if (last_record.length === 0) { connection.release(); throw T.error(211008); } last_record = last_record[0]; if (last_record.to_node_id !== instance.current_node_id) { connection.release(); throw T.error(211005); } //当前节点信息 sql.clear() .push(sqlMapper.getNodeSimplyInfo) .and('node_id = :node_id') .set('node_id', instance.current_node_id); current_node = await query(sql.compile()); if (current_node.length === 0) { connection.release(); throw T.error(211008); } current_node = current_node[0]; } /*处理操作*/ record.action_record_id = T.guid(2); record.instance_id = instance.instance_id; record.action_userid = user.userid; record.action_username = T.username(user); record.action_time = moment().format('YYYY/MM/DD HH:mm:ss'); record.from_node_id = instance.current_node_id; let action_type = +record.action_type; delete record.action_type; switch (action_type) { /*废弃操作*/ case consts.ACTION_TYPE_DISCARD : if (record.action_id === consts.ACTION_DISCARD_ID) { //只能在有实例时执行 if (instances.length === 0) { connection.release(); throw T.error(211010); } await T.P(connection.beginTransaction, connection); try { //操作纪录保存 record.to_node_id = instance.current_node_id; sql.clear() .push(sqlMapper.insertRecord).set('record', record); query(sql.compile()); //流程实例保存 instance.instance_state = consts.INSTANCE_STATE_DISCARD; instance.last_record_id = record.action_record_id; sql.clear() .push(sqlMapper.updateInstance) .set('instance', instance) .set('instance_id', instance.instance_id); query(sql.compile()); await T.P(connection.commit, connection)(); } catch (e) { sails.log.error(JSON.stringify(e)); await T.P(connection.rollback, connection)(); throw T.error(211011); } finally { connection.release(); } return instance.instance_id; } else { connection.release(); throw T.error(211006); } break; /*废弃还原操作*/ case consts.ACTION_TYPE_UN_DISCARD : if (record.action_id === consts.ACTION_UN_DISCARD_ID) { //只能在有实例时执行 if (instances.length === 0) { connection.release(); throw T.error(211010); } await T.P(connection.beginTransaction, connection); try { //操作纪录保存 record.to_node_id = instance.current_node_id; sql.clear() .push(sqlMapper.insertRecord).set('record', record); query(sql.compile()); //流程实例保存,流程实例的状态 从 废弃还原时,需要判断当前节点是否是完成节点,如果是完成节点,则状态变为 正常,否则变为 完成 if (current_node.node_type === consts.NODE_TYPE_END) { instance.instance_state = consts.INSTANCE_STATE_END; } else { instance.instance_state = consts.INSTANCE_STATE_NORMAL; } instance.last_record_id = record.action_record_id; sql.clear() .push(sqlMapper.updateInstance) .set('instance', instance) .set('instance_id', instance.instance_id); query(sql.compile()); await T.P(connection.commit, connection)(); } catch (e) { sails.log.error(JSON.stringify(e)); await T.P(connection.rollback, connection)(); throw T.error(211011); } finally { connection.release(); } return instance.instance_id; } else { connection.release(); throw T.error(211006); } break; /*回退操作*/ case consts.ACTION_TYPE_GOBACK : if (record.action_id === consts.ACTION_GOBACK_ID) { //只能在有实例时执行 if (instances.length === false) { connection.release(); throw T.error(211005); } await T.P(connection.beginTransaction, connection); try { //操作纪录保存 //界定回退的to_node_id以及回退后的当前节点id,理论上应取 最新操作的 from_node_id --> but // P:from_node_id=开始节点时,流程无法回退到开始节点,只能回退到草稿节点 //查询from_node_id对应的节点信息 sql.clear() .push(sqlMapper.getNodeSimplyInfo) .and('node_id = :node_id') .set('node_id', last_record.from_node_id); let last_node = await query(sql.compile()); if (last_node.length === 0) { throw T.error(211006); } last_node = last_node[0]; if (last_node.node_type === consts.NODE_TYPE_START) { //中,from_node_id=开始节点;此时查找草稿节点(每个流程都有一个草稿节点) sql.clear() .push(sqlMapper.getNodeSimplyInfo) .and('flow_id = :flow_id') .and('node_type = :node_type') .set('flow_id', flow.flow_id) .set('node_type', consts.NODE_TYPE_DRTAFT); let drtaft = await query(sql.compile()); if (drtaft.length === 0) { throw T.error(211006); } drtaft = drtaft[0]; record.to_node_id = drtaft.node_id; } else { record.to_node_id = last_record.from_node_id; } sql.clear() .push(sqlMapper.insertRecord) .set('record', record); query(sql.compile()); instance.current_node_id = record.to_node_id; instance.last_record_id = record.action_record_id; sql.clear() .push(sqlMapper.updateInstance) .set('instance', instance) .set('instance_id', instance.instance_id); query(sql.compile()); await T.P(connection.commit, connection)(); } catch (e) { sails.log.error(JSON.stringify(e)); await T.P(connection.rollback, connection)(); throw e.isFlow === true ? e : T.error(211011); } finally { connection.release(); } return instance.instance_id; } break; /*保存操作*/ case consts.ACTION_TYPE_SAVE : if (record.action_id === consts.ACTION_SAVE_ID) { //只能在有实例时执行 if (instances.length === false) { connection.release(); throw T.error(211005); } //保存后台脚本 let saveMD5 = await getFileName(`${current_node.node_id}NCS`); if (saveMD5[1] !== `${current_node.controller_save_md5}.js`) { //需更新文件 //查询保存后台脚本 sql.clear() .push(sqlMapper.getNodeControllerSave) .and('node_id = :node_id') .set('node_id', current_node.node_id); let saveController = await query(sql.compile()); saveMD5[0] = await newFile(`${current_node.node_id}NCS`, saveMD5[0], saveController[0].controller, true); } saveMD5 = T.P(require(saveMD5[0])); //执行环境 let Flow = { node: 0, biz_id: 0, biz_code: 0, data: {}, goto: function (code) { this.node = code; return this; }, getInstance: function () { return instances[0] || instance; }, getCurrentNode: function () { return current_node; }, getLastRecord: function () { return last_record; }, getFlow: function () { return flow; }, getData: function (key) { return this.data[key]; }, setData: function (key, value) { this.data[key] = value; }, removeData: function (key) { delete this.data[key]; }, rollback: function () { }, setBiz: function (biz_id, biz_code) { if (biz_id === undefined || biz_code === undefined) { throw T.error(211005); } this.biz_id = biz_id; this.biz_code = biz_code; } }; //执行后台代码 await saveMD5(req, res, Flow); return instance.instance_id; } else { connection.release(); throw T.error(211006); } break; /*删除操作*/ case consts.ACTION_TYPE_DEL : if (record.action_id === consts.ACTION_DEL_ID) { //只能在有实例时执行 if (instances.length === false) { connection.release(); throw T.error(211005); } //删除后台脚本 let delMD5 = await getFileName(`${current_node.node_id}NCD`); if (delMD5[1] !== `${current_node.controller_del_md5}.js`) { //需更新文件 //查询删除后台脚本 sql.clear() .push(sqlMapper.getNodeControllerDel) .and('node_id = :node_id') .set('node_id', current_node.node_id); let delController = await query(sql.compile()); delMD5[0] = await newFile(`${current_node.node_id}NCS`, delMD5[0], delController[0].controller, true); } delMD5 = T.P(require(delMD5[0])); //执行环境 let Flow = { node: 0, biz_id: 0, biz_code: 0, data: {}, goto: function (code) { this.node = code; return this; }, getInstance: function () { return instances[0] || instance; }, getCurrentNode: function () { return current_node; }, getLastRecord: function () { return last_record; }, getFlow: function () { return flow; }, getData: function (key) { return this.data[key]; }, setData: function (key, value) { this.data[key] = value; }, removeData: function (key) { delete this.data[key]; }, rollback: function () { }, setBiz: function (biz_id, biz_code) { if (biz_id === undefined || biz_code === undefined) { throw T.error(211005); } this.biz_id = biz_id; this.biz_code = biz_code; } }; //执行后台代码 await delMD5(req, res, Flow); //删除流程 if (res.headersSent === false) { await T.P(connection.beginTransaction, connection); try { sql.clear() .push(sqlMapper.delInstanceByInstanceid) .set('instance_id', instance.instance_id); await query(sql.compile()); await T.P(connection.commit, connection)(); } catch (e) { sails.log.error(JSON.stringify(e)); await T.P(connection.rollback, connection)(); Flow.rollback(); throw e.isFlow === true ? e : T.error(211011); } finally { connection.release(); } } return 0; } else { connection.release(); throw T.error(211006); } break; /*普通操作*/ case consts.ACTION_TYPE_NORMAL : /*操作对象*/ sql.clear() .push(sqlMapper.getActionSimplyInfo) .and('action_id = :action_id') .set('action_id', record.action_id); let action = await query(sql.compile()); if (action.length === 0) { throw T.error(211006); } action = action[0]; /*普通操作的from_node_id与当前节点id不一致,说明错了*/ if (action.from_node_id === instance.current_node_id) { //操作后台脚本 let actionMD5 = await getFileName(`${action.action_id}AC`); if (actionMD5[1] !== `${action.controller_md5}.js`) { //需更新文件 //查询操作页面脚本 sql.clear() .push(sqlMapper.getActionController) .and('action_id = :action_id') .set('action_id', action.action_id); let controller = await query(sql.compile()); actionMD5[0] = await newFile(`${action.action_id}AC`, actionMD5[0], controller[0].controller, true); } actionMD5 = T.P(require(actionMD5[0])); //执行环境 let Flow = { node: 0, biz_id: 0,