@steedos-labs/plugin-workflow 3.0.0 → 3.0.1-beta.2

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.
Files changed (24) hide show
  1. package/main/default/client/socket.client.js +46 -3
  2. package/main/default/manager/instance_manager.js +20 -6
  3. package/main/default/manager/uuflow_manager.js +3 -1
  4. package/main/default/methods/instance_approve.js +258 -0
  5. package/main/default/methods/trace_approve_cc.js +13 -10
  6. package/main/default/objectTranslations/forms.en/forms.en.objectTranslation.yml +191 -0
  7. package/main/default/objectTranslations/forms.zh-CN/forms.zh-CN.objectTranslation.yml +246 -0
  8. package/main/default/objectTranslations/instance_tasks.en/instance_tasks.en.objectTranslation.yml +2 -0
  9. package/main/default/objectTranslations/instance_tasks.zh-CN/instance_tasks.zh-CN.objectTranslation.yml +2 -0
  10. package/main/default/objects/forms/forms.object.yml +46 -0
  11. package/main/default/pages/flowdetail.page.amis.json +2 -2
  12. package/main/default/pages/instance_detail.page.amis.json +22 -34
  13. package/main/default/pages/instance_tasks_detail.page.amis.json +18 -2
  14. package/main/default/routes/afterHook.js +34 -0
  15. package/main/default/routes/amis_form_design.ejs +67 -26
  16. package/main/default/routes/api_have_read.router.js +73 -0
  17. package/main/default/routes/api_workflow_approve_save.router.js +2 -1
  18. package/main/default/routes/api_workflow_engine.router.js +3 -3
  19. package/main/default/routes/api_workflow_flow_version.router.js +61 -0
  20. package/main/default/routes/api_workflow_form_version.router.js +61 -0
  21. package/main/default/routes/api_workflow_next_step_users.router.js +1 -1
  22. package/main/default/routes/api_workflow_relocate.router.js +2 -1
  23. package/main/default/routes/flow_form_design.ejs +57 -18
  24. package/package.json +1 -1
