资信与授信流程
diff --git a/YLErpWeb/wwwroot/Scripts/app/system/Approvalprocess.js b/YLErpWeb/wwwroot/Scripts/app/system/Approvalprocess.js
index 3b34f24d..b86af4fd 100644
--- a/YLErpWeb/wwwroot/Scripts/app/system/Approvalprocess.js
+++ b/YLErpWeb/wwwroot/Scripts/app/system/Approvalprocess.js
@@ -10,11 +10,7 @@ function initSelectize(selector, options) {
});
}
};
- if (options) {
- _.assign(options, defaultOptions);
- } else {
- options = defaultOptions;
- }
+ options = _.assign({}, defaultOptions, options || {});
$(selector).selectize(options);
}
@@ -47,18 +43,21 @@ var app = new Vue({
{ text: '客户开户', value: '1' },
{ text: '客户信息修改', value: '5' },
{ text: '交易', value: '2' },
+ { text: '交易了结', value: '6' },
/* { text: '资信与授信', value: '3' },*/
{ text: '出金', value: '4' }
-
+
],
isOpen: false,
isTrade: false,
+ isClose: false,
isCredit: false,
isOutCash: false,
isClient: false,
openItems: [],
clientItems: [],
tradeItems: [],
+ closeItems: [],
creditItems: [],
outCashItems: [],
openCounter: 0,
@@ -67,23 +66,32 @@ var app = new Vue({
clientCounter: 0,
tradeIndex: 0,
grouplist: [],
- node: 0
+ node: 0,
+ // 需求①:节点触发条件字段(期初名义本金 / 本次交易名义本金)
+ // 开仓流程只能选期初名义本金;了结流程两个都可选
+ conditionFields: [
+ { value: 'initialNotional', text: '期初名义本金' },
+ { value: 'currentNotional', text: '本次交易名义本金' }
+ ],
+ // 开仓流程可选字段(仅期初)
+ conditionFieldsOpen: [
+ { value: 'initialNotional', text: '期初名义本金' }
+ ],
+ conditionOps: [
+ { value: 'gt', text: '>' },
+ { value: 'lt', text: '<' },
+ { value: 'gte', text: '>=' },
+ { value: 'lte', text: '<=' },
+ { value: 'eq', text: '=' },
+ { value: 'neq', text: '≠' }
+ ],
+ conditionLogics: [
+ { value: 'AND', text: '满足全部条件时触发' },
+ { value: 'OR', text: '满足任一条件时触发' }
+ ],
+ roleOptions: []
},
computed: {
- roleOptions: function () {
- var items = [];
- main.post("/AccountOpeningProcess/GetRolesOption", {}, { async: false }).done(
- function (res) {
- for (var i = 0; i < res.length; i++) {
- items.push({
- Value: res[i].Value,
- Text: res[i].Text
- });
- }
- }
- );
- return items;
- },
filterBranch() {
return this.tradeItems.filter(x => x.approvalCondition != 0);
},
@@ -92,27 +100,56 @@ var app = new Vue({
},
clientFilterBranch() {
return this.clientItems.filter(x => x.approvalCondition != 0);
+ },
+ // 需求①:开仓流程只能选期初名义本金;了结流程两个都可选
+ availableConditionFields() {
+ return this.isClose ? this.conditionFields : this.conditionFieldsOpen;
}
},
methods: {
+ loadRoleOptions: function () {
+ var thisObj = this;
+ main.post("/AccountOpeningProcess/GetRolesOption", {}, { async: false }).done(
+ function (res) {
+ var items = [];
+ for (var i = 0; i < res.length; i++) {
+ items.push({
+ Value: res[i].Value,
+ Text: res[i].Text
+ });
+ }
+ thisObj.roleOptions = items;
+ }
+ );
+ },
changeType: function () {
var thisObj = this;
$("#addtooltip-warpper").hide();
if (thisObj.selected === '1') {
thisObj.isOpen = true;
thisObj.isTrade = false;
+ thisObj.isClose = false;
thisObj.isCredit = false;
thisObj.isOutCash = false;
thisObj.isClient = false;
} else if (thisObj.selected === '2') {
thisObj.isOpen = false;
thisObj.isTrade = true;
+ thisObj.isClose = false;
+ thisObj.isCredit = false;
+ thisObj.isOutCash = false;
+ thisObj.isClient = false;
+ } else if (thisObj.selected === '6') { // 需求②:交易了结流程
+ thisObj.isOpen = false;
+ thisObj.isTrade = false;
+ thisObj.isClose = true;
thisObj.isCredit = false;
thisObj.isOutCash = false;
thisObj.isClient = false;
} else if (thisObj.selected === '3') {
thisObj.isOpen = false;
thisObj.isTrade = false;
+ thisObj.isClose = false;
thisObj.isCredit = true;
thisObj.isOutCash = false;
thisObj.isClient = false;
@@ -120,6 +157,7 @@ var app = new Vue({
else if (thisObj.selected === '4') {
thisObj.isOpen = false;
thisObj.isTrade = false;
+ thisObj.isClose = false;
thisObj.isCredit = false;
thisObj.isOutCash = true;
thisObj.isClient = false;
@@ -127,6 +165,7 @@ var app = new Vue({
else if (thisObj.selected === '5') {
thisObj.isOpen = false;
thisObj.isTrade = false;
+ thisObj.isClose = false;
thisObj.isCredit = false;
thisObj.isOutCash = false;
thisObj.isClient = true;
@@ -134,6 +173,7 @@ var app = new Vue({
else {
thisObj.isOpen = false;
thisObj.isTrade = false;
+ thisObj.isClose = false;
thisObj.isCredit = false;
thisObj.isOutCash = false;
thisObj.isClient = false;
@@ -227,6 +267,9 @@ var app = new Vue({
if (selectType == "5") {
typeName = 'ClientProcess'
}
+ if (selectType == "6") {
+ typeName = 'CloseProcess'
+ }
var item = {
id: 0,
Type: typeName,
@@ -235,7 +278,10 @@ var app = new Vue({
approvalCondition: 1,
node: 1,
parentNode: thisObj.node,
- approvalGroupId: 0
+ approvalGroupId: 0,
+ conditionConfig: '',
+ triggerCondition: '',
+ _trigger: { tokens: [] }
}
var item2 = {
id: 0,
@@ -245,7 +291,10 @@ var app = new Vue({
approvalCondition: 1,
node: 2,
parentNode: thisObj.node,
- approvalGroupId: 0
+ approvalGroupId: 0,
+ conditionConfig: '',
+ triggerCondition: '',
+ _trigger: { tokens: [] }
}
if (selectType == "2") { //交易
thisObj.tradeItems.splice(thisObj.node, 0, item, item2);
@@ -258,7 +307,10 @@ var app = new Vue({
thisObj.clientItems.splice(thisObj.node, 0, item, item2);
thisObj.initClientItemIndex();
}
-
+ else if (selectType == "6") { //交易了结
+ thisObj.closeItems.splice(thisObj.node, 0, item, item2);
+ thisObj.initCloseItemIndex();
+ }
}
$("#addtooltip-warpper").hide(100);
@@ -321,6 +373,10 @@ var app = new Vue({
thisObj.addClientProcess(index, child, node);
return;
}
+ else if (selectType === "6") { //交易了结
+ thisObj.addCloseNode(index, child, node);
+ return;
+ }
},
delProcess: function (openItem) {
@@ -331,12 +387,9 @@ var app = new Vue({
return;
}
- if (selectType === "1") { //客户开户
- thisObj.delOpenProcess(openItem);
- return;
- }
- else if (selectType === "2") { //交易
- thisObj.delTradeProcess(openItem);
+ if (selectType === "1" || selectType === "2" || selectType === "5" || selectType === "6") {
+ // 客户开户/交易/客户信息/交易了结:统一走通用删除(支持多分支)
+ thisObj.commonDeleteProcess(openItem);
return;
}
@@ -356,89 +409,6 @@ var app = new Vue({
});
return;
}
- else if (selectType === "5") { //客户信息
- thisObj.delClientProcess(openItem);
- return;
- }
- },
- delOpenProcess(openItem) {
- var thisObj = this;
- if (openItem.approvalCondition != 0) {//删除分支下,所有东西
- var childNodes = thisObj.openItems.filter(x => x.node != 0);
- thisObj.openItems = thisObj.openItems.concat(childNodes).filter(function (v) {
- return thisObj.openItems.indexOf(v) === -1 || childNodes.indexOf(v) === -1
- });
- thisObj.initOpenItemIndex();
- } else if (openItem.node != 0) {//删除分支下某节点
- var index = thisObj.openItems.indexOf(openItem);
- thisObj.openItems.splice(index, 1);
- var childNodes = thisObj.openItems.filter(x => x.node == openItem.node && x.Index >= openItem.Index);
- childNodes.forEach(item => {
- item.parentNode = item.parentNode - 1;
- item.Index = item.Index - 1;
- });
- } else {//删除非分支下某节点
- var index = thisObj.openItems.indexOf(openItem);
- thisObj.openItems.splice(index, 1);
- var nodes = thisObj.openItems.filter(x => x.Index >= openItem.Index);
- nodes.forEach(item => {
- item.Index = item.Index - 1;
- });
- thisObj.initOpenItemIndex();
- }
- },
- delTradeProcess(tradeItem) {
- var thisObj = this;
- thisObj.getRuleType();
- if (tradeItem.approvalCondition != 0) {//删除分支下,所有东西
- var childNodes = thisObj.tradeItems.filter(x => x.node != 0);
- thisObj.tradeItems = thisObj.tradeItems.concat(childNodes).filter(function (v) {
- return thisObj.tradeItems.indexOf(v) === -1 || childNodes.indexOf(v) === -1
- });
- thisObj.initTradeItemIndex();
- } else if (tradeItem.node != 0) {//删除分支下某节点
- var index = thisObj.tradeItems.indexOf(tradeItem);
- thisObj.tradeItems.splice(index, 1);
- var childNodes = thisObj.tradeItems.filter(x => x.node == tradeItem.node && x.Index >= tradeItem.Index);
- childNodes.forEach(item => {
- item.parentNode = item.parentNode - 1;
- item.Index = item.Index - 1;
- });
- } else {//删除非分支下某节点
- var index = thisObj.tradeItems.indexOf(tradeItem);
- thisObj.tradeItems.splice(index, 1);
- var nodes = thisObj.tradeItems.filter(x => x.Index >= tradeItem.Index);
- nodes.forEach(item => {
- item.Index = item.Index - 1;
- });
- thisObj.initTradeItemIndex();
- }
- },
- delClientProcess(clientItem) {
- var thisObj = this;
- if (clientItem.approvalCondition != 0) {//删除分支下,所有东西
- var childNodes = thisObj.clientItems.filter(x => x.node != 0);
- thisObj.clientItems = thisObj.clientItems.concat(childNodes).filter(function (v) {
- return thisObj.clientItems.indexOf(v) === -1 || childNodes.indexOf(v) === -1
- });
- thisObj.initClientItemIndex();
- } else if (clientItem.node != 0) {//删除分支下某节点
- var index = thisObj.clientItems.indexOf(clientItem);
- thisObj.clientItems.splice(index, 1);
- var childNodes = thisObj.clientItems.filter(x => x.node == clientItem.node && x.Index >= clientItem.Index);
- childNodes.forEach(item => {
- item.parentNode = item.parentNode - 1;
- item.Index = item.Index - 1;
- });
- } else {//删除非分支下某节点
- var index = thisObj.clientItems.indexOf(clientItem);
- thisObj.clientItems.splice(index, 1);
- var nodes = thisObj.clientItems.filter(x => x.Index >= clientItem.Index);
- nodes.forEach(item => {
- item.Index = item.Index - 1;
- });
- thisObj.initClientItemIndex();
- }
},
addOpenProcess(index, child, node) {
var thisObj = this;
@@ -449,7 +419,10 @@ var app = new Vue({
approvalCondition: 0,
node: node,
parentNode: child ? index : 0,
- approvalGroupId: 0
+ approvalGroupId: 0,
+ conditionConfig: '',
+ triggerCondition: '',
+ _trigger: { tokens: [] }
}
var childNodes = thisObj.openItems.filter(x => x.Index > index);
childNodes.forEach(item => {
@@ -471,7 +444,10 @@ var app = new Vue({
approvalCondition: 0,
node: node,
parentNode: child ? index : 0,
- approvalGroupId: 0
+ approvalGroupId: 0,
+ conditionConfig: '',
+ triggerCondition: '',
+ _trigger: { tokens: [] }
}
thisObj.getRuleType();
var childNodes = thisObj.tradeItems.filter(x => x.Index > index);
@@ -494,7 +470,10 @@ var app = new Vue({
approvalCondition: 0,
node: node,
parentNode: child ? index : 0,
- approvalGroupId: 0
+ approvalGroupId: 0,
+ conditionConfig: '',
+ triggerCondition: '',
+ _trigger: { tokens: [] }
}
var childNodes = thisObj.clientItems.filter(x => x.Index > index);
childNodes.forEach(item => {
@@ -537,6 +516,10 @@ var app = new Vue({
thisObj.clientOk();
return;
}
+ else if (selectType === "6") { // 需求②:交易了结
+ thisObj.saveCloseProcess();
+ return;
+ }
},
openOk() {
var thisObj = this;
@@ -665,6 +648,12 @@ var app = new Vue({
thisObj.getRuleType();
thisObj.initTradeItemIndex();
+ var triggerValid = thisObj.validateAllTriggers(thisObj.tradeItems);
+ if (!triggerValid.valid) {
+ main.message(triggerValid.message);
+ return;
+ }
+ thisObj.stringifyAllTrigger(thisObj.tradeItems); // 需求①:序列化触发条件
var firstChildTradeItem = thisObj.tradeItems.filter(x => x.node == 1);
var secondchildTradeItem = thisObj.tradeItems.filter(x => x.node == 2);
if (firstChildTradeItem.length == 1 && secondchildTradeItem.length == 1) {
@@ -864,6 +853,7 @@ var app = new Vue({
var thisObj = this;
thisObj.openItems = [];
thisObj.tradeItems = [];
+ thisObj.closeItems = [];
thisObj.creditItems = [];
thisObj.outCashItems = [];
thisObj.clientItems = [];
@@ -880,7 +870,9 @@ var app = new Vue({
node: value.node,
parentNode: value.parentNode,
approvalGroupId: value.approvalGroupId,
- approvalCondition: value.approvalCondition
+ approvalCondition: value.approvalCondition,
+ conditionConfig: value.conditionConfig,
+ triggerCondition: value.triggerCondition
});
});
@@ -894,9 +886,29 @@ var app = new Vue({
node: value.node,
parentNode: value.parentNode,
approvalGroupId: value.approvalGroupId,
- approvalCondition: value.approvalCondition
+ approvalCondition: value.approvalCondition,
+ conditionConfig: value.conditionConfig,
+ triggerCondition: value.triggerCondition
});
});
+ // 需求②:了结/平仓/行权审批流程
+ if (res.CloseProcess) {
+ res.CloseProcess.forEach(function (value, index, array) {
+ thisObj.closeItems.push({
+ id: value.id,
+ Type: value.processType,
+ Index: value.order,
+ SelectValue: value.roleId,
+ ApprovalRules: value.ruleType,
+ node: value.node,
+ parentNode: value.parentNode,
+ approvalGroupId: value.approvalGroupId,
+ approvalCondition: value.approvalCondition,
+ conditionConfig: value.conditionConfig,
+ triggerCondition: value.triggerCondition
+ });
+ });
+ }
res.CreditProcess.forEach(function (value, index, array) {
thisObj.creditItems.push({
Type: value.processType,
@@ -920,7 +932,15 @@ var app = new Vue({
node: value.node,
parentNode: value.parentNode,
approvalGroupId: value.approvalGroupId,
- approvalCondition: value.approvalCondition
+ approvalCondition: value.approvalCondition,
+ conditionConfig: value.conditionConfig,
+ triggerCondition: value.triggerCondition
+ });
+ });
+ // 需求①:加载后把 triggerCondition(JSON)解析为结构化对象供 UI 编辑
+ ['openItems', 'tradeItems', 'closeItems', 'clientItems'].forEach(function (arr) {
+ thisObj[arr].forEach(function (item) {
+ thisObj.parseTriggerCondition(item);
});
});
}
@@ -943,156 +963,503 @@ var app = new Vue({
clientFilterChild(node) {
return this.clientItems.filter(x => x.node == node && x.approvalCondition == 0);
},
- initTradeItemIndex() {
- var thisObj = this;
- var newSortTradeItems = [];
- var mainTradeItems = thisObj.tradeItems.filter(x => x.node == 0).sort((a, b) => a.Index - b.Index);
- var childTradeItem = thisObj.tradeItems.filter(x => x.node != 0);
- var childTradeItemSort = childTradeItem.sort((a, b) => a.Index - b.Index);
- var firstChildIndex = childTradeItemSort.length > 0 ? childTradeItemSort[0].Index : -1;
- var j = 1;
- for (var i = 0; i < mainTradeItems.length; i++) {
- if (mainTradeItems[i].Index >= firstChildIndex) {
- if (childTradeItemSort.length > 0) {
- mainTradeItems[i].Index = childTradeItemSort[childTradeItemSort.length - 1].Index + j;
+ // ===== 需求③:多分支支持(参考中粮版)通用方法 =====
+ // 通用分支重编号:动态把分支节点编号为 1,2,3...N(不再写死 1/2)
+ commonInitIndex(targetProp) {
+ const that = this;
+ const newSortedItems = [];
+ const mainItems = that[targetProp].filter(x => x.node == 0).sort((a, b) => a.Index - b.Index);
+ const childItems = that[targetProp].filter(x => x.node != 0);
+ const sortedChildItems = childItems.sort((a, b) => a.Index - b.Index);
+ const firstChildIndex = sortedChildItems.length > 0 ? sortedChildItems[0].Index : -1;
+ let j = 1;
+ for (let i = 0; i < mainItems.length; i++) {
+ if (mainItems[i].Index >= firstChildIndex) {
+ if (sortedChildItems.length > 0) {
+ mainItems[i].Index = sortedChildItems[sortedChildItems.length - 1].Index + j;
j++;
} else {
- mainTradeItems[i].Index = i + 1;
+ mainItems[i].Index = i + 1;
}
-
}
- newSortTradeItems.push(mainTradeItems[i]);
+ newSortedItems.push(mainItems[i]);
}
- var firstChildTradeItems = childTradeItem.filter(x => x.node == 1);
- var secondChildTradeItems = childTradeItem.filter(x => x.node == 2);
- firstChildTradeItems.forEach((x, index) => { //分支index不用再排序
- if (x.approvalCondition == 0) {
- x.Index = firstChildIndex + index;
- x.parentNode = firstChildIndex + index - 1;
+
+ // 为分支条件的 node 重新排序(1,2,3...N)——多分支的核心
+ let tempNode = 1;
+ childItems.forEach((i) => {
+ if (i.approvalCondition != 0) {
+ i.node = tempNode++;
}
- newSortTradeItems.push(x);
});
- secondChildTradeItems.forEach((x, index) => {
- if (x.approvalCondition == 0) {
- x.Index = firstChildIndex + index;
- x.parentNode = firstChildIndex + index - 1;
+
+ // 按分支 node 分组,重建每个分支下的子节点 Index/parentNode
+ for (let i = 0; i < childItems.length; i++) {
+ var filteredChildItems = childItems.filter(x => x.node == i + 1);
+ filteredChildItems.forEach((i, index) => {
+ if (i.approvalCondition == 0) {
+ i.Index = firstChildIndex + index;
+ i.parentNode = firstChildIndex + index - 1;
+ }
+ newSortedItems.push(i);
+ });
+ }
+ that[targetProp] = newSortedItems.sort((a, b) => a.Index - b.Index);
+ },
+ // 通用添加分支条件:push 一个 node:999 占位的分支节点,再重编号
+ commonAddCondition(item) {
+ const that = this;
+ const typeToPropMap = {
+ 'OpenProcess': 'openItems',
+ 'ClientProcess': 'clientItems',
+ 'TradeProcess': 'tradeItems',
+ 'CloseProcess': 'closeItems'
+ };
+ const typeToInitFnMap = {
+ 'OpenProcess': that.initOpenItemIndex,
+ 'ClientProcess': that.initClientItemIndex,
+ 'TradeProcess': that.initTradeItemIndex,
+ 'CloseProcess': that.initCloseItemIndex
+ };
+ const prop = typeToPropMap[item.Type];
+ const initFn = typeToInitFnMap[item.Type];
+ that[prop].push({
+ id: 0,
+ Type: item.Type,
+ Index: item.Index,
+ SelectValue: 0,
+ approvalCondition: 1,
+ node: 999,
+ parentNode: item.Index,
+ ApprovalRules: '',
+ approvalGroupId: 0,
+ conditionConfig: '',
+ triggerCondition: '',
+ _trigger: { tokens: [] }
+ });
+ initFn();
+ },
+ // 添加条件入口("添加条件"按钮调用)
+ addCondition(item) {
+ this.commonAddCondition(item);
+ },
+ // 通用删除分支/节点
+ commonDeleteProcess(item) {
+ const that = this;
+ const typeToPropMap = {
+ 'OpenProcess': 'openItems',
+ 'ClientProcess': 'clientItems',
+ 'TradeProcess': 'tradeItems',
+ 'CloseProcess': 'closeItems'
+ };
+ const typeToInitFnMap = {
+ 'OpenProcess': that.initOpenItemIndex,
+ 'ClientProcess': that.initClientItemIndex,
+ 'TradeProcess': that.initTradeItemIndex,
+ 'CloseProcess': that.initCloseItemIndex
+ };
+ const prop = typeToPropMap[item.Type];
+ const initFn = typeToInitFnMap[item.Type];
+
+ // 删除的不是分支条件节点(普通审批节点)
+ if (item.approvalCondition == 0) {
+ const index = that[prop].indexOf(item);
+ that[prop].splice(index, 1);
+ const nodes = that[prop].filter(x => x.Index >= item.Index);
+ nodes.forEach(item => {
+ item.Index = item.Index - 1;
+ });
+ initFn();
+ return;
+ }
+
+ // 分支条件数量<=2 时,删除整个分支组
+ var conditionBranchesLen = that[prop].filter(i => i.approvalCondition != 0 && i.node != 0).length;
+ if (item.approvalCondition != 0 && conditionBranchesLen <= 2) {
+ var childNodes = that[prop].filter(x => x.node != 0);
+ that[prop] = that[prop].filter(x => childNodes.indexOf(x) === -1);
+ initFn();
+ return;
+ }
+
+ // 分支条件数量>2 时,只删除该分支(同 node 的全部节点)
+ if (item.node != 0 && item.approvalCondition != 0) {
+ that[prop] = that[prop].filter(x => x.node != item.node);
+ initFn();
+ }
+ },
+ initTradeItemIndex() {
+ this.commonInitIndex('tradeItems');
+ this.initRuleType();
+ },
+ // ===== 需求①:节点触发条件 结构化编辑器(token 数组,支持每行独立且/或 + 括号)=====
+ // _trigger = { tokens: [ {type:'condition',condition:{field,op,value}}, {type:'operator',connector:'and'|'or'}, {type:'lparen'|'rparen'} ] }
+ // op 用字母标识符(gt/lt/gte/lte/eq/neq),规避 > < 在传输中被 HTML 编码导致加载不出来的问题
+ // 把历史符号 op 归一化为字母标识符
+ normalizeOp(op) {
+ var map = { '>': 'gt', '<': 'lt', '>=': 'gte', '<=': 'lte', '==': 'eq', '!=': 'neq', '=': 'eq', '<>': 'neq' };
+ if (!op) return 'gt';
+ var lower = ('' + op).toLowerCase();
+ if (['gt','lt','gte','lte','eq','neq'].indexOf(lower) >= 0) return lower;
+ return map[op] || lower;
+ },
+ // 字段归一化:历史 notional → initialNotional;空默认 initialNotional
+ normalizeField(field) {
+ if (!field) return 'initialNotional';
+ var f = ('' + field);
+ // 历史兼容
+ if (f.toLowerCase() == 'notional') return 'initialNotional';
+ return f;
+ },
+ // 把 item.triggerCondition(JSON 字符串)解析为 item._trigger 结构化对象供 UI 编辑
+ parseTriggerCondition(item) {
+ if (!item) return;
+ if (item._trigger) return; // 已解析则不重复处理
+ var thisObj = this;
+ var parsed = { tokens: [] };
+ if (item.triggerCondition) {
+ try {
+ var obj = JSON.parse(item.triggerCondition);
+ if (obj.tokens && obj.tokens.length) {
+ // 新结构:直接复用 token,规范化字段
+ parsed.tokens = obj.tokens.map(function (t) {
+ if (t.type == 'condition') {
+ var c = t.condition || {};
+ return { type: 'condition', condition: { field: thisObj.normalizeField(c.field), op: thisObj.normalizeOp(c.op), value: c.value != null ? c.value : '' } };
+ }
+ if (t.type == 'operator') return { type: 'operator', connector: (t.connector || 'and').toLowerCase() };
+ if (t.type == 'lparen') return { type: 'lparen' };
+ if (t.type == 'rparen') return { type: 'rparen' };
+ return null;
+ }).filter(function (t) { return t != null; });
+ }
+ } catch (e) {
+ // 非法 JSON,按空处理
}
- newSortTradeItems.push(x);
+ }
+ this.$set(item, '_trigger', parsed);
+ },
+ // 新增一条触发条件(自动在前方补连接符,首个不补)
+ addTriggerCondition(item) {
+ this.parseTriggerCondition(item);
+ var toks = item._trigger.tokens;
+ if (toks.length > 0) {
+ var last = toks[toks.length - 1];
+ // 若上一 token 是条件或右括号,则需要连接符
+ if (last.type == 'condition' || last.type == 'rparen') {
+ toks.push({ type: 'operator', connector: 'and' });
+ }
+ }
+ toks.push({ type: 'condition', condition: { field: 'initialNotional', op: 'gt', value: '' } });
+ },
+ // 切换某连接符 and/or
+ toggleTriggerConnector(item, idx) {
+ var t = item._trigger.tokens[idx];
+ if (t && t.type == 'operator') {
+ t.connector = (t.connector == 'and') ? 'or' : 'and';
+ }
+ },
+ // 插入左/右括号
+ addTriggerParen(item, side) {
+ this.parseTriggerCondition(item);
+ var toks = item._trigger.tokens;
+ var type = side == 'left' ? 'lparen' : 'rparen';
+ if (type == 'lparen') {
+ // 左括号前若接条件/右括号,需补连接符
+ if (toks.length > 0) {
+ var last = toks[toks.length - 1];
+ if (last.type == 'condition' || last.type == 'rparen') {
+ toks.push({ type: 'operator', connector: 'and' });
+ }
+ }
+ toks.push({ type: 'lparen' });
+ } else {
+ toks.push({ type: 'rparen' });
+ }
+ },
+ // 删除一个 token,并清理其旁孤立连接符
+ removeTriggerToken(item, idx) {
+ var toks = item._trigger.tokens;
+ if (idx < 0 || idx >= toks.length) return;
+ toks.splice(idx, 1);
+ // 清理首部连接符 / 尾部连接符 / 连续连接符
+ var i = 0;
+ while (i < toks.length) {
+ var t = toks[i];
+ if (t.type == 'operator' && (i == 0 || i == toks.length - 1
+ || toks[i - 1].type == 'operator')) {
+ toks.splice(i, 1);
+ } else {
+ i++;
+ }
+ }
+ },
+ // 保存前:把 item._trigger 序列化回 item.triggerCondition JSON
+ stringifyTriggerCondition(item) {
+ if (!item || !item._trigger) return;
+ var toks = item._trigger.tokens || [];
+ if (toks.length == 0) {
+ item.triggerCondition = '';
+ return;
+ }
+ // 过滤掉无效条件(字段/值缺失)
+ var valid = toks.filter(function (t) {
+ if (t.type == 'condition') {
+ var c = t.condition || {};
+ return c.field && c.op && c.value !== '';
+ }
+ return true;
});
- thisObj.tradeItems = newSortTradeItems.sort((a, b) => a.Index - b.Index);
- thisObj.initRuleType();
+ // 移除首尾连接符
+ while (valid.length > 0 && valid[0].type == 'operator') valid.shift();
+ while (valid.length > 0 && valid[valid.length - 1].type == 'operator') valid.pop();
+ item.triggerCondition = valid.length > 0 ? JSON.stringify({ tokens: valid }) : '';
+ },
+ // 批量把一组 items 的 _trigger 序列化(保存前调用)
+ stringifyAllTrigger(items) {
+ var thisObj = this;
+ if (!items) return;
+ items.forEach(function (item) {
+ if (item.node == 0 || item.approvalCondition == 0) {
+ thisObj.stringifyTriggerCondition(item);
+ }
+ });
+ },
+ // 校验触发条件 token 列表是否合法:括号平衡、无空括号、无首尾连接符等
+ validateTriggerTokens(tokens) {
+ if (!tokens || tokens.length == 0) return { valid: true, message: '' };
+ var paren = 0;
+ for (var i = 0; i < tokens.length; i++) {
+ var t = tokens[i];
+ if (t.type == 'lparen') paren++;
+ if (t.type == 'rparen') paren--;
+ if (paren < 0) return { valid: false, message: '触发条件中右括号过多,请检查括号匹配' };
+ if (t.type == 'operator') {
+ if (i == 0 || i == tokens.length - 1) return { valid: false, message: '触发条件首尾不能为连接符(且/或)' };
+ var prev = tokens[i - 1];
+ if (prev.type == 'operator' || prev.type == 'lparen') return { valid: false, message: '触发条件中连接符(且/或)位置不正确' };
+ }
+ if (t.type == 'condition') {
+ var c = t.condition || {};
+ if (!c.field || !c.op || c.value === '') return { valid: false, message: '触发条件中存在未填写完整的条件' };
+ }
+ }
+ if (paren != 0) return { valid: false, message: '触发条件中括号不匹配,请检查' };
+ return { valid: true, message: '' };
+ },
+ // 校验一组 items 的触发条件,返回第一个错误信息
+ validateAllTriggers(items) {
+ var thisObj = this;
+ if (!items) return { valid: true, message: '' };
+ for (var i = 0; i < items.length; i++) {
+ var item = items[i];
+ if ((item.node == 0 || item.approvalCondition == 0) && item._trigger && item._trigger.tokens) {
+ var res = thisObj.validateTriggerTokens(item._trigger.tokens);
+ if (!res.valid) return res;
+ }
+ }
+ return { valid: true, message: '' };
+ },
+ // ===== 需求②:交易了结流程(closeItems)方法集,算法同交易流程 =====
+ closeFilterBranch() {
+ return this.closeItems.filter(x => x.approvalCondition != 0);
+ },
+ closeFilterChild(node) {
+ return this.closeItems.filter(x => x.node == node && x.approvalCondition == 0);
+ },
+ initCloseItemIndex() {
+ this.commonInitIndex('closeItems');
+ this.initRuleType();
+ },
+ closeShowProcess(index, child, obj) {
+ var thisObj = this;
+ var closeBranch = thisObj.closeItems.find(x => x.approvalCondition != 0);
+ if (!closeBranch) {
+ let offsetTop = $(obj.target).offset().top;
+ let offsetLeft = $(obj.target).offset().left;
+ $("#addtooltip-warpper").css({ "left": offsetLeft - 180, "top": offsetTop - 110, "margin-left": "30px" });
+ $("#addtooltip-warpper").hide();
+ $("#addtooltip-warpper").show(150);
+ this.tradeIndex = index;
+ thisObj.node = index;
+ } else {
+ thisObj.closeAddProcess(index, child, 0);
+ $("#addtooltip-warpper").hide(100);
+ }
+ },
+ closeAddProcess(index, child, node) {
+ var thisObj = this;
+ thisObj.addCloseNode(index, child, node);
+ $("#addtooltip-warpper").hide(100);
+ },
+ addCloseNode(index, child, node) {
+ var thisObj = this;
+ var item = {
+ id: 0,
+ Type: 'CloseProcess',
+ Index: index + 1,
+ SelectValue: 0,
+ ApprovalRules: '',
+ node: node,
+ parentNode: child ? index : 0,
+ approvalGroupId: 0,
+ approvalCondition: 0,
+ conditionConfig: '',
+ triggerCondition: '',
+ _trigger: { tokens: [] }
+ };
+ thisObj.closeItems.forEach(x => {
+ if (x.Index >= index) {
+ x.Index = x.Index + 1;
+ }
+ });
+ thisObj.closeItems.splice(index, 0, item);
+ thisObj.initCloseItemIndex();
+ },
+ closeSelectChangeType(index, value) {
+ var thisObj = this;
+ for (var j = 0; j < thisObj.closeItems.length; j++) {
+ if (j === index) continue;
+ if (thisObj.closeItems[j].SelectValue === parseInt(value) && thisObj.closeItems[j].node == 0) {
+ main.message("不得选择重复角色");
+ return;
+ }
+ }
+ },
+ saveCloseProcess() {
+ var thisObj = this;
+ // 角色非空校验
+ for (var i = 0; i < thisObj.closeItems.length; i++) {
+ if (thisObj.closeItems[i].SelectValue === "" || thisObj.closeItems[i].SelectValue === 0) {
+ if (thisObj.closeItems[i].approvalCondition == 0) {
+ main.message('流程中断,请重新选择');
+ return;
+ }
+ }
+ }
+
+ var temp1 = 0;
+ var closeLength = thisObj.closeItems.length;
+ for (var w1 = 0; w1 < closeLength - 1; w1++) {
+ for (var n1 = 1; n1 < closeLength; n1++) {
+ if (w1 !== n1) {
+ if (parseInt(thisObj.closeItems[w1].SelectValue) === parseInt(thisObj.closeItems[n1].SelectValue) && parseInt(thisObj.closeItems[n1].SelectValue) != 0) {
+ if (parseInt(thisObj.closeItems[w1].node) == parseInt(thisObj.closeItems[n1].node)) {
+ temp1 = temp1 + 1;
+ }
+ }
+ }
+ }
+ }
+ var approvalGroupItems = thisObj.closeItems.filter(x => x.approvalGroupId != 0);
+ var approvalCloseLength = approvalGroupItems.length;
+ var temp2 = 0;
+ for (var w1 = 0; w1 < approvalCloseLength - 1; w1++) {
+ for (var n1 = 1; n1 < approvalCloseLength; n1++) {
+ if (w1 !== n1) {
+ if (parseInt(approvalGroupItems[w1].approvalCondition) === parseInt(approvalGroupItems[n1].approvalCondition) && parseInt(approvalGroupItems[w1].approvalGroupId) === parseInt(approvalGroupItems[n1].approvalGroupId)) {
+ temp2 = temp2 + 1;
+ }
+ }
+ }
+ }
+ if (temp1 > 0 || temp2 > 0) {
+ main.message('流程包含重复项,请重新选择');
+ return;
+ }
+
+ thisObj.getCloseRuleType();
+ thisObj.initCloseItemIndex();
+ var firstChildCloseItem = thisObj.closeItems.filter(x => x.node == 1);
+ var secondchildCloseItem = thisObj.closeItems.filter(x => x.node == 2);
+ if (firstChildCloseItem.length == 1 && secondchildCloseItem.length == 1) {
+ main.message('分支节点流程未设置完毕');
+ return;
+ }
+ var triggerValid = thisObj.validateAllTriggers(thisObj.closeItems);
+ if (!triggerValid.valid) {
+ main.message(triggerValid.message);
+ return;
+ }
+ thisObj.stringifyAllTrigger(thisObj.closeItems); // 需求①:序列化触发条件
+ if (thisObj.closeItems != null && thisObj.closeItems.length > 0) {
+ main.confirm("确认修改交易了结审批流程?", function () {
+ main.post("/AccountOpeningProcess/AddProcess",
+ { type: "CloseProcess", data: thisObj.closeItems },
+ { async: false }).done(
+ function (res) {
+ thisObj.getProcess();
+ });
+ });
+ } else {
+ main.confirm("删除审批流程后,交易了结审批就会直接审批通过,确认删除?", function () {
+ main.post("/AccountOpeningProcess/AddProcess",
+ { type: "CloseProcess" },
+ { async: false }).done(
+ function (res) {
+ });
+ });
+ }
},
initOpenItemIndex() {
- var thisObj = this;
- var newSortOpenItems = [];
- var mainOpenItems = thisObj.openItems.filter(x => x.node == 0).sort((a, b) => a.Index - b.Index);
- var childOpenItem = thisObj.openItems.filter(x => x.node != 0);
- var childOpenItemSort = childOpenItem.sort((a, b) => a.Index - b.Index);
- var firstChildIndex = childOpenItemSort.length > 0 ? childOpenItemSort[0].Index : -1;
- var j = 1;
- for (var i = 0; i < mainOpenItems.length; i++) {
- if (mainOpenItems[i].Index >= firstChildIndex) {
- if (childOpenItemSort.length > 0) {
- mainOpenItems[i].Index = childOpenItemSort[childOpenItemSort.length - 1].Index + j;
- j++;
- } else {
- mainOpenItems[i].Index = i + 1;
- }
-
- }
- newSortOpenItems.push(mainOpenItems[i]);
- }
- var firstChildOpenItems = childOpenItem.filter(x => x.node == 1);
- var secondChildOpenItems = childOpenItem.filter(x => x.node == 2);
- firstChildOpenItems.forEach((x, index) => { //分支index不用再排序
- if (x.approvalCondition == 0) {
- x.Index = firstChildIndex + index;
- x.parentNode = firstChildIndex + index - 1;
- }
- newSortOpenItems.push(x);
- });
- secondChildOpenItems.forEach((x, index) => {
- if (x.approvalCondition == 0) {
- x.Index = firstChildIndex + index;
- x.parentNode = firstChildIndex + index - 1;
- }
- newSortOpenItems.push(x);
- });
- thisObj.openItems = newSortOpenItems.sort((a, b) => a.Index - b.Index);
+ this.commonInitIndex('openItems');
},
initClientItemIndex() {
+ this.commonInitIndex('clientItems');
+ },
+ initRuleTypeFor(items, prefix) {
var thisObj = this;
- var newSortClientItems = [];
- var mainClientItems = thisObj.clientItems.filter(x => x.node == 0).sort((a, b) => a.Index - b.Index);
- var childClientItem = thisObj.clientItems.filter(x => x.node != 0);
- var childClientItemSort = childClientItem.sort((a, b) => a.Index - b.Index);
- var firstChildIndex = childClientItemSort.length > 0 ? childClientItemSort[0].Index : -1;
- var j = 1;
- for (var i = 0; i < mainClientItems.length; i++) {
- if (mainClientItems[i].Index >= firstChildIndex) {
- if (childClientItemSort.length > 0) {
- mainClientItems[i].Index = childClientItemSort[childClientItemSort.length - 1].Index + j;
- j++;
- } else {
- mainClientItems[i].Index = i + 1;
- }
-
+ var length = items.length;
+ for (var i = 0; i < length; i++) {
+ var ruleId = "#" + prefix + items[i].Index + items[i].node;
+ var el = $(ruleId).get(0);
+ if (!el || !el.selectize) continue; // DOM 尚未渲染或未初始化 selectize,跳过
+ if (items[i].ApprovalRules != null && items[i].ApprovalRules.length > 0) {
+ var ruleArr = items[i].ApprovalRules.split(',');
+ el.selectize.setValue(ruleArr);
+ } else {
+ el.selectize.setValue([]);
}
- newSortClientItems.push(mainClientItems[i]);
}
- var firstChildClientItems = childClientItem.filter(x => x.node == 1);
- var secondChildClientItems = childClientItem.filter(x => x.node == 2);
- firstChildClientItems.forEach((x, index) => { //分支index不用再排序
- if (x.approvalCondition == 0) {
- x.Index = firstChildIndex + index;
- x.parentNode = firstChildIndex + index - 1;
- }
- newSortClientItems.push(x);
- });
- secondChildClientItems.forEach((x, index) => {
- if (x.approvalCondition == 0) {
- x.Index = firstChildIndex + index;
- x.parentNode = firstChildIndex + index - 1;
- }
- newSortClientItems.push(x);
- });
- thisObj.clientItems = newSortClientItems.sort((a, b) => a.Index - b.Index);
},
initRuleType() {
- var thisObj = this;
- var tradeLength = thisObj.tradeItems.length;
- for (var i = 0; i < tradeLength; i++) {
- var ruleId = "#ruleType" + thisObj.tradeItems[i].Index + thisObj.tradeItems[i].node;
- var $selectize = $(ruleId).get(0);
- if (thisObj.tradeItems[i].ApprovalRules != null && thisObj.tradeItems[i].ApprovalRules.length > 0) {
- var ruleArr = thisObj.tradeItems[i].ApprovalRules.split(',');
- $selectize.selectize.setValue(ruleArr);
- } else if ($selectize) {
- $selectize.selectize.setValue([]);
- }
-
- }
+ this.initRuleTypeFor(this.tradeItems, 'ruleType');
+ this.initRuleTypeFor(this.closeItems, 'closeRuleType');
},
- getRuleType() {
+ getRuleTypeFor(items, prefix) {
var thisObj = this;
- var tradeLength = thisObj.tradeItems.length;
- for (var i = 0; i < tradeLength; i++) {
- var ruleId = "#ruleType" + thisObj.tradeItems[i].Index + thisObj.tradeItems[i].node;
+ var length = items.length;
+ for (var i = 0; i < length; i++) {
+ var ruleId = "#" + prefix + items[i].Index + items[i].node;
var $selectize = $(ruleId).get(0);
if ($selectize) {
var ruleArr = $selectize.selectize.items;
- thisObj.tradeItems[i].ApprovalRules = ruleArr.join(',');
+ items[i].ApprovalRules = ruleArr.join(',');
}
-
}
+ },
+ getRuleType() {
+ this.getRuleTypeFor(this.tradeItems, 'ruleType');
+ },
+ getCloseRuleType() {
+ this.getRuleTypeFor(this.closeItems, 'closeRuleType');
}
},
mounted: function () {
this.getProcess();
this.getApprovalGroup();
+ this.loadRoleOptions();
},
watch: {
tradeItems:
+ {
+ handler(val, oldVal) {
+ this.$nextTick(function () {
+ setRuleDiv();
+ })
+ },
+ },
+ closeItems:
{
handler(val, oldVal) {
this.$nextTick(function () {
diff --git a/YLErpWeb/wwwroot/Statics/libs/selectize/css/accountOpeningProcess.css b/YLErpWeb/wwwroot/Statics/libs/selectize/css/accountOpeningProcess.css
index 17140a3b..30516b45 100644
--- a/YLErpWeb/wwwroot/Statics/libs/selectize/css/accountOpeningProcess.css
+++ b/YLErpWeb/wwwroot/Statics/libs/selectize/css/accountOpeningProcess.css
@@ -50,7 +50,7 @@ html {
flex-direction: column;
align-items: center;
width: 100%;
- padding: 0 50px;
+ /*padding: 0 50px;*/
position: relative;
font-size: 12px;
}
@@ -430,6 +430,149 @@ html {
.glyphicon {
color: #FFFFFF !important;
}
-button:focus {
- outline: none;
-}
\ No newline at end of file
+.trigger-condition-box {
+ background-color: #FFFFFF;
+ border-radius: 5px;
+ box-shadow: 0 2px 5px 0 rgba(0, 0, 0, .1);
+ border: 1px solid #F5F5F5;
+ margin: 8px 10px 10px 10px;
+ overflow: hidden;
+}
+
+.trigger-condition-title {
+ background: rgb(255, 148, 62);
+ color: #FFFFFF;
+ font-size: 12px;
+ padding: 5px 10px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.trigger-condition-title .trigger-actions {
+ display: flex;
+ gap: 6px;
+}
+
+.trigger-action-btn {
+ display: inline-block;
+ border-radius: 15px;
+ color: rgb(50, 150, 250);
+ border: none;
+ box-shadow: 0 2px 5px 0 rgba(0, 0, 0, .1);
+ background: #FFFFFF;
+ padding: 3px 10px;
+ font-size: 12px;
+ cursor: pointer;
+ line-height: 18px;
+}
+
+.trigger-action-btn:hover {
+ background: #f5f7fa;
+ transform: scale(1.05);
+ transition: all .3s;
+}
+
+.trigger-token-list {
+ padding: 8px 10px;
+}
+
+.trigger-token-row {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ min-height: 26px;
+ margin-bottom: 4px;
+ width: 100%;
+}
+
+.trigger-token-row:last-child {
+ margin-bottom: 0;
+}
+
+.trigger-connector {
+ display: inline-block;
+ width: 60px;
+ text-align: center;
+ color: #409eff;
+ cursor: pointer;
+ font-size: 12px;
+}
+
+.trigger-paren {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ font-size: 12px;
+ padding: 4px 0;
+ position: relative;
+}
+
+.trigger-paren .trigger-remove,
+.trigger-condition-row .trigger-remove {
+ opacity: 0.85;
+}
+
+.trigger-paren:hover .trigger-remove,
+.trigger-condition-row:hover .trigger-remove {
+ opacity: 1;
+}
+
+.trigger-paren .trigger-remove {
+ position: absolute;
+ right: 0;
+ top: 50%;
+ transform: translateY(-50%);
+}
+
+.trigger-condition-row {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ width: 100%;
+}
+
+.trigger-condition-row .trigger-remove {
+ margin-left: auto;
+}
+
+.trigger-condition-row select,
+.trigger-condition-row input {
+ height: 20px;
+ font-size: 12px;
+ padding: 0 2px;
+ box-sizing: border-box;
+}
+
+.trigger-condition-row select {
+ width: auto;
+ min-width: 70px;
+}
+
+.trigger-condition-row input {
+ width: 80px;
+ padding-left: 4px;
+}
+
+.trigger-remove {
+ color: #ff4d4f !important;
+ cursor: pointer;
+ margin-left: 4px;
+ font-size: 11px;
+ opacity: 0.7;
+ transition: opacity 0.2s;
+}
+
+.trigger-remove:hover {
+ color: #ff7875 !important;
+ opacity: 1;
+}
+
+/* 需求③:多分支连线。多个 .col-box 时,中间列(非首非尾)的右覆盖线宽度置 0,避免连线断裂 */
+.col-box:not(:first-child):not(:last-child) .top-right-cover-line {
+ width: 0;
+}
+.col-box:not(:first-child):not(:last-child) .bottom-right-cover-line {
+ width: 0;
+}