@steedos-labs/plugin-workflow 3.0.83 → 3.0.85
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/designer/dist/amis-renderer/amis-renderer.js +1 -1
- package/designer/dist/assets/{index-WAa42ctb.js → index-DpFVuLlI.js} +28 -28
- package/designer/dist/index.html +1 -1
- package/main/default/client/flow2_render.client.js +1 -1
- package/main/default/manager/uuflow_manager.js +61 -8
- package/main/default/objects/instances/buttons/instance_delete_many.button.yml +1 -1
- package/main/default/pages/flow_selector.page.amis.json +2 -2
- package/main/default/pages/instance_tasks_detail.page.amis.json +4 -7
- package/main/default/pages/page_instance_print.page.amis.json +2 -2
- package/main/default/routes/api_workflow_chart.router.js +384 -59
- package/main/default/routes/api_workflow_export.router.js +2 -1
- package/main/default/server/ejs/export_instances.ejs +12 -4
- package/main/default/test/test_getApproveValues.js +221 -0
- package/package.json +3 -2
- package/public/amis-renderer/amis-renderer.js +1 -1
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 回归测试:UUFlowManager.getApproveValues 对公式子字段的兜底识别。
|
|
3
|
+
*
|
|
4
|
+
* 背景:
|
|
5
|
+
* - issue: 子表保存后刷新,公式子字段计算结果丢失(线上现象)
|
|
6
|
+
* - PR #781 在过滤规则中加 `c.formula ||` 放权
|
|
7
|
+
* - 但部分历史表单设计器保存时丢失了字段的 `formula` 属性,
|
|
8
|
+
* 公式表达式被转存到 `default_value`,形如 "${...}"
|
|
9
|
+
* - 因此除了 `c.formula` 之外,还需把 `default_value` 形如 "${...}" 的字段视为公式字段
|
|
10
|
+
*
|
|
11
|
+
* 用法:
|
|
12
|
+
* node main/default/test/test_getApproveValues.js
|
|
13
|
+
* 或 yarn workspace @steedos-labs/plugin-workflow test:approve-values
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const assert = require('assert');
|
|
17
|
+
|
|
18
|
+
// 注意:require uuflow_manager.js 会顺带加载 @steedos/objectql 等运行时依赖;
|
|
19
|
+
// 本机已验证可独立加载,无需启动完整 server。
|
|
20
|
+
const UUFlowManager = require('../manager/uuflow_manager.js');
|
|
21
|
+
|
|
22
|
+
// Monkey-patch DB 读取函数,注入测试用 form schema
|
|
23
|
+
const fakeForms = {};
|
|
24
|
+
UUFlowManager.getForm = async function (form_id) {
|
|
25
|
+
if (!fakeForms[form_id]) throw new Error(`fake form not found: ${form_id}`);
|
|
26
|
+
return fakeForms[form_id];
|
|
27
|
+
};
|
|
28
|
+
UUFlowManager.getFormVersion = function (form, form_version) {
|
|
29
|
+
if (form.current && form.current._id === form_version) return form.current;
|
|
30
|
+
const h = (form.historys || []).find(f => f._id === form_version);
|
|
31
|
+
if (!h) throw new Error(`fake form version not found: ${form_version}`);
|
|
32
|
+
return h;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
let passed = 0;
|
|
36
|
+
let failed = 0;
|
|
37
|
+
|
|
38
|
+
async function run(name, fn) {
|
|
39
|
+
try {
|
|
40
|
+
await fn();
|
|
41
|
+
console.log(` ✓ ${name}`);
|
|
42
|
+
passed++;
|
|
43
|
+
} catch (e) {
|
|
44
|
+
console.log(` ✗ ${name}`);
|
|
45
|
+
console.log(` ${e.message}`);
|
|
46
|
+
if (e.actual !== undefined) {
|
|
47
|
+
console.log(` actual: ${JSON.stringify(e.actual)}`);
|
|
48
|
+
console.log(` expected: ${JSON.stringify(e.expected)}`);
|
|
49
|
+
}
|
|
50
|
+
failed++;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
(async () => {
|
|
55
|
+
console.log('UUFlowManager.getApproveValues 公式子字段兜底识别');
|
|
56
|
+
|
|
57
|
+
// 通用:父表 readonly,前两个子字段 editable,第三个(公式)无显式权限
|
|
58
|
+
const permissions = {
|
|
59
|
+
'表格': 'readable',
|
|
60
|
+
'加油量': 'editable',
|
|
61
|
+
'单价': 'editable',
|
|
62
|
+
'金额': 'readable',
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const submittedRow = {
|
|
66
|
+
_id: 'row1',
|
|
67
|
+
'加油量': '10',
|
|
68
|
+
'单价': '8',
|
|
69
|
+
'金额': '80', // 客户端计算出的公式值
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
await run('公式子字段带 formula 属性(本地新版 schema)→ 保留金额', async () => {
|
|
73
|
+
fakeForms['F1'] = {
|
|
74
|
+
current: {
|
|
75
|
+
_id: 'V1',
|
|
76
|
+
fields: [{
|
|
77
|
+
type: 'table',
|
|
78
|
+
code: '表格',
|
|
79
|
+
fields: [
|
|
80
|
+
{ type: 'number', code: '加油量' },
|
|
81
|
+
{ type: 'number', code: '单价' },
|
|
82
|
+
{ type: 'number', code: '金额', formula: '{加油量}*{单价}' },
|
|
83
|
+
],
|
|
84
|
+
}],
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
const approve_values = { '表格': [Object.assign({}, submittedRow)] };
|
|
88
|
+
const out = await UUFlowManager.getApproveValues(approve_values, permissions, 'F1', 'V1');
|
|
89
|
+
assert.deepStrictEqual(out['表格'][0], submittedRow);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
await run('公式子字段无 formula、default_value 为 ${...}(线上老 schema)→ 保留金额', async () => {
|
|
93
|
+
fakeForms['F2'] = {
|
|
94
|
+
current: {
|
|
95
|
+
_id: 'V2',
|
|
96
|
+
fields: [{
|
|
97
|
+
type: 'table',
|
|
98
|
+
code: '表格',
|
|
99
|
+
fields: [
|
|
100
|
+
{ type: 'number', code: '加油量', default_value: '0.00' },
|
|
101
|
+
{ type: 'number', code: '单价', default_value: '0.00' },
|
|
102
|
+
{ type: 'number', code: '金额', default_value: '${加油量*单价}' },
|
|
103
|
+
],
|
|
104
|
+
}],
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
const approve_values = { '表格': [Object.assign({}, submittedRow)] };
|
|
108
|
+
const out = await UUFlowManager.getApproveValues(approve_values, permissions, 'F2', 'V2');
|
|
109
|
+
assert.deepStrictEqual(out['表格'][0], submittedRow,
|
|
110
|
+
'老 schema 公式子字段应被识别保留,否则保存后刷新公式值会丢失');
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
await run('普通子字段 default_value 是纯字符串 → 不当作公式,无 editable 权限则删除', async () => {
|
|
114
|
+
fakeForms['F3'] = {
|
|
115
|
+
current: {
|
|
116
|
+
_id: 'V3',
|
|
117
|
+
fields: [{
|
|
118
|
+
type: 'table',
|
|
119
|
+
code: '表格',
|
|
120
|
+
fields: [
|
|
121
|
+
{ type: 'text', code: '加油量' },
|
|
122
|
+
{ type: 'text', code: '单价' },
|
|
123
|
+
{ type: 'text', code: '备注', default_value: '默认备注' },
|
|
124
|
+
],
|
|
125
|
+
}],
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
const perms = { '表格': 'readable', '加油量': 'editable', '单价': 'editable', '备注': 'readable' };
|
|
129
|
+
const row = { _id: 'r', '加油量': '1', '单价': '2', '备注': '客户端写入' };
|
|
130
|
+
const approve_values = { '表格': [Object.assign({}, row)] };
|
|
131
|
+
const out = await UUFlowManager.getApproveValues(approve_values, perms, 'F3', 'V3');
|
|
132
|
+
assert.strictEqual(out['表格'][0]['备注'], undefined, '普通字段不应被当作公式保留');
|
|
133
|
+
assert.strictEqual(out['表格'][0]['加油量'], '1');
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
await run('default_value 形如 "${"... 但未完整闭合 → 不当作公式', async () => {
|
|
137
|
+
fakeForms['F4'] = {
|
|
138
|
+
current: {
|
|
139
|
+
_id: 'V4',
|
|
140
|
+
fields: [{
|
|
141
|
+
type: 'table',
|
|
142
|
+
code: '表格',
|
|
143
|
+
fields: [
|
|
144
|
+
{ type: 'text', code: '加油量' },
|
|
145
|
+
{ type: 'text', code: '怪字段', default_value: '${unclosed' },
|
|
146
|
+
],
|
|
147
|
+
}],
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
const perms = { '表格': 'readable', '加油量': 'editable', '怪字段': 'readable' };
|
|
151
|
+
const row = { _id: 'r', '加油量': '1', '怪字段': 'x' };
|
|
152
|
+
const approve_values = { '表格': [Object.assign({}, row)] };
|
|
153
|
+
const out = await UUFlowManager.getApproveValues(approve_values, perms, 'F4', 'V4');
|
|
154
|
+
assert.strictEqual(out['表格'][0]['怪字段'], undefined);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
await run('顶层公式字段无 formula、default_value=${...} → 保留', async () => {
|
|
158
|
+
fakeForms['F5'] = {
|
|
159
|
+
current: {
|
|
160
|
+
_id: 'V5',
|
|
161
|
+
fields: [
|
|
162
|
+
{ type: 'number', code: '数量' },
|
|
163
|
+
{ type: 'number', code: '小计', default_value: '${数量*10}' },
|
|
164
|
+
],
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
const perms = { '数量': 'editable', '小计': 'readable' };
|
|
168
|
+
const approve_values = { '数量': '5', '小计': '50' };
|
|
169
|
+
const out = await UUFlowManager.getApproveValues(approve_values, perms, 'F5', 'V5');
|
|
170
|
+
assert.strictEqual(out['小计'], '50', '顶层公式字段应同样被兜底识别');
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
await run('section 内公式子字段无 formula、default_value=${...} → 保留', async () => {
|
|
174
|
+
fakeForms['F6'] = {
|
|
175
|
+
current: {
|
|
176
|
+
_id: 'V6',
|
|
177
|
+
fields: [{
|
|
178
|
+
type: 'section',
|
|
179
|
+
code: 'section1',
|
|
180
|
+
fields: [
|
|
181
|
+
{ type: 'number', code: '数量' },
|
|
182
|
+
{ type: 'number', code: '小计', default_value: '${数量*10}' },
|
|
183
|
+
],
|
|
184
|
+
}],
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
const perms = { '数量': 'editable', '小计': 'readable' };
|
|
188
|
+
const approve_values = { '数量': '5', '小计': '50' };
|
|
189
|
+
const out = await UUFlowManager.getApproveValues(approve_values, perms, 'F6', 'V6');
|
|
190
|
+
assert.strictEqual(out['小计'], '50', 'section 内公式字段应同样被兜底识别');
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
await run('permissions 为 null → 直接返回 {}', async () => {
|
|
194
|
+
const out = await UUFlowManager.getApproveValues({ x: 1 }, null, 'F1', 'V1');
|
|
195
|
+
assert.deepStrictEqual(out, {});
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
await run('historys 版本中的老 schema 同样生效', async () => {
|
|
199
|
+
fakeForms['F7'] = {
|
|
200
|
+
current: { _id: 'V7_NEW', fields: [] },
|
|
201
|
+
historys: [{
|
|
202
|
+
_id: 'V7_OLD',
|
|
203
|
+
fields: [{
|
|
204
|
+
type: 'table',
|
|
205
|
+
code: '表格',
|
|
206
|
+
fields: [
|
|
207
|
+
{ type: 'number', code: '加油量', default_value: '0.00' },
|
|
208
|
+
{ type: 'number', code: '单价', default_value: '0.00' },
|
|
209
|
+
{ type: 'number', code: '金额', default_value: '${加油量*单价}' },
|
|
210
|
+
],
|
|
211
|
+
}],
|
|
212
|
+
}],
|
|
213
|
+
};
|
|
214
|
+
const approve_values = { '表格': [Object.assign({}, submittedRow)] };
|
|
215
|
+
const out = await UUFlowManager.getApproveValues(approve_values, permissions, 'F7', 'V7_OLD');
|
|
216
|
+
assert.deepStrictEqual(out['表格'][0], submittedRow);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
console.log(`\n${passed} passed, ${failed} failed`);
|
|
220
|
+
process.exit(failed === 0 ? 0 : 1);
|
|
221
|
+
})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@steedos-labs/plugin-workflow",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.85",
|
|
4
4
|
"main": "package.service.js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
"release": "npm run build:designer && npm run stamp-version && npm publish --registry https://registry.npmjs.org && npx cnpm sync @steedos-labs/plugin-workflow",
|
|
24
24
|
"export-templates": "node run.js export",
|
|
25
25
|
"convert-templates": "node convert-templates.js",
|
|
26
|
-
"test:formula-compat": "node main/default/test/test_formula_compat.js"
|
|
26
|
+
"test:formula-compat": "node main/default/test/test_formula_compat.js",
|
|
27
|
+
"test:approve-values": "node main/default/test/test_getApproveValues.js"
|
|
27
28
|
},
|
|
28
29
|
"dependencies": {
|
|
29
30
|
"graphql-parse-resolve-info": "^4.12.3",
|