@@ -0,0 +1,246 @@
1
+ name: forms
2
+ label: 表单
3
+ description:
4
+ fields:
5
+ name:
6
+ label: 表单
7
+ help:
8
+ description:
9
+ state:
10
+ label: 表单状态
11
+ help:
12
+ options:
13
+ - label: 启用
14
+ value: enabled
15
+ - label: 停用
16
+ value: disabled
17
+ description:
18
+ description:
19
+ label: 表单描述
20
+ help:
21
+ description:
22
+ category:
23
+ label: 表单分类
24
+ help:
25
+ description:
26
+ is_valid:
27
+ label: 是否有效
28
+ help:
29
+ description:
30
+ instance_style:
31
+ label: 样式
32
+ help:
33
+ options:
34
+ - label: 表格
35
+ value: table
36
+ - label: 默认
37
+ value: default
38
+ description:
39
+ historys:
40
+ label: 历史版本
41
+ help:
42
+ description:
43
+ approve_on_create:
44
+ label: 是否同意审批
45
+ help:
46
+ description:
47
+ approve_on_modify:
48
+ label: 是否修改审批
49
+ help:
50
+ description:
51
+ approve_on_delete:
52
+ label: 是否删除审批
53
+ help:
54
+ description:
55
+ enable_workflow:
56
+ label: 是否启用工作流
57
+ help:
58
+ description:
59
+ enable_view_others:
60
+ label: 是否查看其它表单
61
+ help:
62
+ description:
63
+ current:
64
+ label: 当前版本
65
+ help:
66
+ description:
67
+ current.form_script:
68
+ label: 表单脚本
69
+ help:
70
+ description:
71
+ current.name_forumla:
72
+ label: 标题公式
73
+ help:
74
+ description:
75
+ current.fields:
76
+ label: 字段
77
+ help:
78
+ description:
79
+ current.fields.$.code:
80
+ label: Api 名称
81
+ help:
82
+ description:
83
+ current.fields.$.name:
84
+ label: 名称
85
+ help:
86
+ description:
87
+ current.fields.$.type:
88
+ label: 类型
89
+ help:
90
+ options:
91
+ - label: 勾选框
92
+ value: checkbox
93
+ - label: 日期时间
94
+ value: dateTime
95
+ - label: 日期
96
+ value: date
97
+ - label: 时间
98
+ value: time
99
+ - label: 电子邮件
100
+ value: email
101
+ - label: Group
102
+ value: group
103
+ - label: 输入框
104
+ value: input
105
+ - label: 多选框
106
+ value: multiSelect
107
+ - label: 数字框
108
+ value: number
109
+ - label: 密码
110
+ value: password
111
+ - label: 单选框
112
+ value: radio
113
+ - label: 分组
114
+ value: section
115
+ - label: 下拉框
116
+ value: select
117
+ - label: 表格
118
+ value: table
119
+ - label: 链接
120
+ value: url
121
+ - label: 选择用户
122
+ value: user
123
+ - label: Geolocation
124
+ value: geolocation
125
+ - label: 图片
126
+ value: image
127
+ - label: 附件
128
+ value: file
129
+ - label: 相关记录
130
+ value: lookup
131
+ - label: 文本
132
+ value: text
133
+ - label: 长文本
134
+ value: textarea
135
+ - label: 富文本
136
+ value: html
137
+ - label: 代码
138
+ value: code
139
+ - label: Markdown
140
+ value: markdown
141
+ - label: 选择框
142
+ value: select
143
+ - label: 颜色
144
+ value: color
145
+ - label: 复选框
146
+ value: boolean
147
+ - label: 开关
148
+ value: toggle
149
+ - label: 日期
150
+ value: date
151
+ - label: 日期时间
152
+ value: datetime
153
+ - label: 时间
154
+ value: time
155
+ - label: 数值
156
+ value: number
157
+ - label: 金额
158
+ value: currency
159
+ - label: 百分比
160
+ value: percent
161
+ - label: 密码
162
+ value: password
163
+ - label: 相关表关系
164
+ value: lookup
165
+ - label: 主/子表关系
166
+ value: master_detail
167
+ - label: 自动编号
168
+ value: autonumber
169
+ - label: 网址
170
+ value: url
171
+ - label: 邮件地址
172
+ value: email
173
+ - label: 地理位置
174
+ value: location
175
+ - label: 图片
176
+ value: image
177
+ - label: 附件
178
+ value: file
179
+ - label: 公式
180
+ value: formula
181
+ - label: 累计汇总
182
+ value: summary
183
+ description:
184
+ current.fields.$.is_required:
185
+ label: 必填
186
+ help:
187
+ description:
188
+ current.fields.$.is_wide:
189
+ label: 宽字段
190
+ help:
191
+ description:
192
+ current.fields.$.is_list_display:
193
+ label: 显示在列表内
194
+ help:
195
+ description:
196
+ current.fields.$.is_searchable:
197
+ label: 可搜索
198
+ help:
199
+ description:
200
+ current.fields.$.is_multiselect:
201
+ label: 可复选
202
+ help:
203
+ description:
204
+ current.fields.$.visibleOn:
205
+ label: 显隐的条件
206
+ listviews:
207
+ all:
208
+ label: 所有
209
+ actions:
210
+ standard_new:
211
+ label: 新建
212
+ standard_edit:
213
+ label: 编辑
214
+ standard_delete:
215
+ label: 删除
216
+ designForm:
217
+ label: 表单设计器
218
+ CustomLabels:
219
+ _forms_field_code_error: 字段名 %s 不能包含'.'
220
+ forms_field_current.fields:
221
+ forms_field_current.fields_$_code:
222
+ forms_field_current.fields_$_is_list_display:
223
+ forms_field_current.fields_$_is_multiselect:
224
+ forms_field_current.fields_$_is_required:
225
+ forms_field_current.fields_$_is_searchable:
226
+ forms_field_current.fields_$_is_wide:
227
+ forms_field_current.fields_$_name:
228
+ forms_field_current.fields_$_type:
229
+ forms_field_current.fields_$_type_options_checkbox:
230
+ forms_field_current.fields_$_type_options_date:
231
+ forms_field_current.fields_$_type_options_dateTime:
232
+ forms_field_current.fields_$_type_options_email:
233
+ forms_field_current.fields_$_type_options_geolocation:
234
+ forms_field_current.fields_$_type_options_group:
235
+ forms_field_current.fields_$_type_options_input:
236
+ forms_field_current.fields_$_type_options_multiSelect:
237
+ forms_field_current.fields_$_type_options_number:
238
+ forms_field_current.fields_$_type_options_password:
239
+ forms_field_current.fields_$_type_options_radio:
240
+ forms_field_current.fields_$_type_options_section:
241
+ forms_field_current.fields_$_type_options_select:
242
+ forms_field_current.fields_$_type_options_table:
243
+ forms_field_current.fields_$_type_options_url:
244
+ forms_field_current.fields_$_type_options_user:
245
+ forms_field_current.form_script:
246
+ forms_field_current.name_forumla:
@@ -209,3 +209,5 @@ listviews:
209
209
  actions:
210
210
  instance_new:
211
211
  label: New
212
+ CustomLabels:
213
+ instance_task_set_have_read_failed: Set as read failed
@@ -209,3 +209,5 @@ listviews:
209
209
  actions:
210
210
  instance_new:
211
211
  label: 新建
212
+ CustomLabels:
213
+ instance_task_set_have_read_failed: 设置为已读失败
@@ -209,6 +209,52 @@ fields:
209
209
  value: file
210
210
  - label: Lookup
211
211
  value: lookup
212
+ - label: Steedos Field
213
+ value: steedos-field
214
+ - label: Text
215
+ value: text
216
+ - label: Textarea
217
+ value: textarea
218
+ - label: Html
219
+ value: html
220
+ - label: Lookup
221
+ value: lookup
222
+ - label: Master Detail
223
+ value: master_detail
224
+ - label: Select
225
+ value: select
226
+ - label: Boolean
227
+ value: boolean
228
+ - label: Date
229
+ value: date
230
+ - label: Datetime
231
+ value: datetime
232
+ - label: Time
233
+ value: time
234
+ - label: Number
235
+ value: number
236
+ - label: Currency
237
+ value: currency
238
+ - label: Percent
239
+ value: percent
240
+ - label: Image
241
+ value: image
242
+ - label: File
243
+ value: file
244
+ - label: Code
245
+ value: code
246
+ - label: Markdown
247
+ value: markdown
248
+ - label: Color
249
+ value: color
250
+ - label: Toggle
251
+ value: toggle
252
+ - label: Password
253
+ value: password
254
+ - label: Url
255
+ value: url
256
+ - label: Email
257
+ value: email
212
258
  readonly: true
213
259
  name: current.fields.$.type
214
260
  filterable: true
@@ -615,7 +615,7 @@
615
615
  "id": "u:5df987ad9bc8",
616
616
  "className": "bg-white",
617
617
  "mode": "edit",
618
- "initApiAdaptor": "_.each(payload.data.current.fields, (item)=>{if(item.type =='table' || item.type == 'section'){ var _item = _.find(payload.data.current.fields, function(__item){return __item.code == item.code}); if(_item){_item.children = item.fields;} }}); return payload",
618
+ "initApiAdaptor": "_.each(payload.data.current.fields, (item)=>{if(item.type=='steedos-field'){item.type = item.config.type} if(item.type =='table' || item.type == 'section'){ var _item = _.find(payload.data.current.fields, function(__item){return __item.code == item.code}); if(_item){_item.children = item.fields;} }}); return payload",
619
619
  "fields": [
620
620
  "current",
621
621
  "current.fields",
@@ -630,7 +630,7 @@
630
630
  "current.fields.$.visibleOn"
631
631
  ],
632
632
  "fieldsExtend": "{\n \"current\": {\n \"label\": false\n },\n \"current.fields\": {\n \"label\": false\n }\n}",
