@nocobase/plugin-workflow-aggregate 0.18.0-alpha.1 → 0.18.0-alpha.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- (function(e,t){typeof exports=="object"&&typeof module!="undefined"?t(exports,require("@nocobase/client"),require("react/jsx-runtime"),require("@formily/react"),require("antd"),require("react"),require("@nocobase/plugin-workflow/client"),require("react-i18next")):typeof define=="function"&&define.amd?define(["exports","@nocobase/client","react/jsx-runtime","@formily/react","antd","react","@nocobase/plugin-workflow/client","react-i18next"],t):(e=typeof globalThis!="undefined"?globalThis:e||self,t(e["@nocobase/plugin-workflow-aggregate"]={},e["@nocobase/client"],e.jsxRuntime,e["@formily/react"],e.antd,e.react,e["@nocobase/plugin-workflow"],e["react-i18next"]))})(this,function(e,t,n,s,S,h,c,C){"use strict";var H=Object.defineProperty,J=Object.defineProperties;var W=Object.getOwnPropertyDescriptors;var I=Object.getOwnPropertySymbols;var A=Object.prototype.hasOwnProperty,D=Object.prototype.propertyIsEnumerable;var $=(e,t,n)=>t in e?H(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,O=(e,t)=>{for(var n in t||(t={}))A.call(t,n)&&$(e,n,t[n]);if(I)for(var n of I(t))D.call(t,n)&&$(e,n,t[n]);return e},V=(e,t)=>J(e,W(t));var G=(e,t)=>{var n={};for(var s in e)A.call(e,s)&&t.indexOf(s)<0&&(n[s]=e[s]);if(e!=null&&I)for(var s of I(e))t.indexOf(s)<0&&D.call(e,s)&&(n[s]=e[s]);return n};var g=(e,t,n)=>($(e,typeof t!="symbol"?t+"":t,n),n);var x=(e,t,n)=>new Promise((s,S)=>{var h=i=>{try{C(n.next(i))}catch(b){S(b)}},c=i=>{try{C(n.throw(i))}catch(b){S(b)}},C=i=>i.done?s(i.value):Promise.resolve(i.value).then(h,c);C((n=n.apply(e,t)).next())});const i="workflow-aggregate";function b(l,r={}){const{t:o}=B(r);return o(l)}function B(l){return C.useTranslation(i,l)}function N(l){return["hasMany","belongsToMany"].includes(l.type)}function P(){const l=t.useCompile();return[c.nodesOptions,c.triggerOptions].map(r=>{var p;const o=(p=r.useOptions({types:[N],appends:null,depth:4}))==null?void 0:p.filter(Boolean);return{label:l(r.label),value:r.value,key:r.value,children:l(o),disabled:o&&!o.length}})}function K(p){var f=p,{value:l,onChange:r}=f,o=G(f,["value","onChange"]);const{setValuesIn:v}=s.useForm(),{getCollection:T}=t.useCollectionManager(),M=P(),[F,q]=h.useState(M),{associatedKey:L="",name:z}=l!=null?l:{};let w=[];const j=L.match(/^{{(.*)}}$/);j&&(w=[...j[1].trim().split(".").slice(0,-1),z]);const U=m=>x(this,null,function*(){var u;const a=m[m.length-1];!((u=a.children)!=null&&u.length)&&!a.isLeaf&&a.loadChildren&&(yield a.loadChildren(a),q(d=>[...d]))});h.useEffect(()=>{x(this,null,function*(){var u;if(!w||F.length<=1)return;let a=null;for(let d=0;d<w.length;d++){const k=w[d];try{d===0?a=F.find(y=>y.value===k):(a.loadChildren&&!((u=a.children)!=null&&u.length)&&(yield a.loadChildren(a)),a=a.children.find(y=>y.value===k))}catch(y){console.error(y)}}q([...F])})},[l,F.length]);const _=h.useCallback((m,a)=>{if(!(m!=null&&m.length)){v("collection",null),r({});return}const{field:u}=a.pop();if(!u||!["hasMany","belongsToMany"].includes(u.type))return;const{collectionName:d,target:k,name:y}=u,Q=T(d).fields.find(X=>X.primaryKey);v("collection",k),r({name:y,associatedKey:`{{${m.slice(0,-1).join(".")}.${Q.name}}}`,associatedCollection:d})},[r]);return n.jsx(S.Cascader,V(O({},o),{value:w,options:F,onChange:_,loadData:U}))}class R extends c.Instruction{constructor(){super(...arguments);g(this,"title",`{{t("Aggregate", { ns: "${i}" })}}`);g(this,"type","aggregate");g(this,"group","collection");g(this,"description",`{{t("Counting, summing, finding maximum, minimum, and average values for multiple records of a collection or associated data of a record.", { ns: "${i}" })}}`);g(this,"fieldset",{aggregator:{type:"string",title:`{{t("Aggregator function", { ns: "${i}" })}}`,"x-decorator":"FormItem","x-component":"Radio.Group",enum:[{label:"COUNT",value:"count"},{label:"SUM",value:"sum"},{label:"AVG",value:"avg"},{label:"MIN",value:"min"},{label:"MAX",value:"max"}],required:!0,default:"count"},associated:{type:"boolean",title:`{{t("Target type", { ns: "${i}" })}}`,"x-decorator":"FormItem","x-component":"Radio.Group",enum:[{label:`{{t("Data of collection", { ns: "${i}" })}}`,value:!1},{label:`{{t("Data of associated collection", { ns: "${i}" })}}`,value:!0}],required:!0,default:!1,"x-reactions":[{target:"collection",effects:["onFieldValueChange"],fulfill:{state:{value:null}}},{target:"association",effects:["onFieldValueChange"],fulfill:{state:{value:null}}}]},collectionField:{type:"void","x-decorator":"SchemaComponentContext.Provider","x-decorator-props":{value:{designable:!1}},"x-component":"Grid",properties:{row:{type:"void","x-component":"Grid.Row",properties:{target:{type:"void","x-component":"Grid.Col",properties:{collection:{type:"string",required:!0,"x-decorator":"FormItem","x-component":"CollectionSelect",title:`{{t("Data of collection", { ns: "${i}" })}}`,"x-reactions":[{dependencies:["associated"],fulfill:{state:{display:'{{$deps[0] ? "hidden" : "visible"}}'}}},{target:"params.field",effects:["onFieldValueChange"],fulfill:{state:{value:null}}},{target:"params.filter",effects:["onFieldValueChange"],fulfill:{state:{value:null}}}]},association:{type:"object",title:`{{t("Data of associated collection", { ns: "${i}" })}}`,"x-decorator":"FormItem","x-component":"AssociatedConfig","x-component-props":{changeOnSelect:!0},"x-reactions":[{dependencies:["associated"],fulfill:{state:{visible:"{{!!$deps[0]}}"}}}],required:!0}}},field:{type:"void","x-component":"Grid.Col",properties:{"params.field":{type:"string",title:`{{t("Field to aggregate", { ns: "${i}" })}}`,"x-decorator":"FormItem","x-component":"FieldsSelect","x-component-props":{filter(o){return!o.hidden&&o.interface&&!["belongsTo","hasOne","hasMany","belongsToMany"].includes(o.type)}},required:!0,"x-reactions":[{dependencies:["collection"],fulfill:{state:{visible:"{{!!$deps[0]}}"}}}]}}}}}}},params:{type:"object",properties:{distinct:{type:"boolean",title:`{{t("Distinct", { ns: "${i}" })}}`,"x-decorator":"FormItem","x-component":"Checkbox","x-reactions":[{dependencies:["collection","aggregator"],fulfill:{state:{visible:'{{!!$deps[0] && ["count"].includes($deps[1])}}'}}}]},filter:{type:"object",title:'{{t("Filter")}}',"x-decorator":"FormItem","x-component":"Filter","x-component-props":{useProps(){const{values:o}=s.useForm();return{options:t.useCollectionFilterOptions(o==null?void 0:o.collection),className:t.css`
1
+ (function(e,t){typeof exports=="object"&&typeof module!="undefined"?t(exports,require("@nocobase/client"),require("react/jsx-runtime"),require("@formily/react"),require("antd"),require("react"),require("@nocobase/plugin-workflow/client"),require("react-i18next")):typeof define=="function"&&define.amd?define(["exports","@nocobase/client","react/jsx-runtime","@formily/react","antd","react","@nocobase/plugin-workflow/client","react-i18next"],t):(e=typeof globalThis!="undefined"?globalThis:e||self,t(e["@nocobase/plugin-workflow-aggregate"]={},e["@nocobase/client"],e.jsxRuntime,e["@formily/react"],e.antd,e.react,e["@nocobase/plugin-workflow"],e["react-i18next"]))})(this,function(e,t,o,s,S,h,r,C){"use strict";var H=Object.defineProperty,J=Object.defineProperties;var W=Object.getOwnPropertyDescriptors;var I=Object.getOwnPropertySymbols;var A=Object.prototype.hasOwnProperty,D=Object.prototype.propertyIsEnumerable;var $=(e,t,o)=>t in e?H(e,t,{enumerable:!0,configurable:!0,writable:!0,value:o}):e[t]=o,O=(e,t)=>{for(var o in t||(t={}))A.call(t,o)&&$(e,o,t[o]);if(I)for(var o of I(t))D.call(t,o)&&$(e,o,t[o]);return e},V=(e,t)=>J(e,W(t));var G=(e,t)=>{var o={};for(var s in e)A.call(e,s)&&t.indexOf(s)<0&&(o[s]=e[s]);if(e!=null&&I)for(var s of I(e))t.indexOf(s)<0&&D.call(e,s)&&(o[s]=e[s]);return o};var g=(e,t,o)=>($(e,typeof t!="symbol"?t+"":t,o),o);var x=(e,t,o)=>new Promise((s,S)=>{var h=i=>{try{C(o.next(i))}catch(b){S(b)}},r=i=>{try{C(o.throw(i))}catch(b){S(b)}},C=i=>i.done?s(i.value):Promise.resolve(i.value).then(h,r);C((o=o.apply(e,t)).next())});const i="workflow-aggregate";function b(l,c={}){const{t:n}=B(c);return n(l)}function B(l){return C.useTranslation(i,l)}function N(l){return["hasMany","belongsToMany"].includes(l.type)}function P(){const l=t.useCompile();return[r.nodesOptions,r.triggerOptions].map(c=>{var p;const n=(p=c.useOptions({types:[N],appends:null,depth:4}))==null?void 0:p.filter(Boolean);return{label:l(c.label),value:c.value,key:c.value,children:l(n),disabled:n&&!n.length}})}function K(p){var f=p,{value:l,onChange:c}=f,n=G(f,["value","onChange"]);const{setValuesIn:v}=s.useForm(),{getCollection:k}=t.useCollectionManager(),M=P(),[F,q]=h.useState(M),{associatedKey:L="",name:z}=l!=null?l:{};let w=[];const j=L.match(/^{{(.*)}}$/);j&&(w=[...j[1].trim().split(".").slice(0,-1),z]);const U=m=>x(this,null,function*(){var u;const a=m[m.length-1];!((u=a.children)!=null&&u.length)&&!a.isLeaf&&a.loadChildren&&(yield a.loadChildren(a),q(d=>[...d]))});h.useEffect(()=>{x(this,null,function*(){var u;if(!w||F.length<=1)return;let a=null;for(let d=0;d<w.length;d++){const T=w[d];try{d===0?a=F.find(y=>y.value===T):(a.loadChildren&&!((u=a.children)!=null&&u.length)&&(yield a.loadChildren(a)),a=a.children.find(y=>y.value===T))}catch(y){console.error(y)}}q([...F])})},[l,F.length]);const _=h.useCallback((m,a)=>{if(!(m!=null&&m.length)){v("collection",null),c({});return}const{field:u}=a.pop();if(!u||!["hasMany","belongsToMany"].includes(u.type))return;const{collectionName:d,target:T,name:y}=u,Q=k(d).fields.find(X=>X.primaryKey);v("collection",T),c({name:y,associatedKey:`{{${m.slice(0,-1).join(".")}.${Q.name}}}`,associatedCollection:d})},[c]);return o.jsx(S.Cascader,V(O({},n),{value:w,options:F,onChange:_,loadData:U}))}class R extends r.Instruction{constructor(){super(...arguments);g(this,"title",`{{t("Aggregate", { ns: "${i}" })}}`);g(this,"type","aggregate");g(this,"group","collection");g(this,"description",`{{t("Counting, summing, finding maximum, minimum, and average values for multiple records of a collection or associated data of a record.", { ns: "${i}" })}}`);g(this,"fieldset",{aggregator:{type:"string",title:`{{t("Aggregator function", { ns: "${i}" })}}`,"x-decorator":"FormItem","x-component":"Radio.Group",enum:[{label:"COUNT",value:"count"},{label:"SUM",value:"sum"},{label:"AVG",value:"avg"},{label:"MIN",value:"min"},{label:"MAX",value:"max"}],required:!0,default:"count"},associated:{type:"boolean",title:`{{t("Target type", { ns: "${i}" })}}`,"x-decorator":"FormItem","x-component":"Radio.Group",enum:[{label:`{{t("Data of collection", { ns: "${i}" })}}`,value:!1},{label:`{{t("Data of associated collection", { ns: "${i}" })}}`,value:!0}],required:!0,default:!1,"x-reactions":[{target:"collection",effects:["onFieldValueChange"],fulfill:{state:{value:null}}},{target:"association",effects:["onFieldValueChange"],fulfill:{state:{value:null}}}]},collectionField:{type:"void","x-decorator":"SchemaComponentContext.Provider","x-decorator-props":{value:{designable:!1}},"x-component":"Grid",properties:{row:{type:"void","x-component":"Grid.Row",properties:{target:{type:"void","x-component":"Grid.Col",properties:{collection:{type:"string",required:!0,"x-decorator":"FormItem","x-component":"CollectionSelect",title:`{{t("Data of collection", { ns: "${i}" })}}`,"x-reactions":[{dependencies:["associated"],fulfill:{state:{display:'{{$deps[0] ? "hidden" : "visible"}}'}}},{target:"params.field",effects:["onFieldValueChange"],fulfill:{state:{value:null}}},{target:"params.filter",effects:["onFieldValueChange"],fulfill:{state:{value:null}}}]},association:{type:"object",title:`{{t("Data of associated collection", { ns: "${i}" })}}`,"x-decorator":"FormItem","x-component":"AssociatedConfig","x-component-props":{changeOnSelect:!0},"x-reactions":[{dependencies:["associated"],fulfill:{state:{visible:"{{!!$deps[0]}}"}}}],required:!0}}},field:{type:"void","x-component":"Grid.Col",properties:{"params.field":{type:"string",title:`{{t("Field to aggregate", { ns: "${i}" })}}`,"x-decorator":"FormItem","x-component":"FieldsSelect","x-component-props":{filter(n){return!n.hidden&&n.interface&&!["belongsTo","hasOne","hasMany","belongsToMany"].includes(n.type)}},required:!0,"x-reactions":[{dependencies:["collection"],fulfill:{state:{visible:"{{!!$deps[0]}}"}}}]}}}}}}},params:{type:"object",properties:{distinct:{type:"boolean",title:`{{t("Distinct", { ns: "${i}" })}}`,"x-decorator":"FormItem","x-component":"Checkbox","x-reactions":[{dependencies:["collection","aggregator"],fulfill:{state:{visible:'{{!!$deps[0] && ["count"].includes($deps[1])}}'}}}]},filter:{type:"object",title:'{{t("Filter")}}',"x-decorator":"FormItem","x-component":"Filter","x-component-props":{useProps(){const{values:n}=s.useForm();return{options:t.useCollectionFilterOptions(n==null?void 0:n.collection),className:t.css`
2
2
  position: relative;
3
3
  width: 100%;
4
- `}},dynamicComponent:"FilterDynamicComponent"},"x-reactions":[{dependencies:["collection"],fulfill:{state:{visible:"{{!!$deps[0]}}"}}}]}}}});g(this,"scope",{useCollectionDataSource:t.useCollectionDataSource});g(this,"components",{SchemaComponentContext:t.SchemaComponentContext,FilterDynamicComponent:c.FilterDynamicComponent,FieldsSelect:c.FieldsSelect,ValueBlock:c.ValueBlock,AssociatedConfig:K})}useVariables({key:o,title:p},{types:f,fieldNames:v=c.defaultFieldNames}){return f&&!f.some(T=>T in c.BaseTypeSets||Object.values(c.BaseTypeSets).some(M=>M.has(T)))?null:{[v.value]:o,[v.label]:p}}useInitializers(o){var f;const p=b("Query result");return o.config.collection?{name:`#${o.id}`,type:"item",title:(f=o.title)!=null?f:`#${o.id}`,Component:c.ValueBlock.Initializer,node:o,resultTitle:p}:null}}class E extends t.Plugin{afterAdd(){return x(this,null,function*(){})}beforeLoad(){return x(this,null,function*(){})}load(){return x(this,null,function*(){const r=this.app.pm.get("workflow"),o=new R;r.instructions.register(o.type,o)})}}e.default=E,Object.defineProperties(e,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
4
+ `}},dynamicComponent:"FilterDynamicComponent"},"x-reactions":[{dependencies:["collection"],fulfill:{state:{visible:"{{!!$deps[0]}}"}}}]}}}});g(this,"scope",{useCollectionDataSource:t.useCollectionDataSource});g(this,"components",{SchemaComponentContext:t.SchemaComponentContext,FilterDynamicComponent:r.FilterDynamicComponent,FieldsSelect:r.FieldsSelect,ValueBlock:r.ValueBlock,AssociatedConfig:K})}useVariables({key:n,title:p},{types:f,fieldNames:v=r.defaultFieldNames}){return f&&!f.some(k=>k in r.BaseTypeSets||Object.values(r.BaseTypeSets).some(M=>M.has(k)))?null:{[v.value]:n,[v.label]:p}}useInitializers(n){var f;const p=b("Query result");return n.config.collection?{name:`#${n.id}`,type:"item",title:(f=n.title)!=null?f:`#${n.id}`,Component:r.ValueBlock.Initializer,node:n,resultTitle:p}:null}}class E extends t.Plugin{afterAdd(){return x(this,null,function*(){})}beforeLoad(){return x(this,null,function*(){})}load(){return x(this,null,function*(){this.app.pm.get("workflow").registerInstruction("aggregate",R)})}}e.default=E,Object.defineProperties(e,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
@@ -2,9 +2,12 @@ module.exports = {
2
2
  "@formily/react": "2.3.0",
3
3
  "antd": "5.12.2",
4
4
  "react": "18.2.0",
5
- "@nocobase/client": "0.18.0-alpha.1",
6
- "@nocobase/plugin-workflow": "0.18.0-alpha.1",
5
+ "@nocobase/client": "0.18.0-alpha.8",
6
+ "@nocobase/plugin-workflow": "0.18.0-alpha.8",
7
7
  "react-i18next": "11.18.6",
8
- "@nocobase/database": "0.18.0-alpha.1",
9
- "@nocobase/server": "0.18.0-alpha.1"
8
+ "@nocobase/database": "0.18.0-alpha.8",
9
+ "@nocobase/server": "0.18.0-alpha.8",
10
+ "@nocobase/plugin-workflow-test": "0.18.0-alpha.8",
11
+ "@nocobase/test": "0.18.0-alpha.8",
12
+ "@nocobase/utils": "0.18.0-alpha.8"
10
13
  };
@@ -2,6 +2,6 @@ import { Processor, Instruction, FlowNodeModel } from '@nocobase/plugin-workflow
2
2
  export default class extends Instruction {
3
3
  run(node: FlowNodeModel, input: any, processor: Processor): Promise<{
4
4
  result: any;
5
- status: number;
5
+ status: 1;
6
6
  }>;
7
7
  }
@@ -43,8 +43,8 @@ class AggregateInstruction_default extends import_plugin_workflow.Instruction {
43
43
  }
44
44
  const result = await repo.aggregate({
45
45
  ...options,
46
- method: aggregators[aggregator],
47
- transaction: processor.transaction
46
+ method: aggregators[aggregator]
47
+ // transaction: processor.transaction,
48
48
  });
49
49
  return {
50
50
  result: options.dataType === import_database.DataTypes.DOUBLE ? Number(result) : result,
@@ -1,6 +1,4 @@
1
1
  import { Plugin } from '@nocobase/server';
2
- import WorkflowPlugin from '@nocobase/plugin-workflow';
3
2
  export default class extends Plugin {
4
- workflow: WorkflowPlugin;
5
3
  load(): Promise<void>;
6
4
  }
@@ -30,13 +30,12 @@ __export(Plugin_exports, {
30
30
  default: () => Plugin_default
31
31
  });
32
32
  module.exports = __toCommonJS(Plugin_exports);
33
+ var import_plugin_workflow = __toESM(require("@nocobase/plugin-workflow"));
33
34
  var import_server = require("@nocobase/server");
34
35
  var import_AggregateInstruction = __toESM(require("./AggregateInstruction"));
35
36
  class Plugin_default extends import_server.Plugin {
36
- workflow;
37
37
  async load() {
38
- const workflowPlugin = this.app.getPlugin("workflow");
39
- this.workflow = workflowPlugin;
40
- workflowPlugin.instructions.register("aggregate", new import_AggregateInstruction.default(workflowPlugin));
38
+ const workflowPlugin = this.app.getPlugin(import_plugin_workflow.default);
39
+ workflowPlugin.registerInstruction("aggregate", import_AggregateInstruction.default);
41
40
  }
42
41
  }
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "displayName.zh-CN": "工作流:聚合查询节点",
5
5
  "description": "Used to aggregate data against the database in workflow, such as: statistics, sum, average, etc.",
6
6
  "description.zh-CN": "可用于在工作流中对数据库进行聚合查询,如:统计数量、求和、平均值等。",
7
- "version": "0.18.0-alpha.1",
7
+ "version": "0.18.0-alpha.8",
8
8
  "license": "AGPL-3.0",
9
9
  "main": "./dist/server/index.js",
10
10
  "devDependencies": {
@@ -16,9 +16,8 @@
16
16
  "@nocobase/client": "0.x",
17
17
  "@nocobase/database": "0.x",
18
18
  "@nocobase/plugin-workflow": ">=0.17.0-alpha.3",
19
- "@nocobase/plugin-workflow-test": ">=0.17.0-alpha.3",
20
19
  "@nocobase/server": "0.x",
21
20
  "@nocobase/test": "0.x"
22
21
  },
23
- "gitHead": "0f5f1c0a37dc397a9dc4c8eec0c4ec20fd8107b0"
22
+ "gitHead": "727d42f6f14e5f863831da3dbf3255ba1165b567"
24
23
  }
@@ -0,0 +1,519 @@
1
+ import { faker } from '@faker-js/faker';
2
+ import {
3
+ AggregateNode,
4
+ CollectionTriggerNode,
5
+ apiCreateWorkflow,
6
+ apiDeleteWorkflow,
7
+ apiGetWorkflow,
8
+ apiGetWorkflowNodeExecutions,
9
+ apiUpdateWorkflowTrigger,
10
+ appendJsonCollectionName,
11
+ generalWithNoRelationalFields,
12
+ } from '@nocobase/plugin-workflow-test/e2e';
13
+ import { expect, test } from '@nocobase/test/e2e';
14
+ import { dayjs } from '@nocobase/utils';
15
+
16
+ test('Collection event add data trigger, aggregated data table, no filtering, normal table integer fields not de-emphasised COUNT', async ({
17
+ page,
18
+ mockCollections,
19
+ mockRecords,
20
+ }) => {
21
+ //数据表后缀标识
22
+ const triggerNodeAppendText = 'a' + faker.string.alphanumeric(4);
23
+ const aggregateNodeAppendText = 'b' + faker.string.alphanumeric(4);
24
+ //创建触发器节点数据表
25
+ const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
26
+ const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
27
+ const triggerNodeFieldName = 'orgname';
28
+ const triggerNodeFieldDisplayName = '公司名称(单行文本)';
29
+ await mockCollections(
30
+ appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
31
+ .collections,
32
+ );
33
+
34
+ // 创建聚合节点数据表
35
+ const aggregateNodeCollectionDisplayName = `自动>组织[普通表]${aggregateNodeAppendText}`;
36
+ const aggregateNodeCollectionName = `tt_amt_org${aggregateNodeAppendText}`;
37
+ const aggregateNodeFieldName = 'staffnum';
38
+ const aggregateNodeFieldDisplayName = '员工人数(整数)';
39
+ await mockCollections(
40
+ appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), aggregateNodeAppendText)
41
+ .collections,
42
+ );
43
+ const aggregateNodeCollectionData = [
44
+ { staffnum: 3, regcapital: 3.12 },
45
+ { staffnum: 3, regcapital: 3.6 },
46
+ { staffnum: 4, regcapital: 4.6 },
47
+ { staffnum: 4, regcapital: 4.6 },
48
+ { staffnum: 5, regcapital: 5.6 },
49
+ ];
50
+ const aggregateNodeCollectionRecords = await mockRecords(aggregateNodeCollectionName, aggregateNodeCollectionData);
51
+
52
+ //添加工作流
53
+ const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
54
+ const workflowData = {
55
+ current: true,
56
+ options: { deleteExecutionOnStatus: [] },
57
+ title: workFlowName,
58
+ type: 'collection',
59
+ enabled: true,
60
+ };
61
+ const workflow = await apiCreateWorkflow(workflowData);
62
+ const workflowObj = JSON.parse(JSON.stringify(workflow));
63
+ const workflowId = workflowObj.id;
64
+ //配置工作流触发器
65
+ const triggerNodeData = {
66
+ config: { appends: [], collection: triggerNodeCollectionName, changed: [], condition: { $and: [] }, mode: 1 },
67
+ };
68
+ const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
69
+ const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
70
+
71
+ //配置聚合数据节点
72
+ await page.goto(`admin/workflow/workflows/${workflowId}`);
73
+ await page.waitForLoadState('networkidle');
74
+ const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
75
+ await collectionTriggerNode.addNodeButton.click();
76
+ await page.getByRole('button', { name: 'aggregate', exact: true }).click();
77
+ const aggregateRecordNodeName = 'Aggregate' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
78
+ await page.getByLabel('Aggregate-Aggregate', { exact: true }).getByRole('textbox').fill(aggregateRecordNodeName);
79
+ const aggregateRecordNode = new AggregateNode(page, aggregateRecordNodeName);
80
+ const aggregateRecordNodeId = await aggregateRecordNode.node.locator('.workflow-node-id').innerText();
81
+ await aggregateRecordNode.nodeConfigure.click();
82
+ await aggregateRecordNode.collectionDropDown.click();
83
+ await page.getByText(aggregateNodeCollectionDisplayName).click();
84
+ await aggregateRecordNode.aggregatedFieldDropDown.click();
85
+ await page.getByRole('option', { name: aggregateNodeFieldDisplayName }).click();
86
+ await aggregateRecordNode.submitButton.click();
87
+
88
+ // 2、测试步骤:添加数据触发工作流
89
+ const triggerNodeCollectionRecordOne = triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
90
+ const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
91
+ { orgname: triggerNodeCollectionRecordOne },
92
+ ]);
93
+ await page.waitForTimeout(1000);
94
+
95
+ // 3、预期结果:工作流成功触发,数据查询成功
96
+ const getWorkflow = await apiGetWorkflow(workflowId);
97
+ const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
98
+ const getWorkflowExecuted = getWorkflowObj.executed;
99
+ expect(getWorkflowExecuted).toBe(1);
100
+ const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
101
+ const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
102
+ getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
103
+ return b.id - a.id;
104
+ });
105
+ const jobs = getWorkflowNodeExecutionsObj[0].jobs;
106
+ const queryRecordNodeJob = jobs.find((job) => job.nodeId.toString() === aggregateRecordNodeId);
107
+ const queryRecordNodeJobResult = queryRecordNodeJob.result;
108
+ expect(queryRecordNodeJobResult).toBe(aggregateNodeCollectionData.length);
109
+ // 4、后置处理:删除工作流
110
+ await apiDeleteWorkflow(workflowId);
111
+ });
112
+
113
+ test('Collection event add data trigger, aggregated data table, no filtering, normal table integer fields not de-emphasised SUM', async ({
114
+ page,
115
+ mockCollections,
116
+ mockRecords,
117
+ }) => {
118
+ //数据表后缀标识
119
+ const triggerNodeAppendText = 'a' + faker.string.alphanumeric(4);
120
+ const aggregateNodeAppendText = 'b' + faker.string.alphanumeric(4);
121
+ //创建触发器节点数据表
122
+ const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
123
+ const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
124
+ const triggerNodeFieldName = 'orgname';
125
+ const triggerNodeFieldDisplayName = '公司名称(单行文本)';
126
+ await mockCollections(
127
+ appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
128
+ .collections,
129
+ );
130
+
131
+ // 创建聚合节点数据表
132
+ const aggregateNodeCollectionDisplayName = `自动>组织[普通表]${aggregateNodeAppendText}`;
133
+ const aggregateNodeCollectionName = `tt_amt_org${aggregateNodeAppendText}`;
134
+ const aggregateNodeFieldName = 'staffnum';
135
+ const aggregateNodeFieldDisplayName = '员工人数(整数)';
136
+ await mockCollections(
137
+ appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), aggregateNodeAppendText)
138
+ .collections,
139
+ );
140
+ const aggregateNodeCollectionData = [
141
+ { staffnum: 3, regcapital: 3.12 },
142
+ { staffnum: 3, regcapital: 3.6 },
143
+ { staffnum: 4, regcapital: 4.6 },
144
+ { staffnum: 4, regcapital: 4.6 },
145
+ { staffnum: 5, regcapital: 5.6 },
146
+ ];
147
+ const aggregateNodeCollectionRecords = await mockRecords(aggregateNodeCollectionName, aggregateNodeCollectionData);
148
+
149
+ //添加工作流
150
+ const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
151
+ const workflowData = {
152
+ current: true,
153
+ options: { deleteExecutionOnStatus: [] },
154
+ title: workFlowName,
155
+ type: 'collection',
156
+ enabled: true,
157
+ };
158
+ const workflow = await apiCreateWorkflow(workflowData);
159
+ const workflowObj = JSON.parse(JSON.stringify(workflow));
160
+ const workflowId = workflowObj.id;
161
+ //配置工作流触发器
162
+ const triggerNodeData = {
163
+ config: { appends: [], collection: triggerNodeCollectionName, changed: [], condition: { $and: [] }, mode: 1 },
164
+ };
165
+ const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
166
+ const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
167
+
168
+ //配置聚合数据节点
169
+ await page.goto(`admin/workflow/workflows/${workflowId}`);
170
+ await page.waitForLoadState('networkidle');
171
+ const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
172
+ await collectionTriggerNode.addNodeButton.click();
173
+ await page.getByRole('button', { name: 'aggregate', exact: true }).click();
174
+ const aggregateRecordNodeName = 'Aggregate' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
175
+ await page.getByLabel('Aggregate-Aggregate', { exact: true }).getByRole('textbox').fill(aggregateRecordNodeName);
176
+ const aggregateRecordNode = new AggregateNode(page, aggregateRecordNodeName);
177
+ const aggregateRecordNodeId = await aggregateRecordNode.node.locator('.workflow-node-id').innerText();
178
+ await aggregateRecordNode.nodeConfigure.click();
179
+ await aggregateRecordNode.sumRadio.click();
180
+ await aggregateRecordNode.collectionDropDown.click();
181
+ await page.getByText(aggregateNodeCollectionDisplayName).click();
182
+ await aggregateRecordNode.aggregatedFieldDropDown.click();
183
+ await page.getByRole('option', { name: aggregateNodeFieldDisplayName }).click();
184
+ await aggregateRecordNode.submitButton.click();
185
+
186
+ // 2、测试步骤:添加数据触发工作流
187
+ const triggerNodeCollectionRecordOne = triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
188
+ const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
189
+ { orgname: triggerNodeCollectionRecordOne },
190
+ ]);
191
+ await page.waitForTimeout(1000);
192
+
193
+ // 3、预期结果:工作流成功触发,数据查询成功
194
+ const getWorkflow = await apiGetWorkflow(workflowId);
195
+ const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
196
+ const getWorkflowExecuted = getWorkflowObj.executed;
197
+ expect(getWorkflowExecuted).toBe(1);
198
+ const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
199
+ const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
200
+ getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
201
+ return b.id - a.id;
202
+ });
203
+ const jobs = getWorkflowNodeExecutionsObj[0].jobs;
204
+ const queryRecordNodeJob = jobs.find((job) => job.nodeId.toString() === aggregateRecordNodeId);
205
+ const queryRecordNodeJobResult = queryRecordNodeJob.result;
206
+ // aggregateNodeCollectionData中staffnum字段值总和
207
+ const aggregateNodeCollectionDataSum = aggregateNodeCollectionData.reduce((total, currentValue) => {
208
+ return total + currentValue.staffnum;
209
+ }, 0);
210
+ expect(queryRecordNodeJobResult).toBe(aggregateNodeCollectionDataSum);
211
+ // 4、后置处理:删除工作流
212
+ await apiDeleteWorkflow(workflowId);
213
+ });
214
+
215
+ test('Collection event add data trigger, aggregated data table, no filtering, normal table integer fields not de-emphasised AVG', async ({
216
+ page,
217
+ mockCollections,
218
+ mockRecords,
219
+ }) => {
220
+ //数据表后缀标识
221
+ const triggerNodeAppendText = 'a' + faker.string.alphanumeric(4);
222
+ const aggregateNodeAppendText = 'b' + faker.string.alphanumeric(4);
223
+ //创建触发器节点数据表
224
+ const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
225
+ const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
226
+ const triggerNodeFieldName = 'orgname';
227
+ const triggerNodeFieldDisplayName = '公司名称(单行文本)';
228
+ await mockCollections(
229
+ appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
230
+ .collections,
231
+ );
232
+
233
+ // 创建聚合节点数据表
234
+ const aggregateNodeCollectionDisplayName = `自动>组织[普通表]${aggregateNodeAppendText}`;
235
+ const aggregateNodeCollectionName = `tt_amt_org${aggregateNodeAppendText}`;
236
+ const aggregateNodeFieldName = 'staffnum';
237
+ const aggregateNodeFieldDisplayName = '员工人数(整数)';
238
+ await mockCollections(
239
+ appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), aggregateNodeAppendText)
240
+ .collections,
241
+ );
242
+ const aggregateNodeCollectionData = [
243
+ { staffnum: 3, regcapital: 3.12 },
244
+ { staffnum: 3, regcapital: 3.6 },
245
+ { staffnum: 4, regcapital: 4.6 },
246
+ { staffnum: 4, regcapital: 4.6 },
247
+ { staffnum: 5, regcapital: 5.6 },
248
+ ];
249
+ const aggregateNodeCollectionRecords = await mockRecords(aggregateNodeCollectionName, aggregateNodeCollectionData);
250
+
251
+ //添加工作流
252
+ const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
253
+ const workflowData = {
254
+ current: true,
255
+ options: { deleteExecutionOnStatus: [] },
256
+ title: workFlowName,
257
+ type: 'collection',
258
+ enabled: true,
259
+ };
260
+ const workflow = await apiCreateWorkflow(workflowData);
261
+ const workflowObj = JSON.parse(JSON.stringify(workflow));
262
+ const workflowId = workflowObj.id;
263
+ //配置工作流触发器
264
+ const triggerNodeData = {
265
+ config: { appends: [], collection: triggerNodeCollectionName, changed: [], condition: { $and: [] }, mode: 1 },
266
+ };
267
+ const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
268
+ const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
269
+ //配置聚合数据节点
270
+ await page.goto(`admin/workflow/workflows/${workflowId}`);
271
+ await page.waitForLoadState('networkidle');
272
+ const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
273
+ await collectionTriggerNode.addNodeButton.click();
274
+ await page.getByRole('button', { name: 'aggregate', exact: true }).click();
275
+ const aggregateRecordNodeName = 'Aggregate' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
276
+ await page.getByLabel('Aggregate-Aggregate', { exact: true }).getByRole('textbox').fill(aggregateRecordNodeName);
277
+ const aggregateRecordNode = new AggregateNode(page, aggregateRecordNodeName);
278
+ const aggregateRecordNodeId = await aggregateRecordNode.node.locator('.workflow-node-id').innerText();
279
+ await aggregateRecordNode.nodeConfigure.click();
280
+ await aggregateRecordNode.avgRadio.click();
281
+ await aggregateRecordNode.collectionDropDown.click();
282
+ await page.getByText(aggregateNodeCollectionDisplayName).click();
283
+ await aggregateRecordNode.aggregatedFieldDropDown.click();
284
+ await page.getByRole('option', { name: aggregateNodeFieldDisplayName }).click();
285
+ await aggregateRecordNode.submitButton.click();
286
+
287
+ // 2、测试步骤:添加数据触发工作流
288
+ const triggerNodeCollectionRecordOne = triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
289
+ const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
290
+ { orgname: triggerNodeCollectionRecordOne },
291
+ ]);
292
+ await page.waitForTimeout(1000);
293
+
294
+ // 3、预期结果:工作流成功触发,数据查询成功
295
+ const getWorkflow = await apiGetWorkflow(workflowId);
296
+ const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
297
+ const getWorkflowExecuted = getWorkflowObj.executed;
298
+ expect(getWorkflowExecuted).toBe(1);
299
+ const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
300
+ const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
301
+ getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
302
+ return b.id - a.id;
303
+ });
304
+ const jobs = getWorkflowNodeExecutionsObj[0].jobs;
305
+ const queryRecordNodeJob = jobs.find((job) => job.nodeId.toString() === aggregateRecordNodeId);
306
+ const queryRecordNodeJobResult = queryRecordNodeJob.result;
307
+ // aggregateNodeCollectionData中staffnum字段值平均值
308
+ const aggregateNodeCollectionDataAvg =
309
+ aggregateNodeCollectionData.reduce((total, currentValue) => {
310
+ return total + currentValue.staffnum;
311
+ }, 0) / aggregateNodeCollectionData.length;
312
+ expect(queryRecordNodeJobResult).toBe(aggregateNodeCollectionDataAvg);
313
+ // 4、后置处理:删除工作流
314
+ await apiDeleteWorkflow(workflowId);
315
+ });
316
+
317
+ test('Collection event add data trigger, aggregated data table, no filtering, normal table integer fields not de-emphasised MIN', async ({
318
+ page,
319
+ mockCollections,
320
+ mockRecords,
321
+ }) => {
322
+ //数据表后缀标识
323
+ const triggerNodeAppendText = 'a' + faker.string.alphanumeric(4);
324
+ const aggregateNodeAppendText = 'b' + faker.string.alphanumeric(4);
325
+ //创建触发器节点数据表
326
+ const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
327
+ const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
328
+ const triggerNodeFieldName = 'orgname';
329
+ const triggerNodeFieldDisplayName = '公司名称(单行文本)';
330
+ await mockCollections(
331
+ appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
332
+ .collections,
333
+ );
334
+
335
+ // 创建聚合节点数据表
336
+ const aggregateNodeCollectionDisplayName = `自动>组织[普通表]${aggregateNodeAppendText}`;
337
+ const aggregateNodeCollectionName = `tt_amt_org${aggregateNodeAppendText}`;
338
+ const aggregateNodeFieldName = 'staffnum';
339
+ const aggregateNodeFieldDisplayName = '员工人数(整数)';
340
+ await mockCollections(
341
+ appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), aggregateNodeAppendText)
342
+ .collections,
343
+ );
344
+ const aggregateNodeCollectionData = [
345
+ { staffnum: 3, regcapital: 3.12 },
346
+ { staffnum: 3, regcapital: 3.6 },
347
+ { staffnum: 4, regcapital: 4.6 },
348
+ { staffnum: 4, regcapital: 4.6 },
349
+ { staffnum: 5, regcapital: 5.6 },
350
+ ];
351
+ const aggregateNodeCollectionRecords = await mockRecords(aggregateNodeCollectionName, aggregateNodeCollectionData);
352
+
353
+ //添加工作流
354
+ const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
355
+ const workflowData = {
356
+ current: true,
357
+ options: { deleteExecutionOnStatus: [] },
358
+ title: workFlowName,
359
+ type: 'collection',
360
+ enabled: true,
361
+ };
362
+ const workflow = await apiCreateWorkflow(workflowData);
363
+ const workflowObj = JSON.parse(JSON.stringify(workflow));
364
+ const workflowId = workflowObj.id;
365
+ //配置工作流触发器
366
+ const triggerNodeData = {
367
+ config: { appends: [], collection: triggerNodeCollectionName, changed: [], condition: { $and: [] }, mode: 1 },
368
+ };
369
+ const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
370
+ const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
371
+
372
+ //配置聚合数据节点
373
+ await page.goto(`admin/workflow/workflows/${workflowId}`);
374
+ await page.waitForLoadState('networkidle');
375
+ const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
376
+ await collectionTriggerNode.addNodeButton.click();
377
+ await page.getByRole('button', { name: 'aggregate', exact: true }).click();
378
+ const aggregateRecordNodeName = 'Aggregate' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
379
+ await page.getByLabel('Aggregate-Aggregate', { exact: true }).getByRole('textbox').fill(aggregateRecordNodeName);
380
+ const aggregateRecordNode = new AggregateNode(page, aggregateRecordNodeName);
381
+ const aggregateRecordNodeId = await aggregateRecordNode.node.locator('.workflow-node-id').innerText();
382
+ await aggregateRecordNode.nodeConfigure.click();
383
+ await aggregateRecordNode.minRadio.click();
384
+ await aggregateRecordNode.collectionDropDown.click();
385
+ await page.getByText(aggregateNodeCollectionDisplayName).click();
386
+ await aggregateRecordNode.aggregatedFieldDropDown.click();
387
+ await page.getByRole('option', { name: aggregateNodeFieldDisplayName }).click();
388
+ await aggregateRecordNode.submitButton.click();
389
+
390
+ // 2、测试步骤:添加数据触发工作流
391
+ const triggerNodeCollectionRecordOne = triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
392
+ const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
393
+ { orgname: triggerNodeCollectionRecordOne },
394
+ ]);
395
+ await page.waitForTimeout(1000);
396
+
397
+ // 3、预期结果:工作流成功触发,数据查询成功
398
+ const getWorkflow = await apiGetWorkflow(workflowId);
399
+ const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
400
+ const getWorkflowExecuted = getWorkflowObj.executed;
401
+ expect(getWorkflowExecuted).toBe(1);
402
+ const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
403
+ const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
404
+ getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
405
+ return b.id - a.id;
406
+ });
407
+ const jobs = getWorkflowNodeExecutionsObj[0].jobs;
408
+ const queryRecordNodeJob = jobs.find((job) => job.nodeId.toString() === aggregateRecordNodeId);
409
+ const queryRecordNodeJobResult = queryRecordNodeJob.result;
410
+ // aggregateNodeCollectionData中staffnum字段值最小值
411
+ const aggregateNodeCollectionDataMin = aggregateNodeCollectionData.reduce((min, currentValue) => {
412
+ return currentValue.staffnum < min ? currentValue.staffnum : min;
413
+ }, aggregateNodeCollectionData[0].staffnum);
414
+ expect(queryRecordNodeJobResult).toBe(aggregateNodeCollectionDataMin);
415
+ // 4、后置处理:删除工作流
416
+ await apiDeleteWorkflow(workflowId);
417
+ });
418
+
419
+ test('Collection event add data trigger, aggregated data table, no filtering, normal table integer fields not de-emphasised MAX', async ({
420
+ page,
421
+ mockCollections,
422
+ mockRecords,
423
+ }) => {
424
+ //数据表后缀标识
425
+ const triggerNodeAppendText = 'a' + faker.string.alphanumeric(4);
426
+ const aggregateNodeAppendText = 'b' + faker.string.alphanumeric(4);
427
+ //创建触发器节点数据表
428
+ const triggerNodeCollectionDisplayName = `自动>组织[普通表]${triggerNodeAppendText}`;
429
+ const triggerNodeCollectionName = `tt_amt_org${triggerNodeAppendText}`;
430
+ const triggerNodeFieldName = 'orgname';
431
+ const triggerNodeFieldDisplayName = '公司名称(单行文本)';
432
+ await mockCollections(
433
+ appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), triggerNodeAppendText)
434
+ .collections,
435
+ );
436
+
437
+ // 创建聚合节点数据表
438
+ const aggregateNodeCollectionDisplayName = `自动>组织[普通表]${aggregateNodeAppendText}`;
439
+ const aggregateNodeCollectionName = `tt_amt_org${aggregateNodeAppendText}`;
440
+ const aggregateNodeFieldName = 'staffnum';
441
+ const aggregateNodeFieldDisplayName = '员工人数(整数)';
442
+ await mockCollections(
443
+ appendJsonCollectionName(JSON.parse(JSON.stringify(generalWithNoRelationalFields)), aggregateNodeAppendText)
444
+ .collections,
445
+ );
446
+ const aggregateNodeCollectionData = [
447
+ { staffnum: 3, regcapital: 3.12 },
448
+ { staffnum: 3, regcapital: 3.6 },
449
+ { staffnum: 4, regcapital: 4.6 },
450
+ { staffnum: 4, regcapital: 4.6 },
451
+ { staffnum: 5, regcapital: 5.6 },
452
+ ];
453
+ const aggregateNodeCollectionRecords = await mockRecords(aggregateNodeCollectionName, aggregateNodeCollectionData);
454
+
455
+ //添加工作流
456
+ const workFlowName = faker.string.alphanumeric(5) + triggerNodeAppendText;
457
+ const workflowData = {
458
+ current: true,
459
+ options: { deleteExecutionOnStatus: [] },
460
+ title: workFlowName,
461
+ type: 'collection',
462
+ enabled: true,
463
+ };
464
+ const workflow = await apiCreateWorkflow(workflowData);
465
+ const workflowObj = JSON.parse(JSON.stringify(workflow));
466
+ const workflowId = workflowObj.id;
467
+ //配置工作流触发器
468
+ const triggerNodeData = {
469
+ config: { appends: [], collection: triggerNodeCollectionName, changed: [], condition: { $and: [] }, mode: 1 },
470
+ };
471
+ const triggerNode = await apiUpdateWorkflowTrigger(workflowId, triggerNodeData);
472
+ const triggerNodeObj = JSON.parse(JSON.stringify(triggerNode));
473
+
474
+ //配置聚合数据节点
475
+ await page.goto(`admin/workflow/workflows/${workflowId}`);
476
+ await page.waitForLoadState('networkidle');
477
+ const collectionTriggerNode = new CollectionTriggerNode(page, workFlowName, triggerNodeCollectionName);
478
+ await collectionTriggerNode.addNodeButton.click();
479
+ await page.getByRole('button', { name: 'aggregate', exact: true }).click();
480
+ const aggregateRecordNodeName = 'Aggregate' + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
481
+ await page.getByLabel('Aggregate-Aggregate', { exact: true }).getByRole('textbox').fill(aggregateRecordNodeName);
482
+ const aggregateRecordNode = new AggregateNode(page, aggregateRecordNodeName);
483
+ const aggregateRecordNodeId = await aggregateRecordNode.node.locator('.workflow-node-id').innerText();
484
+ await aggregateRecordNode.nodeConfigure.click();
485
+ await aggregateRecordNode.maxRadio.click();
486
+ await aggregateRecordNode.collectionDropDown.click();
487
+ await page.getByText(aggregateNodeCollectionDisplayName).click();
488
+ await aggregateRecordNode.aggregatedFieldDropDown.click();
489
+ await page.getByRole('option', { name: aggregateNodeFieldDisplayName }).click();
490
+ await aggregateRecordNode.submitButton.click();
491
+
492
+ // 2、测试步骤:添加数据触发工作流
493
+ const triggerNodeCollectionRecordOne = triggerNodeFieldDisplayName + dayjs().format('YYYYMMDDHHmmss.SSS').toString();
494
+ const triggerNodeCollectionRecords = await mockRecords(triggerNodeCollectionName, [
495
+ { orgname: triggerNodeCollectionRecordOne },
496
+ ]);
497
+ await page.waitForTimeout(1000);
498
+
499
+ // 3、预期结果:工作流成功触发,数据查询成功
500
+ const getWorkflow = await apiGetWorkflow(workflowId);
501
+ const getWorkflowObj = JSON.parse(JSON.stringify(getWorkflow));
502
+ const getWorkflowExecuted = getWorkflowObj.executed;
503
+ expect(getWorkflowExecuted).toBe(1);
504
+ const getWorkflowNodeExecutions = await apiGetWorkflowNodeExecutions(workflowId);
505
+ const getWorkflowNodeExecutionsObj = JSON.parse(JSON.stringify(getWorkflowNodeExecutions));
506
+ getWorkflowNodeExecutionsObj.sort(function (a: { id: number }, b: { id: number }) {
507
+ return b.id - a.id;
508
+ });
509
+ const jobs = getWorkflowNodeExecutionsObj[0].jobs;
510
+ const queryRecordNodeJob = jobs.find((job) => job.nodeId.toString() === aggregateRecordNodeId);
511
+ const queryRecordNodeJobResult = queryRecordNodeJob.result;
512
+ // aggregateNodeCollectionData中staffnum字段值最大值
513
+ const aggregateNodeCollectionDataMax = aggregateNodeCollectionData.reduce((max, currentValue) => {
514
+ return currentValue.staffnum > max ? currentValue.staffnum : max;
515
+ }, aggregateNodeCollectionData[0].staffnum);
516
+ expect(queryRecordNodeJobResult).toBe(aggregateNodeCollectionDataMax);
517
+ // 4、后置处理:删除工作流
518
+ await apiDeleteWorkflow(workflowId);
519
+ });
@@ -13,7 +13,6 @@ export default class extends Plugin {
13
13
  // You can get and modify the app instance here
14
14
  async load() {
15
15
  const workflow = this.app.pm.get('workflow') as WorkflowPlugin;
16
- const aggregateInstruction = new AggregateInstruction();
17
- workflow.instructions.register(aggregateInstruction.type, aggregateInstruction);
16
+ workflow.registerInstruction('aggregate', AggregateInstruction);
18
17
  }
19
18
  }
@@ -28,7 +28,7 @@ export default class extends Instruction {
28
28
  const result = await repo.aggregate({
29
29
  ...options,
30
30
  method: aggregators[aggregator],
31
- transaction: processor.transaction,
31
+ // transaction: processor.transaction,
32
32
  });
33
33
 
34
34
  return {
@@ -1,14 +1,11 @@
1
- import { Plugin } from '@nocobase/server';
2
1
  import WorkflowPlugin from '@nocobase/plugin-workflow';
2
+ import { Plugin } from '@nocobase/server';
3
3
 
4
4
  import AggregateInstruction from './AggregateInstruction';
5
5
 
6
6
  export default class extends Plugin {
7
- workflow: WorkflowPlugin;
8
-
9
7
  async load() {
10
- const workflowPlugin = this.app.getPlugin('workflow') as WorkflowPlugin;
11
- this.workflow = workflowPlugin;
12
- workflowPlugin.instructions.register('aggregate', new AggregateInstruction(workflowPlugin));
8
+ const workflowPlugin = this.app.getPlugin<WorkflowPlugin>(WorkflowPlugin);
9
+ workflowPlugin.registerInstruction('aggregate', AggregateInstruction);
13
10
  }
14
11
  }