@steedos-labs/plugin-workflow 3.0.21 → 3.0.23

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.
@@ -1,9 +1,9 @@
1
-
2
1
  const _ = require('underscore');
3
2
 
4
3
  const { getCollection } = require('../utils/collection');
5
4
  const { excuteTriggers } = require('../utils/trigger')
6
5
  const WorkflowManager = require('./workflow_manager');
6
+ // const UUFlowManager = require('./uuflow_manager'); // Moved inside function to avoid circular dependency
7
7
 
8
8
  const getHandlersManager = {};
9
9
 
@@ -20,7 +20,7 @@ getHandlersManager.getHandlersByUsersAndRoles = async function (user_ids, role_i
20
20
  approve_users = approve_users.concat(users);
21
21
  }
22
22
  } else {
23
- throw new Error('error! user_id不合法不合法');
23
+ throw new Error('error! user_id不合法');
24
24
  }
25
25
  }
26
26
 
@@ -147,6 +147,7 @@ getHandlersManager.getHandlersByOrgAndRole = async function (org_id, role_id, sp
147
147
  };
148
148
 
149
149
  getHandlersManager.getHandlers = async function (instance_id, step_id, login_user_id) {
150
+ const UUFlowManager = require('./uuflow_manager');
150
151
  const instancesCollection = await getCollection('instances');
151
152
  const flowsCollection = await getCollection('flows');
152
153
  const formsCollection = await getCollection('forms');
@@ -287,7 +288,7 @@ getHandlersManager.getHandlers = async function (instance_id, step_id, login_use
287
288
  }
288
289
  }
289
290
 
290
- const newest_values = await uuflowManager.getUpdatedValues(instance);
291
+ const newest_values = await UUFlowManager.getUpdatedValues(instance);
291
292
  let org_ids = [];
292
293
  let org_ids_names = [];
293
294
 
@@ -363,7 +364,7 @@ getHandlersManager.getHandlers = async function (instance_id, step_id, login_use
363
364
  }
364
365
  }
365
366
 
366
- const newest_values = await uuflowManager.getUpdatedValues(instance);
367
+ const newest_values = await UUFlowManager.getUpdatedValues(instance);
367
368
  let org_ids = [];
368
369
  let org_ids_names = [];
369
370
 
@@ -468,7 +469,7 @@ getHandlersManager.getHandlers = async function (instance_id, step_id, login_use
468
469
  }
469
470
  }
470
471
 
471
- const newest_values = await uuflowManager.getUpdatedValues(instance);
472
+ const newest_values = await UUFlowManager.getUpdatedValues(instance);
472
473
  let user_ids_names = [];
473
474
 
474
475
  if (newest_values[field_code]) {
@@ -484,14 +485,14 @@ getHandlersManager.getHandlers = async function (instance_id, step_id, login_use
484
485
  for (const user of user_ids_names) {
485
486
  const check_user_count = await spaceUsersCollection.find({
486
487
  space: space_id,
487
- user: user["id"]
488
+ user: _.isString(user) ? user : user["id"]
488
489
  }).count();
489
490
 
490
491
  if (check_user_count === 0) {
491
492
  throw new Error('error! 人员ID不合法');
492
493
  }
493
494
 
494
- user_ids.push(user["id"]);
495
+ user_ids.push(_.isString(user) ? user : user["id"]);
495
496
  }
496
497
 
497
498
  user_ids = _.uniq(user_ids);
@@ -548,7 +549,7 @@ getHandlersManager.getHandlers = async function (instance_id, step_id, login_use
548
549
  }
549
550
  }
550
551
 
551
- const newest_values = await uuflowManager.getUpdatedValues(instance);
552
+ const newest_values = await UUFlowManager.getUpdatedValues(instance);
552
553
  let user_ids_names = [];
553
554
 
554
555
  if (newest_values[field_code]) {
@@ -560,18 +561,16 @@ getHandlersManager.getHandlers = async function (instance_id, step_id, login_use
560
561
  }
561
562
 
562
563
  let user_ids = [];
563
-
564
564
  for (const user of user_ids_names) {
565
565
  const check_user_count = await spaceUsersCollection.find({
566
566
  space: space_id,
567
- user: user["id"]
567
+ user: _.isString(user) ? user : user["id"]
568
568
  }).count();
569
-
570
569
  if (check_user_count === 0) {
571
570
  throw new Error('error! 人员ID不合法');
572
571
  }
573
572
 
574
- user_ids.push(user["id"]);
573
+ user_ids.push(_.isString(user) ? user : user["id"]);
575
574
  }
576
575
 
577
576
  users = _.uniq(user_ids);
@@ -897,7 +897,7 @@ UUFlowManager.getNextSteps = async function (instance, flow, step, judge, values
897
897
  }
898
898
  else {
899
899
  step_line_condition = step_line.condition.replace(reg, (vowel) => {
900
- return prefix + vowel.replace(/\{\s*/, "[\"").replace(/\s*\}/, "\"]").replace(/\s*\.\s*/g, "\"][\"");
900
+ return prefix + vowel.replace(/\{\s*/, "[\"").replace(/\s*\}/, "\"]").replace(/\s*\.\s*/g, "\"]?.[\"");
901
901
  });
902
902
  allow = UUFlowManager.calculateCondition(__values, step_line_condition);
903
903
  }
@@ -1029,6 +1029,9 @@ UUFlowManager.getNextSteps = async function (instance, flow, step, judge, values
1029
1029
  }
1030
1030
  }
1031
1031
  }
