@steedos-labs/plugin-workflow 3.0.35 → 3.0.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,8 +5,8 @@
5
5
  <link rel="icon" type="image/svg+xml" href="/api/workflow/designer-v2/vite.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>designer</title>
8
- <script type="module" crossorigin src="/api/workflow/designer-v2/assets/index-r2EtJdFh.js"></script>
9
- <link rel="stylesheet" crossorigin href="/api/workflow/designer-v2/assets/index-CzP9-MzW.css">
8
+ <script type="module" crossorigin src="/api/workflow/designer-v2/assets/index-DkVFo_s4.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/api/workflow/designer-v2/assets/index-BVsRCpLO.css">
10
10
  </head>
11
11
  <body>
12
12
  <div id="root"></div>
@@ -1496,6 +1496,41 @@ UUFlowManager.workflow_engine = async function (approve_from_client, current_use
1496
1496
  }
1497
1497
  console.log(`[workflow/engine] [workflow_engine] update instance(second part) took ${Date.now() - t8}ms`);
1498
1498
 
1499
+ // Skip Processed: Update processed_user_ids based on step type and judge
1500
+ const t8_skip = Date.now();
1501
+ if (step_type === 'sign' && judge === 'approved') {
1502
+ // Sign node approval - add current user to processed set
1503
+ await instancesCollection.updateOne(
1504
+ { _id: instance_id },
1505
+ { $addToSet: { processed_user_ids: current_user } }
1506
+ );
1507
+ } else if (step_type === 'sign' && judge === 'rejected') {
1508
+ // Sign node rejection - reset processed set to applicant only
1509
+ await instancesCollection.updateOne(
1510
+ { _id: instance_id },
1511
+ { $set: { processed_user_ids: [updatedInstance.applicant] } }
1512
+ );
1513
+ } else if (step_type === 'counterSign') {
1514
+ // Check if the counterSign trace is now fully finished
1515
+ const csInstance = await UUFlowManager.getInstance(instance_id);
1516
+ const csTrace = _.find(csInstance.traces, t => t._id === trace_id);
1517
+ if (csTrace && csTrace.is_finished) {
1518
+ // All finished - add all non-cc/distribute approved users to processed set
1519
+ const approvedUsers = csTrace.approves
1520
+ .filter(a => isNormalApprove(a) && a.is_finished && a.judge !== 'skipped')
1521
+ .map(a => a.user);
1522
+ if (approvedUsers.length > 0) {
1523
+ await instancesCollection.updateOne(
1524
+ { _id: instance_id },
1525
+ { $addToSet: { processed_user_ids: { $each: approvedUsers } } }
1526
+ );
1527
+ }
1528
+ }
1529
+ }
1530
+ // Skip Processed: Check if next step should be auto-skipped
1531
+ await UUFlowManager.handleSkipProcessed(instance_id, flow);
1532
+ console.log(`[workflow/engine] [workflow_engine] handleSkipProcessed took ${Date.now() - t8_skip}ms`);
1533
+
1499
1534
  const t9 = Date.now();
1500
1535
  // Get final updated instance
1501
1536
  const finalInstance = await UUFlowManager.getInstance(instance_id);
@@ -1549,6 +1584,360 @@ UUFlowManager.workflow_engine = async function (approve_from_client, current_use
1549
1584
  return finalInstance;
1550
1585
  };
1551
1586
 
