@steedos-labs/plugin-workflow 3.0.10 → 3.0.12

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.
@@ -4279,6 +4279,11 @@ UUFlowManager.draft_save_instance = async function (ins, userId) {
4279
4279
 
4280
4280
  if (form?.current?.name_forumla) {
4281
4281
  setObj.name = await UUFlowManager.getInstanceName(ins, values);
4282
+ if(result !== 'upgraded'){
4283
+ result = {
4284
+ name: setObj.name
4285
+ }
4286
+ }
4282
4287
  }
4283
4288
 
4284
4289
  await db.instances.updateOne(
@@ -286,7 +286,7 @@ actions:
286
286
  designForm:
287
287
  label: 表单设计器
288
288
  design_form_layout:
289
- label: 表单设计器(New)
289
+ label: 表单设计器
290
290
  enableFlow:
291
291
  label: 启用
292
292
  disableFlow:
@@ -693,10 +693,7 @@ actions:
693
693
  type: amis_button
694
694
  design:
695
695
  label: Designer
696
- visible: !<tag:yaml.org,2002:js/function> |-
697
- function () {
698
- return true;
699
- }
696
+ visible: false
700
697
  'on': list
701
698
  todo: !<tag:yaml.org,2002:js/function> |-
702
699
  function (object_name, record_id, fields) {
@@ -840,7 +837,7 @@ actions:
840
837
  'on': record_more
841
838
  visible: !<tag:yaml.org,2002:js/function> |-
842
839
  function () {
843
- return true;
840
+ return false;
844
841
  }
845
842
  todo: !<tag:yaml.org,2002:js/function> |-
846
843
  function (object_name, record_id, fields) {
@@ -13,14 +13,11 @@ amis_schema: |-
13
13
  {
14
14
  "args": {
15
15
  "api": {
16
- "url": "${context.rootUrl}/api/workflow/v2/remove",
16
+ "url": "/api/workflow/v2/remove",
17
17
  "method": "post",
18
18
  "requestAdaptor": "api.data = {\n instance: {\n _id: context.context._id\n }\n}\n\nreturn api;",
19
19
  "data": {
20
20
  "record_id": "$record_id"
21
- },
22
- "headers": {
23
- "Authorization": "Bearer ${context.tenantId},${context.authToken}"
24
21
  }
25
22
  },
26
23
  "messages": {}
@@ -30,28 +27,11 @@ amis_schema: |-
30
27
  {
31
28
  "ignoreError": false,
32
29
  "actionType": "custom",
33
- "script": "navigate('/app/approve_workflow/instances/grid/draft?additionalFilters=&flowId=&categoryId=')"
34
- },
35
- {
36
- "actionType": "broadcast",
37
- "args": {
38
- "eventName": "@data.changed.instances"
39
- },
40
- "data": {
41
- "objectName": "instances",
42
- "__deletedRecord": true
43
- }
30
+ "script": "SteedosWorkflow.Instance.changed=false; navigate('/app/approve_workflow/instances/view/none?side_object=instances&side_listview_id=draft&additionalFilters=&flowId=&categoryId=')"
44
31
  },
45
32
  {
46
- "actionType": "broadcast",
47
- "args": {
48
- "eventName": "@data.changed.steedos_keyvalues"
49
- },
50
- "data": {
51
- "type": "",
52
- "keyvalue": "",
53
- "keyvalues": "${ss:keyvalues}"
54
- }
33
+ "actionType": "custom",
34
+ "script":"window.$('.list-view-btn-reload').click()"
55
35
  }
56
36
  ],
57
37
  "weight": 0
@@ -18,16 +18,16 @@ amis_schema: |-
18
18
  "type": "dialog",
19
19
  "title": "${'CustomLabels.instance_action_new_dialog_title' | t}",
20
20
  "body": [
21
- {
22
- "type": "steedos-select-flow",
23
- "id": "instanceNewFlowSelect",
24
- "showIcon": true,
25
- "showRadio": false,
26
- "onlyLeaf": true,
27
- "name": "flow",
28
- "action": "new",
29
- "onEvent": {
30
- "change": {
21
+ {
22
+ "type": "service",
23
+ "dsType": "api",
24
+ "schemaApi": {
25
+ "url": "/api/v6/functions/pages/schema?pageId=flow_selector",
26
+ "method": "get"
27
+ },
28
+ "initFetchSchema": true,
29
+ "onEvent": {
30
+ "flows.selected": {
31
31
  "weight": 0,
32
32
  "actions": [
33
33
  {
@@ -82,7 +82,7 @@ amis_schema: |-
82
82
  "closeOnEsc": true,
83
83
  "closeOnOutside": false,
84
84
  "showCloseButton": true,
85
- "size": "lg",
85
+ "size": "xl",
86
86
  "actions": false
87
87
  }
88
88
  }
@@ -18,10 +18,7 @@ amis_schema: |-
18
18
  "method": "post",
19
19
  "sendOn": "",
20
20
  "requestAdaptor": "var _SteedosUI$getRef$get, _approveValues$next_s;\nconst formValues = context._scoped.getComponentById(\"instance_form\").getValues();const _formValues = JSON.parse(JSON.stringify(formValues)); if(_formValues){delete _formValues.__applicant} \nconst approveValues = (_SteedosUI$getRef$get = context._scoped.getComponentById(\"instance_approval\")) === null || _SteedosUI$getRef$get === void 0 ? void 0 : _SteedosUI$getRef$get.getValues();\nlet nextUsers = approveValues === null || approveValues === void 0 ? void 0 : approveValues.next_users;\nif (_.isString(nextUsers)) {\n nextUsers = [approveValues.next_users];\n}\nconst instance = context.record;\nconst body = {\n instance: {\n _id: instance._id,\n applicant: formValues.applicant.user,\n submitter: formValues.submitter,\n traces: [{\n _id: instance.trace._id,\n step: instance.step._id,\n approves: [{\n _id: instance.approve._id,\n next_steps: [{\n step: approveValues === null || approveValues === void 0 || (_approveValues$next_s = approveValues.next_step) === null || _approveValues$next_s === void 0 ? void 0 : _approveValues$next_s._id,\n users: nextUsers\n }],\n description: approveValues === null || approveValues === void 0 ? void 0 : approveValues.suggestion,\n values: _formValues\n }]\n }]\n }\n};\napi.data = body;\nreturn api;",
21
- "adaptor": "window.SteedosWorkflow.Instance.changed = false; if (payload.instance == \"upgraded\") { window.setTimeout(function(){ window.location.reload(); }, 2000); return {...payload, status: 1, msg: t('instance_action_instance_save_msg_upgraded')}; } \n return payload.instance === true ? {...payload, status: 0, msg: t('instance_action_instance_save_msg_success')} : {...payload, status: 1, msg: t('instance_action_instance_save_msg_failed')};",
22
- "headers": {
23
- "Authorization": "Bearer ${context.tenantId},${context.authToken}"
24
- },
21
+ "adaptor": "window.SteedosWorkflow.Instance.changed = false; if (payload.instance == \"upgraded\") { window.setTimeout(function(){ $('.steedos-workflow-reload-btn').trigger('click'); }, 2000); return {...payload, status: 1, msg: t('instance_action_instance_save_msg_upgraded')}; } \n return payload.instance != false ? {data: payload, status: 0, msg: t('instance_action_instance_save_msg_success')} : {...payload, status: 1, msg: t('instance_action_instance_save_msg_failed')};",
25
22
  "data": {
26
23
  "&": "$$"
27
24
  }
@@ -33,14 +30,11 @@ amis_schema: |-
33
30
  {
34
31
  "args": {
35
32
  "api": {
36
- "url": "${context.rootUrl}/api/workflow/v2/approve/save",
33
+ "url": "/api/workflow/v2/approve/save",
37
34
  "method": "post",
38
35
  "sendOn": "",
39
36
  "requestAdaptor": "var _SteedosUI$getRef$get, _approveValues$next_s;\nconst formValues = context._scoped.getComponentById(\"instance_form\").getValues();\nconst approveValues = (_SteedosUI$getRef$get = context._scoped.getComponentById(\"instance_approval\")) === null || _SteedosUI$getRef$get === void 0 ? void 0 : _SteedosUI$getRef$get.getValues();\nlet nextUsers = approveValues === null || approveValues === void 0 ? void 0 : approveValues.next_users;\nif (_.isString(nextUsers)) {\n nextUsers = [approveValues.next_users];\n}\nconst instance = context.record;\nconst body = {\n approve: {\n id: instance.approve._id,\n instance: instance._id,\n trace: instance.trace._id,\n next_steps: [{\n step: approveValues === null || approveValues === void 0 || (_approveValues$next_s = approveValues.next_step) === null || _approveValues$next_s === void 0 ? void 0 : _approveValues$next_s._id,\n users: nextUsers\n }],\n description: approveValues === null || approveValues === void 0 ? void 0 : approveValues.suggestion,\n judge: approveValues === null || approveValues === void 0 ? void 0 : approveValues.judge,\n values: formValues\n }\n};\napi.data = body;\nreturn api;",
40
37
  "adaptor": "window.SteedosWorkflow.Instance.changed = false; return payload.instance ? {...payload, status: 0, msg: t('instance_action_instance_save_msg_success')} : {...payload, status: 1, msg: t('instance_action_instance_save_msg_failed')};",
41
- "headers": {
42
- "Authorization": "Bearer ${context.tenantId},${context.authToken}"
43
- },
44
38
  "data": {
45
39
  "&": "$$"
46
40
  }
@@ -48,6 +42,10 @@ amis_schema: |-
48
42
  },
49
43
  "actionType": "ajax",
50
44
  "expression": "record.box != 'draft' && record.state != 'draft'"
45
+ },
46
+ {
47
+ "actionType": "custom",
48
+ "script": "if(event.data.instance && event.data.instance.name){doAction({actionType: 'setValue',componentId: 'u:instancePage',args: { value: {title: event.data.instance.name} }});}"
51
49
  }
52
50
  ],
53
51
  "weight": 0
@@ -0,0 +1,5 @@
1
+ {
2
+ "type": "liquid",
3
+ "template": "<style>\n /* 动效 */\n @keyframes fadeUpSpring {\n 0% {\n opacity: 0;\n transform: translateY(10px);\n }\n\n 100% {\n opacity: 1;\n transform: translateY(0);\n }\n }\n\n @keyframes starPop {\n 0% {\n transform: scale(1);\n }\n\n 40% {\n transform: scale(1.35) rotate(15deg);\n }\n\n 100% {\n transform: scale(1) rotate(0);\n }\n }\n\n .no-scrollbar::-webkit-scrollbar {\n display: none;\n }\n\n .no-scrollbar {\n -ms-overflow-style: none;\n scrollbar-width: none;\n }\n\n .line-clamp-2 {\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n }\n</style>\n\n<div class=\"flex h-full w-full flex-row items-stretch overflow-hidden bg-white font-sans text-gray-900 antialiased\">\n\n <div class=\"flex h-full w-[260px] shrink-0 flex-col border-r border-gray-200/80 bg-[#F2F2F7] z-20\">\n\n <div class=\"shrink-0 px-3 pt-4 pb-2\">\n <div class=\"px-2 mb-3 text-2xl font-bold tracking-tight text-black\">流程</div>\n <div class=\"relative group\">\n <div class=\"pointer-events-none absolute inset-y-0 left-0 flex items-center pl-2.5 text-gray-500\">\n <svg class=\"h-4 w-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <circle cx=\"11\" cy=\"11\" r=\"8\"></circle>\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"></line>\n </svg>\n </div>\n <input type=\"text\" id=\"searchInput\" placeholder=\"搜索\"\n class=\"w-full rounded-[10px] border-none bg-[#767680]/10 py-1.5 pl-9 pr-3 text-[14px] text-gray-900 placeholder:text-gray-500 outline-none transition-all duration-200 focus:bg-white focus:shadow-sm focus:ring-2 focus:ring-blue-500/20\">\n </div>\n </div>\n\n <div class=\"flex-1 overflow-y-auto px-2 pb-4 no-scrollbar space-y-0.5\" id=\"sidebarList\">\n </div>\n </div>\n\n <div class=\"relative flex-1 h-full overflow-y-auto scroll-smooth bg-white z-10\" id=\"mainContent\">\n <div id=\"contentContainer\" class=\"flex h-full w-full flex-col items-center justify-center\">\n <div class=\"inline-flex items-center gap-2 text-gray-400 text-sm animate-pulse\">\n <svg class=\"animate-spin h-4 w-4\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\"></circle>\n <path class=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\"></path>\n </svg>\n <span>正在加载资源...</span>\n </div>\n </div>\n </div>\n</div>\n\n<script>\n // --- Service Layer ---\n const WorkflowService = {\n apiBase: \"\", \n \n getHeaders: function() { return { 'Content-Type': 'application/json' }; },\n \n getCategories: async function() {\n try {\n const url = `\\${this.apiBase}/api/v6/data/categories?skip=0&top=100&sort=sort_no&fields=name`;\n const res = await fetch(url, { headers: this.getHeaders() });\n const json = await res.json();\n return json.data || [];\n } catch (e) { return []; }\n },\n \n getFlows: async function() {\n try {\n const filters = JSON.stringify([[\"perms.users_can_add\",\"=\",data.context.userId], \"or\", [\"perms.orgs_can_add\",\"in\",data.context.user.organizations_parents]]);\n const url = `\\${this.apiBase}/api/v6/data/flows?skip=0&top=5000&sort=sort_no&fields=name%2Ccategory&filters=\\${encodeURIComponent(filters)}`;\n const res = await fetch(url, { headers: this.getHeaders() });\n const json = await res.json();\n return json.data || [];\n } catch (e) { return []; }\n },\n \n getData: async function() {\n const [categories, flows] = await Promise.all([this.getCategories(), this.getFlows()]);\n const categoryMap = {};\n categories.forEach(c => categoryMap[c._id] = c.name);\n const mappedFlows = flows.map(f => ({\n id: f._id, name: f.name, categoryId: f.category,\n categoryName: categoryMap[f.category] || \"其他流程\" \n }));\n return { categories: categories, flows: mappedFlows };\n },\n \n getFavorites: function() {\n const saved = localStorage.getItem('steedos_fav_ids');\n return saved ? JSON.parse(saved) : [];\n },\n \n toggleFavorite: function(flowId, isFav) {\n let favs = this.getFavorites();\n if (isFav) { if (!favs.includes(flowId)) favs.push(flowId); } \n else { favs = favs.filter(id => id !== flowId); }\n localStorage.setItem('steedos_fav_ids', JSON.stringify(favs));\n return favs;\n }\n };\n\n // --- UI Controller ---\n const AppState = { allFlows: [], categories: [], favorites: [] };\n const sidebarEl = document.getElementById('sidebarList');\n const contentEl = document.getElementById('contentContainer');\n const searchInput = document.getElementById('searchInput');\n\n async function init() {\n try {\n const data = await WorkflowService.getData();\n AppState.allFlows = data.flows;\n AppState.categories = data.categories;\n AppState.favorites = WorkflowService.getFavorites();\n renderUI();\n } catch (e) {\n contentEl.innerHTML = `<div class=\"text-gray-400 text-sm\">加载失败,请检查网络</div>`;\n }\n }\n\n function renderUI(filterText = \"\") {\n sidebarEl.innerHTML = \"\";\n contentEl.innerHTML = \"\";\n contentEl.className = \"block w-full h-full pt-4 px-8 pb-10\";\n\n const isSearching = filterText.length > 0;\n let groups = [];\n\n const favFlows = AppState.allFlows.filter(f => \n AppState.favorites.includes(f.id) && \n (isSearching ? f.name.includes(filterText) : true)\n );\n if (favFlows.length > 0) {\n groups.push({ id: 'fav', name: \"我的收藏\", items: favFlows, isFav: true });\n }\n\n AppState.categories.forEach(cat => {\n const items = AppState.allFlows.filter(f => \n f.categoryId === cat._id &&\n (isSearching ? f.name.includes(filterText) : true)\n );\n if (items.length > 0) {\n groups.push({ id: cat._id, name: cat.name, items: items, isFav: false });\n }\n });\n\n const otherItems = AppState.allFlows.filter(f => \n !AppState.categories.find(c => c._id === f.categoryId) &&\n (isSearching ? f.name.includes(filterText) : true)\n );\n if (otherItems.length > 0) {\n groups.push({ id: 'other', name: \"其他流程\", items: otherItems, isFav: false });\n }\n\n if (groups.length === 0) {\n contentEl.className = \"flex h-full w-full flex-col items-center justify-center\";\n contentEl.innerHTML = `<div class=\"animate-[fadeUpSpring_0.5s_ease-out] text-center\"><div class=\"text-gray-200 text-7xl mb-4\">∅</div><div class=\"text-gray-400 text-sm\">未找到匹配流程</div></div>`;\n return;\n }\n\n groups.forEach((group, index) => {\n const groupId = `group-\\${group.id}`;\n \n // Sidebar Item\n const navItem = document.createElement('div');\n let navBase = \"group flex cursor-pointer items-center justify-between rounded-md px-3 py-2 text-[14px] transition-all duration-200 ease-out select-none\";\n let activeClass = \"bg-[#007AFF] text-white shadow-sm font-medium\";\n let inactiveClass = \"text-gray-700 hover:bg-black/5 active:bg-black/10\";\n \n navItem.className = `\\${navBase} \\${index === 0 ? activeClass : inactiveClass}`;\n const badgeClass = index === 0 ? \"text-white/80\" : \"text-gray-400 group-hover:text-gray-500\";\n \n navItem.innerHTML = `\n <span class=\"truncate\">\\${group.isFav ? '★ ' : ''}\\${group.name}</span>\n <span class=\"\\${badgeClass} text-[12px] font-medium transition-colors\">\\${group.items.length}</span>\n `;\n navItem.onclick = () => {\n Array.from(sidebarEl.children).forEach(el => {\n el.className = `\\${navBase} \\${inactiveClass}`;\n el.querySelector('span:last-child').className = \"text-gray-400 group-hover:text-gray-500 text-[12px] font-medium transition-colors\";\n });\n navItem.className = `\\${navBase} \\${activeClass}`;\n navItem.querySelector('span:last-child').className = \"text-white/80 text-[12px] font-medium transition-colors\";\n document.getElementById(groupId)?.scrollIntoView({ behavior: 'smooth', block: 'start' });\n };\n sidebarEl.appendChild(navItem);\n\n // Content Header\n const section = document.createElement('div');\n section.id = groupId;\n section.className = \"mb-10\";\n const headerColor = group.isFav ? 'text-amber-500' : 'text-gray-900';\n section.innerHTML = `<div class=\"sticky top-0 z-20 mb-4 bg-white/95 py-3 text-xl font-bold tracking-tight backdrop-blur-xl text-left border-b border-gray-100 \\${headerColor}\">\\${group.name}</div>`;\n\n const grid = document.createElement('div');\n grid.className = 'grid grid-cols-[repeat(auto-fill,minmax(260px,1fr))] gap-4';\n\n group.items.forEach((flow, i) => {\n const isFav = AppState.favorites.includes(flow.id);\n const colorMap = [\n 'bg-blue-50 text-blue-600',\n 'bg-orange-50 text-orange-600',\n 'bg-emerald-50 text-emerald-600',\n 'bg-indigo-50 text-indigo-600'\n ];\n const colorClass = colorMap[(flow.name.length + i) % 4];\n const firstChar = flow.name.replace(/【.*?】/g, '').charAt(0) || flow.name.charAt(0);\n\n const card = document.createElement('div');\n card.className = 'group relative flex h-auto min-h-[72px] cursor-pointer items-center rounded-2xl border border-gray-100 bg-white p-3 text-left shadow-[0_2px_8px_rgba(0,0,0,0.04)] ring-1 ring-black/[0.02] transition-all duration-300 ease-out animate-[fadeUpSpring_0.6s_cubic-bezier(0.16,1,0.3,1)_forwards] hover:-translate-y-1 hover:border-gray-200 hover:shadow-[0_12px_24px_rgba(0,0,0,0.08)] active:scale-[0.98] active:bg-gray-50';\n card.style.animationDelay = `\\${Math.min(i * 0.04, 0.6)}s`;\n card.style.opacity = '0'; \n \n const iconClass = isFav \n ? 'text-yellow-400 fill-current' \n : 'text-gray-300 group-hover/btn:text-gray-400 fill-none stroke-current stroke-[1.5]';\n const btnBgClass = isFav\n ? 'opacity-100 hover:scale-110'\n : 'opacity-0 group-hover:opacity-100 hover:bg-gray-100 hover:scale-110';\n\n // 修改点: 添加 top-1/2 -translate-y-1/2 实现绝对垂直居中\n card.innerHTML = `\n <div class=\"star-btn group/btn absolute right-2 top-1/2 -translate-y-1/2 z-20 flex h-8 w-8 items-center justify-center rounded-full transition-all duration-200 \\${btnBgClass}\" title=\"\\${isFav ? '取消收藏' : '加入收藏'}\">\n <svg class=\"h-5 w-5 transition-colors duration-300 \\${iconClass}\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M11.48 3.499a.562.562 0 011.04 0l2.125 5.111a.563.563 0 00.475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 00-.182.557l1.285 5.385a.562.562 0 01-.84.61l-4.725-2.885a.563.563 0 00-.586 0L6.982 20.54a.562.562 0 01-.84-.61l1.285-5.386a.562.562 0 00-.182-.557l-4.204-3.602a.563.563 0 01.321-.988l5.518-.442a.563.563 0 00.475-.345L11.48 3.5z\" />\n </svg>\n </div>\n \n <div class=\"mr-4 flex h-11 w-11 shrink-0 items-center justify-center rounded-xl text-[16px] font-bold \\${colorClass}\">\\${firstChar}</div>\n <div class=\"flex-1 pr-8 text-[15px] font-medium text-gray-900 line-clamp-2 leading-relaxed tracking-tight\" title=\"\\${flow.name}\">\\${flow.name}</div>\n `;\n\n card.onclick = () => {\n setTimeout(() => {\n console.log(\"选中的流程ID:\", flow.id);\n //alert(`准备发起: \\${data.context.user.name}`);\n data._scoped.doAction([\n {\n \"actionType\": \"broadcast\",\n \"args\": {\n \"eventName\": \"flows.selected\"\n },\n \"data\": {\n \"value\": flow.id\n }\n }\n ])\n }, 50);\n };\n\n const starBtn = card.querySelector('.star-btn');\n const starIcon = starBtn.querySelector('svg');\n \n starBtn.onclick = (e) => {\n e.stopPropagation();\n const newFavState = !starBtn.classList.contains('active-fav');\n \n if (newFavState) {\n starBtn.classList.add('active-fav', 'opacity-100');\n starBtn.classList.add('animate-[starPop_0.4s_ease-out]');\n starIcon.setAttribute('class', 'h-5 w-5 transition-colors duration-300 text-yellow-400 fill-current');\n } else {\n starBtn.classList.remove('active-fav', 'opacity-100');\n starBtn.classList.remove('animate-[starPop_0.4s_ease-out]');\n starIcon.setAttribute('class', 'h-5 w-5 transition-colors duration-300 text-gray-300 group-hover/btn:text-gray-400 fill-none stroke-current stroke-[1.5]');\n }\n\n AppState.favorites = WorkflowService.toggleFavorite(flow.id, newFavState);\n setTimeout(() => renderUI(searchInput.value), 300);\n };\n \n if (isFav) starBtn.classList.add('active-fav');\n\n grid.appendChild(card);\n });\n\n section.appendChild(grid);\n contentEl.appendChild(section);\n });\n }\n\n searchInput.addEventListener('input', (e) => renderUI(e.target.value.trim()));\n init();\n</script>",
4
+ "className": "h-full"
5
+ }
@@ -0,0 +1,7 @@
1
+ name: flow_selector
2
+ is_active: true
3
+ label: 流程选择
4
+ pageAssignments: []
5
+ render_engine: amis
6
+ type: app
7
+ widgets: []
@@ -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 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})"
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 && 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",
@@ -266,6 +266,30 @@ router.post('/api/workflow/v2/nextSteps', requireAuthentication, async function
266
266
  }
267
267
  })
268
268
 
269
+ router.get('/api/workflow/v2/get_instance_steps/:instanceId', requireAuthentication, async function (req, res) {
270
+ try {
271
+ const { instanceId } = req.params;
272
+ if(instanceId === 'none'){
273
+ return res.status(200).send({ status: 0 });
274
+ }
275
+ const instance = await objectql.getObject('instances').findOne(instanceId);
276
+ if(!instance){
277
+ return res.status(200).send({
278
+ error: 'not find instance'
279
+ });
280
+ }
281
+ return res.status(200).send({ status: 0, data: {
282
+ step_approve: instance.step_approve,
283
+ skip_steps: instance.skip_steps
284
+ } });
285
+ } catch (error) {
286
+ console.error(error);
287
+ res.status(200).send({
288
+ error: error.message
289
+ });
290
+ }
291
+ })
292
+
269
293
  router.post('/api/workflow/v2/set_instance_steps', requireAuthentication, async function (req, res) {
270
294
  try {
271
295
  const userSession = req.user;
@@ -14,6 +14,23 @@ 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
+
18
+ const getFieldName = (fields, fieldId)=>{
19
+ const field = _.find(fields, (item)=>{
20
+ return item._id === fieldId
21
+ });
22
+ return field?.code || fieldId
23
+ }
24
+
25
+ const getFieldValue = (values, code)=>{
26
+ return values[code]
27
+ }
28
+
29
+ const getFormFieldValue = (fields, values, fieldId)=>{
30
+ const code = getFieldName(fields, fieldId);
31
+ return getFieldValue(values, code);
32
+ }
33
+
17
34
  /**
18
35
  * 计算下一步处理人
19
36
  * body {
@@ -41,8 +58,15 @@ router.post('/api/workflow/v2/nextStepUsers', requireAuthentication, async funct
41
58
  } = req.body;
42
59
 
43
60
  let instance = await UUFlowManager.getInstance(insId);
44
- let flow = await UUFlowManager.getFlow(instance.flow);
45
- let nextStep = await UUFlowManager.getStep(instance, flow, nextStepId);
61
+ const [flow, form] = await Promise.all([
62
+ UUFlowManager.getFlow(instance.flow),
63
+ UUFlowManager.getForm(instance.form)
64
+ ]);
65
+ const [formVersion, nextStep] = await Promise.all([
66
+ UUFlowManager.getFormVersion(form, instance.form_version),
67
+ UUFlowManager.getStep(instance, flow, nextStepId)
68
+ ]);
69
+ const formFields = formVersion.fields;
46
70
  switch (nextStep.step_type) {
47
71
  case 'start':
48
72
  var applicantId = instance.applicant;
@@ -82,7 +106,7 @@ router.post('/api/workflow/v2/nextStepUsers', requireAuthentication, async funct
82
106
  case 'userField':
83
107
  var
84
108
  userField = nextStep.approver_user_field,
85
- userFieldValue = values[userField];
109
+ userFieldValue = getFormFieldValue(formFields, values, userField);
86
110
  if(userFieldValue){
87
111
  if (_.isArray(userFieldValue)) { //如果多选,以userFieldValue值为Array
88
112
  nextStepUsers = await WorkflowManager.getUsers(spaceId, userFieldValue);
@@ -90,7 +114,7 @@ router.post('/api/workflow/v2/nextStepUsers', requireAuthentication, async funct
90
114
  nextStepUsers.push(await WorkflowManager.getUser(spaceId, userFieldValue));
91
115
  }
92
116
  }else {
93
- error = "FIELD_VALUE_EMPTY";
117
+ error = "请先填写表单值";
94
118
  }
95
119
 
96
120
  break;
@@ -99,7 +123,7 @@ router.post('/api/workflow/v2/nextStepUsers', requireAuthentication, async funct
99
123
  orgs,
100
124
  orgChildrens,
101
125
  orgField = nextStep.approver_org_field,
102
- orgFieldValue = values[orgField];
126
+ orgFieldValue = getFormFieldValue(formFields, values, orgField);
103
127
  if (orgFieldValue) {
104
128
  if (_.isArray(orgFieldValue)) { //如果多选,以orgFieldValue值为Array
105
129
  orgs = await WorkflowManager.getOrganizations(orgFieldValue);
@@ -118,7 +142,7 @@ router.post('/api/workflow/v2/nextStepUsers', requireAuthentication, async funct
118
142
  error = "ORG_NO_MEMBERS";
119
143
  }
120
144
  } else {
121
- error = "FIELD_VALUE_EMPTY";
145
+ error = "请先填写表单值";
122
146
  }
123
147
 
124
148
  break;
@@ -133,7 +157,7 @@ router.post('/api/workflow/v2/nextStepUsers', requireAuthentication, async funct
133
157
  case 'userFieldRole':
134
158
  var
135
159
  userField = nextStep.approver_user_field,
136
- userFieldValue = values[userField],
160
+ userFieldValue = getFormFieldValue(formFields, values, userField),
137
161
  approverRoleIds = nextStep.approver_roles;
138
162
  if (userFieldValue) {
139
163
  if (_.isArray(userFieldValue)) { //如果多选,以userFieldValue值为Array
@@ -146,7 +170,7 @@ router.post('/api/workflow/v2/nextStepUsers', requireAuthentication, async funct
146
170
  error = "ROLE_NO_MEMBERS";
147
171
  }
148
172
  } else {
149
- error = "FIELD_VALUE_EMPTY";
173
+ error = "请先填写表单值";
150
174
  }
151
175
 
152
176
 
@@ -154,7 +178,7 @@ router.post('/api/workflow/v2/nextStepUsers', requireAuthentication, async funct
154
178
  case 'orgFieldRole':
155
179
  var
156
180
  orgField = nextStep.approver_org_field,
157
- orgFieldValue = values[orgField],
181
+ orgFieldValue = getFormFieldValue(formFields, values, orgField),
158
182
  approverRoleIds = nextStep.approver_roles;
159
183
 
160
184
  if (orgFieldValue) {
@@ -168,7 +192,7 @@ router.post('/api/workflow/v2/nextStepUsers', requireAuthentication, async funct
168
192
  error = "ROLE_NO_MEMBERS";
169
193
  }
170
194
  } else {
171
- error = "FIELD_VALUE_EMPTY";
195
+ error = "请先填写表单值";
172
196
  }
173
197
  break;
174
198
  default:
@@ -214,4 +238,33 @@ router.post('/api/workflow/v2/nextStepUsers', requireAuthentication, async funct
214
238
  });
215
239
  }
216
240
  });
241
+
242
+ router.post('/api/workflow/v2/nextStepUsersValue', requireAuthentication, async function (req, res) {
243
+ try {
244
+ let userSession = req.user;
245
+ const userId = userSession.userId;
246
+ const spaceId = userSession.spaceId;
247
+ var error = "";
248
+
249
+ if (!spaceId) {
250
+ throw new Error('缺少参数')
251
+ }
252
+
253
+ const { instanceId, nextStepId } = req.body;
254
+
255
+ let instance = await UUFlowManager.getInstance(instanceId);
256
+ const step_approve = instance.step_approve || {};
257
+ const newNextUsers = step_approve[nextStepId] || []
258
+ res.status(200).send({
259
+ 'value': newNextUsers,
260
+ 'error': error
261
+ });
262
+ } catch (error) {
263
+ console.error(error);
264
+ res.status(200).send({
265
+ error: error.message
266
+ });
267
+ }
268
+ });
269
+
217
270
  exports.default = router;
@@ -114,7 +114,7 @@ router.post('/api/workflow/nextStepUsers', requireAuthentication, async function
114
114
  error = "ORG_NO_MEMBERS";
115
115
  }
116
116
  } else {
117
- error = "FIELD_VALUE_EMPTY";
117
+ error = "请先填写表单值";
118
118
  }
119
119
 
120
120
  break;
@@ -142,7 +142,7 @@ router.post('/api/workflow/nextStepUsers', requireAuthentication, async function
142
142
  error = "ROLE_NO_MEMBERS";
143
143
  }
144
144
  } else {
145
- error = "FIELD_VALUE_EMPTY";
145
+ error = "请先填写表单值";
146
146
  }
147
147
 
148
148
 
@@ -164,7 +164,7 @@ router.post('/api/workflow/nextStepUsers', requireAuthentication, async function
164
164
  error = "ROLE_NO_MEMBERS";
165
165
  }
166
166
  } else {
167
- error = "FIELD_VALUE_EMPTY";
167
+ error = "请先填写表单值";
168
168
  }
169
169
  break;
170
170
  default:
@@ -166,15 +166,7 @@ module.exports = {
166
166
  case 'monitor':
167
167
  filter.push(['state', 'in', ["pending", "completed"]]);
168
168
  if(!is_space_admin){
169
- const flowIds = await new Promise(function (resolve, reject) {
170
- Fiber(function () {
171
- try {
172
- resolve(WorkflowManager.getMyAdminOrMonitorFlows(spaceId, userId));
173
- } catch (error) {
174
- reject(error);
175
- }
176
- }).run()
177
- })
169
+ const flowIds = await WorkflowManager.getMyAdminOrMonitorFlows(spaceId, userId);
178
170
  if(flowId){
179
171
  if(!_.includes(flowIds, flowId)){
180
172
  // filter.push([
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steedos-labs/plugin-workflow",
3
- "version": "3.0.10",
3
+ "version": "3.0.12",
4
4
  "main": "package.service.js",
5
5
  "license": "MIT",
6
6
  "scripts": {