1032
+
1033
+ // rev_nextSteps 不能包含当前步骤
1034
+ rev_nextSteps = rev_nextSteps.filter(ns => ns !== step._id);
1032
1035
 
1033
1036
  return _.uniq(rev_nextSteps);
1034
1037
  };
@@ -116,6 +116,18 @@ WorkflowManager.getRole = async function (spaceId, roleId) {
116
116
  });
117
117
  };
118
118
 
119
+ WorkflowManager.getRoles = async function (spaceId, roleIds) {
120
+ if (!roleIds || !spaceId) {
121
+ return;
122
+ }
123
+
124
+ const flowRolesCollection = await getCollection('flow_roles');
125
+ return await flowRolesCollection.find({
126
+ _id: { $in: roleIds },
127
+ space: spaceId
128
+ }).toArray();
129
+ };
130
+
119
131
  WorkflowManager.getSpacePositions = async function (spaceId) {
120
132
  const flowPositionsCollection = await getCollection('flow_positions');
121
133
  return await flowPositionsCollection.find({
@@ -1,6 +1,22 @@
1
1
  {
2
2
  "type": "page",
3
3
  "body": [
4
+ {
5
+ "type": "button",
6
+ "label": "刷新",
7
+ "className": "steedos-workflow-reload-btn hidden",
8
+ "onEvent": {
9
+ "click": {
10
+ "actions": [
11
+ {
12
+ "componentId": "u:d6db0c84f150",
13
+ "groupType": "component",
14
+ "actionType": "rebuild"
15
+ }
16
+ ]
17
+ }
18
+ }
19
+ },
4
20
  {
5
21
  "type": "wrapper",
6
22
  "className": "steedos-instance-detail-wrapper m-0 p-0 flex-1 focus:outline-none lg:order-last sm:m-4 shadow sm:rounded",
@@ -182,7 +182,7 @@
182
182
  "body": [
183
183
  {
184
184
  "type": "wrapper",
185
- "className": "steedos-instance-detail-wrapper m-0 p-0 flex-1 focus:outline-none lg:order-last sm:m-4 shadow sm:rounded",
185
+ "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
186
  "body": [
187
187
  {
188
188
  "type": "service",
@@ -7,7 +7,21 @@ const _ = require('lodash');
7
7
  router.delete('/api/workflow/v2/attachment/:instanceId/:id', requireAuthentication, async function (req, res) {
8
8
  try {
9
9
  const { instanceId, id} = req.params;
10
- await getObject('cfs_instances_filerecord').delete(id);
10
+ const fileObject = getObject('cfs_instances_filerecord');
11
+ await fileObject.delete(id);
12
+
13
+ const files = await fileObject.find({
14
+ filters: [['metadata.parent', '=', instanceId]],
15
+ sort: 'uploadedAt desc',
16
+ top: 1
17
+ });
18
+
19
+ if (files && files.length > 0) {
20
+ const current = files[0];
21
+ const metadata = Object.assign({}, current.metadata || {}, { current: true });
22
+ await fileObject.update(current._id, { metadata });
23
+ }
24
+
11
25
  res.status(200).send({
12
26
  status: 0
13
27
  })
@@ -39,7 +39,7 @@ const FlowversionAPI = {
39
39
  return str.replace(/\"/g, "&quot;").replace(/\n/g, "<br/>");
40
40
  },
41
41
 
42
- getStepHandlerName: async function (step, insId) {
42
+ getStepHandlerName: async function (step, insId, instance) {
43
43
  const db = {
44
44
  users: await getCollection('users'),
45
45
  // flow_roles: await getCollection('flow_roles')
@@ -53,9 +53,22 @@ const FlowversionAPI = {
53
53
  return stepHandlerName;
54
54
  }
55
55
  let userIds = await getHandlersManager.getHandlers(insId, stepId, loginUserId);
56
+
57
+ // 如果没有找到处理人,从instance的step_approve中查找
58
+ if ((!userIds || userIds.length === 0) && instance?.step_approve && stepId) {
59
+ let stepApproveUserId = instance.step_approve[stepId];
60
+ if (stepApproveUserId) {
61
+ if (typeof stepApproveUserId === 'string') {
62
+ userIds = [stepApproveUserId];
63
+ } else if (Array.isArray(stepApproveUserId)) {
64
+ userIds = stepApproveUserId;
65
+ }
66
+ }
67
+ }
68
+
56
69
  let usersCol = db.users;
57
70
  let approverNames = [];
58
- for (let userId of userIds) {
71
+ for (let userId of userIds || []) {
59
72
  let user = await usersCol.findOne({ _id: userId }, { projection: { name: 1 } });
60
73
  if (user) {
61
74
  approverNames.push(user.name);
@@ -111,21 +124,22 @@ const FlowversionAPI = {
111
124
  return nodeStr;
112
125
  },
113
126
 
114
- getStepName: async function (step, cachedStepNames, instance_id) {
127
+ getStepName: async function (step, cachedStepNames, instance_id, instance) {
115
128
  // 返回step节点名称,优先从缓存cachedStepNames中取,否则调用getStepLabel生成
116
129
  let cachedStepName = cachedStepNames[step._id];
117
130
  if (cachedStepName) {
118
131
  return cachedStepName;
119
132
  }
120
- let stepHandlerName = await FlowversionAPI.getStepHandlerName(step, instance_id);
133
+ let stepHandlerName = await FlowversionAPI.getStepHandlerName(step, instance_id, instance);
121
134
  let stepName = FlowversionAPI.getStepLabel(step.name, stepHandlerName);
122
135
  cachedStepNames[step._id] = stepName;
123
136
  return stepName;
124
137
  },
125
138
 
126
- generateStepsGraphSyntax: async function (steps, currentStepId, isConvertToString, direction, instance_id) {
139
+ generateStepsGraphSyntax: async function (steps, currentStepId, isConvertToString, direction, instance_id, instance) {
127
140
  let nodes = [`graph ${direction}`];
128
141
  let cachedStepNames = {};
142
+ let skipSteps = new Set(instance?.skip_steps || []);
129
143
  for (let step of steps) {
130
144
  let lines = step.lines;
131
145
  if (lines?.length) {
@@ -136,13 +150,17 @@ const FlowversionAPI = {
136
150
  if (step.step_type === "condition") {
137
151
  nodes.push(` class ${step._id} condition;`);
138
152
  }
139
- stepName = await FlowversionAPI.getStepName(step, cachedStepNames, instance_id);
153
+ stepName = await FlowversionAPI.getStepName(step, cachedStepNames, instance_id, instance);
140
154
  } else {
141
155
  stepName = "";
142
156
  }
157
+ // Mark skipped steps
158
+ if (skipSteps.has(step._id)) {
159
+ nodes.push(` class ${step._id} skip-step;`);
160
+ }
143
161
  // 原findPropertyByPK("_id",line.to_step),转为find
144
162
  let toStep = steps.find(s => s._id === line.to_step);
145
- let toStepName = await FlowversionAPI.getStepName(toStep, cachedStepNames, instance_id);
163
+ let toStepName = await FlowversionAPI.getStepName(toStep, cachedStepNames, instance_id, instance);
146
164
  nodes.push(` ${step._id}("${stepName}")-->${line.to_step}("${toStepName}")`);
147
165
  }
148
166
  }
@@ -487,13 +505,13 @@ const FlowversionAPI = {
487
505
  break;
488
506
  }
489
507
  default: {
490
- let instance = await db.instances.findOne({ _id: instance_id }, { projection: { flow_version: 1, flow: 1, traces: { $slice: -1 } } });
508
+ let instance = await db.instances.findOne({ _id: instance_id }, { projection: { flow_version: 1, flow: 1, step_approve: 1, skip_steps: 1, traces: { $slice: -1 } } });
491
509
  if (instance) {
492
510
  let currentStepId = instance.traces?.[0]?.step;
493
511
  let flowversion = await WorkflowManager.getInstanceFlowVersion(instance);
494
512
  let steps = flowversion?.steps;
495
513
  if (steps?.length) {
496
- graphSyntax = await FlowversionAPI.generateStepsGraphSyntax(steps, currentStepId, false, direction, instance_id);
514
+ graphSyntax = await FlowversionAPI.generateStepsGraphSyntax(steps, currentStepId, false, direction, instance_id, instance);
497
515
  } else {
498
516
  error_msg = "没有找到当前申请单的流程步骤数据";
499
517
  }
@@ -557,6 +575,20 @@ const FlowversionAPI = {
557
575
  stroke: rgb(204, 204, 255);
558
576
  stroke-width: 1px;
559
577
  }
578
+ #flow-steps-svg .node.skip-step rect{
579
+ fill: #e8e8e8;
580
+ stroke: #999999;
581
+ stroke-width: 2px;
582
+ stroke-dasharray: 5, 5;
583
+ opacity: 0.7;
584
+ }
585
+ #flow-steps-svg .node.skip-step .step-name{
586
+ color: #666666;
587
+ text-decoration: line-through;
588
+ }
589
+ #flow-steps-svg .node.skip-step .step-handler-name{
590
+ color: #999999;
591
+ }
560
592
  #flow-steps-svg .node .trace-handler-name{
561
593
  color: #777;
562
594
  }
@@ -401,7 +401,7 @@ router.post('/api/workflow/v2/set_instance_steps', requireAuthentication, async
401
401
  skip_steps: stepId
402
402
  }
403
403
  }
404
- await objectql.getObject('instances').update(instanceId, doc);
404
+ await objectql.getObject('instances').directUpdate(instanceId, doc);
405
405
 
406
406
  return res.status(200).send({ status: 0 });
407
407
  } catch (error) {
@@ -14,6 +14,7 @@ const { excuteTriggers } = require('../utils/trigger');
14
14
  const objectql = require('@steedos/objectql');
15
15
  const WorkflowManager = require('../manager/workflow_manager');
16
16
  const UUFlowManager = require('../manager/uuflow_manager');
17
+ const { t } = require('@steedos/i18n');
17
18
 
18
19
  const getFieldName = (fields, fieldId)=>{
19
20
  const field = _.find(fields, (item)=>{
@@ -167,7 +168,8 @@ router.post('/api/workflow/v2/nextStepUsers', requireAuthentication, async funct
167
168
  }
168
169
 
169
170
  if (!nextStepUsers || nextStepUsers.length < 1) {
170
- error = "ROLE_NO_MEMBERS";
171
+ const roles = await WorkflowManager.getRoles(instance.space, approverRoleIds);
172
+ error = t('next_step_users_not_found.applicant_role', {role_name: _.join(_.map(roles, 'name'), ', ')}, userSession.language)
171
173
  }
172
174
  } else {
173
175
  error = "请先填写表单值";
@@ -189,7 +191,10 @@ router.post('/api/workflow/v2/nextStepUsers', requireAuthentication, async funct
189
191
  }
190
192
 
191
193
  if (!nextStepUsers || nextStepUsers.length < 1) {
192
- error = "ROLE_NO_MEMBERS";
194
+
195
+ const roles = await WorkflowManager.getRoles(instance.space, approverRoleIds);
196
+ console.log(`approverRoleIds`, approverRoleIds, roles)
197
+ error = t('next_step_users_not_found.applicant_role', {role_name: _.join(_.map(roles, 'name'), ', ')}, userSession.language)
193
198
  }
194
199
  } else {
195
200
  error = "请先填写表单值";
@@ -276,11 +276,31 @@
276
276
  if(field.steedos_field){
277
277
  return {
278
278
  type: `sfield-${_.toLower(_.camelCase(field.steedos_field.type))}`,
279
- config: field.steedos_field
279
+ config: field.steedos_field,
280
+ _id: field._id
280
281
  }
281
282
  }
282
283
 
284
+ // Handle new approval_comments field format from migration
285
+ if(field.type === 'steedos-field' && field.config?.type === 'approval_comments'){
286
+ return {
287
+ type: 'sfield-approvalcomments',
288
+ _id: field._id || field.id,
289
+ label: field.config.label,
290
+ name: field.config.name,
291
+ required: field.is_required || field.required,
292
+ className: (field.is_wide ? 'is_wide' : '') +
293
+ (field.is_list_display ? ' is_list_display' : '') +
294
+ (field.is_searchable ? ' is_searchable' : ''),
295
+ id: field.id,
296
+ config: field.config,
297
+ visibleOn: field.visibleOn,
298
+ requiredOn: field.requiredOn
299
+ };
300
+ }
301
+
283
302
  const tpl = {
303
+ _id: field._id,
284
304
  label: field.name || field.code,
285
305
  name: field.code,
286
306
  required: field.is_required,
@@ -1,6 +1,7 @@
1
1
  const _ = require('lodash');
2
2
  const desingerManager = require('../utils/designerManager');
3
3
  const objectql = require("@steedos/objectql");
4
+ const auth = require("@steedos/auth");
4
5
  const { ObjectId } = require("mongodb");
5
6
  const AmisInputTypes = [
6
7
  //44个表单项
@@ -139,7 +140,6 @@ function getFinalFormFields(inputFields) {
139
140
  const temp = transformFormFields(amisField);
140
141
  finalFormFields.push(temp)
141
142
  })
142
-
143
143
  return finalFormFields
144
144
  }
145
145
 
@@ -160,7 +160,7 @@ function transformFormFields(amisField) {
160
160
 
161
161
  if(amisField.type === 'steedos-field'){
162
162
  const sfield = {
163
- _id: amisField.config.name,
163
+ _id: amisField._id || amisField.config.name,
164
164
  code: amisField.config.name,
165
165
  name: amisField.config.label,
166
166
  is_wide: amisField.config.is_wide,
@@ -188,7 +188,7 @@ function transformFormFields(amisField) {
188
188
  };
189
189
 
190
190
  let formFieldsItem = {
191
- _id: new ObjectId().toHexString(),
191
+ _id: amisField._id || new ObjectId().toHexString(),
192
192
  code: amisField.name || amisField.title,
193
193
  name: amisField.label || amisField.title,
194
194
  is_wide: _.includes(amisField.className, "is_wide"),
@@ -559,7 +559,9 @@ module.exports = {
559
559
  let updatedFlows = [];
560
560
  let userId = this.userId || this.doc?.modified_by;
561
561
  let spaceId = this.spaceId || this.doc?.space;
562
- let roles = this.roles;
562
+
563
+ let userSession = await auth.getSessionByUserId(userId, spaceId)
564
+ let roles = userSession.roles;
563
565
  // 执行者的身份校验
564
566
  await desingerManager.checkSpaceUserBeforeUpdate(spaceId, userId, roles);
565
567
  // 更新表单
@@ -146,12 +146,11 @@ async function checkSpaceUserBeforeUpdate(spaceId, userId, roles) {
146
146
  let spaceUser = (await getObject('space_users').find({
147
147
  filters: `(space eq '${spaceId}') and (user eq '${userId}')`
148
148
  }))[0];
149
-
150
149
  if (!spaceUser) {
151
150
  throw new Error('该用户不存在于该工作区中');
152
151
  }
153
152
 
154
- if (!roles.includes('workflow_admin')) { // 校验是否是单位管理员
153
+ if (!_.includes(roles, 'workflow_admin')) { // 校验是否是单位管理员
155
154
  throw new Error('该用户无操作权限');
156
155
  }
157
156
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steedos-labs/plugin-workflow",
3
- "version": "3.0.21",
3
+ "version": "3.0.23",
4
4
  "main": "package.service.js",
5
5
  "license": "MIT",
6
6
  "scripts": {
@@ -505,6 +505,9 @@ tbody .color-priority-muted *{
505
505
  color: #40a9ff
506
506
  }
507
507
 
508
+ .steedos-instance-print-wrapper .liquid-amis-container{
509
+ width: 190mm;
510
+ }
508
511
 
509
512
  @media (max-width: 768px){
510
513
  /* 审批单详细页手机端附件预览按钮样式 */