1587
+ // Skip processed constants and helpers
1588
+ const SKIP_DESCRIPTION = '滑步跳过:已在之前步骤处理过';
1589
+
1590
+ function isNormalApprove(approve) {
1591
+ return !approve.type || approve.type === 'draft' || approve.type === 'reassign';
1592
+ }
1593
+
1594
+ /**
1595
+ * Handle skip processed (滑步) logic for workflow instances.
1596
+ * When a new trace is created for the next step, check if the handlers
1597
+ * should be automatically skipped because they are already in the processed_user_ids set.
1598
+ *
1599
+ * @param {String} instance_id - Instance ID
1600
+ * @param {Object} flow - Flow object
1601
+ * @param {Number} maxDepth - Maximum recursion depth to prevent infinite loops.
1602
+ * Default 20 is generous since typical workflows have fewer than 20 sequential steps.
1603
+ * This prevents infinite loops caused by circular flow definitions.
1604
+ */
1605
+ UUFlowManager.handleSkipProcessed = async function (instance_id, flow, maxDepth = 20) {
1606
+ if (maxDepth <= 0) {
1607
+ console.warn('[workflow/engine] [handleSkipProcessed] Max recursion depth reached');
1608
+ return;
1609
+ }
1610
+
1611
+ const instancesCollection = await getCollection('instances');
1612
+ const instance = await UUFlowManager.getInstance(instance_id);
1613
+
1614
+ // Only process pending instances
1615
+ if (instance.state !== 'pending') return;
1616
+
1617
+ const processedUserIds = instance.processed_user_ids || [];
1618
+ if (processedUserIds.length === 0) return;
1619
+
1620
+ // Get the last trace (the one just created for the next step)
1621
+ const lastTrace = _.last(instance.traces);
1622
+ if (!lastTrace || lastTrace.is_finished) return;
1623
+
1624
+ // Get the step definition for this trace
1625
+ let step;
1626
+ try {
1627
+ step = UUFlowManager.getStep(instance, flow, lastTrace.step);
1628
+ } catch (e) {
1629
+ return;
1630
+ }
1631
+
1632
+ // Only skip for sign and counterSign nodes
1633
+ if (!['sign', 'counterSign'].includes(step.step_type)) return;
1634
+
1635
+ // Check if skip_enabled (default true)
1636
+ if (step.skip_enabled === false) return;
1637
+
1638
+ // Get non-cc/distribute approves
1639
+ const normalApproves = lastTrace.approves.filter(isNormalApprove);
1640
+
1641
+ if (normalApproves.length === 0) return;
1642
+
1643
+ // Check which users should be skipped
1644
+ const shouldSkipApproves = normalApproves.filter(a => processedUserIds.includes(a.user));
1645
+
1646
+ if (shouldSkipApproves.length === 0) return;
1647
+
1648
+ const now = new Date();
1649
+ const traceIdx = instance.traces.length - 1;
1650
+
1651
+ if (shouldSkipApproves.length === normalApproves.length) {
1652
+ // All users should be skipped - skip entire node
1653
+ console.log(`[workflow/engine] [handleSkipProcessed] Skipping entire step "${step.name}" - all handlers already processed`);
1654
+
1655
+ // Determine the next step from this skipped step
1656
+ // For sign: use "approved" lines; for counterSign: use "submitted" lines
1657
+ const lineState = step.step_type === 'sign' ? 'approved' : 'submitted';
1658
+ const lines = (step.lines || []).filter(l => l.state === lineState);
1659
+
1660
+ if (lines.length === 0) {
1661
+ console.warn('[workflow/engine] [handleSkipProcessed] No outgoing lines found for skipped step');
1662
+ return;
1663
+ }
1664
+
1665
+ const next_step_id = lines[0].to_step;
1666
+ let next_step;
1667
+ try {
1668
+ next_step = UUFlowManager.getStep(instance, flow, next_step_id);
1669
+ } catch (e) {
1670
+ return;
1671
+ }
1672
+
1673
+ // Mark current trace as finished with all approves as skipped
1674
+ const setObj = {};
1675
+ setObj[`traces.${traceIdx}.is_finished`] = true;
1676
+ setObj[`traces.${traceIdx}.finish_date`] = now;
1677
+ setObj[`traces.${traceIdx}.judge`] = 'skipped';
1678
+
1679
+ for (let h = 0; h < lastTrace.approves.length; h++) {
1680
+ const approve = lastTrace.approves[h];
1681
+ if (isNormalApprove(approve)) {
1682
+ setObj[`traces.${traceIdx}.approves.${h}.is_finished`] = true;
1683
+ setObj[`traces.${traceIdx}.approves.${h}.finish_date`] = now;
1684
+ setObj[`traces.${traceIdx}.approves.${h}.judge`] = 'skipped';
1685
+ setObj[`traces.${traceIdx}.approves.${h}.is_read`] = true;
1686
+ setObj[`traces.${traceIdx}.approves.${h}.read_date`] = now;
1687
+ setObj[`traces.${traceIdx}.approves.${h}.cost_time`] = 0;
1688
+ setObj[`traces.${traceIdx}.approves.${h}.description`] = SKIP_DESCRIPTION;
1689
+ }
1690
+ }
1691
+
1692
+ // Collect skipped user IDs to add to processed set
1693
+ const skippedUserIds = shouldSkipApproves.map(a => a.user);
1694
+ const skippedHandlers = shouldSkipApproves.map(a => a.handler);
1695
+
1696
+ if (next_step.step_type === 'end') {
1697
+ // Flow ends
1698
+ const newEndTrace = {
1699
+ _id: _makeNewID(),
1700
+ instance: instance_id,
1701
+ previous_trace_ids: [lastTrace._id],
1702
+ is_finished: true,
1703
+ step: next_step_id,
1704
+ name: next_step.name,
1705
+ start_date: now,
1706
+ finish_date: now
1707
+ };
1708
+
1709
+ setObj.state = 'completed';
1710
+ setObj.finish_date = now;
1711
+ setObj.inbox_users = [];
1712
+ setObj.current_step_name = next_step.name;
1713
+ setObj.final_decision = 'approved';
1714
+ setObj.current_step_auto_submit = false;
1715
+ setObj.modified = now;
1716
+
1717
+ // Split into two updates to avoid MongoDB conflict on 'traces' path
1718
+ // 1) $set trace sub-paths (traces.X.Y)
1719
+ const traceSetObj1 = {};
1720
+ const otherSetObj1 = {};
1721
+ for (const key of Object.keys(setObj)) {
1722
+ if (key.startsWith('traces.')) {
1723
+ traceSetObj1[key] = setObj[key];
1724
+ } else {
1725
+ otherSetObj1[key] = setObj[key];
1726
+ }
1727
+ }
1728
+
1729
+ if (Object.keys(traceSetObj1).length > 0) {
1730
+ await instancesCollection.updateOne(
1731
+ { _id: instance_id },
1732
+ { $set: traceSetObj1 }
1733
+ );
1734
+ }
1735
+
1736
+ // 2) $push new trace + $set non-trace fields + $addToSet
1737
+ await instancesCollection.updateOne(
1738
+ { _id: instance_id },
1739
+ {
1740
+ $set: otherSetObj1,
1741
+ $push: { traces: newEndTrace },
1742
+ $addToSet: {
1743
+ processed_user_ids: { $each: skippedUserIds },
1744
+ outbox_users: { $each: skippedHandlers }
1745
+ }
1746
+ }
1747
+ );
1748
+
1749
+ // Update instance tasks for skipped approves
1750
+ for (const approve of shouldSkipApproves) {
1751
+ await update_instance_tasks(instance_id, lastTrace._id, approve._id);
1752
+ }
1753
+ } else {
1754
+ // Create new trace for the next step
1755
+ const space_id = instance.space;
1756
+ const next_step_users = await HandlersManager.getHandlers(instance_id, next_step_id, instance.applicant);
1757
+
1758
+ if (!next_step_users || next_step_users.length === 0) {
1759
+ console.warn('[workflow/engine] [handleSkipProcessed] No handlers found for next step after skip');
1760
+ return;
1761
+ }
1762
+
1763
+ // For non-counterSign steps, use only the first handler
1764
+ let usersForTrace = next_step_users.slice();
1765
+ if (next_step.step_type !== 'counterSign' && usersForTrace.length > 1) {
1766
+ usersForTrace = [usersForTrace[0]];
1767
+ }
1768
+
1769
+ const newTrace = {
1770
+ _id: _makeNewID(),
1771
+ instance: instance_id,
1772
+ previous_trace_ids: [lastTrace._id],
1773
+ is_finished: false,
1774
+ step: next_step_id,
1775
+ name: next_step.name,
1776
+ start_date: now,
1777
+ due_date: UUFlowManager.getDueDate(next_step.timeout_hours, space_id),
1778
+ approves: []
1779
+ };
1780
+
1781
+ const usersCollection = await getCollection('users');
1782
+ const spaceUsersCollection = await getCollection('space_users');
1783
+ const updatedValues = await UUFlowManager.getUpdatedValues(instance);
1784
+
1785
+ const traceUserIds = [];
1786
+ for (let idx = 0; idx < usersForTrace.length; idx++) {
1787
+ const next_step_user_id = usersForTrace[idx];
1788
+ const user_info = await usersCollection.findOne(
1789
+ { _id: next_step_user_id },
1790
+ { projection: { name: 1 } }
1791
+ );
1792
+
1793
+ if (!user_info) continue;
1794
+
1795
+ const newApprove = {
1796
+ _id: _makeNewID(),
1797
+ instance: instance_id,
1798
+ trace: newTrace._id,
1799
+ is_finished: false,
1800
+ user: next_step_user_id,
1801
+ user_name: user_info.name
1802
+ };
1803
+
1804
+ let handler_id = next_step_user_id;
1805
+ let handler_info = user_info;
1806
+ const agent = await UUFlowManager.getAgent(space_id, next_step_user_id);
1807
+
1808
+ if (agent) {
1809
+ usersForTrace[idx] = agent;
1810
+ handler_id = agent;
1811
+ handler_info = await usersCollection.findOne(
1812
+ { _id: agent },
1813
+ { projection: { name: 1 } }
1814
+ );
1815
+ newApprove.agent = agent;
1816
+ }
1817
+
1818
+ newApprove.handler = handler_id;
1819
+ newApprove.handler_name = handler_info.name;
1820
+
1821
+ const next_step_space_user = await spaceUsersCollection.findOne({
1822
+ space: space_id,
1823
+ user: handler_id
1824
+ });
1825
+
1826
+ if (next_step_space_user) {
1827
+ const org_info = await UUFlowManager.getSpaceUserOrgInfo(next_step_space_user);
1828
+ newApprove.handler_organization = org_info.organization;
1829
+ newApprove.handler_organization_name = org_info.organization_name;
1830
+ newApprove.handler_organization_fullname = org_info.organization_fullname;
1831
+ }
1832
+
1833
+ newApprove.start_date = now;
1834
+ newApprove.due_date = newTrace.due_date;
1835
+ newApprove.is_read = false;
1836
+ newApprove.is_error = false;
1837
+ newApprove.values = {};
1838
+
1839
+ UUFlowManager.setRemindInfo(updatedValues, newApprove);
1840
+ newTrace.approves.push(newApprove);
1841
+ traceUserIds.push(handler_id);
1842
+ }
1843
+
1844
+ if (newTrace.approves.length === 0) {
1845
+ console.warn('[workflow/engine] [handleSkipProcessed] No valid approves created for next step');
1846
+ return;
1847
+ }
1848
+
1849
+ setObj.inbox_users = traceUserIds;
1850
+ setObj.current_step_name = next_step.name;
1851
+ setObj.modified = now;
1852
+
1853
+ // Split into two updates to avoid MongoDB conflict on 'traces' path
1854
+ // 1) $set trace sub-paths (traces.X.Y)
1855
+ const traceSetObj2 = {};
1856
+ const otherSetObj2 = {};
1857
+ for (const key of Object.keys(setObj)) {
1858
+ if (key.startsWith('traces.')) {
1859
+ traceSetObj2[key] = setObj[key];
1860
+ } else {
1861
+ otherSetObj2[key] = setObj[key];
1862
+ }
1863
+ }
1864
+
1865
+ if (Object.keys(traceSetObj2).length > 0) {
1866
+ await instancesCollection.updateOne(
1867
+ { _id: instance_id },
1868
+ { $set: traceSetObj2 }
1869
+ );
1870
+ }
1871
+
1872
+ // 2) $push new trace + $set non-trace fields + $addToSet
1873
+ await instancesCollection.updateOne(
1874
+ { _id: instance_id },
1875
+ {
1876
+ $set: otherSetObj2,
1877
+ $push: { traces: newTrace },
1878
+ $addToSet: {
1879
+ processed_user_ids: { $each: skippedUserIds },
1880
+ outbox_users: { $each: skippedHandlers }
1881
+ }
1882
+ }
1883
+ );
1884
+
1885
+ // Update instance tasks for skipped approves
1886
+ for (const approve of shouldSkipApproves) {
1887
+ await update_instance_tasks(instance_id, lastTrace._id, approve._id);
1888
+ }
1889
+
1890
+ // Insert tasks for new trace
1891
+ const approveIds = newTrace.approves.map(a => a._id);
1892
+ await insert_many_instance_tasks(instance_id, newTrace._id, approveIds);
1893
+
1894
+ // Recursively check if the new trace should also be skipped
1895
+ await UUFlowManager.handleSkipProcessed(instance_id, flow, maxDepth - 1);
1896
+ }
1897
+ } else {
1898
+ // Partial skip (counterSign) - mark skipped users' approves as finished
1899
+ console.log(`[workflow/engine] [handleSkipProcessed] Partial skip in counterSign step "${step.name}" - ${shouldSkipApproves.length}/${normalApproves.length} handlers already processed`);
1900
+
1901
+ const setObj = {};
1902
+
1903
+ for (let h = 0; h < lastTrace.approves.length; h++) {
1904
+ const approve = lastTrace.approves[h];
1905
+ if (processedUserIds.includes(approve.user) && isNormalApprove(approve)) {
1906
+ setObj[`traces.${traceIdx}.approves.${h}.is_finished`] = true;
1907
+ setObj[`traces.${traceIdx}.approves.${h}.finish_date`] = now;
1908
+ setObj[`traces.${traceIdx}.approves.${h}.judge`] = 'skipped';
1909
+ setObj[`traces.${traceIdx}.approves.${h}.is_read`] = true;
1910
+ setObj[`traces.${traceIdx}.approves.${h}.read_date`] = now;
1911
+ setObj[`traces.${traceIdx}.approves.${h}.cost_time`] = 0;
1912
+ setObj[`traces.${traceIdx}.approves.${h}.description`] = SKIP_DESCRIPTION;
1913
+ }
1914
+ }
1915
+
1916
+ // Remove skipped users from inbox_users
1917
+ const skippedHandlers = shouldSkipApproves.map(a => a.handler);
1918
+ const newInboxUsers = (instance.inbox_users || []).filter(u => !skippedHandlers.includes(u));
1919
+ setObj.inbox_users = newInboxUsers;
1920
+
1921
+ const skippedUserIds = shouldSkipApproves.map(a => a.user);
1922
+
1923
+ await instancesCollection.updateOne(
1924
+ { _id: instance_id },
1925
+ {
1926
+ $set: setObj,
1927
+ $addToSet: {
1928
+ processed_user_ids: { $each: skippedUserIds },
1929
+ outbox_users: { $each: skippedHandlers }
1930
+ }
1931
+ }
1932
+ );
1933
+
1934
+ // Update instance tasks for skipped approves
1935
+ for (const approve of shouldSkipApproves) {
1936
+ await update_instance_tasks(instance_id, lastTrace._id, approve._id);
1937
+ }
1938
+ }
1939
+ };
1940
+
1552
1941
  /**
1553
1942
  * Handle workflow engine for start/submit/condition steps
1554
1943
  * @param {String} instance_id - Instance ID
@@ -3155,6 +3544,18 @@ UUFlowManager.submit_instance = async function (instance_from_client, user_info)
3155
3544
  await insert_many_instance_tasks(instance_id, nextTrace._id, approveIds);
3156
3545
  }
3157
3546
 
3547
+ // Skip Processed: Initialize processed_user_ids with applicant
3548
+ const instancesCollectionForSkip = await getCollection('instances');
3549
+ await instancesCollectionForSkip.updateOne(
3550
+ { _id: instance_id },
3551
+ { $set: { processed_user_ids: [applicant_id] } }
3552
+ );
3553
+
3554
+ // Skip Processed: Check if next step should be auto-skipped
3555
+ if (next_step.step_type !== "end") {
3556
+ await UUFlowManager.handleSkipProcessed(instance_id, flow);
3557
+ }
3558
+
3158
3559
  if (next_step.step_type !== "end") {
3159
3560
  const finalInstance = await UUFlowManager.getInstance(instance_id);
3160
3561
  // 发送短消息给申请人
@@ -17,7 +17,7 @@ amis_schema: |-
17
17
  "url": "/api/workflow/v2/instance/save",
18
18
  "method": "post",
19
19
  "sendOn": "",
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;",
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 || 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
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')};",
22
22
  "data": {
23
23
  "&": "$$"
@@ -0,0 +1,62 @@
1
+ name: workflow_designer_backups
2
+ label: Designer Backups
3
+ icon: backup
4
+ hidden: true
5
+ enable_dataloader: false
6
+ fields:
7
+ name:
8
+ type: text
9
+ label: Name
10
+ required: true
11
+ name: name
12
+ form_id:
13
+ type: text
14
+ label: Form ID
15
+ required: true
16
+ name: form_id
17
+ index: true
18
+ flow_id:
19
+ type: text
20
+ label: Flow ID
21
+ name: flow_id
22
+ backup_type:
23
+ type: select
24
+ label: Backup Type
25
+ options:
26
+ - label: AI Upgrade
27
+ value: ai_upgrade
28
+ - label: Import
29
+ value: import
30
+ name: backup_type
31
+ form_snapshot:
32
+ type: textarea
33
+ label: Form Snapshot
34
+ name: form_snapshot
35
+ is_wide: true
36
+ flow_snapshot:
37
+ type: textarea
38
+ label: Flow Snapshot
39
+ name: flow_snapshot
40
+ is_wide: true
41
+ list_views:
42
+ all:
43
+ label: All
44
+ columns:
45
+ - name
46
+ - form_id
47
+ - backup_type
48
+ - created
49
+ sort:
50
+ - - created
51
+ - desc
52
+ permission_set:
53
+ user:
54
+ allowCreate: true
55
+ allowRead: true
56
+ allowEdit: true
57
+ allowDelete: true
58
+ admin:
59
+ allowCreate: true
60
+ allowRead: true
61
+ allowEdit: true
62
+ allowDelete: true
@@ -171,6 +171,13 @@ router.post('/api/workflow/v2/instance/return', requireAuthentication, async fun
171
171
  });
172
172
  // 生成新记录
173
173
  await insert_instance_tasks(instance_id, newTrace._id, newTrace.approves[0]._id)
174
+
175
+ // Skip Processed: Reset processed_user_ids to applicant only on return/rejection
176
+ await instancesCollection.updateOne(
177
+ { _id: instance_id },
178
+ { $set: { processed_user_ids: [ins.applicant] } }
179
+ );
180
+
174
181
  if (r && b) {
175
182
  await pushManager.send_message_to_specifyUser("current_user", current_user);
176
183
  instance = await UUFlowManager.getInstance(instance_id);
@@ -267,6 +267,8 @@ async function updateForm(formId, form, forms, flows, currentUserId) {
267
267
  current.viewMode = form["current"]["viewMode"];
268
268
  current.tableColumns = form["current"]["tableColumns"];
269
269
 
270
+ current.events = form["current"]["events"];
271
+
270
272
  formUpdateObj.$set = {
271
273
  'current': current,
272
274
  'name': form["name"],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steedos-labs/plugin-workflow",
3
- "version": "3.0.35",
3
+ "version": "3.0.37",
4
4
  "main": "package.service.js",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -9,6 +9,7 @@
9
9
  "designer/dist",
10
10
  "public/applications",
11
11
  "public/office",
12
+ "public/amis-renderer",
12
13
  "public/workflow",
13
14
  "package.service.js",
14
15
  "package.service.yml",