@steedos-labs/plugin-workflow 3.0.86 → 3.0.88

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.
@@ -5,8 +5,8 @@
5
5
  <link rel="shortcut icon" type="image/svg+xml" href="/images/logo.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>designer</title>
8
- <script type="module" crossorigin src="/api/workflow/designer-v2/assets/index-CUTUedfe.js"></script>
9
- <link rel="stylesheet" crossorigin href="/api/workflow/designer-v2/assets/index-B56yvQDB.css">
8
+ <script type="module" crossorigin src="/api/workflow/designer-v2/assets/index-Cg85h361.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/api/workflow/designer-v2/assets/index-CNcDjHgd.css">
10
10
  </head>
11
11
  <body>
12
12
  <div id="root"></div>
@@ -1,5 +1,5 @@
1
1
  waitForThing(window, 'antd').then(function(){
2
- var v = '3.0.86';
2
+ var v = '3.0.88';
3
3
  loadJs('/amis-renderer/amis-renderer.js?v=' + v);
4
4
  loadCss('/amis-renderer/amis-renderer.css?v=' + v)
5
5
  })
@@ -1834,14 +1834,14 @@ UUFlowManager.handleSkipProcessed = async function (instance_id, flow, maxDepth
1834
1834
  const consecutiveOnly = process.env.STEEDOS_WORKFLOW_SKIP_CONSECUTIVE_ONLY;
1835
1835
  let effectiveProcessedUserIds = processedUserIds;
1836
1836
  if (consecutiveOnly === 'true' || consecutiveOnly === '1') {
1837
- // 仅连续步骤模式:只检查紧邻的上一步骤的处理人
1837
+ // 仅连续步骤模式:只检查紧邻的上一步骤的处理人;滑步产生的 skipped 记录也算连续链路
1838
1838
  const previousTraceIds = lastTrace.previous_trace_ids || [];
1839
1839
  const previousTraces = (instance.traces || []).filter(t => previousTraceIds.includes(t._id));
1840
1840
  effectiveProcessedUserIds = [];
1841
1841
  for (const prevTrace of previousTraces) {
1842
1842
  if (prevTrace.approves) {
1843
1843
  for (const approve of prevTrace.approves) {
1844
- if (isNormalApprove(approve) && approve.is_finished && approve.judge !== 'skipped') {
1844
+ if (isNormalApprove(approve) && approve.is_finished) {
1845
1845
  if (!effectiveProcessedUserIds.includes(approve.user)) {
1846
1846
  effectiveProcessedUserIds.push(approve.user);
1847
1847
  }
@@ -19,7 +19,7 @@
19
19
  "actions": [
20
20
  {
21
21
  "actionType": "custom",
22
- "script": "var el=document.querySelector('.instance-name');if(el){var name=(el.innerText||el.textContent||'').trim().replace(/\\s+/g,' ');if(name)document.title=name;}window.print();"
22
+ "script": "var flowName='';try{var scoped=event&&event.data&&event.data._scoped;var instancePage=scoped&&scoped.getComponentById&&scoped.getComponentById('u:instancePage');var pageData=instancePage&&instancePage.getData&&instancePage.getData();flowName=pageData&&pageData.context&&pageData.context.flow&&pageData.context.flow.name;}catch(e){flowName='';}flowName=(flowName||'').trim().replace(/\\s+/g,' ');if(!flowName){var msg='打印页面数据异常,未找到流程名称';if(event&&event.context&&event.context.env&&event.context.env.notify){event.context.env.notify('warning',msg);}else{alert(msg);}return;}document.title=flowName;window.print();"
23
23
  }
24
24
  ]
25
25
  }
@@ -576,4 +576,4 @@
576
576
  ]
577
577
  }
578
578
  }
579
- }
579
+ }
@@ -41,12 +41,21 @@ const FlowversionAPI = {
41
41
  },
42
42
 
43
43
  getSafeEdgeLabel: function (str) {
44
- // Mermaid edge label (A-->|text|B) 对部分符号(如括号/竖线)解析不稳定,先做保守清洗。
45
- return FlowversionAPI.replaceErrorSymbol(String(str || ''))
46
- .replace(/[|]/g, '|')
47
- .replace(/[()()\[\]{}<>]/g, ' ')
48
- .replace(/\s+/g, ' ')
49
- .trim();
44
+ // Mermaid edge label (A-->|text|B) 的 jison 词法器对特殊符号非常敏感,
45
+ // 括号()[]{}、顿号、书名号《》、破折号—、省略号…等均会触发 Lexical error。
46
+ // 采用白名单策略:只保留中文汉字、ASCII字母数字、空格及少量安全标点,
47
+ // 其余一律替换为空格,彻底规避逐一枚举遗漏的问题。
48
+ let safe = String(str || '');
49
+ safe = safe.replace(/\|/g, '|'); // 竖线→全角竖线(保留视觉区分)
50
+ safe = safe.replace(/[\r\n\t]+/g, ' '); // 换行/制表符→空格(避免换行符破坏语法)
51
+ safe = safe.replace(/、/g, ','); // 顿号→逗号(语义等价,顿号是CJK标点不被jison识别)
52
+ // 白名单:中文汉字(U+4E00-9FFF 基本区 + U+3400-4DBF 扩展A区)
53
+ // + ASCII字母数字 + 空格 + 安全标点(-_.,:/ ·)
54
+ // 白名单以外的其他符号(全角括号、书名号、破折号、省略号等)均替换为空格,
55
+ // 避免 Mermaid flow.jison 词法器遇到未知 token 而崩溃(Unrecognized text 报错)。
56
+ // 白名单额外保留全角竖线 |(U+FF5C),因为上面已把 | 转为 | 作为视觉保留
57
+ safe = safe.replace(/[^\u4E00-\u9FFF\u3400-\u4DBFa-zA-Z0-9\s\-_.,:\/·\uFF5C]/g, ' ');
58
+ return safe.replace(/\s+/g, ' ').trim();
50
59
  },
51
60
 
52
61
  getStepHandlerName: async function (step, insId, instance) {
@@ -291,9 +291,10 @@ router.post('/api/workflow/v2/nextStepUsersValue', requireAuthentication, async
291
291
  for (let i = traces.length - 1; i >= 0; i--) {
292
292
  const trace = traces[i];
293
293
  if (trace.step === nextStepId && trace.approves && trace.approves.length > 0) {
294
- // 排除 returned/terminated/retrieved 的 approve
294
+ // 排除非实际处理人的 approve
295
+ const excludedApproveJudges = ['returned', 'relocated', 'terminated', 'retrieved'];
295
296
  newNextUsers = trace.approves
296
- .filter(approve => !['returned', 'terminated', 'retrieved'].includes(approve.judge))
297
+ .filter(approve => !excludedApproveJudges.includes(approve.judge))
297
298
  .map(approve => approve.handler);
298
299
  break;
299
300
  }
@@ -327,4 +328,4 @@ router.post('/api/workflow/v2/nextStepUsersValue', requireAuthentication, async
327
328
  }
328
329
  });
329
330
 
330
- exports.default = router;
331
+ exports.default = router;
@@ -14,6 +14,89 @@
14
14
  }
15
15
  return field.label || field.title || field.name || field.code || '';
16
16
  };