633
- "formDataFilter": "if (!form.onEvent.change) {\n form.onEvent.change = { actions: [] }\n};\nform.onEvent.change.actions.push({\n actionType: \"custom\",\n script: \"console.log('onChange event.data', event.data)\"\n}, {\n \"actionType\": \"ajax\",\n \"outputVar\": \"responseResult\",\n \"args\": {\n \"options\": { \"silent\": false },\n \"api\": {\n \"url\": \"/api/workflow/updateFormFields\",\n \"method\": \"post\",\n \"requestAdaptor\": `\n console.log('api.data', api, 'context', context);\n var fields = (context.current.fields || []).map(function(item){\n // 有时编辑children子行记录时未同步到fields属性值中,造成保存数据不成功\n if(item.children){\n var newItem = _.clone(item);\n newItem.fields = newItem.children;\n delete newItem.children;\n return newItem;\n }\n else{\n return item;\n }\n });\n api.data = { \n formId: context.current.form, \n fields: fields\n };\n return api;\n `,\n \"adaptor\": \"\",\n \"messages\": {},\n \"dataType\": \"json\"\n }\n }\n})"
633
+ "formDataFilter": "if (!form.onEvent.change) {\n form.onEvent.change = { actions: [] }\n};\nform.onEvent.change.actions.push({\n actionType: \"custom\",\n script: \"console.log('onChange event.data', event.data)\"\n}, {\n \"actionType\": \"ajax\",\n \"outputVar\": \"responseResult\",\n \"args\": {\n \"options\": { \"silent\": false },\n \"api\": {\n \"url\": \"/api/workflow/updateFormFields\",\n \"method\": \"post\",\n \"requestAdaptor\": `\n console.log('api.data', api, 'context', context);\n var fields = (context.current.fields || []).map(function(item){\n if(item.config.type){item.type='steedos-field'} // 有时编辑children子行记录时未同步到fields属性值中,造成保存数据不成功\n if(item.children){\n var newItem = _.clone(item);\n newItem.fields = newItem.children;\n delete newItem.children;\n return newItem;\n }\n else{\n return item;\n }\n });\n api.data = { \n formId: context.current.form, \n fields: fields\n };\n return api;\n `,\n \"adaptor\": \"\",\n \"messages\": {},\n \"dataType\": \"json\"\n }\n }\n})"
634
634
  }
635
635
  ],
636
636
  "id": "u:827750209c5d",
@@ -85,46 +85,34 @@
85
85
  "visibleOn": "false"
86
86
  }
87
87
  },
