@steedos-labs/plugin-workflow 3.0.63 → 3.0.65

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-CugibT25.js"></script>
9
- <link rel="stylesheet" crossorigin href="/api/workflow/designer-v2/assets/index-DIAKZCeb.css">
8
+ <script type="module" crossorigin src="/api/workflow/designer-v2/assets/index-CdtiiXeP.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/api/workflow/designer-v2/assets/index-CFR_MNwA.css">
10
10
  </head>
11
11
  <body>
12
12
  <div id="root"></div>
@@ -3304,10 +3304,9 @@ UUFlowManager.create_instance = async function (instance_from_client, user_info)
3304
3304
  };
3305
3305
 
3306
3306
  UUFlowManager.getCurrentStepAutoSubmit = function (timeout_auto_submit, lines) {
3307
- if (timeout_auto_submit && lines) {
3308
- return lines.some(l => l.timeout_line === true);
3309
- }
3310
- return false;
3307
+ const timeoutLines = lines ? lines.filter(l => l.timeout_line === true) : [];
3308
+ const result = !!(timeout_auto_submit && timeoutLines.length > 0);
3309
+ return result;
3311
3310
  };
3312
3311
 
3313
3312
  UUFlowManager.getDueDate = async function (hours, spaceId) {
@@ -4077,9 +4076,16 @@ UUFlowManager.checkValueFieldsRequire = function (values = {}, form, form_versio
4077
4076
 
4078
4077
  if (!form_v) return require_but_empty_fields;
4079
4078
 
4079
+ // 判断字段值是否为空(兼容数字类型,0 不算空)
4080
+ const isFieldValueEmpty = (value) => {
4081
+ if (typeof value === 'number') return false;
4082
+ if (typeof value === 'boolean') return false;
4083
+ return _.isEmpty(value);
4084
+ };
4085
+
4080
4086
  form_v.fields.forEach(field => {
4081
4087
  if (field.type !== 'table') {
4082
- if (field.is_required && _.isEmpty(values[field.code])) {
4088
+ if (field.is_required && isFieldValueEmpty(values[field.code])) {
4083
4089
  require_but_empty_fields.push(field.name || field.code);
4084
4090
  }
4085
4091
  } else {
@@ -4092,7 +4098,7 @@ UUFlowManager.checkValueFieldsRequire = function (values = {}, form, form_versio
4092
4098
  } else {
4093
4099
  values[field.code].forEach(s_value => {
4094
4100
  field.fields.forEach(s_field => {
4095
- if (s_field.is_required && _.isEmpty(s_value[s_field.code])) {
4101
+ if (s_field.is_required && isFieldValueEmpty(s_value[s_field.code])) {
4096
4102
  require_but_empty_fields.push(s_field.name || s_field.code);
4097
4103
  }
4098
4104
  });
@@ -4379,6 +4385,7 @@ UUFlowManager.timeoutAutoSubmit = async function (ins_id) {
4379
4385
  const query = {
4380
4386
  state: 'pending',
4381
4387
  current_step_auto_submit: true,
4388
+ timeout_auto_submit_exhausted: { $ne: true },
4382
4389
  traces: {
4383
4390
  $elemMatch: {
4384
4391
  is_finished: false,
@@ -4392,15 +4399,12 @@ UUFlowManager.timeoutAutoSubmit = async function (ins_id) {
4392
4399
  }
4393
4400
 
4394
4401
  const startTime = Date.now();
4395
- console.log(`[timeout_auto_submit] Starting timeout check with query:`, JSON.stringify(query));
4396
-
4397
4402
  const instances = await db.instances.find(query).toArray();
4398
4403
 
4399
- console.log(`[timeout_auto_submit] Found ${instances.length} instance(s) matching timeout criteria`);
4400
- if (instances.length > 0) {
4401
- const instanceIds = instances.map(i => i._id).join(', ');
4402
- console.log(`[timeout_auto_submit] Instance IDs: [${instanceIds}]`);
4404
+ if (instances.length === 0) {
4405
+ return;
4403
4406
  }
4407
+ console.log(`${new Date().toISOString()} [timeout_auto_submit] Found ${instances.length} instance(s) to process`);
4404
4408
 
4405
4409
  for (const ins of instances) {
4406
4410
  try {
@@ -4410,7 +4414,6 @@ UUFlowManager.timeoutAutoSubmit = async function (ins_id) {
4410
4414
 
4411
4415
  // Only process if trace is not finished and due_date has passed
4412
4416
  if (trace.is_finished || !trace.due_date || new Date(trace.due_date) > new Date()) {
4413
- console.log(`[timeout_auto_submit] Skipping instance ${instance_id}: trace finished=${trace.is_finished}, due_date=${trace.due_date}, now=${new Date()}`);
4414
4417
  continue;
4415
4418
  }
4416
4419
 
@@ -4429,7 +4432,7 @@ UUFlowManager.timeoutAutoSubmit = async function (ins_id) {
4429
4432
  if (nextStep.step_type === 'condition') {
4430
4433
  const nextSteps = await UUFlowManager.getNextSteps(ins, flow, nextStep, "");
4431
4434
  if (!nextSteps || nextSteps.length === 0) {
4432
- console.error(`[timeout_auto_submit] No next steps resolved for condition step, instance: ${instance_id}`);
4435
+ console.error(`${new Date().toISOString()} [timeout_auto_submit] No next steps resolved for condition step, instance: ${instance_id}`);
4433
4436
  continue;
4434
4437
  }
4435
4438
  nextStepId = nextSteps[0];
@@ -4441,7 +4444,6 @@ UUFlowManager.timeoutAutoSubmit = async function (ins_id) {
4441
4444
 
4442
4445
  // Process each unfinished approve in the trace sequentially to avoid race conditions
4443
4446
  const unfinishedApproves = trace.approves.filter(a => !a.is_finished);
4444
- console.log(`[timeout_auto_submit] Instance ${instance_id}: Processing ${unfinishedApproves.length} unfinished approve(s) | flow=${flow_id} | step=${trace.step} | type=${step_type}`);
4445
4447
 
4446
4448
  let successCount = 0;
4447
4449
  let failureCount_approves = 0;
@@ -4451,7 +4453,6 @@ UUFlowManager.timeoutAutoSubmit = async function (ins_id) {
4451
4453
  // Check failure count for this approve
4452
4454
  const failureCount = a.timeout_auto_submit_failures || 0;
4453
4455
  if (failureCount >= 3) {
4454
- console.log(`[timeout_auto_submit] Skipping approve ${a._id} - exceeded max failures (count=${failureCount}), instance: ${instance_id}`);
4455
4456
  skipCount++;
4456
4457
  continue;
4457
4458
  }
@@ -4474,12 +4475,34 @@ UUFlowManager.timeoutAutoSubmit = async function (ins_id) {
4474
4475
  );
4475
4476
 
4476
4477
  if (!current_user_info) {
4477
- console.error(`[timeout_auto_submit] User not found: ${a.handler}, instance: ${instance_id}`);
4478
+ const userNotFoundFailureCount = (a.timeout_auto_submit_failures || 0) + 1;
4479
+ console.error(`${new Date().toISOString()} [timeout_auto_submit] User not found: ${a.handler}, instance: ${instance_id}, approve: ${a._id}`);
4480
+ try {
4481
+ await db.instances.updateOne(
4482
+ {
4483
+ _id: instance_id,
4484
+ "traces._id": trace._id
4485
+ },
4486
+ {
4487
+ $set: {
4488
+ "traces.$[trace].approves.$[approve].timeout_auto_submit_failures": userNotFoundFailureCount
4489
+ }
4490
+ },
4491
+ {
4492
+ arrayFilters: [
4493
+ { "trace._id": trace._id },
4494
+ { "approve._id": a._id }
4495
+ ]
4496
+ }
4497
+ );
4498
+ } catch (updateError) {
4499
+ console.error(`${new Date().toISOString()} [timeout_auto_submit] Failed to update failure count for approve ${a._id}: `, updateError.message || updateError);
4500
+ }
4501
+ failureCount_approves++;
4478
4502
  continue;
4479
4503
  }
4480
4504
 
4481
- console.log(`[timeout_auto_submit] Processing approve ${a._id} for instance ${instance_id} (failure_count=${failureCount})`);
4482
- console.log(`[timeout_auto_submit] current_user_info: ${JSON.stringify(current_user_info)}`);
4505
+ console.log(`${new Date().toISOString()} [timeout_auto_submit] Processing approve ${a._id} for instance ${instance_id}`);
4483
4506
 
4484
4507
  const updatedInstance = await UUFlowManager.workflow_engine(
4485
4508
  approve_from_client,
@@ -4497,7 +4520,7 @@ UUFlowManager.timeoutAutoSubmit = async function (ins_id) {
4497
4520
  successCount++;
4498
4521
  } catch (approveError) {
4499
4522
  const failureCount = (a.timeout_auto_submit_failures || 0) + 1;
4500
- console.error(`[timeout_auto_submit] Error processing approve ${a._id} for instance ${instance_id} (failure_count=${failureCount}): ${approveError.message || approveError}`);
4523
+ console.error(`${new Date().toISOString()} [timeout_auto_submit] Error processing approve ${a._id} for instance ${instance_id} (failure_count=${failureCount}): ${approveError.message || approveError}`);
4501
4524
 
4502
4525
  // Update the failure count in the database
4503
4526
  try {
@@ -4518,21 +4541,35 @@ UUFlowManager.timeoutAutoSubmit = async function (ins_id) {
4518
4541
  ]
4519
4542
  }
4520
4543
  );
4521
- console.log(`[timeout_auto_submit] Updated failure count for approve ${a._id}: ${failureCount}`);
4522
4544
  } catch (updateError) {
4523
- console.error(`[timeout_auto_submit] Failed to update failure count for approve ${a._id}: `, updateError.message || updateError);
4545
+ console.error(`${new Date().toISOString()} [timeout_auto_submit] Failed to update failure count for approve ${a._id}: `, updateError.message || updateError);
4524
4546
  }
4525
4547
  failureCount_approves++;
4526
4548
  }
4527
4549
  }
4528
- console.log(`[timeout_auto_submit] Instance ${instance_id} completed: success=${successCount} | failed=${failureCount_approves} | skipped=${skipCount}`);
4550
+ if (successCount > 0 || failureCount_approves > 0) {
4551
+ console.log(`${new Date().toISOString()} [timeout_auto_submit] Instance ${instance_id}: success=${successCount} | failed=${failureCount_approves} | skipped=${skipCount}`);
4552
+ }
4553
+
4554
+ // If all approves were skipped (all exceeded max failures), mark instance as exhausted
4555
+ if (skipCount > 0 && skipCount === unfinishedApproves.length) {
4556
+ try {
4557
+ await db.instances.updateOne(
4558
+ { _id: instance_id },
4559
+ { $set: { timeout_auto_submit_exhausted: true } }
4560
+ );
4561
+ console.log(`${new Date().toISOString()} [timeout_auto_submit] Instance ${instance_id} marked as exhausted`);
4562
+ } catch (updateError) {
4563
+ console.error(`${new Date().toISOString()} [timeout_auto_submit] Failed to mark instance ${instance_id} as exhausted: `, updateError.message || updateError);
4564
+ }
4565
+ }
4529
4566
  } catch (error) {
4530
- console.error(`[timeout_auto_submit] Error processing instance ${ins._id}: `, error.stack);
4567
+ console.error(`${new Date().toISOString()} [timeout_auto_submit] Error processing instance ${ins._id}: `, error.stack);
4531
4568
  }
4532
4569
  }
4533
4570
 
4534
4571
  const duration = Date.now() - startTime;
4535
- console.log(`[timeout_auto_submit] Completed processing ${instances.length} instance(s) in ${duration}ms`);
4572
+ console.log(`${new Date().toISOString()} [timeout_auto_submit] Processed ${instances.length} instance(s) in ${duration}ms`);
4536
4573
 
4537
4574
  return true;
4538
4575
  };
@@ -282,7 +282,7 @@ actions:
282
282
  standard_delete:
283
283
  label: 删除
284
284
  designFlow:
285
- label: 流程设计器
285
+ label: 流程设计器(旧版)
286
286
  designForm:
287
287
  label: 表单设计器
288
288
  design_form_layout:
@@ -748,7 +748,16 @@ actions:
748
748
  designFlow:
749
749
  label: Flow Designer
750
750
  visible: !<tag:yaml.org,2002:js/function> |-
751
- function (object_name, record_id, record_permissions) {
751
+ function (object_name, record_id, record_permissions, data) {
752
+ var record = data && data.record;
753
+
754
+ if (!record) {
755
+ return false;
756
+ }
757
+
758
+ if(record.upgraded){
759
+ return false;
760
+ }
752
761
  return true;
753
762
  }
754
763
  'on': record
@@ -774,12 +783,12 @@ actions:
774
783
  return Steedos.openWindow(Steedos.absoluteUrl(iframe_url));
775
784
  }
776
785
  designFlowV2:
777
- label: 流程设计器V2(BETA)
786
+ label: 设计器
778
787
  visible: !<tag:yaml.org,2002:js/function> |-
779
788
  function (object_name, record_id, record_permissions) {
780
789
  return true;
781
790
  }
782
- 'on': record_more
791
+ 'on': record
783
792
  todo: !<tag:yaml.org,2002:js/function> |-
784
793
  function (object_name, record_id, record_permissions, data) {
785
794
  const flow = data && data.record;
@@ -37,4 +37,7 @@ extra_columns:
37
37
  - is_read
38
38
  - type
39
39
  - instance.values
40
- disableSwitch: true
40
+ disableSwitch: true
41
+ crudDataFilter: |
42
+ crud.rowClassNameExpr = "<%=(data.is_read === false ? 'unread-instance ' : '') + (data._id === data.recordId ? 'steedos-record-tr steedos-record-tr-' + data._id + ' steedos-record-selected' : 'steedos-record-tr steedos-record-tr-' + data._id) %>";
43
+ return crud;
@@ -183,7 +183,7 @@
183
183
  "body": [
184
184
  {
185
185
  "type": "wrapper",
186
- "className": "steedos-instance-print-wrapper steedos-instance-detail-wrapper m-0 p-0 flex-1 focus:outline-none lg:order-last sm:m-4 shadow sm:rounded",
186
+ "className": "steedos-instance-print-wrapper steedos-instance-detail-wrapper m-0 p-0 flex-1 focus:outline-none lg:order-last sm:m-4 sm:rounded",
187
187
  "body": [
188
188
  {
189
189
  "type": "service",
@@ -333,6 +333,7 @@
333
333
  },
334
334
  ".steedos-instance-related-view-wrapper .steedos-input-table": {
335
335
  "width": "100% !important",
336
+ "max-width": "none !important",
336
337
  "display": "block !important"
337
338
  },
338
339
  ".steedos-instance-related-view-wrapper .antd-Table-contentWrap": {
@@ -340,6 +341,9 @@
340
341
  "display": "block !important",
341
342
  "width": "100% !important"
342
343
  },
344
+ ".steedos-instance-related-view-wrapper .steedos-input-table .antd-Table-table th": {
345
+ "white-space": "normal !important"
346
+ },
343
347
  ".antd-Table-content-colDragLine": {
344
348
  "display": "none !important"
345
349
  },
@@ -385,6 +389,28 @@
385
389
  ".steedos-instance-related-view-wrapper .instance-form-view td": {
386
390
  "border-width": "1px !important"
387
391
  },
392
+ ".steedos-instance-related-view-wrapper .steedos-input-table .antd-Table-table": {
393
+ "-webkit-print-color-adjust": "exact !important",
394
+ "print-color-adjust": "exact !important",
395
+ "table-layout": "auto !important"
396
+ },
397
+ ".steedos-instance-related-view-wrapper .steedos-input-table .antd-Table-table th": {
398
+ "border-left": "1px solid #000 !important",
399
+ "border-bottom": "1px solid #000 !important",
400
+ "white-space": "normal !important"
401
+ },
402
+ ".steedos-instance-related-view-wrapper .steedos-input-table .antd-Table-table td": {
403
+ "border-left": "1px solid #000 !important",
404
+ "border-bottom": "1px solid #000 !important"
405
+ },
406
+ ".steedos-instance-related-view-wrapper .steedos-input-table .antd-Table-table th.antd-Table-operationCell, .steedos-instance-related-view-wrapper .steedos-input-table .antd-Table-table td.antd-Table-operationCell": {
407
+ "visibility": "collapse !important",
408
+ "border": "none !important",
409
+ "padding": "0 !important"
410
+ },
411
+ ".steedos-instance-related-view-wrapper .steedos-input-table .antd-Form-static": {
412
+ "word-break": "normal !important"
413
+ },
388
414
  ".steedos-instance-related-view-wrapper .instance-approve-history .antd-Table-table tr td": {
389
415
  "border-bottom": "1px solid #e8e8e8 !important"
390
416
  }
@@ -69,6 +69,18 @@ router.post('/api/workflow/retrieve', requireAuthentication, async function (req
69
69
  previous_trace = _.find(traces, function (t) {
70
70
  return t._id === previous_trace_id;
71
71
  });
72
+
73
+ // 滑步处理:如果前一步是被跳过的(skipped),沿 previous_trace_ids 向前回溯,
74
+ // 找到用户实际操作过的那个 trace,收集中间所有被跳过的 trace
75
+ var skipped_trace_ids = []; // 记录滑步跳过的中间 trace id
76
+ while (previous_trace && previous_trace.judge === 'skipped' && previous_trace.previous_trace_ids && previous_trace.previous_trace_ids.length > 0) {
77
+ skipped_trace_ids.push(previous_trace._id);
78
+ var prev_id = previous_trace.previous_trace_ids[0];
79
+ previous_trace = _.find(traces, function (t) {
80
+ return t._id === prev_id;
81
+ });
82
+ }
83
+
72
84
  previous_trace_step_id = previous_trace.step;
73
85
  previous_trace_name = previous_trace.name;
74
86
  flow = await UUFlowManager.getFlow(instance.flow);
@@ -76,6 +88,18 @@ router.post('/api/workflow/retrieve', requireAuthentication, async function (req
76
88
  if (previous_step.step_type === "counterSign") {
77
89
  throw new Error('会签不能取回');
78
90
  }
91
+ // 校验当前步骤(下一步)是否已读(取回到填写申请步骤时不受此限制)
92
+ if (previous_step.step_type !== "start") {
93
+ var is_read = false;
94
+ _.each(last_trace.approves, function (ap) {
95
+ if (ap.is_read === true) {
96
+ is_read = true;
97
+ }
98
+ });
99
+ if (is_read) {
100
+ throw new Error('下一步处理人已读,不能取回');
101
+ }
102
+ }
79
103
  // 取回步骤的前一个步骤处理人唯一(即排除掉传阅和转发的approve后,剩余的approve只有一个)并且是当前用户
80
104
  previous_trace_approves = _.filter(previous_trace.approves, function (a) {
81
105
  return a.type !== 'cc' && a.type !== 'distribute' && a.type !== 'forward' && ['approved', 'submitted', 'rejected'].includes(a.judge);
@@ -110,9 +134,12 @@ router.post('/api/workflow/retrieve', requireAuthentication, async function (req
110
134
  let retrieve_appr_id = ''
111
135
 
112
136
 
137
+ // 需要标记为 retrieved 的 trace id 集合:当前步骤 + 滑步跳过的中间步骤
138
+ var traces_to_retrieve = [last_trace_id].concat(skipped_trace_ids);
139
+
113
140
  for (const t of traces) {
114
141
  var current_space_user, current_user_organization, retrieve_appr;
115
- if (t._id === last_trace_id) {
142
+ if (traces_to_retrieve.includes(t._id)) {
116
143
  if (!t.approves) {
117
144
  t.approves = new Array;
118
145
  }
@@ -131,40 +158,44 @@ router.post('/api/workflow/retrieve', requireAuthentication, async function (req
131
158
  finishedApproveIds.push(appr._id)
132
159
  }
133
160
  });
134
- // 在同一trace下插入取回操作者的approve记录
135
- current_space_user = await UUFlowManager.getSpaceUser(space_id, current_user);
136
161
 
137
- current_user_organization = await organizationsCollection.findOne({ _id: current_space_user.organization }, {
138
- projection: {
139
- name: 1,
140
- fullname: 1
141
- }
142
- })
162
+ // 只在最后一个trace(当前步骤)插入取回操作者的approve记录
163
+ if (t._id === last_trace_id) {
164
+ current_space_user = await UUFlowManager.getSpaceUser(space_id, current_user);
165
+
166
+ current_user_organization = await organizationsCollection.findOne({ _id: current_space_user.organization }, {
167
+ projection: {
168
+ name: 1,
169
+ fullname: 1
170
+ }
171
+ })
172
+
173
+ retrieve_appr = new Object;
174
+ retrieve_appr._id = _makeNewID();
175
+ retrieve_appr.instance = instance_id;
176
+ retrieve_appr.trace = t._id;
177
+ retrieve_appr.is_finished = true;
178
+ retrieve_appr.user = current_user;
179
+ retrieve_appr.user_name = current_user_info.name;
180
+ retrieve_appr.handler = current_user;
181
+ retrieve_appr.handler_name = current_user_info.name;
182
+ retrieve_appr.handler_organization = current_space_user.organization;
183
+ retrieve_appr.handler_organization_name = current_user_organization.name;
184
+ retrieve_appr.handler_organization_fullname = current_user_organization.fullname;
185
+ retrieve_appr.start_date = now;
186
+ retrieve_appr.finish_date = now;
187
+ retrieve_appr.due_date = t.due_date;
188
+ retrieve_appr.read_date = now;
189
+ retrieve_appr.judge = "retrieved";
190
+ retrieve_appr.is_read = true;
191
+ retrieve_appr.description = retrieve_comment;
192
+ retrieve_appr.is_error = false;
193
+ retrieve_appr.values = new Object;
194
+ retrieve_appr.cost_time = retrieve_appr.finish_date - retrieve_appr.start_date;
195
+ t.approves.push(retrieve_appr);
196
+ }
143
197
 
144
- retrieve_appr = new Object;
145
- retrieve_appr._id = _makeNewID();
146
- retrieve_appr.instance = instance_id;
147
- retrieve_appr.trace = t._id;
148
- retrieve_appr.is_finished = true;
149
- retrieve_appr.user = current_user;
150
- retrieve_appr.user_name = current_user_info.name;
151
- retrieve_appr.handler = current_user;
152
- retrieve_appr.handler_name = current_user_info.name;
153
- retrieve_appr.handler_organization = current_space_user.organization;
154
- retrieve_appr.handler_organization_name = current_user_organization.name;
155
- retrieve_appr.handler_organization_fullname = current_user_organization.fullname;
156
- retrieve_appr.start_date = now;
157
- retrieve_appr.finish_date = now;
158
- retrieve_appr.due_date = t.due_date;
159
- retrieve_appr.read_date = now;
160
- retrieve_appr.judge = "retrieved";
161
- retrieve_appr.is_read = true;
162
- retrieve_appr.description = retrieve_comment;
163
- retrieve_appr.is_error = false;
164
- retrieve_appr.values = new Object;
165
- retrieve_appr.cost_time = retrieve_appr.finish_date - retrieve_appr.start_date;
166
- t.approves.push(retrieve_appr);
167
- // 更新当前trace记录
198
+ // 更新trace记录
168
199
  t.is_finished = true;
169
200
  t.finish_date = now;
170
201
  t.judge = "retrieved";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steedos-labs/plugin-workflow",
3
- "version": "3.0.63",
3
+ "version": "3.0.65",
4
4
  "main": "package.service.js",
5
5
  "license": "MIT",
6
6
  "files": [