@stalfh233/omc-cli 0.0.0-stage → 0.4.0
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 -0
- package/README.md +304 -3
- package/coverage/m1-coverage-manifest-v1.json +1278 -0
- package/dist/approval-token.js +102 -0
- package/dist/args.js +25 -0
- package/dist/artifacts.js +119 -0
- package/dist/bench/call-face-eval.js +256 -0
- package/dist/bench/context-attribution.js +151 -0
- package/dist/bench/discovery-cost-eval.js +230 -0
- package/dist/bench/driver.js +81 -0
- package/dist/bench/evals.js +236 -0
- package/dist/bench/fake-http-server.js +65 -0
- package/dist/bench/instrument.js +87 -0
- package/dist/bench/intent-face-eval.js +343 -0
- package/dist/bench/run.js +166 -0
- package/dist/bench/scenario.js +343 -0
- package/dist/bench/types.js +76 -0
- package/dist/bi-wire.js +41 -0
- package/dist/bizservice-config.js +581 -0
- package/dist/call.js +153 -0
- package/dist/capability-absences.js +23 -0
- package/dist/capability-overview.js +492 -0
- package/dist/capability-shape.js +154 -0
- package/dist/cli-contract.js +70 -0
- package/dist/cli-output.js +73 -0
- package/dist/cli.js +1418 -0
- package/dist/code-rules.js +69 -0
- package/dist/command-transport.js +155 -0
- package/dist/config-store.js +195 -0
- package/dist/context.js +21 -0
- package/dist/contract-consistency.js +66 -0
- package/dist/contract-resources.js +62 -0
- package/dist/coverage-consistency.js +62 -0
- package/dist/coverage-registry.js +76 -0
- package/dist/coverage.js +130 -0
- package/dist/data-list-filter.js +114 -0
- package/dist/discovery.js +390 -0
- package/dist/endpoints.js +154 -0
- package/dist/environment-policy.js +26 -0
- package/dist/execution-metadata.js +1092 -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 +200 -0
- package/dist/field-families.js +896 -0
- package/dist/form-layout.js +111 -0
- package/dist/form-support.js +821 -0
- package/dist/goal-routes.js +468 -0
- package/dist/governed-execution.js +87 -0
- package/dist/human-summary.js +212 -0
- package/dist/identity.js +62 -0
- package/dist/intent/baseline.js +57 -0
- package/dist/intent/capabilities/bizservice.js +274 -0
- package/dist/intent/capabilities/businessrule.js +493 -0
- package/dist/intent/capabilities/datarule.js +187 -0
- package/dist/intent/capabilities/field.js +545 -0
- package/dist/intent/capabilities/form.js +136 -0
- package/dist/intent/capabilities/index.js +64 -0
- package/dist/intent/capabilities/listview.js +157 -0
- package/dist/intent/capabilities/model.js +100 -0
- package/dist/intent/capabilities/onlinejs.js +108 -0
- package/dist/intent/capabilities/report.js +355 -0
- package/dist/intent/capabilities/workflow.js +458 -0
- package/dist/intent/capability.js +6 -0
- package/dist/intent/cli.js +91 -0
- package/dist/intent/compare.js +56 -0
- package/dist/intent/compiler.js +79 -0
- package/dist/intent/dsl.js +129 -0
- package/dist/intent/plan-file.js +63 -0
- package/dist/intent/readback.js +65 -0
- package/dist/intent/schema.js +158 -0
- package/dist/intent/validation.js +30 -0
- package/dist/intent/yaml.js +315 -0
- package/dist/json-column.js +68 -0
- package/dist/lanes/app-contract.js +95 -0
- package/dist/lanes/app-coverage.js +16 -0
- package/dist/lanes/app.js +174 -0
- package/dist/lanes/apply-changes.js +231 -0
- package/dist/lanes/b2-registration-contract.js +292 -0
- package/dist/lanes/b2-registration-coverage.js +48 -0
- package/dist/lanes/b2-registration.js +1187 -0
- package/dist/lanes/businessrule-contract.js +232 -0
- package/dist/lanes/businessrule-coverage.js +16 -0
- package/dist/lanes/businessrule.js +221 -0
- package/dist/lanes/contract-support.js +65 -0
- package/dist/lanes/coverage-declaration.js +9 -0
- package/dist/lanes/datarule-contract.js +155 -0
- package/dist/lanes/datarule-coverage.js +19 -0
- package/dist/lanes/datarule-protocol.js +308 -0
- package/dist/lanes/datarule.js +818 -0
- package/dist/lanes/dictionary-contract.js +78 -0
- package/dist/lanes/dictionary-coverage.js +24 -0
- package/dist/lanes/dictionary.js +235 -0
- package/dist/lanes/environment-contract.js +70 -0
- package/dist/lanes/environment-coverage.js +14 -0
- package/dist/lanes/environment.js +163 -0
- package/dist/lanes/field-contract.js +223 -0
- package/dist/lanes/field-coverage.js +27 -0
- package/dist/lanes/field.js +374 -0
- package/dist/lanes/form-contract.js +97 -0
- package/dist/lanes/form-coverage.js +16 -0
- package/dist/lanes/form.js +185 -0
- package/dist/lanes/lane-ids.js +34 -0
- package/dist/lanes/list-view-contract.js +175 -0
- package/dist/lanes/list-view-coverage.js +20 -0
- package/dist/lanes/list-view-shapes.js +1207 -0
- package/dist/lanes/list-view.js +578 -0
- package/dist/lanes/meta-contract.js +85 -0
- package/dist/lanes/meta.js +255 -0
- package/dist/lanes/model-contract.js +168 -0
- package/dist/lanes/model-coverage.js +20 -0
- package/dist/lanes/model.js +986 -0
- package/dist/lanes/online-js-contract.js +99 -0
- package/dist/lanes/online-js-coverage.js +28 -0
- package/dist/lanes/online-js.js +127 -0
- package/dist/lanes/report-contract.js +144 -0
- package/dist/lanes/report-coverage.js +21 -0
- package/dist/lanes/report.js +476 -0
- package/dist/lanes/rule-graph.js +1846 -0
- package/dist/lanes/rule-lifecycle-contract.js +92 -0
- package/dist/lanes/rule-lifecycle-coverage.js +20 -0
- package/dist/lanes/rule-lifecycle.js +176 -0
- package/dist/lanes/runtime-data-contract.js +264 -0
- package/dist/lanes/runtime-data-coverage.js +25 -0
- package/dist/lanes/runtime-data.js +1054 -0
- package/dist/lanes/workflow-contract.js +223 -0
- package/dist/lanes/workflow-coverage.js +40 -0
- package/dist/lanes/workflow.js +1813 -0
- package/dist/online-js-layout.js +58 -0
- package/dist/online-js-source.js +276 -0
- package/dist/package-tool.js +51 -0
- package/dist/package.js +73 -0
- package/dist/plan.js +73 -0
- package/dist/read.js +144 -0
- package/dist/redact.js +28 -0
- package/dist/rule-support.js +587 -0
- package/dist/runtime-support.js +134 -0
- package/dist/server.js +92 -0
- package/dist/session-manager.js +30 -0
- package/dist/session.js +149 -0
- package/dist/skills.js +112 -0
- package/dist/support.js +98 -0
- package/dist/tool-types.js +127 -0
- package/dist/tools.js +59 -0
- package/dist/usage-log.js +197 -0
- package/dist/wire.js +287 -0
- package/dist/workflow-support.js +99 -0
- package/dist/write-lease.js +26 -0
- package/dist/write-lock.js +109 -0
- package/dist/write.js +176 -0
- package/dist/zip.js +156 -0
- package/docs/tool-surface-map.md +42 -0
- package/package.json +71 -6
- package/skills/omc-acceptance-criteria.md +47 -0
- package/skills/omc-business-configuration.md +257 -0
- package/skills/omc-capabilities.md +197 -0
- package/skills/omc-capability-scouting.md +55 -0
- package/skills/omc-config-draft-review.md +171 -0
- package/skills/omc-five-piece-flow.md +35 -0
- package/skills/omc-glossary.md +86 -0
- package/skills/omc-refusals.md +110 -0
- package/skills/omc-requirement-analysis.md +161 -0
- package/skills/omc-requirement-vocabulary.md +51 -0
- package/skills/omc-start-here.md +82 -0
- package/skills/omc-tool-selection.md +119 -0
- package/skills/omc-write-hazards.md +87 -0
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
import { ENDPOINTS } from "../../endpoints.js";
|
|
2
|
+
import { wireCall, WireError } from "../../wire.js";
|
|
3
|
+
import { biCall, DEFAULT_BI_CORP_ID } from "../../bi-wire.js";
|
|
4
|
+
import { refuse } from "../capability.js";
|
|
5
|
+
import { sameValue } from "../compare.js";
|
|
6
|
+
import { isScalarString, pushError } from "../validation.js";
|
|
7
|
+
import { toPlain } from "../yaml.js";
|
|
8
|
+
/**
|
|
9
|
+
* R1-report on the intent face — a root-scoped capability (a report is
|
|
10
|
+
* app-scoped config, sibling to a business service, not a model slice).
|
|
11
|
+
*
|
|
12
|
+
* A report is a PAGE on the platform channel plus a BI dashboard
|
|
13
|
+
* (global/attributes/charts) on `/dashboard/v1`. Ownership is ensure-present:
|
|
14
|
+
* only declared reports are read/planned, and only charts are removed when the
|
|
15
|
+
* report explicitly sets `removeUnlistedCharts:true` — undeclared BI charts on
|
|
16
|
+
* an otherwise matching report are never touched unless that flag is set.
|
|
17
|
+
*
|
|
18
|
+
* A report page has no BI dashboard until it is saved, so a fresh report plans
|
|
19
|
+
* `report.create` (which seeds the dashboard) followed by `report.configure`
|
|
20
|
+
* (global/attributes/charts). An existing report converges through
|
|
21
|
+
* `report.update` (metadata) and `report.configure` (dashboard + chart diff).
|
|
22
|
+
*/
|
|
23
|
+
const REPORT_KEYS = new Set(["code", "name", "appCode", "parentId", "icon", "pcAble", "mobileAble", "corpId", "global", "attributes", "charts", "removeUnlistedCharts"]);
|
|
24
|
+
const CHART_KEYS = new Set(["uuid", "title", "type", "dataSourceId", "mainTable", "position", "styles", "data", "options", "authorization", "useType", "mobileOptions"]);
|
|
25
|
+
function reportAuth(report) {
|
|
26
|
+
return { corpId: report.corpId ?? DEFAULT_BI_CORP_ID, reportCode: report.code, appCode: report.appCode };
|
|
27
|
+
}
|
|
28
|
+
/** Parse a JSON column; leave a non-string / unparseable value as-is. */
|
|
29
|
+
function decodeJson(value) {
|
|
30
|
+
if (typeof value !== "string")
|
|
31
|
+
return value;
|
|
32
|
+
const text = value.trim();
|
|
33
|
+
if (!text)
|
|
34
|
+
return undefined;
|
|
35
|
+
try {
|
|
36
|
+
return JSON.parse(text);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function isEmptyObject(value) {
|
|
43
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 0;
|
|
44
|
+
}
|
|
45
|
+
/** A declared chart normalized into the stored BI chart object the write face takes. */
|
|
46
|
+
function chartObject(chart) {
|
|
47
|
+
const value = { uuid: chart.uuid, title: chart.title, type: chart.type };
|
|
48
|
+
for (const key of ["dataSourceId", "mainTable", "authorization", "useType"])
|
|
49
|
+
if (chart[key] !== undefined)
|
|
50
|
+
value[key] = chart[key];
|
|
51
|
+
// Charts may pass structured sub-objects; the BI column wants JSON strings.
|
|
52
|
+
for (const key of ["position", "styles", "data", "mobileOptions"]) {
|
|
53
|
+
const entry = chart[key];
|
|
54
|
+
if (entry !== undefined)
|
|
55
|
+
value[key] = typeof entry === "string" ? entry : JSON.stringify(entry);
|
|
56
|
+
}
|
|
57
|
+
return value;
|
|
58
|
+
}
|
|
59
|
+
function configureArgs(report) {
|
|
60
|
+
return {
|
|
61
|
+
reportCode: report.code,
|
|
62
|
+
appCode: report.appCode,
|
|
63
|
+
...(report.corpId ? { corpId: report.corpId } : {}),
|
|
64
|
+
...(report.global !== undefined ? { global: report.global } : {}),
|
|
65
|
+
...(report.attributes !== undefined ? { attributes: report.attributes } : {}),
|
|
66
|
+
...(report.charts !== undefined ? { charts: report.charts.map(chartObject) } : {}),
|
|
67
|
+
...(report.removeUnlistedCharts ? { removeUnlistedCharts: true } : {}),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/** Whether the declared dashboard differs from the live one (idempotence guard). */
|
|
71
|
+
function dashboardNeedsConfigure(report, live) {
|
|
72
|
+
if (report.global !== undefined && !sameValue(report.global, live.global))
|
|
73
|
+
return true;
|
|
74
|
+
if (report.attributes !== undefined && !sameValue(report.attributes, live.attributes))
|
|
75
|
+
return true;
|
|
76
|
+
if (report.charts !== undefined) {
|
|
77
|
+
const liveCharts = new Map((live.charts ?? []).map((chart) => [chart.uuid, chart]));
|
|
78
|
+
for (const chart of report.charts) {
|
|
79
|
+
const current = liveCharts.get(chart.uuid);
|
|
80
|
+
if (!current || current.title !== chart.title || current.type !== chart.type)
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (report.removeUnlistedCharts === true) {
|
|
85
|
+
const declared = new Set((report.charts ?? []).map((chart) => chart.uuid));
|
|
86
|
+
if (live.chartUuids.some((uuid) => !declared.has(uuid)))
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
function validateChartNode(chartNode, chartBase, validation) {
|
|
92
|
+
for (const entry of chartNode.entries)
|
|
93
|
+
if (!CHART_KEYS.has(entry.key))
|
|
94
|
+
pushError(validation, "intent-key-unknown", `chart 不支持键 "${entry.key}"`, `${chartBase}.${entry.key}`);
|
|
95
|
+
const chartValue = (key) => chartNode.entries.find((entry) => entry.key === key)?.value;
|
|
96
|
+
const uuid = chartValue("uuid");
|
|
97
|
+
const title = chartValue("title");
|
|
98
|
+
const type = chartValue("type");
|
|
99
|
+
if (!isScalarString(uuid) || uuid.value.trim().length === 0)
|
|
100
|
+
pushError(validation, "intent-report-chart-uuid-invalid", "chart.uuid 必须是非空字符串", `${chartBase}.uuid`, "value");
|
|
101
|
+
if (!isScalarString(title) || title.value.trim().length === 0)
|
|
102
|
+
pushError(validation, "intent-report-chart-title-invalid", "chart.title 必须是非空字符串", `${chartBase}.title`, "value");
|
|
103
|
+
if (!isScalarString(type) || type.value.trim().length === 0)
|
|
104
|
+
pushError(validation, "intent-report-chart-type-invalid", "chart.type 必须是非空字符串(bar/line/pie/card/table/list…)", `${chartBase}.type`, "value");
|
|
105
|
+
if (!isScalarString(uuid) || !isScalarString(title) || !isScalarString(type))
|
|
106
|
+
return undefined;
|
|
107
|
+
const chart = { uuid: uuid.value.trim(), title: title.value.trim(), type: type.value.trim() };
|
|
108
|
+
for (const key of ["dataSourceId", "mainTable", "authorization", "useType"]) {
|
|
109
|
+
const entry = chartValue(key);
|
|
110
|
+
if (isScalarString(entry))
|
|
111
|
+
chart[key] = entry.value;
|
|
112
|
+
}
|
|
113
|
+
for (const key of ["position", "styles", "data", "mobileOptions", "options"]) {
|
|
114
|
+
const entry = chartValue(key);
|
|
115
|
+
if (entry !== undefined)
|
|
116
|
+
chart[key] = toPlain(entry);
|
|
117
|
+
}
|
|
118
|
+
return chart;
|
|
119
|
+
}
|
|
120
|
+
function validateReportNode(node, index, draft, validation) {
|
|
121
|
+
const base = `reports[${index}]`;
|
|
122
|
+
for (const entry of node.entries)
|
|
123
|
+
if (!REPORT_KEYS.has(entry.key))
|
|
124
|
+
pushError(validation, "intent-key-unknown", `report 不支持键 "${entry.key}"`, `${base}.${entry.key}`);
|
|
125
|
+
const value = (key) => node.entries.find((entry) => entry.key === key)?.value;
|
|
126
|
+
const code = value("code");
|
|
127
|
+
const name = value("name");
|
|
128
|
+
const appCode = value("appCode");
|
|
129
|
+
const parentId = value("parentId");
|
|
130
|
+
if (!isScalarString(code) || code.value.trim().length === 0)
|
|
131
|
+
pushError(validation, "intent-report-code-invalid", "report.code 必须是非空字符串", `${base}.code`, "value");
|
|
132
|
+
if (isScalarString(code) && !/^[A-Za-z][A-Za-z0-9_]{0,59}$/.test(code.value.trim()))
|
|
133
|
+
pushError(validation, "intent-report-code-invalid", "report.code 必须字母开头、≤60、仅字母数字下划线", `${base}.code`, "value");
|
|
134
|
+
if (!isScalarString(name) || name.value.trim().length === 0)
|
|
135
|
+
pushError(validation, "intent-report-name-invalid", "report.name 必须是非空字符串", `${base}.name`, "value");
|
|
136
|
+
if (!isScalarString(appCode) || appCode.value.trim().length === 0)
|
|
137
|
+
pushError(validation, "intent-report-appcode-invalid", "report.appCode 必须是非空字符串", `${base}.appCode`, "value");
|
|
138
|
+
if (!isScalarString(parentId) || parentId.value.trim().length === 0)
|
|
139
|
+
pushError(validation, "intent-report-parent-invalid", "report.parentId 必须是直属分组 id(新建报表页必填)", `${base}.parentId`, "value");
|
|
140
|
+
const chartsNode = value("charts");
|
|
141
|
+
if (chartsNode !== undefined && chartsNode.kind !== "seq")
|
|
142
|
+
pushError(validation, "intent-report-charts-invalid", "report.charts 必须是列表", `${base}.charts`, "value");
|
|
143
|
+
if (!isScalarString(code) || !isScalarString(name) || !isScalarString(appCode) || !isScalarString(parentId))
|
|
144
|
+
return;
|
|
145
|
+
const charts = [];
|
|
146
|
+
if (chartsNode?.kind === "seq") {
|
|
147
|
+
chartsNode.items.forEach((chartNode, chartIndex) => {
|
|
148
|
+
const chartBase = `${base}.charts[${chartIndex}]`;
|
|
149
|
+
if (chartNode.kind !== "map") {
|
|
150
|
+
pushError(validation, "intent-report-chart-invalid", "chart 必须是映射", chartBase, "value");
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const chart = validateChartNode(chartNode, chartBase, validation);
|
|
154
|
+
if (chart)
|
|
155
|
+
charts.push(chart);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
const seen = new Set();
|
|
159
|
+
for (const chart of charts) {
|
|
160
|
+
if (seen.has(chart.uuid))
|
|
161
|
+
pushError(validation, "intent-report-chart-uuid-duplicate", `chart uuid 重复:${chart.uuid}`, `${base}.charts`, "value");
|
|
162
|
+
seen.add(chart.uuid);
|
|
163
|
+
}
|
|
164
|
+
const globalEntry = value("global");
|
|
165
|
+
const attributesEntry = value("attributes");
|
|
166
|
+
const removeNode = value("removeUnlistedCharts");
|
|
167
|
+
const corpNode = value("corpId");
|
|
168
|
+
const bool = (key) => {
|
|
169
|
+
const entry = value(key);
|
|
170
|
+
return entry?.kind === "scalar" && typeof entry.value === "boolean" ? entry.value : undefined;
|
|
171
|
+
};
|
|
172
|
+
const pcAble = bool("pcAble");
|
|
173
|
+
const mobileAble = bool("mobileAble");
|
|
174
|
+
const removeUnlisted = removeNode?.kind === "scalar" && removeNode.value === true;
|
|
175
|
+
const icon = value("icon");
|
|
176
|
+
draft.reports.push({
|
|
177
|
+
code: code.value.trim(),
|
|
178
|
+
name: name.value.trim(),
|
|
179
|
+
appCode: appCode.value.trim(),
|
|
180
|
+
parentId: parentId.value.trim(),
|
|
181
|
+
...(isScalarString(icon) ? { icon: icon.value } : {}),
|
|
182
|
+
...(pcAble !== undefined ? { pcAble } : {}),
|
|
183
|
+
...(mobileAble !== undefined ? { mobileAble } : {}),
|
|
184
|
+
...(isScalarString(corpNode) ? { corpId: corpNode.value } : {}),
|
|
185
|
+
...(globalEntry !== undefined ? { global: toPlain(globalEntry) } : {}),
|
|
186
|
+
...(attributesEntry !== undefined ? { attributes: toPlain(attributesEntry) } : {}),
|
|
187
|
+
...(charts.length > 0 ? { charts } : {}),
|
|
188
|
+
...(removeUnlisted ? { removeUnlistedCharts: true } : {}),
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
export const reportCapability = {
|
|
192
|
+
id: "report",
|
|
193
|
+
title: "报表",
|
|
194
|
+
requires: [],
|
|
195
|
+
operations: ["create", "update", "delete", "configure"],
|
|
196
|
+
validateRoot(tree, draft, validation) {
|
|
197
|
+
const reportsNode = tree.entries.find((entry) => entry.key === "reports")?.value;
|
|
198
|
+
if (reportsNode === undefined || (reportsNode.kind === "scalar" && reportsNode.value === null))
|
|
199
|
+
return;
|
|
200
|
+
if (reportsNode.kind !== "seq") {
|
|
201
|
+
pushError(validation, "intent-reports-not-a-list", "reports 必须是列表", "reports", "value");
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const seen = new Set();
|
|
205
|
+
reportsNode.items.forEach((node, index) => {
|
|
206
|
+
if (node.kind !== "map") {
|
|
207
|
+
pushError(validation, "intent-report-not-a-map", "report 必须是映射", `reports[${index}]`, "value");
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const before = draft.reports.length;
|
|
211
|
+
validateReportNode(node, index, draft, validation);
|
|
212
|
+
const added = draft.reports[before];
|
|
213
|
+
if (added && seen.has(added.code))
|
|
214
|
+
pushError(validation, "intent-report-code-duplicate", `report code 重复:${added.code}`, `reports[${index}].code`, "value");
|
|
215
|
+
if (added)
|
|
216
|
+
seen.add(added.code);
|
|
217
|
+
});
|
|
218
|
+
},
|
|
219
|
+
async readRoot(session, intent) {
|
|
220
|
+
const reports = intent.reports ?? [];
|
|
221
|
+
const result = [];
|
|
222
|
+
for (const report of reports) {
|
|
223
|
+
let page = null;
|
|
224
|
+
try {
|
|
225
|
+
page = (await wireCall(session, { path: ENDPOINTS.reportGet, query: { code: report.code } })).data;
|
|
226
|
+
}
|
|
227
|
+
catch (error) {
|
|
228
|
+
if (!(error instanceof WireError && error.kind === "business"))
|
|
229
|
+
throw error;
|
|
230
|
+
}
|
|
231
|
+
if (!page || !page.id) {
|
|
232
|
+
result.push({ code: report.code, present: false, name: null, appCode: null, objectId: null, biPresent: false, chartUuids: [] });
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
const objectId = String(page.id);
|
|
236
|
+
let biPresent = false;
|
|
237
|
+
const chartUuids = [];
|
|
238
|
+
const charts = [];
|
|
239
|
+
let global;
|
|
240
|
+
let attributes;
|
|
241
|
+
try {
|
|
242
|
+
const data = (await biCall(session, { path: ENDPOINTS.biReportConfig, body: { objectId }, query: { lang: "cn" }, auth: reportAuth(report) }));
|
|
243
|
+
if (data && typeof data === "object") {
|
|
244
|
+
biPresent = true;
|
|
245
|
+
if (Array.isArray(data.charts))
|
|
246
|
+
for (const chart of data.charts) {
|
|
247
|
+
chartUuids.push(String(chart.uuid));
|
|
248
|
+
charts.push({ uuid: String(chart.uuid), title: String(chart.title ?? ""), type: String(chart.type ?? "") });
|
|
249
|
+
}
|
|
250
|
+
global = decodeJson(data.global);
|
|
251
|
+
attributes = decodeJson(data.attributes);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
catch (error) {
|
|
255
|
+
if (!(error instanceof WireError && /dashboard\.not\.exist|does not exist/i.test(error.message)))
|
|
256
|
+
throw error;
|
|
257
|
+
}
|
|
258
|
+
result.push({
|
|
259
|
+
code: report.code,
|
|
260
|
+
present: true,
|
|
261
|
+
name: typeof page.name === "string" ? page.name : null,
|
|
262
|
+
appCode: typeof page.appCode === "string" ? page.appCode : null,
|
|
263
|
+
objectId,
|
|
264
|
+
biPresent,
|
|
265
|
+
chartUuids,
|
|
266
|
+
...(global !== undefined && !isEmptyObject(global) ? { global } : {}),
|
|
267
|
+
...(attributes !== undefined && !isEmptyObject(attributes) ? { attributes } : {}),
|
|
268
|
+
...(charts.length > 0 ? { charts } : {}),
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
return result;
|
|
272
|
+
},
|
|
273
|
+
planRoot(intent, baseline, emit) {
|
|
274
|
+
const reports = intent.reports ?? [];
|
|
275
|
+
const current = baseline.reports ?? [];
|
|
276
|
+
for (const report of reports) {
|
|
277
|
+
const live = current.find((entry) => entry.code === report.code);
|
|
278
|
+
const resource = `report:${report.code}`;
|
|
279
|
+
if (!live?.present) {
|
|
280
|
+
emit.change("report.create", {
|
|
281
|
+
code: report.code,
|
|
282
|
+
name: report.name,
|
|
283
|
+
appCode: report.appCode,
|
|
284
|
+
parentId: report.parentId,
|
|
285
|
+
...(report.icon ? { icon: report.icon } : {}),
|
|
286
|
+
...(report.pcAble !== undefined ? { pcAble: report.pcAble } : {}),
|
|
287
|
+
...(report.mobileAble !== undefined ? { mobileAble: report.mobileAble } : {}),
|
|
288
|
+
...(report.corpId ? { corpId: report.corpId } : {}),
|
|
289
|
+
}, resource, "report-absent");
|
|
290
|
+
if (report.global !== undefined || report.attributes !== undefined || (report.charts?.length ?? 0) > 0)
|
|
291
|
+
emit.change("report.configure", configureArgs(report), `report:${report.code}#configure`, "report-configure");
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
if (live.name !== report.name || live.appCode !== report.appCode)
|
|
295
|
+
emit.change("report.update", {
|
|
296
|
+
code: report.code,
|
|
297
|
+
name: report.name,
|
|
298
|
+
nameI18n: { zh: report.name },
|
|
299
|
+
...(report.icon ? { icon: report.icon } : {}),
|
|
300
|
+
...(report.pcAble !== undefined ? { pcAble: report.pcAble } : {}),
|
|
301
|
+
...(report.mobileAble !== undefined ? { mobileAble: report.mobileAble } : {}),
|
|
302
|
+
}, resource, "report-drift");
|
|
303
|
+
if (!live.biPresent)
|
|
304
|
+
refuse("intent-report-dashboard-absent", `报表 ${report.code} 的 BI dashboard 不存在(页面在但 dashboard 未初始化);删除页面后用 intent 重建,或走 omc call report.create`, { resource });
|
|
305
|
+
if (!dashboardNeedsConfigure(report, live)) {
|
|
306
|
+
emit.skip(resource, "report-present");
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
emit.change("report.configure", configureArgs(report), `report:${report.code}#configure`, "report-configure");
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
decodeRoot(baseline, live) {
|
|
313
|
+
if (baseline.reports !== undefined)
|
|
314
|
+
live.reports = baseline.reports.map((report) => ({ ...report }));
|
|
315
|
+
},
|
|
316
|
+
compareRoot(intent, live, emit) {
|
|
317
|
+
for (const report of intent.reports ?? []) {
|
|
318
|
+
const current = live.reports?.find((entry) => entry.code === report.code);
|
|
319
|
+
const resource = `report:${report.code}`;
|
|
320
|
+
if (!current?.present) {
|
|
321
|
+
emit.difference("report-missing", resource, `报表 ${report.code} 不存在`);
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
if (current.name !== report.name || current.appCode !== report.appCode)
|
|
325
|
+
emit.difference("report-mismatch", resource, `报表 ${report.code} 的名称/应用不等价`);
|
|
326
|
+
if (!current.biPresent) {
|
|
327
|
+
emit.difference("report-dashboard-missing", resource, `报表 ${report.code} 的 BI dashboard 不存在`);
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
if (report.global !== undefined && !sameValue(report.global, current.global))
|
|
331
|
+
emit.difference("report-mismatch", resource, `报表 ${report.code} 的 global 样式不等价`);
|
|
332
|
+
if (report.attributes !== undefined && !sameValue(report.attributes, current.attributes))
|
|
333
|
+
emit.difference("report-mismatch", resource, `报表 ${report.code} 的全局筛选不等价`);
|
|
334
|
+
if (report.charts !== undefined) {
|
|
335
|
+
const liveCharts = new Map((current.charts ?? []).map((chart) => [chart.uuid, chart]));
|
|
336
|
+
for (const chart of report.charts) {
|
|
337
|
+
const entry = liveCharts.get(chart.uuid);
|
|
338
|
+
if (!entry) {
|
|
339
|
+
emit.difference("report-charts-mismatch", resource, `报表 ${report.code} 缺图表 ${chart.uuid}`);
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
if (entry.title !== chart.title || entry.type !== chart.type)
|
|
343
|
+
emit.difference("report-charts-mismatch", resource, `报表 ${report.code} 图表 ${chart.uuid} 的标题/类型不等价`);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
if (report.removeUnlistedCharts === true) {
|
|
347
|
+
const declared = new Set((report.charts ?? []).map((chart) => chart.uuid));
|
|
348
|
+
const unlisted = current.chartUuids.filter((uuid) => !declared.has(uuid));
|
|
349
|
+
if (unlisted.length > 0)
|
|
350
|
+
emit.difference("report-charts-unexpected", resource, `报表 ${report.code} 含未声明图表:${unlisted.join(", ")}`);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
},
|
|
354
|
+
};
|
|
355
|
+
//# sourceMappingURL=report.js.map
|