17
+ var escapeXml = function(value) {
18
+ if (value === undefined || value === null) {
19
+ return '';
20
+ }
21
+ return String(value).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&apos;');
22
+ };
23
+ var isMultiValueField = function(field, value) {
24
+ return field && (field.is_multiselect == true || ['memberMulti', 'orgMulti'].includes(field.type) || Array.isArray(value));
25
+ };
26
+ var getObjectDisplayValue = function(value, fieldType) {
27
+ if (value === undefined || value === null) {
28
+ return '';
29
+ }
30
+ if (typeof(value) != 'object') {
31
+ return value;
32
+ }
33
+ if (['group', 'org', 'orgMulti'].includes(fieldType)) {
34
+ return value.fullname || value.name || value.label || value.title || value.id || value._id || '';
35
+ }
36
+ return value.name || value.fullname || value.username || value.label || value.title || value.id || value.user || value._id || '';
37
+ };
38
+ var formatPickerValue = function(field, value) {
39
+ if (isMultiValueField(field, value)) {
40
+ return _.map(Array.isArray(value) ? value : [value], function(item) {
41
+ return getObjectDisplayValue(item, field.type);
42
+ }).filter(function(item) {
43
+ return item !== undefined && item !== null && item !== '';
44
+ }).join(',');
45
+ }
46
+ return getObjectDisplayValue(value, field.type);
47
+ };
48
+ var renderDataCell = function(field, value) {
49
+ if (value === undefined || value === null || value === '') {
50
+ return '<Cell><Data ss:Type="String"></Data></Cell>';
51
+ }
52
+ if (['user', 'group', 'member', 'memberMulti', 'org', 'orgMulti'].includes(field.type)) {
53
+ return '<Cell><Data ss:Type="String">' + escapeXml(formatPickerValue(field, value)) + '</Data></Cell>';
54
+ }
55
+ if (field.type == 'checkbox') {
56
+ return '<Cell><Data ss:Type="String">' + escapeXml(value == 'true' ? t('instance.formatter.checkbox.checked',{},lang) : t('instance.formatter.checkbox.unchecked',{},lang)) + '</Data></Cell>';
57
+ }
58
+ if (field.type == 'password') {
59
+ return '<Cell><Data ss:Type="String">******</Data></Cell>';
60
+ }
61
+ if (field.type == 'number') {
62
+ return '<Cell><Data ss:Type="Number">' + (Number(value) ? Number(Number(value).toFixed(field.digits)) : 0) + '</Data></Cell>';
63
+ }
64
+ if (field.type == 'date') {
65
+ var v = value;
66
+ if (typeof(v) == 'string' && v) {
67
+ try {
68
+ v = formatDate(v, t('instance.formatter.date.export_date',{},lang));
69
+ } catch (e) {
70
+ console.error(e);
71
+ }
72
+ }
73
+ if (v instanceof Date) {
74
+ v = formatDate(v, t('instance.formatter.date.export_date',{},lang));
75
+ }
76
+ return '<Cell><Data ss:Type="String">' + escapeXml(v || '') + '</Data></Cell>';
77
+ }
78
+ if (['dateTime', 'datetime'].includes(field.type)) {
79
+ var v = value;
80
+ if (typeof(v) == 'string' && v) {
81
+ try {
82
+ v = formatDate(v, t('instance.formatter.date.export_datetime',{},lang));
83
+ } catch (e) {
84
+ console.error(e);
85
+ }
86
+ }
87
+ if (v instanceof Date) {
88
+ v = formatDate(v, t('instance.formatter.date.export_datetime',{},lang));
89
+ }
90
+ return '<Cell><Data ss:Type="String">' + escapeXml(v || '') + '</Data></Cell>';
91
+ }
92
+ if (field.type == 'odata') {
93
+ return '<Cell><Data ss:Type="String">' + escapeXml((value && value['@label']) ? value['@label'] : '') + '</Data></Cell>';
94
+ }
95
+ if (typeof(value) == 'object') {
96
+ value = getObjectDisplayValue(value, field.type);
97
+ }
98
+ return '<Cell><Data ss:Type="String">' + escapeXml(value) + '</Data></Cell>';
99
+ };
17
100
  %>