88
+ {
89
+ "type": "button",
90
+ "label": "刷新",
91
+ "className": "steedos-workflow-reload-btn hidden",
92
+ "onEvent": {
93
+ "click": {
94
+ "actions": [
95
+ {
96
+ "componentId": "u:d6db0c84f150",
97
+ "groupType": "component",
98
+ "actionType": "rebuild"
99
+ }
100
+ ]
101
+ }
102
+ }
103
+ },
88
104
  {
89
105
  "type": "wrapper",
90
106
  "className": "steedos-instance-detail-wrapper m-0 p-0 flex-1 focus:outline-none lg:order-last sm:m-4 shadow sm:rounded",
91
107
  "body": [{
92
108
  "type": "service",
93
109
  "id": "u:d6db0c84f150",
94
- "body": [{
95
- "type": "wrapper",
96
- "className": "p-0 h-full",
97
- "body": [{
98
- "type": "steedos-instance-detail",
99
- "id": "u:40052b3812c1",
100
- "label": "Instance Detail",
101
- "instanceId": "${recordId}",
102
- "boxName": "${side_listview_id}",
103
- "hiddenOn": "!!!this.recordId"
104
- }],
105
- "visibleOn": "${window:InstanceDetailEnabledAmisRender != false}",
106
- "id": "u:829a40757f0a"
107
- },
108
- {
109
- "type": "wrapper",
110
- "className": "workflow-main flex w-full h-full no-columns instance-show instance-detail-service-wrapper",
111
- "visibleOn": "${window:InstanceDetailEnabledAmisRender == false}",
112
- "body": [{
113
- "type": "custom",
114
- "html": "<div className='workflow-main flex w-full h-full no-columns instance-show instance-detail-service-wrapper'></div>",
115
- "onMount": "try {\n Session.set(\"instance_change\", false);\n\n Session.set(\"instance_loading\", true);\n Session.set(\"judge\", null);\n Session.set(\"next_step_id\", null);\n Session.set(\"next_step_multiple\", null);\n Session.set(\"next_user_multiple\", null);\n let box;\n let recordId;\n if (props.data._inDrawer) {\n // 主表记录详细页面审批相关列表中点击名称字段右侧弹出drawer时,box写死,recordId取作用域中值\n box = \"outbox\";\n recordId = props.data.recordId;\n }\n else {\n box = props.data.side_listview_id;\n recordId = Session.get(\"record_id\");\n }\n Session.set(\"box\", box);\n Session.set(\"instanceId\", recordId);\n Session.set(\"instanceTaskId\", null);\n window.instanceDetailBlazeRenderView = Blaze.render(Blaze._getTemplate('instance_view_wrapper'), document.getElementsByClassName('instance-detail-service-wrapper')[0])\n} catch (error) {\n console.error(error)\n};\nif (window.instanceDetailBlazeRenderView) {\n window.instanceDetailBlazeRenderView.autorun(() => {\n if (FlowRouter.current().params.object_name == \"instances\") {\n console.debug('====onMount=', props);\n Session.set(\"instanceId\", Session.get(\"record_id\"));\n Session.set(\"instanceTaskId\", null)\n }\n }\n )\n};",
116
- "id": "u:a6e0685d1da3",
117
- "onUnmount": "if(window.instanceDetailBlazeRenderView){console.log('Blaze.remove===>instanceDetailBlazeRenderView');Blaze.remove(window.instanceDetailBlazeRenderView); window.instanceDetailBlazeRenderView = null;}"
118
- }],
119
- "id": "u:16cf880c925a",
120
- "style": {
121
- "position": "static",
122
- "display": "block"
123
- },
124
- "isFixedHeight": false,
125
- "isFixedWidth": false
126
- }
127
- ],
110
+ "schemaApi": {
111
+ "method": "get",
112
+ "url": "/api/health_check",
113
+ "adaptor": "return {data: {'type':'wrapper','className':'p-0 h-full','body':[{'type':'steedos-instance-detail','id':'u:40052b3812c1','label':'Instance Detail','instanceId':context.recordId,'boxName':context.side_listview_id}],'id':'u:829a40757f0a'}}"
114
+ },
115
+ "body": {},
128
116
  "className": "h-full",
129
117
  "dsType": "api"
130
118
  }],
@@ -123,8 +123,24 @@
123
123
  "headers": {
124
124
  "Authorization": "Bearer ${context.tenantId},${context.authToken}"
125
125
  },
126
- "requestAdaptor": "\nconst { recordId } = api.body;\napi.data = {\n query: `{instance_task:instance_tasks__findOne(id: \"${recordId}\"){_id,instance}}`\n};\n\nreturn api;",
127
- "adaptor": "\nlet boxName = api.body.side_listview_id === 'inbox' ? 'inbox' : 'outbox';\npayload.data = {\n instanceId: payload.data.instance_task.instance,\n boxName: boxName\n}\n; console.log('=======>payload===>', payload); \nreturn payload;"
126
+ "requestAdaptor": "\nconst { recordId } = api.body;\napi.data = {\n query: `{instance_task:instance_tasks__findOne(id: \"${recordId}\"){_id,instance,is_read}}`\n};\n\nreturn api;",
127
+ "adaptor": "\nlet boxName = api.body.side_listview_id === 'inbox' ? 'inbox' : 'outbox';\npayload.data = {\n instanceId: payload.data.instance_task.instance,\n boxName: boxName,\n isRead: payload.data.instance_task.is_read\n}\n; console.log('=======>payload===>', payload); \nreturn payload;"
128
+ },
129
+ "onEvent": {
130
+ "fetchInited": {
131
+ "actions": [
132
+ {
133
+ "actionType": "ajax",
134
+ "api": {
135
+ "url": "${context.rootUrl}/api/workflow/v2/set_have_read",
136
+ "method": "post",
137
+ "requestAdaptor": "api.data={instanceTaskId: context.recordId, isRead: context.isRead}\n\n\nreturn api;",
138
+ "adaptor": "return payload.success ? {data: {...payload}, status: 0} : {...payload, status: 1, msg: (t('CustomLabels.instance_task_set_have_read_failed') + ':' + payload.error)};"
139
+ },
140
+ "expression": "${!event.data.isRead}"
141
+ }
142
+ ]
143
+ }
128
144
  },
129
145
  "className": "h-full"
130
146
  }
@@ -0,0 +1,34 @@
1
+ const afterHook = (req, res, next) => {
2
+ res.on('finish', () => {
3
+ if (req.url.includes('/api/workflow/v2/approve/save')) {
4
+ const { approve } = req.body;
5
+ const ins_id = approve.instance;
6
+ broker.call('objectql.update', {
7
+ objectName: 'instances',
8
+ id: ins_id,
9
+ doc: {},
10
+ })
11
+ }else if(req.url.includes('/api/workflow/engine')){
12
+ var hashData = req.body;
13
+ const approve_from_client = hashData['Approvals'][0];
14
+ const ins_id = approve_from_client.instance;
15
+ broker.call('objectql.update', {
16
+ objectName: 'instances',
17
+ id: ins_id,
18
+ doc: {},
19
+ })
20
+ }else if(req.ulr.includes('/api/workflow/relocate')){
21
+ var hashData = req.body;
22
+ const instance_from_client = hashData['Instances'][0];
23
+ const ins_id = instance_from_client._id;
24
+ broker.call('objectql.update', {
25
+ objectName: 'instances',
26
+ id: ins_id,
27
+ doc: {},
28
+ })
29
+ }
30
+ });
31
+ next();
32
+ };
33
+
34
+ module.exports = afterHook;
@@ -31,6 +31,22 @@
31
31
 
