@stalfh233/omc-cli 0.5.0 → 0.5.1
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/LICENSE +21 -21
- package/README.md +359 -359
- package/coverage/m1-coverage-manifest-v1.json +1414 -1414
- package/dist/approval-flow.js +0 -0
- package/dist/approval-token.js +102 -0
- package/dist/args.js +0 -0
- package/dist/artifacts.js +0 -0
- package/dist/batch-call.js +0 -0
- package/dist/bench/call-face-eval.js +0 -0
- package/dist/bench/context-attribution.js +0 -0
- package/dist/bench/discovery-cost-eval.js +0 -0
- package/dist/bench/driver.js +0 -0
- package/dist/bench/evals.js +0 -0
- package/dist/bench/fake-http-server.js +65 -0
- package/dist/bench/instrument.js +0 -0
- package/dist/bench/intent-face-eval.js +40 -40
- package/dist/bench/run.js +0 -0
- package/dist/bench/scenario.js +0 -0
- package/dist/bench/types.js +0 -0
- package/dist/bi-wire.js +0 -0
- package/dist/bizservice-config.js +0 -0
- package/dist/call.js +0 -0
- package/dist/capability-absences.js +0 -0
- package/dist/capability-overview.js +0 -0
- package/dist/capability-shape.js +0 -0
- package/dist/cli-contract.js +38 -1
- package/dist/cli-output.js +8 -2
- package/dist/cli.js +9 -1
- package/dist/closest-match.js +0 -0
- package/dist/code-rules.js +0 -0
- package/dist/command-transport.js +0 -0
- package/dist/compound-writes.js +0 -0
- package/dist/compute.js +0 -0
- package/dist/config-store.js +0 -0
- package/dist/context.js +0 -0
- package/dist/contract-consistency.js +0 -0
- package/dist/contract-resources.js +0 -0
- package/dist/coverage-consistency.js +0 -0
- package/dist/coverage-registry.js +0 -0
- package/dist/coverage.js +0 -0
- package/dist/data-list-filter.js +0 -0
- package/dist/describe-cache.js +0 -0
- package/dist/discovery.js +0 -0
- package/dist/endpoints.js +0 -0
- package/dist/environment-policy.js +0 -0
- package/dist/execution-metadata.js +0 -0
- package/dist/fake/app.js +45 -0
- package/dist/fake/b2-registration.js +594 -0
- package/dist/fake/businessrule.js +242 -0
- package/dist/fake/datarule.js +72 -0
- package/dist/fake/dictionary.js +108 -0
- package/dist/fake/environment.js +30 -0
- package/dist/fake/field.js +167 -0
- package/dist/fake/form.js +101 -0
- package/dist/fake/index.js +121 -0
- package/dist/fake/list-view.js +289 -0
- package/dist/fake/model.js +136 -0
- package/dist/fake/online-js.js +18 -0
- package/dist/fake/report.js +253 -0
- package/dist/fake/routes.js +47 -0
- package/dist/fake/rule-lifecycle.js +37 -0
- package/dist/fake/runtime-data.js +367 -0
- package/dist/fake/state.js +67 -0
- package/dist/fake/workflow.js +364 -0
- package/dist/field-change.js +75 -7
- package/dist/field-families.js +59 -9
- package/dist/form-default.js +0 -0
- package/dist/form-layout.js +0 -0
- package/dist/form-support.js +0 -0
- package/dist/formula-lint.js +0 -0
- package/dist/goal-routes.js +16 -16
- package/dist/governed-execution.js +0 -0
- package/dist/graph.js +29 -29
- package/dist/human-summary.js +0 -0
- package/dist/identity.js +0 -0
- package/dist/intent/baseline.js +0 -0
- package/dist/intent/capabilities/bizservice.js +0 -0
- package/dist/intent/capabilities/businessrule.js +0 -0
- package/dist/intent/capabilities/datarule.js +0 -0
- package/dist/intent/capabilities/field.js +0 -0
- package/dist/intent/capabilities/form.js +0 -0
- package/dist/intent/capabilities/index.js +0 -0
- package/dist/intent/capabilities/listview.js +0 -0
- package/dist/intent/capabilities/model.js +0 -0
- package/dist/intent/capabilities/onlinejs.js +0 -0
- package/dist/intent/capabilities/report.js +0 -0
- package/dist/intent/capabilities/workflow.js +0 -0
- package/dist/intent/capability.js +0 -0
- package/dist/intent/cli.js +0 -0
- package/dist/intent/compare.js +0 -0
- package/dist/intent/compiler.js +0 -0
- package/dist/intent/dsl.js +0 -0
- package/dist/intent/plan-apply.js +0 -0
- package/dist/intent/plan-file.js +0 -0
- package/dist/intent/readback.js +0 -0
- package/dist/intent/schema.js +0 -0
- package/dist/intent/validation.js +0 -0
- package/dist/intent/yaml.js +0 -0
- package/dist/journal.js +0 -0
- package/dist/json-column.js +0 -0
- package/dist/lanes/app-contract.js +0 -0
- package/dist/lanes/app-coverage.js +0 -0
- package/dist/lanes/app.js +0 -0
- package/dist/lanes/apply-changes.js +0 -0
- package/dist/lanes/b2-registration-contract.js +0 -0
- package/dist/lanes/b2-registration-coverage.js +0 -0
- package/dist/lanes/b2-registration.js +0 -0
- package/dist/lanes/businessrule-contract.js +0 -0
- package/dist/lanes/businessrule-coverage.js +0 -0
- package/dist/lanes/businessrule.js +0 -0
- package/dist/lanes/contract-support.js +0 -0
- package/dist/lanes/coverage-declaration.js +0 -0
- package/dist/lanes/custom-page.js +0 -0
- package/dist/lanes/datarule-contract.js +0 -0
- package/dist/lanes/datarule-coverage.js +0 -0
- package/dist/lanes/datarule-protocol.js +0 -0
- package/dist/lanes/datarule.js +0 -0
- package/dist/lanes/dictionary-contract.js +0 -0
- package/dist/lanes/dictionary-coverage.js +0 -0
- package/dist/lanes/dictionary.js +0 -0
- package/dist/lanes/environment-contract.js +0 -0
- package/dist/lanes/environment-coverage.js +0 -0
- package/dist/lanes/environment.js +0 -0
- package/dist/lanes/field-contract.js +0 -0
- package/dist/lanes/field-coverage.js +0 -0
- package/dist/lanes/field.js +6 -1
- package/dist/lanes/folder-contract.js +0 -0
- package/dist/lanes/folder-coverage.js +0 -0
- package/dist/lanes/folder.js +0 -0
- package/dist/lanes/form-contract.js +0 -0
- package/dist/lanes/form-coverage.js +0 -0
- package/dist/lanes/form.js +0 -0
- package/dist/lanes/lane-ids.js +0 -0
- package/dist/lanes/list-view-contract.js +0 -0
- package/dist/lanes/list-view-coverage.js +0 -0
- package/dist/lanes/list-view-shapes.js +0 -0
- package/dist/lanes/list-view.js +0 -0
- package/dist/lanes/meta-contract.js +0 -0
- package/dist/lanes/meta.js +6 -0
- package/dist/lanes/model-contract.js +0 -0
- package/dist/lanes/model-coverage.js +0 -0
- package/dist/lanes/model.js +4 -2
- package/dist/lanes/online-js-contract.js +0 -0
- package/dist/lanes/online-js-coverage.js +0 -0
- package/dist/lanes/online-js.js +0 -0
- package/dist/lanes/org-tree.js +0 -0
- package/dist/lanes/organization.js +0 -0
- package/dist/lanes/report-contract.js +0 -0
- package/dist/lanes/report-coverage.js +0 -0
- package/dist/lanes/report.js +0 -0
- package/dist/lanes/rule-graph.js +0 -0
- package/dist/lanes/rule-lifecycle-contract.js +0 -0
- package/dist/lanes/rule-lifecycle-coverage.js +0 -0
- package/dist/lanes/rule-lifecycle.js +0 -0
- package/dist/lanes/runtime-data-contract.js +0 -0
- package/dist/lanes/runtime-data-coverage.js +0 -0
- package/dist/lanes/runtime-data.js +0 -0
- package/dist/lanes/workflow-contract.js +0 -0
- package/dist/lanes/workflow-coverage.js +0 -0
- package/dist/lanes/workflow.js +0 -0
- package/dist/model-purge.js +0 -0
- package/dist/model-scaffold.js +0 -0
- package/dist/omc-core-lazy.js +0 -0
- package/dist/online-js-layout.js +0 -0
- package/dist/online-js-source.js +28 -28
- package/dist/package-tool.js +0 -0
- package/dist/package.js +0 -0
- package/dist/path-projection.js +0 -0
- package/dist/plan.js +0 -0
- package/dist/read.js +0 -0
- package/dist/recipes/b2-registration.js +0 -0
- package/dist/recipes/businessrule.js +0 -0
- package/dist/recipes/datarule.js +0 -0
- package/dist/recipes/dictionary.js +0 -0
- package/dist/recipes/field.js +0 -0
- package/dist/recipes/form.js +0 -0
- package/dist/recipes/list-view.js +0 -0
- package/dist/recipes/model.js +0 -0
- package/dist/recipes/online-js.js +0 -0
- package/dist/recipes/runtime-data.js +0 -0
- package/dist/recipes/shared.js +0 -0
- package/dist/recipes/workflow.js +0 -0
- package/dist/redact.js +0 -0
- package/dist/refusal-guidance.js +0 -0
- package/dist/rollback-spec.js +0 -0
- package/dist/rollback.js +0 -0
- package/dist/rule-support.js +0 -0
- package/dist/rule-when.js +0 -0
- package/dist/runtime-support.js +0 -0
- package/dist/script.js +0 -0
- package/dist/server.js +92 -0
- package/dist/service-doctor.js +0 -0
- package/dist/session-manager.js +0 -0
- package/dist/session.js +12 -0
- package/dist/skills.js +12 -2
- package/dist/sqlite-warning-filter.js +0 -0
- package/dist/support.js +0 -0
- package/dist/token-cache.js +0 -0
- package/dist/tool-types.js +0 -0
- package/dist/tools.js +0 -0
- package/dist/usage-log.js +0 -0
- package/dist/wire.js +0 -0
- package/dist/workflow-support.js +0 -0
- package/dist/write-lease.js +0 -0
- package/dist/write-lock.js +0 -0
- package/dist/write.js +0 -0
- package/dist/zip.js +0 -0
- package/docs/images/omc-nixi/README.md +41 -41
- package/docs/omc-introduction.md +851 -851
- package/docs/tool-surface-map.md +42 -42
- package/package.json +4 -4
- package/skills/omc-acceptance-criteria.md +50 -50
- package/skills/omc-business-configuration.md +334 -334
- package/skills/omc-capabilities.md +214 -214
- package/skills/omc-capability-scouting.md +55 -55
- package/skills/omc-config-draft-review.md +175 -175
- package/skills/omc-five-piece-flow.md +35 -35
- package/skills/omc-glossary.md +86 -86
- package/skills/omc-refusals.md +127 -127
- package/skills/omc-requirement-analysis.md +161 -161
- package/skills/omc-requirement-vocabulary.md +61 -61
- package/skills/omc-start-here.md +106 -106
- package/skills/omc-tool-selection.md +119 -119
- package/skills/omc-write-hazards.md +200 -200
- package/dist/lanes/organization-coverage.js +0 -27
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
import { businessRefusal, malformedEnvelope, NOT_HANDLED } from "./state.js";
|
|
2
|
+
const PENDING_STATES = new Set(["NOTSTARTED", "INPROGRESS"]);
|
|
3
|
+
const ACTIVITY_TYPES = new Set(["START", "END", "CONNECTION", "PARTICIPANT", "SUB_INSTANCE", "CIRCULATE", "SYSTEM_ACTIVITY", "AGENT_ACTIVITY"]);
|
|
4
|
+
const POINT = /^-?\d+(?:\.\d+)?,\s-?\d+(?:\.\d+)?$/;
|
|
5
|
+
/**
|
|
6
|
+
* Live 8.6.26 fidelity (2026-09-17 probe): workflow/validate and /publish
|
|
7
|
+
* answer HTTP 200 + errcode 0 and put the truth in `data` as
|
|
8
|
+
* ValidateMessage[]. The originate (first PARTICIPANT) node's `participant`
|
|
9
|
+
* must be the platform keyword `"{Originator}"`; a plain value ("admin")
|
|
10
|
+
* answers `401035 <activityName> ERROR` and the flow never goes live.
|
|
11
|
+
* `"{Creator}"` on a non-originate participant node is a `401062` WARN that
|
|
12
|
+
* does not block.
|
|
13
|
+
*/
|
|
14
|
+
function validateWorkflowParticipants(activities) {
|
|
15
|
+
if (!Array.isArray(activities))
|
|
16
|
+
return [];
|
|
17
|
+
const rows = activities;
|
|
18
|
+
const participants = rows.filter((activity) => String(activity?.activityType ?? "") === "PARTICIPANT");
|
|
19
|
+
const messages = [];
|
|
20
|
+
const originate = participants[0];
|
|
21
|
+
if (originate && String(originate.participant ?? "") !== "{Originator}")
|
|
22
|
+
messages.push({ errCode: 401035, errContent: originate.activityName ?? originate.activityCode ?? "", errMsg: null, errorLevel: "ERROR" });
|
|
23
|
+
for (const activity of participants.slice(1)) {
|
|
24
|
+
if (String(activity.participant ?? "") === "{Creator}")
|
|
25
|
+
messages.push({ errCode: 401062, errContent: activity.activityName ?? activity.activityCode ?? "", errMsg: null, errorLevel: "WARN" });
|
|
26
|
+
}
|
|
27
|
+
return messages;
|
|
28
|
+
}
|
|
29
|
+
function invalidRenderShape(body) {
|
|
30
|
+
if (!Array.isArray(body.activities))
|
|
31
|
+
return "activities";
|
|
32
|
+
const codes = new Set();
|
|
33
|
+
for (const activity of body.activities) {
|
|
34
|
+
const record = activity;
|
|
35
|
+
const code = String(record?.activityCode ?? "").trim();
|
|
36
|
+
const type = String(record?.activityType ?? "").trim();
|
|
37
|
+
if (!code || codes.has(code) || !ACTIVITY_TYPES.has(type))
|
|
38
|
+
return "activities";
|
|
39
|
+
codes.add(code);
|
|
40
|
+
}
|
|
41
|
+
if (!Array.isArray(body.rules))
|
|
42
|
+
return "rules";
|
|
43
|
+
for (const rule of body.rules) {
|
|
44
|
+
const record = rule;
|
|
45
|
+
const pre = String(record?.preActivityCode ?? "");
|
|
46
|
+
const post = String(record?.postActivityCode ?? "");
|
|
47
|
+
const points = record?.points;
|
|
48
|
+
if (!codes.has(pre) || !codes.has(post) || !Array.isArray(points) || points.length === 0 || points.some((point) => typeof point !== "string" || !POINT.test(point)))
|
|
49
|
+
return "rules";
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Spawn the two work items a workflow start produces: the originator fill item
|
|
55
|
+
* (already FINISHED — the start submit is the fill) and the pending approval
|
|
56
|
+
* item that `workitem.list` must surface for `data.submit`.
|
|
57
|
+
*/
|
|
58
|
+
export function startWorkflowInstance(state, input) {
|
|
59
|
+
const sequence = state.workItems.size + 1;
|
|
60
|
+
const instanceId = `wf-${sequence}`;
|
|
61
|
+
const fillId = `wi-${sequence}`;
|
|
62
|
+
const approveId = `wi-${sequence + 1}`;
|
|
63
|
+
state.workItems.set(fillId, {
|
|
64
|
+
id: fillId,
|
|
65
|
+
instanceId,
|
|
66
|
+
activityCode: "fill",
|
|
67
|
+
activityName: "填写申请单",
|
|
68
|
+
participant: "tester",
|
|
69
|
+
state: "FINISHED",
|
|
70
|
+
workflowCode: input.workflowCode,
|
|
71
|
+
schemaCode: input.schemaCode,
|
|
72
|
+
bizObjectId: input.bizObjectId,
|
|
73
|
+
});
|
|
74
|
+
state.workItems.set(approveId, {
|
|
75
|
+
id: approveId,
|
|
76
|
+
instanceId,
|
|
77
|
+
activityCode: "approve",
|
|
78
|
+
activityName: "审批",
|
|
79
|
+
participant: "tester",
|
|
80
|
+
state: "INPROGRESS",
|
|
81
|
+
workflowCode: input.workflowCode,
|
|
82
|
+
schemaCode: input.schemaCode,
|
|
83
|
+
bizObjectId: input.bizObjectId,
|
|
84
|
+
});
|
|
85
|
+
return { workflowInstanceId: instanceId, workItemId: approveId };
|
|
86
|
+
}
|
|
87
|
+
/** Complete a pending work item (approval submit). Returns false if unknown. */
|
|
88
|
+
export function completeWorkItem(state, workItemId) {
|
|
89
|
+
const item = state.workItems.get(workItemId);
|
|
90
|
+
if (!item)
|
|
91
|
+
return false;
|
|
92
|
+
item.state = "FINISHED";
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Portal draft-save shape (finishStart=FALSE): one instance in DRAFT with a
|
|
97
|
+
* single PENDING start work item. Submitting that item (startWorkflowDraft's
|
|
98
|
+
* workItemId) is what advances the instance — see startWorkflowInstance for
|
|
99
|
+
* the finishStart=TRUE twin.
|
|
100
|
+
*/
|
|
101
|
+
export function startWorkflowDraft(state, input) {
|
|
102
|
+
const sequence = state.workItems.size + 1;
|
|
103
|
+
const instanceId = `wf-${sequence}`;
|
|
104
|
+
const startId = `wi-${sequence}`;
|
|
105
|
+
state.workItems.set(startId, {
|
|
106
|
+
id: startId,
|
|
107
|
+
instanceId,
|
|
108
|
+
activityCode: "fill",
|
|
109
|
+
activityName: "填写申请单",
|
|
110
|
+
participant: "tester",
|
|
111
|
+
state: "INPROGRESS",
|
|
112
|
+
workflowCode: input.workflowCode,
|
|
113
|
+
schemaCode: input.schemaCode,
|
|
114
|
+
bizObjectId: input.bizObjectId,
|
|
115
|
+
isStart: true,
|
|
116
|
+
});
|
|
117
|
+
return { workflowInstanceId: instanceId, workItemId: startId };
|
|
118
|
+
}
|
|
119
|
+
/** After the START work item is submitted, the next (approval) activity spawns a pending todo. */
|
|
120
|
+
export function spawnApprovalWorkItem(state, input) {
|
|
121
|
+
const approveId = `wi-${state.workItems.size + 1}`;
|
|
122
|
+
state.workItems.set(approveId, {
|
|
123
|
+
id: approveId,
|
|
124
|
+
instanceId: input.instanceId,
|
|
125
|
+
activityCode: "approve",
|
|
126
|
+
activityName: "审批",
|
|
127
|
+
participant: "tester",
|
|
128
|
+
state: "INPROGRESS",
|
|
129
|
+
workflowCode: input.workflowCode,
|
|
130
|
+
schemaCode: input.schemaCode,
|
|
131
|
+
bizObjectId: input.bizObjectId,
|
|
132
|
+
});
|
|
133
|
+
return approveId;
|
|
134
|
+
}
|
|
135
|
+
function toWorkItemVO(item) {
|
|
136
|
+
return {
|
|
137
|
+
id: item.id,
|
|
138
|
+
instanceId: item.instanceId,
|
|
139
|
+
activityCode: item.activityCode,
|
|
140
|
+
activityName: item.activityName,
|
|
141
|
+
state: item.state,
|
|
142
|
+
workflowCode: item.workflowCode,
|
|
143
|
+
schemaCode: item.schemaCode,
|
|
144
|
+
participant: item.participant,
|
|
145
|
+
participantName: item.participantName ?? item.participant,
|
|
146
|
+
originator: item.originator,
|
|
147
|
+
sequenceNo: item.sequenceNo,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
/** W7-S29-greenfield lane: workflow template authoring + runtime work-item query. Twin of src/lanes/workflow.ts. */
|
|
151
|
+
export const workflowRoute = (ctx, input) => {
|
|
152
|
+
const q = input.query ?? {};
|
|
153
|
+
const body = (input.body ?? {});
|
|
154
|
+
switch (input.path) {
|
|
155
|
+
case "/api/api/workflow/create": {
|
|
156
|
+
const code = String(body.workflowCode ?? body.code ?? "");
|
|
157
|
+
const name = String(body.workflowName ?? body.name ?? code);
|
|
158
|
+
const schemaCode = String(body.schemaCode ?? "");
|
|
159
|
+
// Ticket 76 live fidelity: creating a workflow when the SCHEMA already
|
|
160
|
+
// has one answers an envelope with NO numeric errcode (live:
|
|
161
|
+
// "envelope for /api/api/workflow/create has no numeric errcode") — the
|
|
162
|
+
// tool must decode it as a duplicate-create, not a malformed failure.
|
|
163
|
+
if ([...ctx.state.workflows.values()].some((wf) => wf.schemaCode === schemaCode) && !ctx.state.workflows.has(code))
|
|
164
|
+
return malformedEnvelope({ workflowCode: code, workflowName: name, schemaCode, exist: true });
|
|
165
|
+
if (!ctx.state.workflows.has(code)) {
|
|
166
|
+
// Ticket 112 platform fidelity: the real create auto-generates a
|
|
167
|
+
// full draft (START → PARTICIPANT 填写申请单 → END with canvas rules;
|
|
168
|
+
// WorkflowTemplateController update @ApiImplicitParam example) — the
|
|
169
|
+
// fake seeds the same platform-shaped template so the merge path has
|
|
170
|
+
// real activity boxes and rule shapes to echo.
|
|
171
|
+
ctx.state.workflows.set(code, {
|
|
172
|
+
code,
|
|
173
|
+
name,
|
|
174
|
+
schemaCode,
|
|
175
|
+
template: {
|
|
176
|
+
workflowCode: code,
|
|
177
|
+
name,
|
|
178
|
+
workflowName: name,
|
|
179
|
+
schemaCode,
|
|
180
|
+
// Live create seeds templateType DRAFT ("SAVE" is not a
|
|
181
|
+
// WorkflowTemplateStatus member — S29 contract).
|
|
182
|
+
templateType: "DRAFT",
|
|
183
|
+
activities: [
|
|
184
|
+
{ activityCode: "Activity1", activityType: "START", activityName: "开始", x: 327, y: 36, width: 158, height: 40 },
|
|
185
|
+
{ activityCode: "Activity2", activityType: "PARTICIPANT", activityName: "填写申请单", participant: "{Originator}", x: 327, y: 116, width: 158, height: 40 },
|
|
186
|
+
{ activityCode: "Activity3", activityType: "END", activityName: "结束", x: 327, y: 196, width: 158, height: 40 },
|
|
187
|
+
],
|
|
188
|
+
rules: [
|
|
189
|
+
{ preActivityCode: "Activity1", postActivityCode: "Activity2", points: ["406, 76", "406, 116"] },
|
|
190
|
+
{ preActivityCode: "Activity2", postActivityCode: "Activity3", points: ["406, 156", "406, 196"] },
|
|
191
|
+
],
|
|
192
|
+
},
|
|
193
|
+
published: null,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
return { code };
|
|
197
|
+
}
|
|
198
|
+
case "/api/api/workflow/isworkflow": {
|
|
199
|
+
// WorkflowTemplateController.isWorkFlow(schemaCode): any header for the
|
|
200
|
+
// schema answers true.
|
|
201
|
+
const schemaCode = String(q.schemaCode ?? "");
|
|
202
|
+
return [...ctx.state.workflows.values()].some((wf) => wf.schemaCode === schemaCode);
|
|
203
|
+
}
|
|
204
|
+
case "/api/api/workflow/getWorkflow": {
|
|
205
|
+
// WorkflowTemplateController.getWorkflow(schemaCode): the published
|
|
206
|
+
// template for the schema (carries workflowCode), or null when the model
|
|
207
|
+
// has none. Used to auto-start a workflow-backed data.submit.
|
|
208
|
+
const schemaCode = String(q.schemaCode ?? "");
|
|
209
|
+
const wf = [...ctx.state.workflows.values()].find((candidate) => candidate.schemaCode === schemaCode);
|
|
210
|
+
if (!wf)
|
|
211
|
+
return null;
|
|
212
|
+
const template = (wf.published ?? wf.template);
|
|
213
|
+
return { ...template, workflowCode: wf.code };
|
|
214
|
+
}
|
|
215
|
+
case "/api/api/workflow/get_header": {
|
|
216
|
+
const wf = ctx.state.workflows.get(String(q.workflowCode ?? ""));
|
|
217
|
+
// Round-2 live fidelity (BUG-05): these endpoints answer 401001
|
|
218
|
+
// 流程不存在! for an ABSENT workflow rather than a null payload.
|
|
219
|
+
if (!wf)
|
|
220
|
+
return businessRefusal(401001, "流程不存在!");
|
|
221
|
+
return { code: wf.code, name: wf.name };
|
|
222
|
+
}
|
|
223
|
+
case "/api/api/workflow/get_draft": {
|
|
224
|
+
const wf = ctx.state.workflows.get(String(q.workflowCode ?? ""));
|
|
225
|
+
if (!wf)
|
|
226
|
+
return businessRefusal(401001, "流程不存在!");
|
|
227
|
+
return wf.template;
|
|
228
|
+
}
|
|
229
|
+
case "/api/api/workflow/get_published": {
|
|
230
|
+
const wf = ctx.state.workflows.get(String(q.workflowCode ?? ""));
|
|
231
|
+
// Live fidelity: like get_header/get_draft, an ABSENT workflow answers
|
|
232
|
+
// 401001 流程不存在! rather than a null payload; the tool degrades that
|
|
233
|
+
// to exists:false. Ticket 77: an UNPUBLISHED workflow still answers the
|
|
234
|
+
// DRAFT shape here — data presence is not publish evidence. The
|
|
235
|
+
// published face carries the templateType PUBLISH marker.
|
|
236
|
+
if (!wf)
|
|
237
|
+
return businessRefusal(401001, "流程不存在!");
|
|
238
|
+
return wf.published ?? wf.template ?? null;
|
|
239
|
+
}
|
|
240
|
+
case "/api/api/workflow/update": {
|
|
241
|
+
const code = String(body.workflowCode ?? q.workflowCode ?? "");
|
|
242
|
+
const wf = ctx.state.workflows.get(code);
|
|
243
|
+
if (!wf)
|
|
244
|
+
return null;
|
|
245
|
+
// Ticket 112 platform fidelity (WorkflowTemplateUtil.java:90-171): an
|
|
246
|
+
// illegal templateType ("BusinessProcess" is not a
|
|
247
|
+
// WorkflowTemplateStatus member — valueOf at :136) or an activities
|
|
248
|
+
// element without a type makes the converter swallow the exception
|
|
249
|
+
// into a PARTIAL model; the save chain then fails with errcode 50000.
|
|
250
|
+
if (body.templateType === "BusinessProcess")
|
|
251
|
+
return businessRefusal(50000, "服务异常");
|
|
252
|
+
if (Array.isArray(body.activities) &&
|
|
253
|
+
body.activities.some((activity) => {
|
|
254
|
+
const record = activity;
|
|
255
|
+
const type = record != null && typeof record === "object" ? (record.type ?? record.activityType) : undefined;
|
|
256
|
+
return type === undefined || type === null || String(type).trim() === "";
|
|
257
|
+
}))
|
|
258
|
+
return businessRefusal(50000, "服务异常");
|
|
259
|
+
if (body.activities !== undefined && invalidRenderShape(body))
|
|
260
|
+
return businessRefusal(50000, "服务异常");
|
|
261
|
+
// Platform fidelity (live 2026-09-23; bench12/13/15): an existing
|
|
262
|
+
// activityCode cannot be RENAMED or RETYPED — the stored name/type win.
|
|
263
|
+
// A caller that wants a different name/type must send it under a fresh
|
|
264
|
+
// code (the tool reconciles this before the wire); re-sending the same
|
|
265
|
+
// code with a changed name is a silent no-op on the platform, so the fake
|
|
266
|
+
// must reproduce it rather than store the body verbatim.
|
|
267
|
+
const stored = wf.template.activities;
|
|
268
|
+
const storedByCode = new Map((Array.isArray(stored) ? stored : []).map((activity) => [String(activity.activityCode ?? ""), activity]));
|
|
269
|
+
const pinned = Array.isArray(body.activities)
|
|
270
|
+
? {
|
|
271
|
+
...body,
|
|
272
|
+
activities: body.activities.map((activity) => {
|
|
273
|
+
const prior = storedByCode.get(String(activity.activityCode ?? ""));
|
|
274
|
+
return prior
|
|
275
|
+
? { ...activity, activityName: prior.activityName, i18nMessage: prior.i18nMessage, activityType: prior.activityType }
|
|
276
|
+
: activity;
|
|
277
|
+
}),
|
|
278
|
+
}
|
|
279
|
+
: body;
|
|
280
|
+
wf.template = { ...pinned };
|
|
281
|
+
return { code };
|
|
282
|
+
}
|
|
283
|
+
case "/api/api/workflow/validate":
|
|
284
|
+
case "/api/api/workflow/publish": {
|
|
285
|
+
const code = String(body.workflowCode ?? q.workflowCode ?? "");
|
|
286
|
+
const wf = ctx.state.workflows.get(code);
|
|
287
|
+
if (!wf)
|
|
288
|
+
return null;
|
|
289
|
+
if (body.activities !== undefined && invalidRenderShape(body))
|
|
290
|
+
return businessRefusal(50000, "服务异常");
|
|
291
|
+
// Live 8.6.26 fidelity (2026-09-17): validate/publish REFUSE with HTTP
|
|
292
|
+
// 200 + errcode 0 and the truth in `data` as ValidateMessage[]
|
|
293
|
+
// ({errCode, errContent, errorLevel}). The originate (first PARTICIPANT)
|
|
294
|
+
// node's participant must be the platform keyword "{Originator}" — a
|
|
295
|
+
// plain user/role value answers 401035 ERROR while errcode stays 0, and
|
|
296
|
+
// the flow never goes live. `{Creator}` on a non-originate node is a WARN
|
|
297
|
+
// (401062) that does not block.
|
|
298
|
+
const activities = Array.isArray(body.activities) ? body.activities : wf.template.activities;
|
|
299
|
+
const validation = validateWorkflowParticipants(activities);
|
|
300
|
+
if (input.path === "/api/api/workflow/validate")
|
|
301
|
+
return validation;
|
|
302
|
+
if (validation.some((message) => message.errorLevel === "ERROR"))
|
|
303
|
+
return validation;
|
|
304
|
+
// Ticket 77: the published face carries the PUBLISH marker (live readback
|
|
305
|
+
// evidence: publish state is identified by templateType:PUBLISH /
|
|
306
|
+
// version fields, never by data presence).
|
|
307
|
+
wf.published = { ...body, templateType: "PUBLISH", workflowVersion: (wf.published ? Number(wf.published.workflowVersion ?? 1) : 0) + 1 };
|
|
308
|
+
return { code, workflowVersion: wf.published.workflowVersion };
|
|
309
|
+
}
|
|
310
|
+
case "/api/api/workflow/delete":
|
|
311
|
+
ctx.state.workflows.delete(String(body.workflowCode ?? q.workflowCode ?? q.code ?? ""));
|
|
312
|
+
return null;
|
|
313
|
+
case "/api/api/runtime/workflow/search_workitems": {
|
|
314
|
+
// The real endpoint returns the caller's pending todos (biz_workitem only
|
|
315
|
+
// holds pending rows); finished items move to the finished store. The
|
|
316
|
+
// server's filterWorkflowInstanceId is a NOT-equal exclusion, so it is
|
|
317
|
+
// deliberately not honored here — exact instance matching is client-side.
|
|
318
|
+
let rows = [...ctx.state.workItems.values()].filter((item) => PENDING_STATES.has(item.state));
|
|
319
|
+
if (q.workflowCode)
|
|
320
|
+
rows = rows.filter((item) => item.workflowCode === q.workflowCode);
|
|
321
|
+
if (q.schemaCode)
|
|
322
|
+
rows = rows.filter((item) => item.schemaCode === q.schemaCode);
|
|
323
|
+
const page = Number(q.page ?? 0);
|
|
324
|
+
const size = Number(q.size ?? 20);
|
|
325
|
+
const start = page * size;
|
|
326
|
+
return {
|
|
327
|
+
totalElements: rows.length,
|
|
328
|
+
totalPages: size > 0 ? Math.ceil(rows.length / size) : 0,
|
|
329
|
+
content: rows.slice(start, start + size).map(toWorkItemVO),
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
case "/api/api/runtime/workflow/getBizObjectByWfInstanceId": {
|
|
333
|
+
const instanceId = String(q.workflowInstanceId ?? "");
|
|
334
|
+
const item = [...ctx.state.workItems.values()].find((candidate) => candidate.instanceId === instanceId);
|
|
335
|
+
if (!item)
|
|
336
|
+
return null;
|
|
337
|
+
return { id: item.bizObjectId, schemaCode: item.schemaCode };
|
|
338
|
+
}
|
|
339
|
+
case "/api/api/organization/role/list":
|
|
340
|
+
// Real shape: groups with `children` roles (see real-env observation).
|
|
341
|
+
return [
|
|
342
|
+
{ id: "grp-1", name: "默认", code: "SYS_1000000", children: [{ id: "role-lead", name: "部门负责人", code: "SYS260630023816197", roleType: "SYS", corpId: "corp-1" }] },
|
|
343
|
+
{ id: "role-finance", name: "财务负责人", code: "SYS260515031207258", roleType: "SYS", corpId: "corp-1" },
|
|
344
|
+
];
|
|
345
|
+
case "/api/api/organization/department/tree":
|
|
346
|
+
return { departmentList: [{ id: "dept-1", name: "总所", code: "1", corpId: "corp-1", parentId: null }, { id: "dept-2", name: "业务部", code: "1_1", corpId: "corp-1", parentId: "dept-1" }] };
|
|
347
|
+
case "/api/api/organization/user/search": {
|
|
348
|
+
// UserController.search: @RequestBody {wd,page,size} → PageVO<UserVO>.
|
|
349
|
+
const wd = String(body.wd ?? "");
|
|
350
|
+
if (!wd)
|
|
351
|
+
return businessRefusal(10005, "关键字不能为空");
|
|
352
|
+
const users = [
|
|
353
|
+
{ id: "user-1", username: "18900000001", name: "付文彬", departmentId: "dept-1", userId: "18900000001", status: "ENABLE", deleted: false, corpId: "corp-1" },
|
|
354
|
+
{ id: "user-2", username: "18900000002", name: "李四", departmentId: "dept-2", userId: "18900000002", status: "ENABLE", deleted: false, corpId: "corp-1" },
|
|
355
|
+
].filter((user) => user.name.includes(wd) || user.username.includes(wd));
|
|
356
|
+
const page = Number(body.page ?? 0);
|
|
357
|
+
const size = Number(body.size ?? 100);
|
|
358
|
+
return { totalElements: users.length, totalPages: size > 0 ? Math.ceil(users.length / size) : 0, content: users.slice(page * size, page * size + size) };
|
|
359
|
+
}
|
|
360
|
+
default:
|
|
361
|
+
return NOT_HANDLED;
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
//# sourceMappingURL=workflow.js.map
|
package/dist/field-change.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FIELD_PROPERTY_TYPES } from "./field-families.js";
|
|
2
|
-
import { assertFormConditions, assertNumericalScale, assertFieldOptionsAllowed, buildChildTableSubSchema, buildFieldOptions, ensureRelationDisplayFieldOptions, normalizeFieldPropertyType, relationDisplayFieldCode, } from "./field-families.js";
|
|
2
|
+
import { assertFormConditions, assertNumericalScale, assertFieldOptionsAllowed, buildChildTableSubSchema, buildFieldOptions, ensureRelationDisplayFieldOptions, normalizeFieldPropertyType, optionShapeFamily, relationDisplayFieldCode, withLegacyOptionSetKeys, } from "./field-families.js";
|
|
3
3
|
import { nameI18nJson } from "./field-families.js";
|
|
4
4
|
import { decodeJsonObjectColumn } from "./json-column.js";
|
|
5
5
|
import { normalizeFormConditionOptions } from "./lanes/datarule-protocol.js";
|
|
@@ -50,6 +50,7 @@ export function prepareFieldChange(input) {
|
|
|
50
50
|
propertyType: input.propertyType,
|
|
51
51
|
...(input.choices ? { choices: input.choices } : {}),
|
|
52
52
|
...(input.options ? { options: input.options } : {}),
|
|
53
|
+
...(input.targetVersion ? { targetVersion: input.targetVersion } : {}),
|
|
53
54
|
});
|
|
54
55
|
assertRelationTargetPresent(propertyType, raw, input.relativeCode, input.code);
|
|
55
56
|
// Gates run here so every entry point (direct, orchestrator, intent) shares them.
|
|
@@ -75,6 +76,62 @@ export function fieldChangeWireBody(input, prepared) {
|
|
|
75
76
|
...(input.relativeCode ? { relativeCode: input.relativeCode } : {}),
|
|
76
77
|
};
|
|
77
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* 用新名称改写既有条目的 `name_i18n`,**保持原文形态**(字符串仍字符串、
|
|
81
|
+
* 对象仍对象、locale 键不变),只换承载名称的那一个键。8.1 的下拉原生是
|
|
82
|
+
* 字符串 `{"zh":...}`;8.2+ 用对象。形态跟原文走,避免跨版本写入把设计器
|
|
83
|
+
* 认不了的形态互相覆盖。
|
|
84
|
+
*/
|
|
85
|
+
function retitleI18n(existing, value) {
|
|
86
|
+
if (typeof existing === "string") {
|
|
87
|
+
try {
|
|
88
|
+
const parsed = JSON.parse(existing);
|
|
89
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
90
|
+
const record = parsed;
|
|
91
|
+
const key = Object.prototype.hasOwnProperty.call(record, "zh") ? "zh" : "zh-CN";
|
|
92
|
+
return JSON.stringify({ ...record, [key]: value });
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
/* 原文不是 JSON 对象串:按平台字符串形态重建 */
|
|
97
|
+
}
|
|
98
|
+
return JSON.stringify({ zh: value });
|
|
99
|
+
}
|
|
100
|
+
if (existing && typeof existing === "object" && !Array.isArray(existing)) {
|
|
101
|
+
const record = existing;
|
|
102
|
+
const key = Object.prototype.hasOwnProperty.call(record, "zh") ? "zh" : "zh-CN";
|
|
103
|
+
return { ...record, [key]: value };
|
|
104
|
+
}
|
|
105
|
+
return existing;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* `choices` 更新选项族时的条目级合并:按 code 匹配既有条目,既有的未声明键
|
|
109
|
+
* (color / _key / published / metadata 等跨版本导入态)一律继承,新生成值
|
|
110
|
+
* 覆盖代码与取值;`name_i18n` 的形态跟既有条目走。未匹配的新条目保持生成形态。
|
|
111
|
+
*/
|
|
112
|
+
function mergeChoiceEntries(existing, next) {
|
|
113
|
+
if (!Array.isArray(next))
|
|
114
|
+
return next;
|
|
115
|
+
const previous = new Map();
|
|
116
|
+
if (Array.isArray(existing)) {
|
|
117
|
+
for (const entry of existing) {
|
|
118
|
+
if (entry && typeof entry === "object" && !Array.isArray(entry))
|
|
119
|
+
previous.set(String(entry.code ?? ""), entry);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return next.map((entry) => {
|
|
123
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry))
|
|
124
|
+
return entry;
|
|
125
|
+
const fresh = entry;
|
|
126
|
+
const old = previous.get(String(fresh.code ?? ""));
|
|
127
|
+
if (!old)
|
|
128
|
+
return fresh;
|
|
129
|
+
const merged = { ...old, ...fresh };
|
|
130
|
+
if (old.name_i18n !== undefined)
|
|
131
|
+
merged.name_i18n = retitleI18n(old.name_i18n, String(fresh.value ?? old.value ?? ""));
|
|
132
|
+
return merged;
|
|
133
|
+
});
|
|
134
|
+
}
|
|
78
135
|
export function prepareFieldUpdate(input) {
|
|
79
136
|
// r26 快速装载:符号式/裸值条件就地编译为平台中文规范形状(合规式零改写)。
|
|
80
137
|
const normalizedOptions = input.options === undefined ? undefined : normalizeFormConditionOptions(input.options);
|
|
@@ -99,12 +156,15 @@ export function prepareFieldUpdate(input) {
|
|
|
99
156
|
propertyType: recordType,
|
|
100
157
|
...(input.choices ? { choices: input.choices } : {}),
|
|
101
158
|
...(effectiveOptions ? { options: effectiveOptions } : {}),
|
|
159
|
+
...(input.targetVersion ? { targetVersion: input.targetVersion } : {}),
|
|
102
160
|
}),
|
|
103
161
|
});
|
|
104
|
-
// 2026-10-29
|
|
105
|
-
// optionsSet 走保留式合并——以服务端原文 optionsSet 为基线,只换 custom
|
|
162
|
+
// 2026-10-29 治豪 issue:optionsSet 覆盖风险——以 choices 更新选项族时
|
|
163
|
+
// optionsSet 走保留式合并——以服务端原文 optionsSet 为基线,只换 custom 条目;
|
|
106
164
|
// optionStructure/treeSelect/businessModel 等未声明键(含跨版本导入态)一律继承,
|
|
107
165
|
// 不整体重建。锚定线(8.6/1.1.25)实测无此形状,纯防御。
|
|
166
|
+
// 2026-10-30 cpdocs issue #8:低版本(< 8.2)原文缺 optionStructure/treeSelect
|
|
167
|
+
// 时按族兜底补入,原文已有则不动;custom 条目按 code 级合并,保住 color/_key 等。
|
|
108
168
|
const nextOptions = isChildTable
|
|
109
169
|
? currentOptions
|
|
110
170
|
: input.choices !== undefined
|
|
@@ -112,10 +172,18 @@ export function prepareFieldUpdate(input) {
|
|
|
112
172
|
&& currentOptions.optionsSet !== undefined
|
|
113
173
|
&& currentOptions.optionsSet !== null
|
|
114
174
|
&& typeof currentOptions.optionsSet === "object"
|
|
115
|
-
? {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
175
|
+
? (() => {
|
|
176
|
+
const currentSet = currentOptions.optionsSet;
|
|
177
|
+
const rebuiltSet = rebuiltOptions.optionsSet;
|
|
178
|
+
return {
|
|
179
|
+
...rebuiltOptions,
|
|
180
|
+
optionsSet: withLegacyOptionSetKeys({
|
|
181
|
+
...currentSet,
|
|
182
|
+
...rebuiltSet,
|
|
183
|
+
custom: mergeChoiceEntries(currentSet.custom, rebuiltSet.custom),
|
|
184
|
+
}, optionShapeFamily(input.targetVersion)),
|
|
185
|
+
};
|
|
186
|
+
})()
|
|
119
187
|
: rebuiltOptions;
|
|
120
188
|
if (!isChildTable && !effectiveOptions && !input.choices)
|
|
121
189
|
Object.assign(nextOptions, currentOptions);
|
package/dist/field-families.js
CHANGED
|
@@ -553,8 +553,48 @@ export function normalizeMappingsOption(options) {
|
|
|
553
553
|
const shapeChanged = Array.isArray(mappings) || (typeof mappings === "string" && mappings.trim() === "[]");
|
|
554
554
|
return { options: next, ...(shapeChanged ? { note: `options.mappings 已归一为平台字符串形态:${normalized === "" ? "空串(无映射)" : String(normalized)}` } : {}) };
|
|
555
555
|
}
|
|
556
|
+
/**
|
|
557
|
+
* 8.2 以下的 optionsSet 额外带 `optionStructure` / `treeSelect`;8.2 及以上
|
|
558
|
+
* (实测 8.6.26 锚点、8.8 AI 生成包)不带。cp-model 侧实测(8.1.106/8.1.108):
|
|
559
|
+
* 缺这两个键时设计器打开下拉字段的「自定义选项」弹窗,增删改任意操作点确定
|
|
560
|
+
* 都抛 `Cannot create property 'zh' on string ...`(cpdocs issue #8)。
|
|
561
|
+
* 只有确认是 8.0/8.1 才补——版本探测取不到或落在别的族(如门户版本号
|
|
562
|
+
* 1.1.x)时按未知处理,不猜。
|
|
563
|
+
*/
|
|
564
|
+
export const LEGACY_OPTION_SET_DEFAULTS = Object.freeze({
|
|
565
|
+
optionStructure: "flat",
|
|
566
|
+
treeSelect: Object.freeze({
|
|
567
|
+
fromLevel: 1,
|
|
568
|
+
limitLevelRangeEnabled: false,
|
|
569
|
+
storePathLabel: false,
|
|
570
|
+
enabled: false,
|
|
571
|
+
displayMode: "verticalTree",
|
|
572
|
+
selectableLevel: "leafOnly",
|
|
573
|
+
}),
|
|
574
|
+
});
|
|
575
|
+
export function optionShapeFamily(version) {
|
|
576
|
+
if (typeof version !== "string")
|
|
577
|
+
return undefined;
|
|
578
|
+
const match = /^\s*(\d+)\.(\d+)/u.exec(version);
|
|
579
|
+
if (!match)
|
|
580
|
+
return undefined;
|
|
581
|
+
const major = Number(match[1]);
|
|
582
|
+
const minor = Number(match[2]);
|
|
583
|
+
if (!Number.isInteger(major) || !Number.isInteger(minor))
|
|
584
|
+
return undefined;
|
|
585
|
+
if (major < 8)
|
|
586
|
+
return undefined;
|
|
587
|
+
return major === 8 && minor < 2 ? "legacy" : "modern";
|
|
588
|
+
}
|
|
589
|
+
/** legacy 族补齐 8.1 的 optionsSet 键;已有键不覆盖,modern/未知原样返回。 */
|
|
590
|
+
export function withLegacyOptionSetKeys(optionsSet, family) {
|
|
591
|
+
if (family !== "legacy")
|
|
592
|
+
return optionsSet;
|
|
593
|
+
return { ...LEGACY_OPTION_SET_DEFAULTS, ...optionsSet };
|
|
594
|
+
}
|
|
556
595
|
export function buildFieldOptions(args) {
|
|
557
596
|
const explicit = args.options;
|
|
597
|
+
const family = optionShapeFamily(args.targetVersion);
|
|
558
598
|
const raw = args.propertyType;
|
|
559
599
|
const type = typeof raw === "number" && Number.isInteger(raw)
|
|
560
600
|
? raw
|
|
@@ -586,18 +626,28 @@ export function buildFieldOptions(args) {
|
|
|
586
626
|
// Ticket 108: no dictionaryData on selection rows — designer-produced
|
|
587
627
|
// rows carry none (fwb §12-15) and the platform only accepts the extra
|
|
588
628
|
// key, never requires it (live 8.6.26 write+read 2026-09-15).
|
|
629
|
+
// 8.1 原生条目形态(cpdocs issue #8 证据):name_i18n 是字符串 `{"zh":...}`、
|
|
630
|
+
// 无 published、custom 场景 businessModel 为空对象。低版本按此生成,
|
|
631
|
+
// 8.2+ 维持锚点线(8.6)实测形态。
|
|
632
|
+
const custom = family === "legacy"
|
|
633
|
+
? choices.map((value) => ({
|
|
634
|
+
code: value,
|
|
635
|
+
value,
|
|
636
|
+
name_i18n: JSON.stringify({ zh: value }),
|
|
637
|
+
}))
|
|
638
|
+
: choices.map((value) => ({
|
|
639
|
+
code: value,
|
|
640
|
+
value,
|
|
641
|
+
name_i18n: { "zh-CN": value, en: value },
|
|
642
|
+
published: false,
|
|
643
|
+
}));
|
|
589
644
|
const selection = {
|
|
590
|
-
optionsSet: {
|
|
645
|
+
optionsSet: withLegacyOptionSetKeys({
|
|
591
646
|
optionsType: "custom",
|
|
592
|
-
custom
|
|
593
|
-
code: value,
|
|
594
|
-
value,
|
|
595
|
-
name_i18n: { "zh-CN": value, en: value },
|
|
596
|
-
published: false,
|
|
597
|
-
})),
|
|
647
|
+
custom,
|
|
598
648
|
dictionary: {},
|
|
599
|
-
businessModel: { orderType: 1 },
|
|
600
|
-
},
|
|
649
|
+
businessModel: family === "legacy" ? {} : { orderType: 1 },
|
|
650
|
+
}, family),
|
|
601
651
|
};
|
|
602
652
|
return type !== undefined ? deriveFieldOptions(type, selection) : selection;
|
|
603
653
|
}
|
package/dist/form-default.js
CHANGED
|
File without changes
|
package/dist/form-layout.js
CHANGED
|
File without changes
|
package/dist/form-support.js
CHANGED
|
File without changes
|
package/dist/formula-lint.js
CHANGED
|
File without changes
|
package/dist/goal-routes.js
CHANGED
|
@@ -44,22 +44,22 @@ function intentGuidance() {
|
|
|
44
44
|
return {
|
|
45
45
|
path: "declarative",
|
|
46
46
|
why: "整包需求:用一份声明式意图文件描述 models/fields/form/listview/rules/workflow/onlinejs/services,由编译器合成平台原生结构并按依赖顺序执行;比逐能力拼装更省上下文、更不易漂移。",
|
|
47
|
-
starter: `intentVersion: 1
|
|
48
|
-
models:
|
|
49
|
-
- code: <模型code> # 如 omcTodoTask(小写下划线也合规;字段码必须 lowerCamelCase ≤25 字符——产品实施规范)
|
|
50
|
-
name: <业务名>
|
|
51
|
-
fields:
|
|
52
|
-
- {code: title, name: 标题, type: SHORT_TEXT}
|
|
53
|
-
- {code: amount, name: 数量, type: NUMERICAL, options: {scale: 2}} # NUMERICAL 必带 scale
|
|
54
|
-
- {code: level, name: 等级, type: RADIO, choices: [高, 中, 低]} # 选择族用顶层 choices
|
|
55
|
-
form: {publish: true}
|
|
56
|
-
listview: {fieldCodes: [title, level]}
|
|
57
|
-
rules:
|
|
58
|
-
- code: Create # 平台预置触发行(name 省略)
|
|
59
|
-
enabled: true
|
|
60
|
-
actions:
|
|
61
|
-
- when: [{field: amount, gt: 10}]
|
|
62
|
-
set: [{field: title, value: "超限"}]
|
|
47
|
+
starter: `intentVersion: 1
|
|
48
|
+
models:
|
|
49
|
+
- code: <模型code> # 如 omcTodoTask(小写下划线也合规;字段码必须 lowerCamelCase ≤25 字符——产品实施规范)
|
|
50
|
+
name: <业务名>
|
|
51
|
+
fields:
|
|
52
|
+
- {code: title, name: 标题, type: SHORT_TEXT}
|
|
53
|
+
- {code: amount, name: 数量, type: NUMERICAL, options: {scale: 2}} # NUMERICAL 必带 scale
|
|
54
|
+
- {code: level, name: 等级, type: RADIO, choices: [高, 中, 低]} # 选择族用顶层 choices
|
|
55
|
+
form: {publish: true}
|
|
56
|
+
listview: {fieldCodes: [title, level]}
|
|
57
|
+
rules:
|
|
58
|
+
- code: Create # 平台预置触发行(name 省略)
|
|
59
|
+
enabled: true
|
|
60
|
+
actions:
|
|
61
|
+
- when: [{field: amount, gt: 10}]
|
|
62
|
+
set: [{field: title, value: "超限"}]
|
|
63
63
|
`,
|
|
64
64
|
commands: [
|
|
65
65
|
"把上面的 starter 存成 <file>.yaml 按需求改字段后:omc intent validate <file>.yaml(离线)→ omc intent plan <file>.yaml --env <env> → omc intent apply <file>.yaml --env <env>(apply 也能直接吃 YAML)",
|
|
File without changes
|