18
101
  <!-- 编号 -->
19
102
  <Column ss:Width="35"/>
@@ -115,149 +198,11 @@
115
198
  <Cell><Data ss:Type="String"><%= formatDate(current_trace["start_date"], t('instance.formatter.date.export_datetime',{},lang)) %></Data></Cell>
116
199
  <% _.each(fields, function(field){ %>
117
200
  <% if (field.type != "table" && field.type != "section") { %>
118
- <% if (!ins["values"] || !ins["values"][field.code]) { %>
119
- <Cell><Data ss:Type="String"><%= "" %></Data></Cell>
120
- <% } else { %>
121
- <% if (['user','group'].includes(field.type) && field.is_multiselect != true) { %>
122
- <Cell><Data ss:Type="String"><%= field.type=="user" ? ins["values"][field.code]["name"] : ins["values"][field.code]["fullname"]%></Data></Cell>
123
- <% } else if (['user','group'].includes(field.type) && field.is_multiselect == true) {
124
- var tem_ary = new Array;
125
- _.each(ins["values"][field.code], function(s){
126
- tem_ary.push(field.type=="user" ? s["name"] : s["fullname"])
127
- })
128
- %>
129
- <Cell><Data ss:Type="String"><%= tem_ary.join(",") %></Data></Cell>
130
- <% } else if (field.type == "checkbox") { %>
131
- <Cell><Data ss:Type="String"><%= ins["values"][field.code]=="true" ? t('instance.formatter.checkbox.checked',{},lang) : t('instance.formatter.checkbox.unchecked',{},lang) %></Data></Cell>
132
- <% } else if (field.type == "password") { %>
133
- <Cell><Data ss:Type="String">******</Data></Cell>
134
- <% } else if (field.type == "number") { %>
135
- <Cell><Data ss:Type="Number"><%= Number(ins["values"][field.code]) ? Number(Number(ins["values"][field.code]).toFixed(field.digits)) : 0 %></Data></Cell>
136
- <% } else if (field.type == "date") { %>
137
- <%
138
- var v = ins["values"][field.code];
139
- if (typeof(v) == "string" && v) {
140
- try {
141
- v = formatDate(v, t('instance.formatter.date.export_date',{},lang));
142
- } catch (e) {
143
- console.error(e);
144
- }
145
- }
146
- if (v instanceof Date) {
147
- v = formatDate(v, t('instance.formatter.date.export_date',{},lang));
148
- }
149
- if (!v) {
150
- v = "";
151
- }
152
- %>
153
- <Cell><Data ss:Type="String"><%= v %></Data></Cell>
154
- <% } else if (field.type == "dateTime") { %>
155
- <%
156
- var v = ins["values"][field.code];
157
- if (typeof(v) == "string" && v) {
158
- try {
159
- v = formatDate(v, t('instance.formatter.date.export_datetime',{},lang));
160
- } catch (e) {
161
- console.error(e);
162
- }
163
- }
164
- if (v instanceof Date) {
165
- v = formatDate(v, t('instance.formatter.date.export_datetime',{},lang));
166
- }
167
- if (!v) {
168
- v = "";
169
- }
170
- %>
171
- <Cell><Data ss:Type="String"><%= v %></Data></Cell>
172
- <% } else if (field.type == "odata") { %>
173
- <%
174
- var odataValue = ins["values"][field.code];
175
- var v = (odataValue && odataValue["@label"]) ? odataValue["@label"] : "";
176
- %>
177
- <Cell><Data ss:Type="String"><%= v %></Data></Cell>
178
- <% } else { %>
179
- <%
180
- tem_v = ins["values"][field.code];
181
- if (typeof(tem_v) == "string") {
182
- tem_v = tem_v.replace(/</g, "&lt;").replace(/>/g, "&gt;");
183
- }
184
- %>
185
- <Cell><Data ss:Type="String"><%= tem_v %></Data></Cell>
186
- <% } %>
187
- <% } %>
201
+ <%- renderDataCell(field, ins["values"] && ins["values"][field.code]) %>
188
202
  <% } %>
189
203
  <% if (field.type == "section" && field.fields) { %>
190
204
  <% _.each(field.fields, function(sec){ %>
191
- <% if (!ins["values"] || !ins["values"][sec.code]) { %>
192
- <Cell><Data ss:Type="String"><%= "" %></Data></Cell>
193
- <% } else { %>
194
- <% if (['user','group'].includes(sec.type) && sec.is_multiselect != true) { %>
195
- <Cell><Data ss:Type="String"><%= sec.type=="user" ? ins["values"][sec.code]["name"] : ins["values"][sec.code]["fullname"]%></Data></Cell>
196
- <% } else if (['user','group'].includes(sec.type) && sec.is_multiselect == true) {
197
- var tem_ary = new Array;
198
- _.each(ins["values"][sec.code], function(s){
199
- tem_ary.push(sec.type=="user" ? s["name"] : s["fullname"])
200
- })
201
- %>
202
- <Cell><Data ss:Type="String"><%= tem_ary.join(",") %></Data></Cell>
203
- <% } else if (sec.type == "checkbox") { %>
204
- <Cell><Data ss:Type="String"><%= ins["values"][sec.code]=="true" ? t('instance.formatter.checkbox.checked',{},lang) : t('instance.formatter.checkbox.unchecked',{},lang) %></Data></Cell>
205
- <% } else if (sec.type == "password") { %>
206
- <Cell><Data ss:Type="String">******</Data></Cell>
207
- <% } else if (sec.type == "number") { %>
208
- <Cell><Data ss:Type="Number"><%= Number(ins["values"][sec.code]) ? Number(Number(ins["values"][sec.code]).toFixed(sec.digits)) : 0 %></Data></Cell>
209
- <% } else if (sec.type == "date") { %>
210
- <%
211
- var v = ins["values"][sec.code];
212
- if (typeof(v) == "string" && v) {
213
- try {
214
- v = new Date(v);
215
- } catch (e) {
216
- console.error(e);
217
- }
218
- }
219
- if (v instanceof Date) {
220
- v = moment(v).format(t('instance.formatter.date.export_date',{},lang));
221
- }
222
- if (!v) {
223
- v = "";
224
- }
225
- %>
226
- <Cell><Data ss:Type="String"><%= v %></Data></Cell>
227
- <% } else if (sec.type == "dateTime") { %>
228
- <%
229
- var v = ins["values"][sec.code];
230
- if (typeof(v) == "string" && v) {
231
- try {
232
- v = new Date(v);
233
- } catch (e) {
234
- console.error(e);
235
- }
236
- }
237
- if (v instanceof Date) {
238
- v = moment(v).format(t('instance.formatter.date.export_datetime',{},lang));
239
- }
240
- if (!v) {
241
- v = "";
242
- }
243
- %>
244
- <Cell><Data ss:Type="String"><%= v %></Data></Cell>
245
- <% } else if (sec.type == "odata") { %>
246
- <%
247
- var odataValue = ins["values"][sec.code];
248
- var v = (odataValue && odataValue["@label"]) ? odataValue["@label"] : "";
249
- %>
250
- <Cell><Data ss:Type="String"><%= v %></Data></Cell>
251
- <% } else { %>
252
- <%
253
- tem_v = ins["values"][sec.code];
254
- if (typeof(tem_v) == "string") {
255
- tem_v = tem_v.replace(/</g, "&lt;").replace(/>/g, "&gt;");
256
- }
257
- %>
258
- <Cell><Data ss:Type="String"><%= tem_v %></Data></Cell>
259
- <% } %>
260
- <% } %>
205
+ <%- renderDataCell(sec, ins["values"] && ins["values"][sec.code]) %>
261
206
  <% }) %>
262
207
  <% } %>
263
208
  <% }) %>