32
32
  let comp = document.querySelector("builder-fiddle");
33
33
 
34
+ const getArgumentsList = (func)=>{
35
+ let funcString;
36
+ if (typeof func === 'function') {
37
+ funcString = func.toString();
38
+ } else {
39
+ funcString = func;
40
+ }
41
+ const regExp = /function\s*\w*\(([\s\S]*?)\)/;
42
+ if (regExp.test(funcString)) {
43
+ const argList = RegExp.$1.split(',');
44
+ return argList.map(arg => arg.replace(/\s/g, ''));
45
+ } else {
46
+ return [];
47
+ }
48
+ }
49
+
34
50
  const loadPage = async () => {
35
51
  //settings结果集同样加入formId
36
52
  const { assetUrls, rootUrl, userId, tenantId, authToken, id, formId } = settings;
@@ -182,6 +198,7 @@
182
198
  break;
183
199
  case "number":
184
200
  tpl.type = "input-number";
201
+ tpl.precision=2
185
202
  break;
186
203
  case "date":
187
204
  tpl.type = "input-date";
@@ -279,22 +296,22 @@
279
296
  tpl.options = getSelectOptions(field);
280
297
  break;
281
298
  case "odata":
282
- console.log('field', field);
299
+ const argsName = getArgumentsList(field.filters);
283
300
  var labelField = field.formula.substr(1, field.formula.length - 2);
284
301
  labelField = labelField.substr(labelField.indexOf(".") + 1);
285
302
  // 加入odata标签以示区别 把field-老表单设计器的元素加入
286
303
  tpl.type = "select";
287
- tpl.description = field.description
288
- tpl.detail_url = field.detail_url
289
- tpl.filters = field.filters
290
- tpl.formula = field.formula
291
- tpl.is_list_display = field.is_list_display
292
- tpl.is_multiselect = field.is_multiselect
293
- tpl.is_required = field.is_required
294
- tpl.is_searchable = field.is_searchable
295
- tpl.is_wide = field.is_wide
296
- tpl.search_field = field.search_field
297
- tpl._id = field._id
304
+ tpl.description = field.description
305
+ tpl.detail_url = field.detail_url
306
+ tpl.filters = field.filters
307
+ tpl.formula = field.formula
308
+ tpl.is_list_display = field.is_list_display
309
+ tpl.is_multiselect = field.is_multiselect
310
+ tpl.is_required = field.is_required
311
+ tpl.is_searchable = field.is_searchable
312
+ tpl.is_wide = field.is_wide
313
+ tpl.search_field = field.search_field
314
+ tpl._id = field._id
298
315
  // tpl.labelField = labelField;
299
316
  // tpl.valueField = "_value";
300
317
  tpl.source = {
@@ -308,21 +325,45 @@
308
325
  Authorization: "Bearer ${context.tenantId},${context.authToken}",
309
326
  },
310
327
  adaptor: `
311
- payload.data = {
312
- options: _.map(payload.value, (item)=>{
313
- const value = item;
314
- item["@label"] = item["${labelField}"]
315
- delete item['@odata.editLink'];
316
- delete item['@odata.etag'];
317
- delete item['@odata.id'];
318
- return {
319
- label: item["@label"],
320
- value: value
328
+ payload.data = {
329
+ options: _.map(payload.value, (item)=>{
330
+ const value = item;
331
+ item["@label"] = item["${labelField}"]
332
+ delete item['@odata.editLink'];
333
+ delete item['@odata.etag'];
334
+ delete item['@odata.id'];
335
+ return {
336
+ label: item["@label"],
337
+ value: value
338
+ }
339
+ })
340
+ }
341
+ return payload;
342
+ `,
343
+ requestAdaptor: `
344
+ const filters = ${_.replace(field.filters, /_.pluck/g, '_.map')};
345
+ const url = ${field.url}
346
+ if(filters){
347
+ console.log('filters', filters);
348
+ const joinKey = field.url.indexOf('?') > 0 ? '&' : '?';
349
+ if(filters.startsWith('function(') || filters.startsWith('function (')){
350
+ const argsName = ${JSON.stringify(argsName)};
351
+ const fun = eval('_fun='+filters);
352
+ const funArgs = [];
353
+ for(const item of argsName){
354
+ funArgs.push(context[item])
355
+ }
356
+ api.url = url + joinKey + "$filter=" + fun.apply({}, funArgs)
357
+ }else{
358
+ api.url = url + joinKey + "$filter=" + filters
321
359
  }
322
- })
323
- }
324
- return payload;
325
- `
360
+ }else{
361
+ api.url = url
362
+ }
363
+ api.query = {};
364
+ return api;
365
+ `,
366
+ trackExpression: _.join(_.map(argsName, (item)=>{return `\${${item}|json}`}), '-')
326
367
  };
327
368
  break;
328
369
  case "html":
@@ -0,0 +1,73 @@
1
+ /*
2
+ * @Author: 殷亮辉 yinlianghui@hotoa.com
3
+ * @Date: 2025-10-09 10:12:49
4
+ * @LastEditors: 殷亮辉 yinlianghui@hotoa.com
5
+ * @LastEditTime: 2025-10-29 09:38:43
6
+ */
7
+ const express = require("express");
8
+ const router = express.Router();
9
+ const { requireAuthentication } = require("@steedos/auth");
10
+ const objectql = require('@steedos/objectql')
11
+ // const { cc_do } = require('../methods/trace_approve_cc');
12
+ const { getCollection } = require('../utils/collection');
13
+ const { set_approve_have_read } = require('../methods/instance_approve');
14
+ const { cc_read } = require('../methods/trace_approve_cc');
15
+ // const InstanceManager = global.InstanceManager;
16
+ const InstanceManager = require('../manager/instance_manager');
17
+
18
+ router.post('/api/workflow/v2/set_have_read', requireAuthentication, async function (req, res) {
19
+ try {
20
+ let userSession = req.user;
21
+ if (!userSession) {
22
+ return res.status(200).send({
23
+ error: "unauthorized"
24
+ });
25
+ }
26
+ const userId = userSession.userId;
27
+ const { instanceTaskId, isRead } = req.body;
28
+ if (isRead){
29
+ return res.status(200).send({
30
+ success: true
31
+ });
32
+ }
33
+ const db = {
34
+ instances: await getCollection('instances'),
35
+ instance_tasks: await getCollection('instance_tasks')
36
+ };
37
+ const instance_task = await db.instance_tasks.findOne({
38
+ _id: instanceTaskId
39
+ }, {
40
+ fields: {
41
+ "instance": 1,
42
+ "is_read": 1,
43
+ "type": 1
44
+ }
45
+ });
46
+ if (instance_task.is_read){
47
+ return res.status(200).send({
48
+ success: true
49
+ });
50
+ }
51
+
52
+ const instanceId = instance_task.instance;
53
+ const ins = await db.instances.findOne({_id: instanceId});
54
+ var myApprove = InstanceManager.getCurrentApprove(ins, userId, instance_task.type);
55
+ if (instance_task.type == "cc") {
56
+ // 传阅
57
+ await cc_read(ins, myApprove, { userId });
58
+ }
59
+ else{
60
+ await set_approve_have_read(ins._id, myApprove.trace, myApprove._id, { userId });
61
+ }
62
+ return res.status(200).send({
63
+ success: true
64
+ });
65
+
66
+ } catch (error) {
67
+ console.error(error);
68
+ return res.status(200).send({
69
+ error: error.message
70
+ });
71
+ }
72
+ });
73
+ exports.default = router;
@@ -8,8 +8,9 @@ const {
8
8
  const UUFlowManager = require('../manager/uuflow_manager');
9
9
  const { getCollection } = require('../utils/collection');
10
10
  const approveManager = require('../manager/approve_manager');
11
+ const afterHook = require('./afterHook');
11
12
 
12
- router.post('/api/workflow/v2/approve/save', requireAuthentication, async function (req, res) {
13
+ router.post('/api/workflow/v2/approve/save', requireAuthentication, afterHook, async function (req, res) {
13
14
  try {
14
15
  const userSession = req.user;
15
16
  const { approve } = req.body;