@stalfh233/omc-cli 0.4.35 → 0.4.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.
@@ -0,0 +1,87 @@
1
+ import { environment, commonRecovery } from "./shared.js";
2
+ const restfulQueryService = Object.freeze({
3
+ id: "restful-query-service",
4
+ title: "注册 RESTFUL 查询服务 + 一个方法(含参数面)",
5
+ status: "requires-prior-readback",
6
+ tool: "service.register",
7
+ args: {
8
+ environment,
9
+ serviceCode: "<service_code>",
10
+ name: "供应商查询服务",
11
+ adapterCode: "RESTFUL",
12
+ serviceCategoryId: "<category.id>",
13
+ serviceConfig: {
14
+ auth: { code: "customer", parameterlist: [] },
15
+ commonlist: [{ code: "url", value: "http://<host>/api" }],
16
+ },
17
+ methodName: "querySupplier",
18
+ methodConfig: { httpType: "Post", requestBodyType: "JSON", url: "/supplier/query", frontEndExtensionEnable: true },
19
+ methodInputParameters: [{ code: "keyword", name: "关键字", required: true, configJson: { position: "REQUEST_BODY" } }],
20
+ methodOutputParameters: [{ code: "name", name: "供应商名称", configJson: { position: "REQUEST_BODY" } }],
21
+ },
22
+ preconditions: ["serviceCategoryId 由 service.category.list 解析(「全部」是空 id 虚拟项不可用);RESTFUL 服务 configJson 需要 auth 与 commonlist[url];带 methodName 时必须有 methodConfig"],
23
+ conditionalRequirements: [
24
+ "RESTFUL auth.code ∈ customer(parameterlist=[]) / basic(client… username/password) / oauth_password / oauth_client;parameterlist 每项 {code,value} 且必须与 auth.code 期望参数完全一致",
25
+ "RESTFUL 方法 configJson 必需键:httpType(Post/Get/Put/Patch/Delete)、requestBodyType(Form-urlencoded/JSON/Text)、url、frontEndExtensionEnable(布尔)",
26
+ "RESTFUL 每个输入/输出参数必须带 configJson.position ∈ QUERY_PARAMS/REQUEST_HEADER/REQUEST_BODY/PATH_PARAMS(URL_VARIABLE 被运行时拒 501007)",
27
+ "一次写只建一个方法;给既有服务加方法走 method.create(escape hatch)",
28
+ ],
29
+ priorToolReferences: [
30
+ { tool: "service.category.list", args: { environment }, purpose: "取服务分类 id(所属目录必填)" },
31
+ { tool: "service.adapter_config", args: { environment }, purpose: "确认 RESTFUL 适配器的 commonList/authList 必需键与当前实例一致" },
32
+ ],
33
+ dryRun: { supported: true, command: `omc call service.register --env ${environment} --dry-run --args '<recipe.args>'`, notes: "dry-run 做 adapter/serviceConfig/methodConfig/参数面本地预检,零 wire;用它一次性看清缺哪个键" },
34
+ expectedReadback: { performed: { errcode: 0 }, readback: { servicePresent: true, methodPresent: true, methodCount: 1 }, next: ["service.get 复核(凭据已脱敏)"] },
35
+ refusalRecovery: [
36
+ { code: "bizservice-service-config-invalid", action: "serviceConfig 需要 auth{code,parameterlist[]}+commonlist[{code:'url',value}];按消息补键" },
37
+ { code: "bizservice-method-config-invalid", action: "methodConfig 需要 httpType/requestBodyType/url/frontEndExtensionEnable 四键" },
38
+ { code: "bizservice-parameter-face-invalid", action: "每个参数补 configJson.position;URL_VARIABLE 换 QUERY_PARAMS/REQUEST_BODY" },
39
+ { code: "bizservice-required-field-missing", action: "name/adapterCode/serviceCategoryId 是设计器必填;分类 id 不能为空" },
40
+ { code: "duplicate-service", action: "serviceCode 已存在;改用 service.update" },
41
+ { code: "bizservice-adapter-not-whitelisted", action: "写面仅 RESTFUL/DATA_SQL/DATA_TABLE/SAP/KAFKA/SOAP;INTERNAL 走二开扩展包" },
42
+ ...commonRecovery,
43
+ ],
44
+ requiresEnvironmentDerivedIds: true,
45
+ prerequisiteData: { source: "service.category.list", fields: ["category.id"] },
46
+ });
47
+ const bizserviceSelfCallCorp = Object.freeze({
48
+ id: "bizservice-self-call-corp",
49
+ title: "业务规则自调本实例:oauth_password 为基础;X-LowCode-Corpid 头视环境而定(token 是否自带 corpId,8.5+ 部分配置才需要)——非铁律,真机判定",
50
+ status: "offline-valid",
51
+ tool: "method.update",
52
+ args: {
53
+ environment,
54
+ serviceCode: "<service_code>",
55
+ methodCode: "<method_code>",
56
+ inputParameters: [
57
+ { code: "X-LowCode-Corpid", name: "corpId头", required: false, codeType: 0, bizCode: "<corpId 常量值>", configJson: { position: "REQUEST_HEADER" } },
58
+ ],
59
+ },
60
+ preconditions: [
61
+ "自调本实例(commonlist.url 指回本平台 /api)鉴权以 oauth_password 为基础(Authorization Bearer)。**X-LowCode-Corpid 头非铁律**:token 自带 corpId claim 的环境(生产多数)不配任何 corpid;token corpId=null 的环境(本沙盒 api 客户端;8.5+ 部分配置)缺头会 HTTP 200 但响应体 errcode:50000(corpId can not be blank,r5 实测 2026-10-10)。",
62
+ "**判定法(先做再配)**:带 token 直调一次扩展端点看**响应体 errcode**(HTTP 200 不代表成功,平台错误包在体里);errcode:0 则不配 corpid;errcode:50000 则按本配方补方法参数(code=X-LowCode-Corpid、configJson.position=REQUEST_HEADER、codeType:0 CONST、值放 bizCode——平台注入,调用方无需传;手动 curl 加请求头即可)。",
63
+ "出站第三方接口按对方要求配鉴权,与本配方无关。",
64
+ ],
65
+ conditionalRequirements: [
66
+ "**参数 code 必须精确等于 `X-LowCode-Corpid`**——适配器按「参数 code = header 名」加入请求头(headerParam.add(key, value))。",
67
+ "**corpid 传递有两种实证形状**:①方法级入参 code 为 X-LowCode-Corpid、configJson.position 为 REQUEST_HEADER 整数 2(r3-wms 实证可用);②规则 BIZ_ACTION 的 inputMappings 加 CONST 映射(serviceMethodParameterCode 为 X-LowCode-Corpid、codeType 为 0、bizCode 放真实 corpId——r4-fin 实证:该环境下方法级 position:2 注入为空头值 [\"\"],此形状才生效)。**先用 ②,双跑验证头值;①失效(头空)就换 ②**。CONST 值必须放 bizCode(平台只读 bizCode)。",
68
+ "**corpid 头非空即可(r6-onlinejs R19 实证)**:沙盒 token corpId=null 时,全 0 corpId 头(RELEVANCE-0000…)也 errcode:0;仅空头才 50000。多租户路由才需真值。凭据值不可从读回抄(读面按 ticket 115 掩码——0.4.16 起为结构化 {masked:true,hint},旧版 ***),必须用任务环境事实真值(doctor 显示的 corpId、任务提供的 client_secret)。",
69
+ "configJson.position 用 REQUEST_HEADER 名即可(工具写侧编码为整数索引 2;wire 上是整数——写名字平台侧反序列化失败、header 根本不进,源码 @JsonCreator get(int))。",
70
+ "BIZ_ACTION 节点调用该方法**无需传该常量参数**(方法级常量由平台注入);只需照常映射业务参数。",
71
+ ],
72
+ priorToolReferences: [{ tool: "method.get", args: { environment, serviceCode: "<service_code>", methodCode: "<method_code>" }, purpose: "取现有参数面,update 时整组带回(含本常量头)" }],
73
+ dryRun: { supported: true, command: `omc call method.update --env ${environment} --dry-run --args '<recipe.args>'`, notes: "dry-run 校验参数面/CONST 形状,零 wire" },
74
+ expectedReadback: { readback: { methodPresent: true, corpHeaderParam: "code=X-LowCode-Corpid position=REQUEST_HEADER(2) codeType=0 bizCode=<corpId>" }, next: ["BIZ_ACTION 规则触发后 E2E:被调接口不再回 50000 corpId can not be blank"] },
75
+ refusalRecovery: [
76
+ { code: "bizservice-parameter-face-invalid", action: "常量头也是参数:configJson.position=REQUEST_HEADER 必带" },
77
+ { code: "runtime-50000-corpId-blank", action: "header 仍空 = 常量值放错槽(须 bizCode)或参数 code 不是精确的 X-LowCode-Corpid;method.get 读回核对" },
78
+ { code: "bizservice-auth-credential-placeholder", action: "凭据被掩码/占位值守卫拦截——读回掩码 *** 或自造 RELEVANCE-xxx/全 0 不可注册;凭据必须从任务环境事实取真值(doctor 显示的 corpId、任务提供的 client_secret),不可从读回抄" },
79
+ ...commonRecovery,
80
+ ],
81
+ requiresEnvironmentDerivedIds: false,
82
+ });
83
+ export const B2_METADATA = Object.freeze({
84
+ "service.register": Object.freeze({ recipes: [restfulQueryService], relatedTools: ["service.category.list", "service.adapter_config", "service.get", "method.get"] }),
85
+ "method.update": Object.freeze({ recipes: [bizserviceSelfCallCorp], relatedTools: ["method.get", "method.create", "service.get"] }),
86
+ });
87
+ //# sourceMappingURL=b2-registration.js.map
@@ -0,0 +1,269 @@
1
+ import { environment, model, commonRecovery } from "./shared.js";
2
+ const ruleGraph = Object.freeze({
3
+ id: "standard-business-rule-graph",
4
+ title: "保存并启用最小数据事件规则图",
5
+ status: "requires-prior-readback",
6
+ tool: "rule.save",
7
+ args: {
8
+ environment,
9
+ schemaCode: model,
10
+ ruleCode: "Create",
11
+ name: "创建时写入状态",
12
+ nodeGraph: {
13
+ nodes: [
14
+ { nodeCode: "Start", nodeType: "START" },
15
+ { nodeCode: "UPDATE_1", nodeType: "UPDATE", targetObjectCode: model, inputParam: "_input", filterCondition: { mainConditions: [[{ targetSchemaDataItem: "id", ruleConditionType: "EQ", ruleValueType: "DYNAMIC", currentSchemaDataItem: "id" }]], sheetConditions: [] }, dataActions: [{ targetDataItem: "status", ruleValueType: "FIXED", value: "待处理", ruleActionType: "EQUALS" }] },
16
+ { nodeCode: "Create", nodeName: "新增数据", nodeType: "SYSTEM_CREATE", isSystemNode: true },
17
+ { nodeCode: "End", nodeType: "END" },
18
+ ],
19
+ routes: [
20
+ { preNode: "Start", postNode: "UPDATE_1" },
21
+ { preNode: "UPDATE_1", postNode: "Create" },
22
+ { preNode: "Create", postNode: "End" },
23
+ ],
24
+ },
25
+ publish: true,
26
+ },
27
+ preconditions: ["模型和 target field 已发布;Create 是平台预置触发规则;目标字段可由规则动作写入"],
28
+ conditionalRequirements: ["BIZ_ACTION 的 outputMappings 必须在 SYSTEM_CREATE/SYSTEM_UPDATE 前被消费;自定义 ruleCode 不会被数据事件自动分发"],
29
+ priorToolReferences: [
30
+ { tool: "field.list", args: { environment, schemaCode: model, published: true }, purpose: "确认 status 已发布" },
31
+ ],
32
+ dryRun: { supported: true, command: `omc call rule.save --env ${environment} --dry-run --args '<recipe.args>'`, notes: "dry-run 执行 rule graph dry lint;不会保存/发布规则" },
33
+ expectedReadback: { performed: { published: true, enabled: false }, readback: { published: true, next: "rule.enable", inputParam: "_input", systemNodeOrder: "UPDATE_1 → SYSTEM_CREATE" } },
34
+ refusalRecovery: [
35
+ { code: "rule-graph-validation-failed", action: "按 validation 修正 nodeType、路线、_input 和系统节点顺序后重新 dry-run" },
36
+ { code: "rule-schema-unresolved", action: "先确认模型存在,不要让 list/save 为幻影 schema 补建预置规则" },
37
+ { code: "rule-graph-bizmethod-unresolved", action: "先读取真实 BizMethod 及参数面;不要绑定 registration shell" },
38
+ ...commonRecovery,
39
+ ],
40
+ requiresEnvironmentDerivedIds: false,
41
+ prerequisiteData: { source: "field.list(published:true)", note: "ruleCode=Create 为平台预置代码;自定义代码需 workflow/button 触发" },
42
+ });
43
+ const ruleBranchGraph = Object.freeze({
44
+ id: "business-rule-branch-conditional",
45
+ title: "金额分级:BRANCH 判断 + 两条 UPDATE 分支(真机验证)",
46
+ status: "requires-prior-readback",
47
+ tool: "rule.save",
48
+ args: {
49
+ environment,
50
+ schemaCode: model,
51
+ ruleCode: "Create",
52
+ name: "金额分级",
53
+ nodeGraph: {
54
+ nodes: [
55
+ { nodeCode: "Start", nodeType: "START" },
56
+ { nodeCode: "Create", nodeName: "新增数据", nodeType: "SYSTEM_CREATE", isSystemNode: true },
57
+ { nodeCode: "Branch_1", nodeType: "BRANCH", sourceInputMethod: "PRE_OUT", exitConditionGroups: [[{ currentSchemaDataItem: "amount", ruleDataConditionType: "GT", ruleValueType: "FIXED", value: 10000 }]] },
58
+ { nodeCode: "UPDATE_BIG", nodeType: "UPDATE", targetObjectCode: model, dataActions: [{ targetDataItem: "level", ruleValueType: "FIXED", value: "大额", ruleActionType: "EQUALS" }] },
59
+ { nodeCode: "UPDATE_NORMAL", nodeType: "UPDATE", targetObjectCode: model, dataActions: [{ targetDataItem: "level", ruleValueType: "FIXED", value: "普通", ruleActionType: "EQUALS" }] },
60
+ { nodeCode: "End", nodeType: "END" },
61
+ ],
62
+ routes: [
63
+ { preNode: "Start", postNode: "Create" },
64
+ { preNode: "Create", postNode: "Branch_1" },
65
+ { preNode: "Branch_1", postNode: "UPDATE_BIG" },
66
+ { preNode: "Branch_1", postNode: "UPDATE_NORMAL", routeCondition: false },
67
+ { preNode: "UPDATE_BIG", postNode: "End" },
68
+ { preNode: "UPDATE_NORMAL", postNode: "End" },
69
+ ],
70
+ },
71
+ publish: true,
72
+ },
73
+ preconditions: ["模型和 target field(level/amount)已发布;Create 是平台预置触发规则;目标字段可由规则动作写入"],
74
+ conditionalRequirements: [
75
+ "**系统节点顺序:BRANCH 必须排在 `SYSTEM_CREATE` 之后**——BRANCH 直接接在 START 后会运行时静默不生效、动作不回写(工具 fail closed)。注意这与 BIZ_ACTION 回写场景相反(那里系统节点要在动作之后)——本 recipe 是分支场景。**`SYSTEM_CREATE` 必须显式写**(工具对分支图的自动注入不可靠)。",
76
+ "**出口条件叶只 4 个键** `{currentSchemaDataItem(左值字段),ruleDataConditionType(操作符),ruleValueType,value}`;用 UI 键 `targetSchemaDataItem`+`ruleConditionType` 会 save+publish 过但运行时 50000(工具 fail closed `rule-graph-branch-condition-keys`)。",
77
+ "**下列键可省、工具自动补**(省 token;真机验证极简图 1170B vs 全显式 1690B,−31%):每个节点的 `nodeName`;BRANCH 的 `inputParam:\"_input\"`/`judgeMethod:\"DEFAULT\"`;自更新 UPDATE(`targetObjectCode`=本模型)的 `inputParam:\"_input\"`/`filterCondition`(身份匹配);非兜底路由的 `routeCondition:true`/`matchType`。仅 BRANCH 的 `sourceInputMethod` 与兜底 else 的 `routeCondition:false` 需显式。**跨模型写(UPDATE/CREATE/DELETE 的 `targetObjectCode`≠规则模型)运行时未验证:lint 给非阻断 warning `rule-graph-cross-model-unverified`(2026-09-27 真机 data.submit 探测只有同模型 UPDATE 生效),交付前必须实测;稳妥用同模型回写或 BIZ_ACTION/二开。**",
78
+ "预置规则的系统节点类型必须与 ruleCode 匹配(Create→SYSTEM_CREATE);放 SYSTEM_UPDATE 会 data.submit 50000(工具 fail closed)。",
79
+ ],
80
+ priorToolReferences: [
81
+ { tool: "field.list", args: { environment, schemaCode: model, published: true }, purpose: "确认 amount/level 已发布" },
82
+ ],
83
+ dryRun: { supported: true, command: `omc call rule.save --env ${environment} --dry-run --args '<recipe.args>'`, notes: "dry-run 执行 rule graph dry lint;不写不发布" },
84
+ expectedReadback: { performed: { published: true, enabled: false }, readback: { nodes: "Start,SYSTEM_CREATE,Branch_1,UPDATE_BIG,UPDATE_NORMAL,End", next: "rule.enable 后用 data.submit 两条(命中/不命中)验 level" } },
85
+ refusalRecovery: [
86
+ { code: "rule-graph-branch-before-system-node", action: "把 SYSTEM_CREATE 挪到 BRANCH 之前(本 recipe 顺序)" },
87
+ { code: "rule-graph-branch-condition-keys", action: "出口叶改用 currentSchemaDataItem + ruleDataConditionType(见 conditionalRequirements)" },
88
+ { code: "rule-graph-branch-input-param", action: "给 BRANCH 补 inputParam:\"_input\"" },
89
+ { code: "rule-graph-branch-judge-method", action: "给 BRANCH 补 judgeMethod:\"DEFAULT\"" },
90
+ { code: "rule-graph-preset-system-node-mismatch", action: "把 SYSTEM_* 改成与 ruleCode 匹配的类型(Create→SYSTEM_CREATE)" },
91
+ { code: "rule-graph-validation-failed", action: "按 validation 逐项修正后重新 dry-run" },
92
+ ...commonRecovery,
93
+ ],
94
+ requiresEnvironmentDerivedIds: false,
95
+ prerequisiteData: { source: "field.list(published:true)", note: "ruleCode=Create 为平台预置代码" },
96
+ });
97
+ const ruleTimingTask = Object.freeze({
98
+ id: "rule-timing-task",
99
+ title: "定时任务:每天/周期触发规则(TIMING_TASK,SCHEDULER 节点,配置能力)",
100
+ status: "offline-valid",
101
+ tool: "rule.save",
102
+ args: {
103
+ environment,
104
+ schemaCode: model,
105
+ ruleCode: "<customRuleCode e.g. daily_scan>",
106
+ name: "每日定时作业",
107
+ nodeGraph: {
108
+ bizRuleType: 2,
109
+ nodes: [
110
+ { nodeCode: "Start", nodeName: "开始", nodeType: "START" },
111
+ { nodeCode: "SCHEDULER", nodeName: "定时作业", nodeType: "SCHEDULER", isSystemNode: true, nodeCategory: "systemNode" },
112
+ { nodeCode: "UPDATE_1", nodeName: "执行动作", nodeType: "UPDATE", targetObjectCode: model, dataActions: [{ targetDataItem: "<field>", ruleValueType: "FIXED", value: "<值>", ruleActionType: "EQUALS" }] },
113
+ { nodeCode: "End", nodeName: "结束", nodeType: "END" },
114
+ ],
115
+ routes: [
116
+ { preNode: "Start", postNode: "SCHEDULER", routeCondition: true },
117
+ { preNode: "SCHEDULER", postNode: "UPDATE_1", routeCondition: true },
118
+ { preNode: "UPDATE_1", postNode: "End", routeCondition: true },
119
+ ],
120
+ schedulerSetting: {
121
+ triggerTimeType: "SELECTED_TIME",
122
+ cycleType: "DAY",
123
+ executeType: "CYCLE",
124
+ execCycle: 1,
125
+ hour: 1,
126
+ minute: 0,
127
+ second: 0,
128
+ startTime: "<yyyy-MM-dd HH:mm:ss,未来时刻>",
129
+ endType: "NEVER",
130
+ // 扫描本表:以本模型为触发数据源,filterConditionGroups 是扫描过滤条件;
131
+ // 输入数据 = 被过滤出的行,下游以 inputParam:"_input" 消费其字段。
132
+ dataSourceType: "GET_LIST",
133
+ filterConditionGroups: [[{ targetSchemaDataItem: "<field>", ruleConditionType: "EQ", ruleValueType: "FIXED", value: "<值>" }]],
134
+ latestVersion: true,
135
+ consolidation: false,
136
+ },
137
+ },
138
+ publish: true,
139
+ },
140
+ preconditions: [
141
+ "模型和动作目标字段已发布;本环境需 `cloudpivot.task.enabled=true`(否则平台不建调度任务)",
142
+ "**「每天定时执行」= 定时任务 TIMING_TASK,是平台原生配置能力,不是外部定时器、不是在线 JS、无需二开**",
143
+ ],
144
+ conditionalRequirements: [
145
+ "`bizRuleType:2` 写在 **`nodeGraph.bizRuleType`**(顶层参数被忽略)——平台只对 bizRuleType=2 的行建调度任务(BizRuleScheduling.java:202-205);nodeGraph 内未传时工具推断并 warning。",
146
+ "调度参数在 `nodeGraph.schedulerSetting`,**不在 SCHEDULER 节点上**(ScheduleNode 无时机字段);缺它则规则能存能启用但**永不触发**。`latestVersion` **必须 true**(false 走旧 builder 读 null startDate → publish 50000)。",
147
+ "**「定时扫描某表按条件执行」用 `schedulerSetting.dataSourceType:\"GET_LIST\"` + `filterConditionGroups`(扫描过滤条件,二维数组,与 filterCondition 同构)——本模型即触发数据源,被过滤出的行作输入,下游节点以 `inputParam:\"_input\"` 消费其字段**。不要用 `NONE`(无输入数据集:整图无输入,下游 MESSAGE 字段解析不到、设计器映射框选不出字段),也不要为此额外加 QUERY 节点。`BIZ_SERVICE`=以业务方法返回集合为源(配 methodMapping)。真机 2026-10-08 SCM 沙盒:agent 用 NONE+QUERY,站内通知节点字段选不出。**日期过滤叶用 `ruleValueType:\"today\"` + `currentSchemaDataItem:\"<offset>\"`**(\"0\"=今天、\"-7\"=7天前、\"30\"=30天后、可带单位 \"-1-week\";DateFieldFilter 按 Integer.parseInt(source) 解析,**缺 source 会抛 NumberFormatException → 扫描 0 行 → 规则「永不触发」**,真机 2026-10-08);\"yesterday\"/\"tomorrow\" 无需 source。",
148
+ "`startTime` 用未来时刻;`cycleType`∈NEVER/HOUR/DAY/WEEK/MONTH/YEAR/LAST_DAY_OF_MONTH/CUSTOM。**先分清两类语义**:①时刻型——『每天/每周/每月的某个时刻』(每天 09:00、每周三、每月 1 日 02:00)是平台**原生**(cycleType DAY/WEEK/MONTH/CUSTOM + 触发时刻,真机先例 r3-wms:每日 07:00/07:30、每月 1 日),**别误读成定不了任意时刻**;②间隔型——『每 N 小时/分钟/秒』**也是平台原生**(前台+源码双证 2026-10-09):`cycleType:CUSTOM` + `cycleValue:{unit:HOUR, value, minute, second}`,间隔秒数=value*3600+minute*60+second(设计器 Custom+Hour 单位下有 [0-59]分/[0-59]秒 下拉;JobModelBuilder buildExecuteRule L195-197)。『每 5 分钟』=value:0+minute:5;『每 30 秒』=value:0+minute:0+second:30;『每 2 小时 15 分』=value:2+minute:15。**旧结论『cycleType 最小 HOUR→分钟级无门』是误读**(MES 轮试了不存在的 cycleType=MINUTE 枚举值,漏了 CUSTOM+HOUR 的分/秒槽,源码+设计器复核推翻);扩展内 ScheduledThreadPoolExecutor 仅在需要请求上下文/非规则语义时用。`executeType`∈POLLING/CYCLE 是后端从上述形状推导的内部表示,写面不用直接给;`triggerTimeType`∈SELECTED_TIME/DATE_FIELD(后者须带 triggerDataItem)。保存后需 `rule.enable`。",
149
+ ],
150
+ priorToolReferences: [
151
+ { tool: "field.list", args: { environment, schemaCode: model, published: true }, purpose: "确认动作目标字段已发布" },
152
+ ],
153
+ dryRun: { supported: true, command: `omc call rule.save --env ${environment} --dry-run --args '<recipe.args>'`, notes: "dry-run 跑图校验(含 schedulerSetting 形状/枚举),不写不发布" },
154
+ expectedReadback: { performed: { published: true, enabled: false }, readback: { bizRuleType: 2, nodes: "Start,SCHEDULER,UPDATE_1,End", next: "rule.enable;平台到 startTime 建 cron 并触发" } },
155
+ refusalRecovery: [
156
+ { code: "rule-graph-scheduler-setting-shape", action: "`nodeGraph.schedulerSetting` 必须是对象/JSON 串(不是写在 SCHEDULER 节点上)" },
157
+ { code: "rule-graph-scheduler-setting-enum", action: "按 8.6.26 枚举修正 schedulerSetting 字段值(见 conditionalRequirements)" },
158
+ { code: "rule-graph-bizruletype-inferred-timing-task", action: "已自动推断 bizRuleType=2;如非定时目的请去掉 SCHEDULER 节点" },
159
+ { code: "rule-graph-validation-failed", action: "按 validation 逐项修正后重新 dry-run" },
160
+ ...commonRecovery,
161
+ ],
162
+ requiresEnvironmentDerivedIds: false,
163
+ });
164
+ const dataDuplicateFlag = Object.freeze({
165
+ id: "data-duplicate-flag",
166
+ title: "字段唯一性防重打标(8.6.26 实证唯一可靠路径):预置 Create 规则挂 BIZ_ACTION 自调二开 markDuplicates(规则图内 QUERY→UPDATE 打标会静默空转)",
167
+ status: "offline-valid",
168
+ tool: "rule.save",
169
+ args: {
170
+ environment,
171
+ schemaCode: "wms_material",
172
+ ruleCode: "Create",
173
+ name: "数据新增",
174
+ nodeGraph: {
175
+ nodes: [
176
+ { nodeCode: "Start", nodeName: "开始", nodeType: "START" },
177
+ { nodeCode: "A1", nodeName: "防重打标", nodeType: "BIZ_ACTION", inputParam: "_input", methodMapping: { schemaCode: "wms_material", serviceCode: "wms_material_service", serviceMethodCode: "markDuplicates", inputMappings: [{ serviceMethodParameterCode: "id", codeType: 1, bizCode: "id", required: true }, { serviceMethodParameterCode: "code", codeType: 1, bizCode: "mat_code" }], outputMappings: [] } },
178
+ { nodeCode: "Create", nodeName: "新增数据", nodeType: "SYSTEM_CREATE", isSystemNode: true },
179
+ { nodeCode: "End", nodeName: "结束", nodeType: "END" },
180
+ ],
181
+ routes: [
182
+ { preNode: "Start", postNode: "A1", routeCondition: true },
183
+ { preNode: "A1", postNode: "Create", routeCondition: true },
184
+ { preNode: "Create", postNode: "End", routeCondition: true },
185
+ ],
186
+ },
187
+ publish: true,
188
+ },
189
+ preconditions: [
190
+ "目标模型已有「重复标记」字段(如 `mat_dup_flag` 短文本,表单+列表可见)。",
191
+ "需求方已接受**打标降级**(平台无硬拦原语;BRANCH 不能按 QUERY 空结果分支)。",
192
+ "二开侧已有 markDuplicates 接口:查同键既有行(代码+号码一级、仅键二级覆盖无代码场景)→ UPDATE 给**既有那条**打标(宁可误报原则)。注册为 RESTFUL 服务并自调(oauth_password + 方法参数 X-LowCode-Corpid CONST——见 bizservice-self-call-corp)。",
193
+ "**改写的是预置 Create 规则**(不是自定义 ruleCode):数据事件只分发预置行;自定义 code 落库即 GET_LIST、且其 QUERY→UPDATE 同样空转(r4-fin 双证 2026-10-09)。**节点顺序**:BIZ_ACTION 在 SYSTEM_CREATE 前可用 _input 值操作既有行(打标场景=此形);要 getBizObject 读/改触发行自己的动作必须排 SYSTEM_CREATE 之后(否则行未落库 null 空转——r4-fin review F1)。",
194
+ ],
195
+ conditionalRequirements: [
196
+ "**为什么不是规则图内 QUERY→UPDATE**:8.6.26 UPDATE 节点 inputParam 只认 `_input`(触发行),`_QN_output` 引用被静默空转、UPDATE 始终命中新建那条——与打标既有行的需求相反(r4-fin 两次真机复现 2026-10-09)。规则图内打标不可靠,必须走二开。",
197
+ "预置规则改写要点:SYSTEM_CREATE 身份节点必须保留(nodeCode/nodeName/isSystemNode 平台预置身份,错配会让触发行写错);BIZ_ACTION 插在 START 之后、SYSTEM_CREATE 之前。",
198
+ "写完 `rule.enable`;**验证**:data.save 同键两条 → 既有那条带标记、新提交那条干净;无代码场景用仅键匹配覆盖。",
199
+ "掩码/占位值(RELEVANCE-全 0、全 0 id、整值 <…>、未替换 ${var})会被 rule-graph-masked-or-placeholder-value 出门拦截——从回读复制常量时取真实值。",
200
+ ],
201
+ priorToolReferences: [
202
+ { tool: "model.inspect", args: { environment, schemaCode: "<model>" }, purpose: "确认标记字段已存在且已发布" },
203
+ { tool: "rule.get", args: { environment, schemaCode: "<model>", ruleCode: "Create", full: true }, purpose: "改写预置规则前先取现图,整图带回(保留 SYSTEM_CREATE 身份)" },
204
+ ],
205
+ dryRun: { supported: true, command: `omc call rule.save --env ${environment} --dry-run --args '<recipe.args>'`, notes: "dry-run 校验预置身份/BIZ_ACTION 映射/掩码值,零 wire" },
206
+ expectedReadback: { performed: { errcode: 0 }, readback: { rulePresent: true, enabled: true, bizRuleType: "DATA_OP" }, next: ["同键双跑:既有行打标、新行干净;唯一键不触发"] },
207
+ refusalRecovery: [
208
+ { code: "rule-graph-preset-system-node-mismatch", action: "预置 Create 必须保留 SYSTEM_CREATE 身份节点(不能换成别的系统节点类型)" },
209
+ { code: "rule-graph-masked-or-placeholder-value", action: "常量值是掩码/占位(全 0 corpId、<…>、${var})——用真实值(corpId 取环境事实/方法参数 position:2 方案)" },
210
+ { code: "runtime-50000-corpId-blank", action: "补方法参数 X-LowCode-Corpid(见 bizservice-self-call-corp);HTTP 200 不代表成功,看响应体 errcode" },
211
+ ...commonRecovery,
212
+ ],
213
+ requiresEnvironmentDerivedIds: false,
214
+ });
215
+ const ruleCrossModelCreate = Object.freeze({
216
+ id: "rule-cross-model-create",
217
+ title: "跨模型新增:查/取源后向另一模型 CREATE(含 QUERY 扇出,真机验证)",
218
+ status: "offline-valid",
219
+ tool: "rule.save",
220
+ args: {
221
+ environment,
222
+ schemaCode: model,
223
+ ruleCode: "<Create|Update|或 TIMING ruleCode>",
224
+ name: "跨模型生成",
225
+ nodeGraph: {
226
+ nodes: [
227
+ { nodeCode: "Start", nodeName: "开始", nodeType: "START" },
228
+ { nodeCode: "SYSTEM_CREATE_OR_UPDATE", nodeName: "触发", nodeType: "<SYSTEM_CREATE 或 SYSTEM_UPDATE>", isSystemNode: true },
229
+ { nodeCode: "C1", nodeName: "新增到目标", nodeType: "CREATE", targetObjectCode: "<targetModel 且 ≠ 承载本规则的模型>", inputParam: "_input", originatorValueType: "DYNAMIC", originatorValue: "<触发字段>", dataActions: [{ targetDataItem: "<目标字段>", ruleValueType: "DYNAMIC", value: "", ruleActionType: "EQUALS", currentDataItemValue: "<来源字段>" }] },
230
+ { nodeCode: "End", nodeName: "结束", nodeType: "END" },
231
+ ],
232
+ routes: [
233
+ { preNode: "Start", postNode: "SYSTEM_CREATE_OR_UPDATE", routeCondition: true },
234
+ { preNode: "SYSTEM_CREATE_OR_UPDATE", postNode: "C1", routeCondition: true },
235
+ { preNode: "C1", postNode: "End", routeCondition: true },
236
+ ],
237
+ },
238
+ publish: true,
239
+ },
240
+ preconditions: [
241
+ "目标模型与目标字段已存在并发布;触发字段存在",
242
+ "**`targetObjectCode` 不能等于承载该 Create 触发规则的同一模型**(否则自触发死循环 → 运行时 550009「业务规则执行异常」;平台有时 publish 直接 550018)",
243
+ ],
244
+ conditionalRequirements: [
245
+ "`originatorValueType` **必填**(DYNAMIC=触发字段 code / FIXED=完整用户对象 JSON 串)+ `originatorValue`;`dataActions` **必填**(目标字段映射);缺任一 → rule.save 真机 50000。",
246
+ "**`dataActions` 要把下游记录所需的业务字段逐条映射**(编号/日期/金额/状态/备注…),**别只挂一个关联 id**——否则下游记录其余字段全 null(真机 2026-10-08)。",
247
+ "**`originatorValueType:\"DYNAMIC\"` 的 `originatorValue` 必须指向人员字段**(STAFF_SELECTOR 等);指向文本/编号字段会致发起人错误或为空。",
248
+ "「当前时间」不是规则的 value 类型:`ruleValueType:\"SYSTEM\"` 不会填 now(真机 2026-10-08 落 null)。要让下游日期=生成时刻,把该**日期字段的默认值**设为「当前时间」(平台 `{value:\"current\"}`),或走二开;纯规则映射填不出 now。",
249
+ "上游是 QUERY 时 `inputParam=\"_<QUERY节点code>_output\"`(QUERY 查 N 行→CREATE 逐条生成即 N→N 扇出,真机验证支持,同/跨模型均可);否则 `\"_input\"`。",
250
+ "`QUERY` 节点只能查**主模型行**:查子表 schema(`parent.child` 或子 schema 名)空条件返回 0 行、带条件 550018(真机 2026-10-08)——逐子表明细扇出才需要二开。",
251
+ "跨模型 CREATE/UPDATE 真机验证支持(2026-09-28 / 2026-10-08);承载规则的触发时机要对(Create 在提交时触发、Update 只在 data.update 触发、TIMING 定时触发)。",
252
+ ],
253
+ priorToolReferences: [
254
+ { tool: "field.list", args: { environment, schemaCode: "<targetModel>", published: true }, purpose: "确认目标模型/字段已发布" },
255
+ ],
256
+ dryRun: { supported: true, command: `omc call rule.save --env ${environment} --dry-run --args '<recipe.args>'`, notes: "dry-run 跑图 lint(不会暴露跨模型 CREATE 的 50000,需真机 save 复核)" },
257
+ expectedReadback: { readback: { published: true, next: "rule.enable;构造数据触发后回读目标模型行数" } },
258
+ refusalRecovery: [
259
+ { code: "wire-business", action: "rule.save 真机 50000:多为 CREATE 缺 originatorValueType/dataActions,或 QUERY 查了子表 schema;按 conditionalRequirements 修正" },
260
+ { code: "rule-graph-self-trigger-create-loop", action: "CREATE 目标不能是承载本 Create 规则的同一模型;改为写别的模型或换触发载体" },
261
+ { code: "rule-graph-validation-failed", action: "按 validation 修正节点/路线/inputParam 后重新 dry-run" },
262
+ ...commonRecovery,
263
+ ],
264
+ requiresEnvironmentDerivedIds: false,
265
+ });
266
+ export const BUSINESSRULE_METADATA = Object.freeze({
267
+ "rule.save": Object.freeze({ recipes: [ruleGraph, ruleBranchGraph, ruleTimingTask, dataDuplicateFlag, ruleCrossModelCreate], relatedTools: ["field.list", "rule.get", "rule.enable"] }),
268
+ });
269
+ //# sourceMappingURL=businessrule.js.map
@@ -0,0 +1,215 @@
1
+ import { environment, model, commonRecovery } from "./shared.js";
2
+ const submitCrossFieldCheck = Object.freeze({
3
+ id: "submit-cross-field-check",
4
+ title: "表单提交校验(跨字段比较):datarule type1 + checkType:2 + conditions(右值结构值)+ prompt——在线 JS onValidate 之前的配置正解",
5
+ status: "offline-valid",
6
+ tool: "datarule.create",
7
+ args: {
8
+ environment,
9
+ schemaCode: "svc_repair",
10
+ propertyCode: "rep_plan_finish_time",
11
+ dataRuleType: 1,
12
+ checkType: 2,
13
+ name: "完成时间不早于报告时间",
14
+ options: {
15
+ conditions: `{rep_plan_finish_time} 大于等于 {"valueType":"currentModel","value":"rep_report_time"}`,
16
+ prompt: "预计完成时间不能早于报告时间",
17
+ },
18
+ },
19
+ preconditions: [
20
+ "需求是**提交时跨字段校验并弹提示拦截**(A 字段与 B 字段的比较)——这有**配置正解**,先于在线 JS onValidate 考虑(在线 JS 只在该协议确实表达不了时用)。",
21
+ "比较符支持:等于/不等于/大于/大于等于/小于/小于等于/包含/属于/介于 等(中文或符号)。",
22
+ ],
23
+ conditionalRequirements: [
24
+ `**右值必须用结构值** {"valueType":"currentModel","value":"<字段code>"}——裸 {字段code} 右值平台存储成功但**永不解析、规则静默不生效**(2026-09-24 真机;工具 fail-closed 拦截 + 读回 shapeWarning 标记存量雷)。`,
25
+ "**prompt 存纯文本**:门户对顶层 options.prompt 原样显示,URL 编码会弹 %E5.. 乱码(真机 equipmaint_workorder 案)。",
26
+ "单字段正则/长度类校验用 checkType:1/4/5(REGEX/MAX_LENGTH/EMPTY_ROW)+ 对应 options 键。",
27
+ ],
28
+ priorToolReferences: [{ tool: "field.list", args: { environment, schemaCode: "<模型>" }, purpose: "确认两个比较字段已发布" }],
29
+ dryRun: { supported: true, command: `omc call datarule.create --env ${environment} --dry-run --args '<recipe.args>'`, notes: "dry-run 过协议校验(裸右值/prompt 编码当场拒),零 wire" },
30
+ expectedReadback: { performed: { errcode: 0 }, readback: { rulePresent: true, shapeWarning: null }, next: ["门户提交错误日期 → 弹 prompt 文案并拦截(前台点验)"] },
31
+ refusalRecovery: [
32
+ { code: "datarule-submit-cross-field-bare", action: `右值换成结构值 {"valueType":"currentModel","value":"字段code"}` },
33
+ { code: "datarule-submit-prompt-encoded", action: "prompt 存纯文本,别 URL 编码" },
34
+ ...commonRecovery,
35
+ ],
36
+ requiresEnvironmentDerivedIds: false,
37
+ });
38
+ const dataruleCalcRule = Object.freeze({
39
+ id: "field-compute-rule",
40
+ title: "字段计算规则:普通字段 + 计算规则(type2,勿用「计算公式」字段类型)",
41
+ status: "offline-valid",
42
+ tool: "datarule.create",
43
+ args: {
44
+ environment,
45
+ schemaCode: model,
46
+ propertyCode: "c",
47
+ dataRuleType: 2,
48
+ options: {
49
+ shortTextStitch: JSON.stringify({
50
+ formula: "{a}+{b}",
51
+ editorText: "<field-omc0001>a</field-omc0001>+<field-omc0001>b</field-omc0001>",
52
+ editorMark: "field-omc0001",
53
+ }),
54
+ },
55
+ name: "c=a+b",
56
+ },
57
+ preconditions: [
58
+ "**计算类需求:建普通业务字段(数值优先,文本亦可)+ 本计算规则;不要用「计算公式」字段类型(FORMULA)**——平台约定是普通字段顺带配计算规则(真机 2026-10-08 复核:普通数值字段 + type2 计算规则,门户算出 7.00,设计器「计算规则」弹窗显示公式)。",
59
+ "参与计算的字段已发布",
60
+ ],
61
+ conditionalRequirements: [
62
+ "`options.shortTextStitch` 的值必须是 JSON 对象字符串,**三个键都要给全**:`{\"formula\":\"{a}+{b}\",\"editorText\":\"<field-omc0001>a</field-omc0001>+<field-omc0001>b</field-omc0001>\",\"editorMark\":\"field-omc0001\"}`。",
63
+ "**`editorText`/`editorMark` 不是可选**(真机 2026-10-08):设计器「计算规则」弹窗按 `editorText` 里的 `<field-{editorMark}>…</field-{editorMark}>` 标记解析;`editorMark:\"\"` 或 `editorText` 不带标记 → 弹窗**标红/判非法**。约定:`editorMark` = `field-<任意一致 id>`(如 `field-omc0001`),`editorText` 里**每个字段引用**都包成 `<field-omc0001>ref</field-omc0001>`——**标签内只放裸 token,不要带花括号**(前端 `parseFormulaFromEditorText` 会自己给标签内容套上 `{}`:写 `<field-omc0001>{a}</field-omc0001>` 会被反解成 `{{a}}` ≠ `formula`,该规则显示「已失效」;真机 2026-10-08 SCM 沙盒已复现,OMC 现已 fail closed `datarule-stitch-editor-mismatch`)。",
64
+ "**`formula` 引用语法**(真机 production + 设计器核验):同类字段裸 `{字段code}`(`{a}+{b}`);**子表列用 `{子表字段code.子列code}` 点号全限定**(`{prop_repair_detail.qty}*{prop_repair_detail.unit_price}`);子表聚合 `SUM({子表.子列})`;支持 `IF/CASE/VALUE/AND/=、字符串字面量、运算符空格`。",
65
+ "**计算由门户前端执行、API 不回填**:写测试数据带预算值;正确性由门户表单填表确认。设计器「计算规则」弹窗读取 `bizdatarule/list`(本规则即写入该表)。",
66
+ ],
67
+ priorToolReferences: [
68
+ { tool: "field.list", args: { environment, schemaCode: model, published: true }, purpose: "确认目标字段与来源字段已发布、且目标字段是普通字段" },
69
+ ],
70
+ dryRun: { supported: true, command: `omc call datarule.create --env ${environment} --dry-run --args '<recipe.args>'`, notes: "dry-run 校验类型/公式协议,不写入" },
71
+ expectedReadback: { readback: { dataRuleType: 2, options: { shortTextStitch: "<含 formula 的 JSON 串>" } } },
72
+ refusalRecovery: [
73
+ { code: "datarule-options-invalid", action: "shortTextStitch 必须是含 formula 的 JSON 对象串;同类字段用裸 {字段},子表列用 {子表.子列}" },
74
+ { code: "wire-business", action: "305003 假死循环常见于未发布应用或坏 formula 形状;确认应用已发布、formula 为合法引用" },
75
+ ...commonRecovery,
76
+ ],
77
+ requiresEnvironmentDerivedIds: false,
78
+ });
79
+ const dataruleSubtableSum = Object.freeze({
80
+ id: "field-compute-subtable-sum",
81
+ title: "字段计算规则:子表列求和回主表(普通字段 + type2,SUM({子表.子列}))",
82
+ status: "offline-valid",
83
+ tool: "datarule.create",
84
+ args: {
85
+ environment,
86
+ schemaCode: model,
87
+ propertyCode: "total",
88
+ dataRuleType: 2,
89
+ options: {
90
+ shortTextStitch: JSON.stringify({
91
+ formula: "SUM({<childSchemaCode>.amount})",
92
+ editorText: "SUM(<field-omc0001><childSchemaCode>.amount</field-omc0001>)",
93
+ editorMark: "field-omc0001",
94
+ }),
95
+ },
96
+ name: "合计=明细金额之和",
97
+ },
98
+ preconditions: [
99
+ "**目标 `total` 是普通数值字段(不是「计算公式」字段)**;`<childSchemaCode>` 是子表字段的 code(如 `prop_repair_detail` / `Sub_item_information_table`),`amount` 是其子列 code",
100
+ "子表与其列已发布",
101
+ ],
102
+ conditionalRequirements: [
103
+ "子表列引用用 `{子表字段code.子列code}` 点号全限定;求和 `SUM({子表.子列})`(真机核验:`SUM({prop_repair_detail.amount})`)。",
104
+ "**给全 `editorText`/`editorMark`**:`editorMark=\"field-omc0001\"`,`editorText=\"SUM(<field-omc0001>prop_repair_detail.amount</field-omc0001>)\"`;缺则设计器标红。",
105
+ "计算由门户前端执行、API 不回填(写测试数据带预算值;门户填表确认)。",
106
+ ],
107
+ priorToolReferences: [
108
+ { tool: "field.list", args: { environment, schemaCode: model, published: true }, purpose: "确认主表 total、子表字段及其子列已发布" },
109
+ ],
110
+ dryRun: { supported: true, command: `omc call datarule.create --env ${environment} --dry-run --args '<recipe.args>'`, notes: "dry-run 校验类型/公式协议,不写入" },
111
+ expectedReadback: { readback: { dataRuleType: 2, options: { shortTextStitch: "<含 SUM({子表.子列}) 的 JSON 串>" } } },
112
+ refusalRecovery: [{ code: "datarule-options-invalid", action: "子表列引用必须是 {子表字段code.子列code};SUM 包裹其外" }, ...commonRecovery],
113
+ requiresEnvironmentDerivedIds: false,
114
+ });
115
+ const dataruleChildColumn = Object.freeze({
116
+ id: "field-compute-child-column",
117
+ title: "字段计算规则:子表列同行运算(普通字段 + type2,如 金额=数量×单价)",
118
+ status: "offline-valid",
119
+ tool: "datarule.create",
120
+ args: {
121
+ environment,
122
+ schemaCode: "<childSchemaCode e.g. <model>_items>",
123
+ propertyCode: "amount",
124
+ dataRuleType: 2,
125
+ options: {
126
+ shortTextStitch: JSON.stringify({
127
+ formula: "{<childSchemaCode>.qty}*{<childSchemaCode>.price}",
128
+ editorText: "<field-omc0001><childSchemaCode>.qty</field-omc0001>*<field-omc0001><childSchemaCode>.price</field-omc0001>",
129
+ editorMark: "field-omc0001",
130
+ }),
131
+ },
132
+ name: "金额=数量×单价",
133
+ },
134
+ preconditions: ["**子表列 `amount` 是普通数值字段(不是「计算公式」字段)**,且是子表内的列(schemaCode=子表字段 code)"],
135
+ conditionalRequirements: [
136
+ "**子表内列引用用 `{子表schemaCode.子列code}` 点号全限定**(真机 2026-10-08 设计器产出:`{prop_repair_detail.qty}*{prop_repair_detail.unit_price}`);不要写裸 `{qty}`。",
137
+ "**给全 `editorText`/`editorMark`**:`editorMark=\"field-omc0001\"`,每个引用包成 `<field-omc0001>子表.子列</field-omc0001>`(**标签内裸 token,不带花括号**——编辑器会自己套 `{}`);缺或带括号则设计器标红/已失效。",
138
+ "计算由门户前端执行、API 不回填(门户填表确认)。",
139
+ ],
140
+ priorToolReferences: [{ tool: "field.list", args: { environment, schemaCode: "<childSchemaCode>" }, purpose: "确认子表及其列已发布" }],
141
+ dryRun: { supported: true, command: `omc call datarule.create --env ${environment} --dry-run --args '<recipe.args>'`, notes: "dry-run 校验类型/公式协议,不写入" },
142
+ expectedReadback: { readback: { dataRuleType: 2, options: { shortTextStitch: "<含 {子表.子列} 点号引用的 JSON 串>" } } },
143
+ refusalRecovery: [{ code: "datarule-options-invalid", action: "子表内列用 {子表schemaCode.子列code} 点号;不要裸 {子列code}" }, ...commonRecovery],
144
+ requiresEnvironmentDerivedIds: false,
145
+ });
146
+ const dataruleRequired = Object.freeze({
147
+ id: "datarule-conditional-required",
148
+ title: "金额超过阈值时说明必填(字段级 type4)",
149
+ status: "offline-valid",
150
+ tool: "datarule.create",
151
+ args: {
152
+ environment,
153
+ schemaCode: model,
154
+ propertyCode: "leaveReason",
155
+ dataRuleType: 4,
156
+ options: { requiredFormula: '{leave_amount} 大于 {"valueType":"custom","value":5000}' },
157
+ name: "金额超过阈值说明必填",
158
+ sortKey: 1,
159
+ },
160
+ preconditions: ["目标字段已发布;amount 字段 code 已确认"],
161
+ conditionalRequirements: ["条件串必须是 {field} OP {JSON valueType} 三段单空格;多条件用 &&/||"],
162
+ priorToolReferences: [{ tool: "field.list", args: { environment, schemaCode: model, published: true }, purpose: "确认 leave_amount 与 leave_reason 已发布" }],
163
+ dryRun: { supported: true, command: `omc call datarule.create --env ${environment} --dry-run --args '<recipe.args>'`, notes: "dry-run 校验类型/条件协议,不写入" },
164
+ expectedReadback: { readback: { dataRuleType: 4, options: { requiredFormula: "<protocol>" } } },
165
+ refusalRecovery: [{ code: "datarule-options-invalid", action: "不要写 `{field}>5000` 或裸 true;复制 recipe 的三段协议" }, ...commonRecovery],
166
+ requiresEnvironmentDerivedIds: false,
167
+ });
168
+ const dataruleReadonly = Object.freeze({
169
+ id: "datarule-conditional-readonly",
170
+ title: "字段级条件只读(type5,恒真条件式)",
171
+ status: "offline-valid",
172
+ tool: "datarule.create",
173
+ args: {
174
+ environment,
175
+ schemaCode: model,
176
+ propertyCode: "approvalLevel",
177
+ dataRuleType: 5,
178
+ options: { readonlyCondition: '{approvalLevel} 大于等于 {"valueType":"custom","value":0}' },
179
+ name: "审批级别只读",
180
+ sortKey: 1,
181
+ },
182
+ preconditions: ["目标字段已发布"],
183
+ conditionalRequirements: ["无条件 readonly 的 functionType 形状尚未被 live 复现;使用已验证恒真条件式"],
184
+ priorToolReferences: [{ tool: "field.list", args: { environment, schemaCode: model, published: true }, purpose: "确认 approvalLevel 已发布" }],
185
+ dryRun: { supported: true, command: `omc call datarule.create --env ${environment} --dry-run --args '<recipe.args>'`, notes: "dry-run 校验条件协议,不写入" },
186
+ expectedReadback: { readback: { dataRuleType: 5, options: { readonlyCondition: "<protocol>" } } },
187
+ refusalRecovery: [{ code: "datarule-options-invalid", action: "readonlyCondition 必须是三段条件式;`readonlyCondition:true` 会破坏门户渲染" }, ...commonRecovery],
188
+ requiresEnvironmentDerivedIds: false,
189
+ });
190
+ const dataruleDisplay = Object.freeze({
191
+ id: "datarule-conditional-display",
192
+ title: "字段级显示条件(type3)",
193
+ status: "offline-valid",
194
+ tool: "datarule.create",
195
+ args: {
196
+ environment,
197
+ schemaCode: model,
198
+ propertyCode: "approvalLevel",
199
+ dataRuleType: 3,
200
+ options: { displayFormula: '{isUrgent} == {"valueType":"custom","value":true}' },
201
+ name: "加急时显示审批级别",
202
+ sortKey: 1,
203
+ },
204
+ preconditions: ["目标字段已发布"],
205
+ conditionalRequirements: ["displayFormula 与 requiredFormula/readonlyCondition 共用三段条件协议"],
206
+ priorToolReferences: [{ tool: "field.list", args: { environment, schemaCode: model, published: true }, purpose: "确认字段 codes" }],
207
+ dryRun: { supported: true, command: `omc call datarule.create --env ${environment} --dry-run --args '<recipe.args>'`, notes: "dry-run 校验条件协议,不写入" },
208
+ expectedReadback: { readback: { dataRuleType: 3, options: { displayFormula: "<protocol>" } } },
209
+ refusalRecovery: [{ code: "datarule-options-invalid", action: "复制三段条件协议;不要传裸公式字符串" }, ...commonRecovery],
210
+ requiresEnvironmentDerivedIds: false,
211
+ });
212
+ export const DATARULE_METADATA = Object.freeze({
213
+ "datarule.create": Object.freeze({ recipes: [submitCrossFieldCheck, dataruleCalcRule, dataruleSubtableSum, dataruleChildColumn, dataruleRequired, dataruleReadonly, dataruleDisplay], relatedTools: ["field.list", "datarule.list"] }),
214
+ });
215
+ //# sourceMappingURL=datarule.js.map