eme-flow
Version:
eme flow组件
1,269 lines (1,186 loc) • 61.8 kB
JavaScript
/**
* 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,