@@ -351,76 +296,7 @@
351
296
  <Cell><Data ss:Type="String"><%= current_trace.name %></Data></Cell>
352
297
  <Cell><Data ss:Type="String"><%= formatDate(current_trace["start_date"], t('instance.formatter.date.export_datetime',{},lang)) %></Data></Cell>
353
298
  <% _.each(table_field.fields, function(field) { %>
354
- <% if (!f_obj[field.code]) { %>
355
- <Cell><Data ss:Type="String"><%= "" %></Data></Cell>
356
- <% } else { %>
357
- <% if (['user','group'].includes(field.type) && field.is_multiselect != true) { %>
358
- <Cell><Data ss:Type="String"><%= field.type=="user" ? f_obj[field.code]["name"] : f_obj[field.code]["fullname"]%></Data></Cell>
359
- <% } else if (['user','group'].includes(field.type) && field.is_multiselect == true) {
360
- var tem_ary = new Array;
361
- _.each(f_obj[field.code], function(s){
362
- tem_ary.push(field.type=="user" ? s["name"] : s["fullname"])
363
- })
364
- %>
365
- <Cell><Data ss:Type="String"><%= tem_ary.join(",") %></Data></Cell>
366
- <% } else if (field.type == "checkbox") { %>
367
- <Cell><Data ss:Type="String"><%= f_obj[field.code]=="true" ? t('instance.formatter.checkbox.checked',{},lang) : t('instance.formatter.checkbox.unchecked',{},lang) %></Data></Cell>
368
- <% } else if (field.type == "password") { %>
369
- <Cell><Data ss:Type="String">******</Data></Cell>
370
- <% } else if (field.type == "number") { %>
371
- <Cell><Data ss:Type="Number"><%= Number(f_obj[field.code]) ? Number(Number(f_obj[field.code]).toFixed(field.digits)) : 0 %></Data></Cell>
372
- <% } else if (field.type == "date") { %>
373
- <%
374
- var v = f_obj[field.code];
375
- if (typeof(v) == "string" && v) {
376
- try {
377
- v = formatDate(v, t('instance.formatter.date.export_date',{},lang));
378
- } catch (e) {
379
- console.error(e);
380
- }
381
- }
382
- if (v instanceof Date) {
383
- v = formatDate(v, t('instance.formatter.date.export_date',{},lang));
384
- }
385
- if (!v) {
386
- v = "";
387
- }
388
- %>
389
- <Cell><Data ss:Type="String"><%= v %></Data></Cell>
390
- <% } else if (field.type == "dateTime") { %>
391
- <%
392
- var v = f_obj[field.code];
393
- if (typeof(v) == "string" && v) {
394
- try {
395
- v = formatDate(v, t('instance.formatter.date.export_datetime',{},lang));
396
- } catch (e) {
397
- console.error(e);
398
- }
399
- }
400
- if (v instanceof Date) {
401
- v = formatDate(v, t('instance.formatter.date.export_datetime',{},lang));
402
- }
403
- if (!v) {
404
- v = "";
405
- }
406
- %>
407
- <Cell><Data ss:Type="String"><%= v %></Data></Cell>
408
- <% } else if (field.type == "odata") { %>
409
- <%
410
- var odataValue = f_obj[field.code];
411
- var v = (odataValue && odataValue["@label"]) ? odataValue["@label"] : "";
412
- %>
413
- <Cell><Data ss:Type="String"><%= v %></Data></Cell>
414
- <% } else { %>
415
- <%
416
- tem_v = f_obj[field.code];
417
- if (typeof(tem_v) == "string") {
418
- tem_v = tem_v.replace(/</g, "&lt;").replace(/>/g, "&gt;");
419
- }
420
- %>
421
- <Cell><Data ss:Type="String"><%= tem_v %></Data></Cell>
422
- <% } %>
423
- <% } %>
299
+ <%- renderDataCell(field, f_obj[field.code]) %>
424
300
  <% }) %>
425
301
  </Row>
426
302
  <% }) %>
@@ -429,4 +305,4 @@
429
305
  </Table>
430
306
  </Worksheet>
431
307
  <% }) %>
432
- </Workbook>
308
+ </Workbook>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steedos-labs/plugin-workflow",
3
- "version": "3.0.86",
3
+ "version": "3.0.88",
4
4
  "main": "package.service.js",
5
5
  "license": "MIT",
6
6
  "files": [