@stalfh233/omc-cli 0.4.57 → 0.4.59
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/compute.js +21 -1
- package/dist/lanes/list-view-shapes.js +10 -2
- package/package.json +3 -3
- package/skills/omc-write-hazards.md +16 -2
package/dist/compute.js
CHANGED
|
@@ -62,7 +62,27 @@ export async function cmdCompute(args) {
|
|
|
62
62
|
catch (error) {
|
|
63
63
|
return invalid(error instanceof Error ? error.message : String(error));
|
|
64
64
|
}
|
|
65
|
-
|
|
65
|
+
// Live 2026-10-20 (purchase-request app): a child-table target
|
|
66
|
+
// (schemaCode = 子表 code) made datarule.create throw, and the uncaught error
|
|
67
|
+
// surfaced as `{"code":"internal","message":"command failed"}` — no way to tell
|
|
68
|
+
// whether the formula, the schema, or the tool was at fault. Catch it and hand
|
|
69
|
+
// back an actionable hint; the same shape succeeds via datarule.create.
|
|
70
|
+
let result;
|
|
71
|
+
let exitCode;
|
|
72
|
+
try {
|
|
73
|
+
({ result, exitCode } = await runToolCall("datarule.create", { args: createArgs, requestId: request, environment }));
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
77
|
+
writeEnvelope(envelope("error", {}, request, {
|
|
78
|
+
code: "compute-write-failed",
|
|
79
|
+
message: `compute 调用 datarule.create 失败:${message}\n` +
|
|
80
|
+
"若 --schema 是**子表 code**(子表列计算),改用可跑样例直接发:omc describe datarule.create --example field-compute-child-column," +
|
|
81
|
+
"或 omc call datarule.create --args '<该样例 args>'(含 resultType/formulaType/expression 的嵌套 JSON)。",
|
|
82
|
+
retryable: false,
|
|
83
|
+
}));
|
|
84
|
+
return CLI_EXIT_CODES.internal;
|
|
85
|
+
}
|
|
66
86
|
const classified = classifyResult(result);
|
|
67
87
|
writeEnvelope(envelope(classified.status, result, request, classified.error));
|
|
68
88
|
return exitCode;
|
|
@@ -45,7 +45,15 @@ const QUERY_FILTER_TYPES = new Set(QUERY_FILTER_TYPE);
|
|
|
45
45
|
* (`QueryFilterType.getDefaultQueryFilterType`, QueryFilterType.java) — used
|
|
46
46
|
* when a condition omits `filterType`, so the stored row names its comparison.
|
|
47
47
|
*/
|
|
48
|
-
function defaultQueryFilterType(propertyType) {
|
|
48
|
+
function defaultQueryFilterType(propertyType, displayType) {
|
|
49
|
+
// Live 2026-10-20 (purchase-request app): a SHORT_TEXT field holding 是/否 was
|
|
50
|
+
// configured with `displayType:"SELECT"` but no `filterType`, and the property
|
|
51
|
+
// type table answered "Like" — a fuzzy match on an enum-valued column ("否"
|
|
52
|
+
// also matched text containing that character). An enumerated display control
|
|
53
|
+
// (SELECT/RADIO/CHECKBOX) is a closed value set, so its operator is Eq.
|
|
54
|
+
const display = typeof displayType === "string" ? displayType.toUpperCase() : undefined;
|
|
55
|
+
if (display === "SELECT" || display === "RADIO" || display === "CHECKBOX")
|
|
56
|
+
return "Eq";
|
|
49
57
|
switch (propertyType) {
|
|
50
58
|
case FIELD_PROPERTY_TYPES.LOGICAL:
|
|
51
59
|
case FIELD_PROPERTY_TYPES.WORK_SHEET:
|
|
@@ -818,7 +826,7 @@ export function normalizeConditions(conditions, fieldRows, schemaCode) {
|
|
|
818
826
|
value: requestedFilterType,
|
|
819
827
|
message: `conditions 的 filterType "${String(requestedFilterType)}" 不是平台 QueryFilterType;可选:${QUERY_FILTER_TYPE.join(" / ")}`,
|
|
820
828
|
});
|
|
821
|
-
row.filterType = requestedFilterType !== undefined ? String(requestedFilterType) : defaultQueryFilterType(propertyType);
|
|
829
|
+
row.filterType = requestedFilterType !== undefined ? String(requestedFilterType) : defaultQueryFilterType(propertyType, condition.displayType);
|
|
822
830
|
if (condition.displayType !== undefined)
|
|
823
831
|
row.displayType = DISPLAY_TYPE.index[condition.displayType] ?? null;
|
|
824
832
|
if (condition.defaultValue !== undefined)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stalfh233/omc-cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.59",
|
|
4
4
|
"description": "CloudPivot 8.6 configuration capability CLI — governed, fail-closed, coverage-manifest bounded.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -50,9 +50,9 @@
|
|
|
50
50
|
"access": "public"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@stalfh233/omc-fake-platform": "0.4.
|
|
53
|
+
"@stalfh233/omc-fake-platform": "0.4.59",
|
|
54
54
|
"commander": "14.0.3",
|
|
55
|
-
"omc-core": "0.4.
|
|
55
|
+
"omc-core": "0.4.59",
|
|
56
56
|
"proper-lockfile": "4.1.2",
|
|
57
57
|
"write-file-atomic": "6.0.0",
|
|
58
58
|
"zod": "^3.23.8",
|
|
@@ -32,12 +32,14 @@ omc help omc-write-hazards
|
|
|
32
32
|
- `propertyEmpty` 默认 `false`。模型层保持可空;必填、只读、可见性在表单和流程节点配置。
|
|
33
33
|
- 无映射关联单选 `WORK_SHEET` 使用 `mappings: ""`,不要用 `"[]"`。`"[]"` 是非空字符串,设计器会显示“已设置”,但弹窗没有映射行。
|
|
34
34
|
- 有映射时传非空 JSON 数组字符串,并在 draft/published 两面读回。
|
|
35
|
-
- **运行时写关联值是另一种形状**(`data.save`/`data.update` 的 formData):单选关联(`propertyType 9`)传 **id 字符串或 `{ id }`**,传**数组会稳定 50000
|
|
35
|
+
- **运行时写关联值是另一种形状**(`data.save`/`data.update` 的 formData):单选关联(`propertyType 9`)传 **id 字符串或 `{ id }`**,传**数组会稳定 50000**;**多选关联(11)传分号分隔的 id 字符串 `"id1;id2"`(或 `{id:"id1;id2"}`),传数组稳定 50000**;**人员/组织(50/51/60/61)传 `[{"id","type","name"}]`,`type` 必填**(缺它稳定 50000)——`type` 是 UnitType 索引:**用户=3、部门=1**。用错形状只会拿到一个不透明的 50000。
|
|
36
36
|
- **`mappings` 由表单运行时在用户选择时套用**,服务端 `data.save` **不会**自动回填映射目标字段。API 侧要自己写被映射字段,否则读回为空——别把它误判成“映射配置失败”。
|
|
37
37
|
- **关联映射的事实源在字段行 `options.mappings`,不在表单控件属性**(真机 2026-10-14 实证:改表单 attributes 里的映射会被平台按字段重算覆盖、回读不生效)。改映射走:`field.update` 按完整 options 提交(只改 mappings,其余键原值保留)→ `field.publish` → `form.draft`(**rebuild:false**,保留现有布局与在线JS)重存 → `form.publish` → 回读核对。**别用 field.update 的 cascadeRepublish 刷已带自定义布局/在线JS 的表单**(它会 rebuild 脚手架)。
|
|
38
|
-
- **运行时写值的最小形状**(组合出错只会得到一个不透明的 `50000`/NPE,逐一最小化再合):单选关联(9) → id 字符串 `"<id>"
|
|
38
|
+
- **运行时写值的最小形状**(组合出错只会得到一个不透明的 `50000`/NPE,逐一最小化再合):单选关联(9) → id 字符串 `"<id>"`;**多选关联(11) → 分号串 `"<id1>;<id2>"`**;**人员/组织(50/51/60/61) → `[{"id":"<id>","type":3,"name":"<名>"}]`,`type` 必填且为整数**(缺/非整数 → `BizField.parseFromClient` 拆箱 NPE→50000;用户=3、部门=1);日期(3) → 字符串 `"2026-09-30 10:00:00"`;子表(8) → 行对象数组 `[{"<子列code>":<值>, ...}]`。先各写一条最小行通过,再组合。
|
|
39
39
|
- **DATE(3) 字段的 `options.format` 必须是平台大写枚举**(`YYYY-MM-DD`、`YYYY-MM-DD HH:mm:ss`、`YYYY年MM月DD日`…),**不是 Java 的 `yyyy-MM-dd`**:平台 `DateBizField` 按字面比较,Java 写法能创建字段但**首次运行时 save 稳定 `50000`(`不支持的format`)**(2026-09-30 R5 实测)。`field.create`/`intent` 会就地拒绝非枚举值。
|
|
40
40
|
|
|
41
|
+
- **多选关联(11) 的写入源码依据**(1.1.25 实机 jar):`WorkSheetMultiBizField.contentFromClient` 只接受 `String` 或 `Map`,其它类型直接 `AppAsserts.isTrue(false, "Incorrect value type, should be string or map.")` → 表现为 50000;`contentToDbValue()` 返回 `map.get("id")`,而读回时按 `";"` 切分(`MULTI_WORK_SHEET_SPILT`)并组装 `items` 数组。所以**数组是读写不对称的读侧形状,不能拿来写**;分号串才是写侧形状。实测三种形状:`"<id>"`/`"<id>;<id>"` 成功、`["<id>"]` 50000。
|
|
42
|
+
|
|
41
43
|
## 业务规则与流程事件(源码实证,1.1.25)
|
|
42
44
|
|
|
43
45
|
- **`Create` 的触发判定是「旧状态→新状态」**:旧 `DRAFT` 且新 `PROCESSING` 或 `COMPLETED`(`DomainServiceImpl#getDefaultRuleCode`)。所以无流程模型一调 `data.submit`(→COMPLETED)**和流程表单提交(DRAFT→PROCESSING)都触发 Create**;`data.save` 存草稿不触发。不要因为"目标表没变化"就断言规则没触发。
|
|
@@ -87,6 +89,18 @@ omc call field.publish --env local --args '{"schemaCode":"expense"}'
|
|
|
87
89
|
|
|
88
90
|
父 `CHILD_TABLE` 行不接受 `options/choices/subFields` 更新;子列直接走上面的 CRUD 面。
|
|
89
91
|
|
|
92
|
+
- **提交/审批都不要再回传子表数组**(真机 2026-10-19/20):`data.save` 建草稿后 `data.submit` 若带子表行(无 `id`),平台按新增追加(3→9);**审批提交同样**——`data.submit` 带 `workItemId`+`agree` 推进一步时回传子表,每级再 +1 行(1→2→3)。金额若显式传了合计不会翻倍,但行数与 SUM 口径已被污染,且没有报错。审批只回传标量字段(`agree`/意见/被改标量);确需改子行时带 `id`+`rowStatus:"Modified"`。验收加一条"审批后子表行数不变"。
|
|
93
|
+
|
|
94
|
+
## 写调用纪律
|
|
95
|
+
|
|
96
|
+
- **同一 `<env>` 的写调用必须串行发起**:`write-lock-held` 不只在"并行重放失败请求"时出现,也会在**并行发起两个无关写**时触发(实测:并行两条 `dictionary.save`、并行 `field.update`+`field.publish` 各失败一次)。读可并行,写不要。
|
|
97
|
+
|
|
98
|
+
## 计算规则(datarule)的取值时机
|
|
99
|
+
|
|
100
|
+
- **计算由门户前端执行,API 写入不回填**:`datarule.create` 接受 `IF({实际日期}>{需求日期},"是","否")` 这类比较式并落库,但 `data.save`/`data.submit` 不计算结果值,读回仍是 null。
|
|
101
|
+
- 所以"计算规则是否生效"**无法用 API 判定**,必须在门户录一条看结果;验收清单要写"计算类字段前台确认"。
|
|
102
|
+
- 需要服务端就有值(参与汇总、流程分流、超期判定)时不要依赖 datarule:改用二开接口在保存/审批时算好并回写标量。
|
|
103
|
+
|
|
90
104
|
## 规则与业务集成
|
|
91
105
|
|
|
92
106
|
- 规则节点缺 `nodeName` 时 CLI 按平台 `RuleNodeType` 补默认名并给 warning;业务节点优先显式命名。
|