@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.
- package/main/default/manager/uuflow_manager.js +5 -0
- package/main/default/objectTranslations/flows.zh-CN/flows.zh-CN.objectTranslation.yml +1 -1
- package/main/default/objects/flows/flows.object.yml +2 -5
- package/main/default/objects/instances/buttons/instance_delete.button.yml +4 -24
- package/main/default/objects/instances/buttons/instance_new.button.yml +11 -11
- package/main/default/objects/instances/buttons/instance_save.button.yml +6 -8
- package/main/default/pages/flow_selector.page.amis.json +5 -0
- package/main/default/pages/flow_selector.page.yml +7 -0
- package/main/default/pages/flowdetail.page.amis.json +1 -1
- package/main/default/routes/api_workflow_next_step.router.js +24 -0
- package/main/default/routes/api_workflow_next_step_users.router.js +63 -10
- package/main/default/routes/nextStepUsers.router.js +3 -3
- package/main/default/services/instance.service.js +1 -9
- package/package.json +1 -1
|
@@ -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(
|
|
@@ -693,10 +693,7 @@ actions:
|
|
|
693
693
|
type: amis_button
|
|
694
694
|
design:
|
|
695
695
|
label: Designer
|
|
696
|
-
visible:
|
|
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
|
|
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": "
|
|
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/
|
|
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": "
|
|
47
|
-
"
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"
|
|
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": "
|
|
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(){
|
|
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": "
|
|
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
|
+
}
|
|
@@ -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
|
-
|
|
45
|
-
|
|
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
|
|
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 = "
|
|
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
|
|
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 = "
|
|
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
|
|
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 = "
|
|
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
|
|
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 = "
|
|
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 = "
|
|
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 = "
|
|
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 = "
|
|
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
|
|
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([
|