mcp-xdx-schema-ctx 1.1.9

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.
Files changed (60) hide show
  1. package/.env.example +43 -0
  2. package/README.md +269 -0
  3. package/dist/config.d.ts +131 -0
  4. package/dist/config.js +138 -0
  5. package/dist/config.js.map +1 -0
  6. package/dist/crypto-utils.d.ts +29 -0
  7. package/dist/crypto-utils.js +118 -0
  8. package/dist/crypto-utils.js.map +1 -0
  9. package/dist/db.d.ts +10 -0
  10. package/dist/db.js +149 -0
  11. package/dist/db.js.map +1 -0
  12. package/dist/diff-utils.d.ts +42 -0
  13. package/dist/diff-utils.js +130 -0
  14. package/dist/diff-utils.js.map +1 -0
  15. package/dist/encrypt-secrets.d.ts +12 -0
  16. package/dist/encrypt-secrets.js +190 -0
  17. package/dist/encrypt-secrets.js.map +1 -0
  18. package/dist/index.d.ts +2 -0
  19. package/dist/index.js +30 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/migrate-utils.d.ts +91 -0
  22. package/dist/migrate-utils.js +399 -0
  23. package/dist/migrate-utils.js.map +1 -0
  24. package/dist/schema-compat.d.ts +46 -0
  25. package/dist/schema-compat.js +169 -0
  26. package/dist/schema-compat.js.map +1 -0
  27. package/dist/shared.d.ts +70 -0
  28. package/dist/shared.js +197 -0
  29. package/dist/shared.js.map +1 -0
  30. package/dist/sql-build.d.ts +121 -0
  31. package/dist/sql-build.js +254 -0
  32. package/dist/sql-build.js.map +1 -0
  33. package/dist/tool-availability.d.ts +35 -0
  34. package/dist/tool-availability.js +90 -0
  35. package/dist/tool-availability.js.map +1 -0
  36. package/dist/tools/data-tools.d.ts +2 -0
  37. package/dist/tools/data-tools.js +243 -0
  38. package/dist/tools/data-tools.js.map +1 -0
  39. package/dist/tools/dataflow-tools.d.ts +2 -0
  40. package/dist/tools/dataflow-tools.js +434 -0
  41. package/dist/tools/dataflow-tools.js.map +1 -0
  42. package/dist/tools/dbo-tools.d.ts +2 -0
  43. package/dist/tools/dbo-tools.js +228 -0
  44. package/dist/tools/dbo-tools.js.map +1 -0
  45. package/dist/tools/diff-tools.d.ts +2 -0
  46. package/dist/tools/diff-tools.js +224 -0
  47. package/dist/tools/diff-tools.js.map +1 -0
  48. package/dist/tools/form-tools.d.ts +2 -0
  49. package/dist/tools/form-tools.js +715 -0
  50. package/dist/tools/form-tools.js.map +1 -0
  51. package/dist/tools/migrate-tools.d.ts +2 -0
  52. package/dist/tools/migrate-tools.js +423 -0
  53. package/dist/tools/migrate-tools.js.map +1 -0
  54. package/dist/tools/system-tools.d.ts +2 -0
  55. package/dist/tools/system-tools.js +1102 -0
  56. package/dist/tools/system-tools.js.map +1 -0
  57. package/dist/tools/table-tools.d.ts +2 -0
  58. package/dist/tools/table-tools.js +1322 -0
  59. package/dist/tools/table-tools.js.map +1 -0
  60. package/package.json +48 -0
@@ -0,0 +1,715 @@
1
+ import { z } from "zod";
2
+ import { T, WARNING, envelope, ok, sqlPagination, topNPagination, } from "../shared.js";
3
+ import { getTableInfo, hasCol, resolveSelect, tableExists, tryQuery, } from "../schema-compat.js";
4
+ import { buildWhere, buildOrderBy, buildPagedQuery } from "../sql-build.js";
5
+ /** [Col1], [Col2] ... */
6
+ const sel = (cols) => cols.map((c) => `[${c}]`).join(", ");
7
+ /** 子模块不可用时的统一结构 */
8
+ function unavailable(module, tableRef, warnings) {
9
+ const reason = `环境库缺少 ${tableRef}`;
10
+ warnings.push({
11
+ module,
12
+ message: reason,
13
+ hint: "可改用 include=basic 只取窗体定义;或用 get_capabilities 查看本环境支持的模块",
14
+ fallback: "get_capabilities",
15
+ });
16
+ return { module, available: false, reason };
17
+ }
18
+ /**
19
+ * 子模块查询:先探测依赖表是否存在,再按实际列构造 SELECT。
20
+ * 缺表 → { available:false, reason };缺列 → NULL 占位 + warning;查询失败 → tryQuery 降级。
21
+ */
22
+ async function queryModule(module, tableRef, wanted, whereSql, warnings, orderSql = "") {
23
+ if (!(await tableExists(tableRef))) {
24
+ return unavailable(module, tableRef, warnings);
25
+ }
26
+ const rs = await resolveSelect(tableRef, wanted);
27
+ if (rs.missing.length > 0) {
28
+ warnings.push({
29
+ module,
30
+ message: `以下列在本环境库不存在,已置空: ${rs.missing.join(", ")}`,
31
+ });
32
+ }
33
+ const rows = await tryQuery(module, `SELECT ${rs.select} FROM ${tableRef}${whereSql}${orderSql}`, warnings);
34
+ return { module, available: true, items: rows };
35
+ }
36
+ export function registerFormTools(server) {
37
+ // ============================================================
38
+ // get_form_full
39
+ // ============================================================
40
+ server.registerTool("get_form_full", {
41
+ description: WARNING +
42
+ "\n\n【核心工具】获取窗体完整配置,串联: 窗体定义→表格规则→字段规则→按钮权限→颜色规则→联动规则→右键菜单→参照规则→按钮布局→数据源→SQL替换→数据流。支持按 include 参数选择返回模块。\n" +
43
+ "每个子模块独立探测依赖表:缺失时该模块返回 { module, available:false, reason } 并写入 warnings,不会因某张子表缺失导致整体失败;include=basic 永不失败。",
44
+ inputSchema: {
45
+ formId: z.string().max(128).optional().describe("窗体ID,如 SaleOrder"),
46
+ formName: z.string().max(200).optional().describe("窗体名称关键词"),
47
+ tableName: z.string().max(128).optional().describe("按关联表名查找"),
48
+ formType: z
49
+ .string()
50
+ .max(50)
51
+ .optional()
52
+ .describe("按FormType过滤,如 List/Edit/View"),
53
+ include: z
54
+ .string()
55
+ .max(200)
56
+ .optional()
57
+ .describe("返回模块,逗号分隔: basic,colors,links,menus,refers,buttons,datasource,sqlReplaces,dataflows。默认全部(all)"),
58
+ page: z.number().int().min(1).default(1).describe("页码"),
59
+ pageSize: z
60
+ .number()
61
+ .int()
62
+ .min(1)
63
+ .max(200)
64
+ .default(10)
65
+ .describe("每页数量(列表模式生效)"),
66
+ },
67
+ }, async ({ formId, formName, tableName, formType, include, page = 1, pageSize = 10, }) => {
68
+ const warnings = [];
69
+ const mods = include ? include.split(",").map((s) => s.trim()) : ["all"];
70
+ const has = (name) => mods.includes("all") || mods.includes(name);
71
+ // ---- 第一步:只查 FormSetTB(登记窗体),任何子表缺失都不影响这一步 ----
72
+ const formInfo = await getTableInfo(T("formDef"));
73
+ if (!formInfo.exists) {
74
+ return ok(envelope({
75
+ items: [],
76
+ pagination: null,
77
+ warnings: [
78
+ {
79
+ module: "get_form_full.basic",
80
+ message: `环境库缺少 ${T("formDef")},窗体定义不可用`,
81
+ hint: "可用 get_capabilities 查看本环境支持的元数据表",
82
+ fallback: "get_capabilities",
83
+ },
84
+ ],
85
+ }));
86
+ }
87
+ const formSelect = await resolveSelect(T("formDef"), [
88
+ "FormID",
89
+ "FormName",
90
+ "LinkTable",
91
+ "FormType",
92
+ "ApiPath",
93
+ "ServiceType",
94
+ ]);
95
+ if (formSelect.missing.length > 0) {
96
+ warnings.push({
97
+ module: "get_form_full.basic",
98
+ message: `FormSetTB 缺少列,已置空: ${formSelect.missing.join(", ")}`,
99
+ });
100
+ }
101
+ const groups = [];
102
+ const safeId = formId ? formId.replace(/[^a-zA-Z0-9_]/g, "") : "";
103
+ if (safeId)
104
+ groups.push({ filters: [{ col: "FormID", op: "eq", value: safeId }] });
105
+ if (formName)
106
+ groups.push({ filters: [{ col: "FormName", op: "like", value: formName }] });
107
+ if (tableName)
108
+ groups.push({ filters: [{ col: "LinkTable", op: "eq", value: tableName }] });
109
+ if (formType)
110
+ groups.push({ filters: [{ col: "FormType", op: "eq", value: formType }] });
111
+ const { where, skipped } = buildWhere(formInfo.columns, groups);
112
+ if (skipped.length > 0) {
113
+ warnings.push({
114
+ module: "get_form_full.basic",
115
+ message: `以下列在本环境库不存在,条件已跳过: ${skipped.join(", ")}`,
116
+ });
117
+ }
118
+ const order = buildOrderBy(formInfo.columns, ["FormID"]);
119
+ let forms = [];
120
+ let pagination = null;
121
+ if (safeId) {
122
+ // 单窗体模式:不分页
123
+ forms = (await tryQuery("get_form_full.basic", `SELECT ${formSelect.select} FROM ${T("formDef")}${where}${order.orderBy}`, warnings));
124
+ }
125
+ else {
126
+ const q = buildPagedQuery({
127
+ table: T("formDef"),
128
+ cols: formSelect.present.length > 0 ? formSelect.present.map((c) => `[${c}]`) : ["[FormID]"],
129
+ where,
130
+ orderBy: order.orderBy,
131
+ page,
132
+ pageSize,
133
+ });
134
+ const cnt = await tryQuery("get_form_full.basic.count", q.countSql, warnings);
135
+ const total = Number(cnt[0]?.Total ?? 0);
136
+ forms =
137
+ total > 0
138
+ ? (await tryQuery("get_form_full.basic", q.sql, warnings))
139
+ : [];
140
+ pagination = sqlPagination(page, pageSize, total);
141
+ }
142
+ if (forms.length === 0) {
143
+ return ok(envelope({
144
+ items: [],
145
+ pagination,
146
+ warnings,
147
+ query: { formId, formName, tableName, formType, include },
148
+ hint: "未匹配到窗体。可用 list_forms(keyword=...) 先按中文名定位 FormID。",
149
+ }));
150
+ }
151
+ const result = [];
152
+ for (const f of forms) {
153
+ const fid = String(f.FormID ?? "").replace(/[^a-zA-Z0-9_]/g, "");
154
+ const linkTable = f.LinkTable;
155
+ const entry = {};
156
+ // --- basic 模块(永不失败)---
157
+ if (has("basic")) {
158
+ entry.form = f;
159
+ // 表格规则头
160
+ let rulePxdids = [];
161
+ if (await tableExists(T("formRuleHed"))) {
162
+ const rs = await resolveSelect(T("formRuleHed"), [
163
+ "XDID",
164
+ "FormID",
165
+ "MainTable",
166
+ "DataSourceType",
167
+ "GridType",
168
+ "iPageSize",
169
+ "KeyField",
170
+ "ParentField",
171
+ "PrimaryKeyField",
172
+ "BillNoField",
173
+ "ApiPath",
174
+ "StyleVer",
175
+ "DataSourceId",
176
+ "DataSourceName",
177
+ ]);
178
+ const ruleHeds = await tryQuery("get_form_full.ruleHeds", `SELECT ${rs.select} FROM ${T("formRuleHed")} WHERE [FormID]='${fid}'`, warnings);
179
+ rulePxdids = ruleHeds
180
+ .map((r) => `'${String(r.XDID)}'`)
181
+ .filter((s) => s !== "'undefined'");
182
+ entry.ruleHeds = ruleHeds;
183
+ }
184
+ else {
185
+ entry.ruleHeds = unavailable("ruleHeds", T("formRuleHed"), warnings);
186
+ }
187
+ // 字段规则明细
188
+ if (rulePxdids.length > 0 && (await tableExists(T("formRuleDet")))) {
189
+ const rs = await resolveSelect(T("formRuleDet"), [
190
+ "PXDID",
191
+ "FieldName",
192
+ "FieldDesc",
193
+ "bReadOnly",
194
+ "bShow",
195
+ "bRequired",
196
+ "bSearchField",
197
+ "cControlType",
198
+ "iWidth",
199
+ "SummaryType",
200
+ "cDataSource",
201
+ "DefaultValue",
202
+ ]);
203
+ const showCond = hasCol((await getTableInfo(T("formRuleDet"))).columns, "bShow")
204
+ ? " AND [bShow]=1"
205
+ : "";
206
+ entry.ruleDets = await tryQuery("get_form_full.ruleDets", `SELECT ${rs.select} FROM ${T("formRuleDet")} WHERE [PXDID] IN (${rulePxdids.join(",")})${showCond} ORDER BY [FieldName]`, warnings);
207
+ }
208
+ else {
209
+ entry.ruleDets = [];
210
+ }
211
+ // 按钮状态
212
+ entry.buttonStates = await queryModule("buttonStates", T("formState"), [
213
+ "FormID",
214
+ "ButtonText",
215
+ "AddState",
216
+ "UpdState",
217
+ "AuditState",
218
+ "ViewState",
219
+ "ConfirmState",
220
+ "ReCheckState",
221
+ "DisableState",
222
+ ], ` WHERE [FormID]='${fid}'`, warnings);
223
+ // 关联表定义 + 字段
224
+ if (linkTable) {
225
+ if (await tableExists(T("tableDef"))) {
226
+ const rs = await resolveSelect(T("tableDef"), [
227
+ "TableName",
228
+ "TableDesc",
229
+ "TableType",
230
+ "ParentTable",
231
+ "Modular1",
232
+ "Code",
233
+ "EnglishDesc",
234
+ ]);
235
+ const rows = await tryQuery("get_form_full.linkTable", `SELECT ${rs.select} FROM ${T("tableDef")} WHERE [TableName]='${linkTable.replace(/'/g, "''")}'`, warnings);
236
+ entry.linkTable = rows[0] ?? null;
237
+ }
238
+ else {
239
+ entry.linkTable = unavailable("linkTable", T("tableDef"), warnings);
240
+ }
241
+ if (await tableExists(T("fieldDef"))) {
242
+ const rs = await resolveSelect(T("fieldDef"), [
243
+ "TableName",
244
+ "FieldName",
245
+ "FieldDesc",
246
+ "FieldType",
247
+ "iPrecision",
248
+ "bAllowNull",
249
+ "bSearchField",
250
+ "cLinkTable",
251
+ "cLinkField",
252
+ "EnglishDesc",
253
+ ]);
254
+ const info = await getTableInfo(T("fieldDef"));
255
+ const ord = buildOrderBy(info.columns, ["iLineNo"]).orderBy;
256
+ entry.tableFields = await tryQuery("get_form_full.tableFields", `SELECT ${rs.select} FROM ${T("fieldDef")} WHERE [TableName]='${linkTable.replace(/'/g, "''")}'${ord}`, warnings);
257
+ }
258
+ else {
259
+ entry.tableFields = unavailable("tableFields", T("fieldDef"), warnings);
260
+ }
261
+ }
262
+ else {
263
+ entry.linkTable = null;
264
+ entry.tableFields = [];
265
+ }
266
+ // 同表关联窗体
267
+ entry.relatedForms = await tryQuery("get_form_full.relatedForms", `SELECT TOP 10 ${formSelect.select} FROM ${T("formDef")} WHERE [LinkTable]='${String(linkTable ?? "").replace(/'/g, "''")}' AND [FormID]!='${fid}'`, warnings);
268
+ }
269
+ // --- colors ---
270
+ if (has("colors")) {
271
+ entry.colors = await queryModule("colors", T("formRuleColor"), [
272
+ "FormID",
273
+ "TableName",
274
+ "XDBgColor",
275
+ "XDFgColor",
276
+ "ColorDesc",
277
+ "TempField",
278
+ ], ` WHERE [FormID]='${fid}'`, warnings);
279
+ }
280
+ // --- links ---
281
+ if (has("links")) {
282
+ entry.links = await queryModule("links", T("formRuleLink"), [
283
+ "FormID",
284
+ "TableName",
285
+ "ShowField",
286
+ "FieldName",
287
+ "LinkForm",
288
+ "LinkField",
289
+ "bDoubleClick",
290
+ ], ` WHERE [FormID]='${fid}'`, warnings);
291
+ }
292
+ // --- menus ---
293
+ if (has("menus")) {
294
+ entry.menus = await queryModule("menus", T("formRuleMenu"), [
295
+ "FormID",
296
+ "TableName",
297
+ "MenuName",
298
+ "FieldName",
299
+ "LinkForm",
300
+ "LinkField",
301
+ "bStop",
302
+ "cVisibleState",
303
+ "iFormWidth",
304
+ "iFormHeight",
305
+ "bDialog",
306
+ "ExCondition",
307
+ "Params",
308
+ ], ` WHERE [FormID]='${fid}'`, warnings, " ORDER BY [FormID], [iLineNo]");
309
+ }
310
+ // --- refers ---
311
+ if (has("refers")) {
312
+ if (!(await tableExists(T("formRuleReferHed")))) {
313
+ entry.refers = unavailable("refers", T("formRuleReferHed"), warnings);
314
+ }
315
+ else {
316
+ const rs = await resolveSelect(T("formRuleReferHed"), [
317
+ "XDID",
318
+ "PXDID",
319
+ "ReferFormName",
320
+ "ReferForm",
321
+ "Condition",
322
+ "Remark",
323
+ "iSort",
324
+ "iLineNo",
325
+ ]);
326
+ const refs = await tryQuery("get_form_full.refers", `SELECT TOP 20 ${rs.select} FROM ${T("formRuleReferHed")} WHERE [PXDID] IN (SELECT [XDID] FROM ${T("formRuleHed")} WHERE [FormID]='${fid}')`, warnings);
327
+ const refersResult = [];
328
+ for (const ref of refs) {
329
+ const r = ref;
330
+ const referId = String(r.XDID);
331
+ refersResult.push({
332
+ referInfo: r,
333
+ displayFields: await queryModule("refers.displayFields", T("formRuleRefer"), [
334
+ "PXDID",
335
+ "ValueField",
336
+ "Remark",
337
+ "bReferField",
338
+ "iSort",
339
+ "ValueTable",
340
+ "ReferForm",
341
+ "ReferTable",
342
+ "ReferValue",
343
+ "Condition",
344
+ ], ` WHERE [PXDID]='${referId}'`, warnings),
345
+ cases: await queryModule("refers.cases", T("formRuleReferCase"), [
346
+ "PXDID",
347
+ "CaseName",
348
+ "Condition",
349
+ "Remark",
350
+ "LinkFormName",
351
+ "Params",
352
+ ], ` WHERE [PXDID]='${referId}'`, warnings),
353
+ filters: await queryModule("refers.filters", T("formRuleReferFilter"), [
354
+ "PXDID",
355
+ "FieldName",
356
+ "CompareWay",
357
+ "FieldValue",
358
+ "Remark",
359
+ "Condition",
360
+ "FilterTable",
361
+ ], ` WHERE [PXDID]='${referId}'`, warnings),
362
+ });
363
+ }
364
+ entry.refers = { module: "refers", available: true, items: refersResult };
365
+ }
366
+ }
367
+ // --- buttons ---
368
+ if (has("buttons")) {
369
+ entry.buttons = await queryModule("buttons", T("formRuleButton"), [
370
+ "FormID",
371
+ "cPosition",
372
+ "ButtonCaption",
373
+ "XDID",
374
+ "Sort",
375
+ ], ` WHERE [FormID]='${fid}'`, warnings, " ORDER BY [FormID], [cPosition], [Sort]");
376
+ }
377
+ // --- datasource ---
378
+ if (has("datasource")) {
379
+ entry.dataSources = await queryModule("datasource", T("formRuleDataSource"), [
380
+ "ID",
381
+ "Code",
382
+ "Name",
383
+ "ServiceType",
384
+ "AssemblyName",
385
+ "DataSourceXDID",
386
+ "BillNoField",
387
+ ], "", warnings, " ORDER BY [Code]");
388
+ }
389
+ // --- sqlReplaces ---
390
+ if (has("sqlReplaces")) {
391
+ entry.sqlReplaces = await queryModule("sqlReplaces", T("formRuleSQLReplace"), [
392
+ "FormID",
393
+ "cAction",
394
+ "OldSQL",
395
+ "NewSQL",
396
+ "Sort",
397
+ ], ` WHERE [FormID]='${fid}'`, warnings, " ORDER BY [FormID], [Sort]");
398
+ }
399
+ // --- dataflows ---
400
+ if (has("dataflows")) {
401
+ entry.dataflows = await queryModule("dataflows", T("formRuleDataFlow"), ["FormID", "FlowName", "FlowNo", "bCreated", "bStop", "ShowFilter"], ` WHERE [FormID]='${fid}'`, warnings);
402
+ }
403
+ result.push(entry);
404
+ }
405
+ // 紧凑清单:字段名并集 + 各窗体模块计数(截断后仍可读;safeJson 保留 fieldNames/summary)
406
+ const fieldNameSet = new Set();
407
+ for (const entry of result) {
408
+ const tf = entry.tableFields;
409
+ if (Array.isArray(tf)) {
410
+ for (const f of tf) {
411
+ if (f && f.FieldName)
412
+ fieldNameSet.add(String(f.FieldName));
413
+ }
414
+ }
415
+ }
416
+ const fieldNames = [...fieldNameSet].slice(0, 500);
417
+ const summary = result.map((entry) => {
418
+ const form = entry.form;
419
+ const modules = {};
420
+ for (const [k, v] of Object.entries(entry)) {
421
+ if (Array.isArray(v))
422
+ modules[k] = v.length;
423
+ else if (v &&
424
+ typeof v === "object" &&
425
+ Array.isArray(v.items)) {
426
+ modules[k] = v.items.length;
427
+ }
428
+ }
429
+ return {
430
+ formId: form?.FormID ?? null,
431
+ formName: form?.FormName ?? null,
432
+ modules,
433
+ };
434
+ });
435
+ return ok(envelope({
436
+ items: result,
437
+ pagination,
438
+ warnings,
439
+ query: { formId, formName, tableName, formType, include },
440
+ moduleStatus: mods.includes("all")
441
+ ? "all"
442
+ : mods.filter((m) => m !== "all"),
443
+ fieldNames,
444
+ summary,
445
+ }));
446
+ });
447
+ // ============================================================
448
+ // get_form(窗体存在性 — 只查 FormSetTB)
449
+ // ============================================================
450
+ server.registerTool("get_form", {
451
+ description: WARNING +
452
+ "\n\n【窗体存在性】只查询 FormSetTB 一行,永不因其它子表缺失而失败。用于把「中文窗体名 → FormID」变成正式能力。数据来源: XDWmsCommon.dbo.FormSetTB",
453
+ inputSchema: {
454
+ formId: z.string().max(128).optional().describe("窗体ID,如 FrmOutMoveEdit"),
455
+ formName: z.string().max(200).optional().describe("窗体名称关键词"),
456
+ },
457
+ }, async ({ formId, formName }) => {
458
+ const warnings = [];
459
+ if (!formId && !formName) {
460
+ return ok(envelope({
461
+ items: [],
462
+ pagination: null,
463
+ warnings: [
464
+ {
465
+ module: "get_form",
466
+ message: "请至少提供 formId 或 formName",
467
+ },
468
+ ],
469
+ }));
470
+ }
471
+ const info = await getTableInfo(T("formDef"));
472
+ if (!info.exists) {
473
+ return ok(envelope({
474
+ items: [],
475
+ pagination: null,
476
+ warnings: [
477
+ {
478
+ module: "get_form",
479
+ message: `环境库缺少 ${T("formDef")}`,
480
+ hint: "可用 get_capabilities 查看本环境支持的元数据表",
481
+ fallback: "get_capabilities",
482
+ },
483
+ ],
484
+ }));
485
+ }
486
+ const rs = await resolveSelect(T("formDef"), [
487
+ "FormID",
488
+ "FormName",
489
+ "LinkTable",
490
+ "FormType",
491
+ "ApiPath",
492
+ "ServiceType",
493
+ ]);
494
+ const groups = [];
495
+ if (formId)
496
+ groups.push({
497
+ filters: [
498
+ {
499
+ col: "FormID",
500
+ op: "eq",
501
+ value: formId.replace(/[^a-zA-Z0-9_]/g, ""),
502
+ },
503
+ ],
504
+ });
505
+ if (formName)
506
+ groups.push({
507
+ filters: [{ col: "FormName", op: "like", value: formName }],
508
+ });
509
+ const { where, skipped } = buildWhere(info.columns, groups);
510
+ if (skipped.length > 0) {
511
+ warnings.push({
512
+ module: "get_form",
513
+ message: `以下列在本环境库不存在,条件已跳过: ${skipped.join(", ")}`,
514
+ });
515
+ }
516
+ const items = await tryQuery("get_form", `SELECT TOP 50 ${rs.select} FROM ${T("formDef")}${where} ORDER BY [FormID]`, warnings);
517
+ if (items.length === 0 && warnings.length === 0) {
518
+ warnings.push({
519
+ module: "get_form",
520
+ message: "未匹配到窗体(FormSetTB 中无该 FormID/名称)",
521
+ hint: "可用 list_forms(keyword=...) 做模糊定位",
522
+ });
523
+ }
524
+ return ok(envelope({
525
+ items,
526
+ pagination: topNPagination(50, items.length),
527
+ warnings,
528
+ }));
529
+ });
530
+ // ============================================================
531
+ // list_forms(窗体清单 — 定位 FormID 的标准入口)
532
+ // ============================================================
533
+ server.registerTool("list_forms", {
534
+ description: WARNING +
535
+ "\n\n列出环境库已登记窗体(FormID/FormName/LinkTable/FormType)。支持按中文名/表名/窗体类型过滤,SQL 端真实分页。定位 XDFormID 的标准入口。数据来源: XDWmsCommon.dbo.FormSetTB",
536
+ inputSchema: {
537
+ keyword: z.string().max(200).optional().describe("窗体名/FormID 关键词"),
538
+ formType: z
539
+ .string()
540
+ .max(50)
541
+ .optional()
542
+ .describe("按 FormType 过滤,如 List/Edit/View"),
543
+ tableName: z.string().max(128).optional().describe("按关联表名过滤"),
544
+ page: z.number().int().min(1).default(1).describe("页码"),
545
+ pageSize: z
546
+ .number()
547
+ .int()
548
+ .min(1)
549
+ .max(200)
550
+ .default(50)
551
+ .describe("每页数量"),
552
+ },
553
+ }, async ({ keyword, formType, tableName, page = 1, pageSize = 50 }) => {
554
+ const warnings = [];
555
+ const info = await getTableInfo(T("formDef"));
556
+ if (!info.exists) {
557
+ return ok(envelope({
558
+ items: [],
559
+ pagination: sqlPagination(page, pageSize, 0),
560
+ warnings: [
561
+ {
562
+ module: "list_forms",
563
+ message: `环境库缺少 ${T("formDef")}`,
564
+ hint: "可用 get_capabilities 查看本环境支持的元数据表",
565
+ fallback: "get_capabilities",
566
+ },
567
+ ],
568
+ }));
569
+ }
570
+ const rs = await resolveSelect(T("formDef"), [
571
+ "FormID",
572
+ "FormName",
573
+ "LinkTable",
574
+ "FormType",
575
+ ]);
576
+ const groups = [];
577
+ if (keyword) {
578
+ const filters = ["FormID", "FormName"]
579
+ .filter((c) => hasCol(info.columns, c))
580
+ .map((c) => ({ col: c, op: "like", value: keyword }));
581
+ if (filters.length > 0)
582
+ groups.push({ logic: "or", filters });
583
+ }
584
+ if (formType)
585
+ groups.push({ filters: [{ col: "FormType", op: "eq", value: formType }] });
586
+ if (tableName)
587
+ groups.push({ filters: [{ col: "LinkTable", op: "eq", value: tableName }] });
588
+ const { where, skipped } = buildWhere(info.columns, groups);
589
+ if (skipped.length > 0) {
590
+ warnings.push({
591
+ module: "list_forms",
592
+ message: `以下列在本环境库不存在,条件已跳过: ${skipped.join(", ")}`,
593
+ });
594
+ }
595
+ const order = buildOrderBy(info.columns, ["FormID"]);
596
+ const q = buildPagedQuery({
597
+ table: T("formDef"),
598
+ cols: rs.present.length > 0 ? rs.present.map((c) => `[${c}]`) : ["[FormID]"],
599
+ where,
600
+ orderBy: order.orderBy,
601
+ page,
602
+ pageSize,
603
+ });
604
+ const cnt = await tryQuery("list_forms.count", q.countSql, warnings);
605
+ const total = Number(cnt[0]?.Total ?? 0);
606
+ const items = total > 0 ? await tryQuery("list_forms", q.sql, warnings) : [];
607
+ return ok(envelope({
608
+ items,
609
+ pagination: sqlPagination(page, pageSize, total),
610
+ warnings,
611
+ }));
612
+ });
613
+ // ============================================================
614
+ // get_user_form_schemes
615
+ // ============================================================
616
+ server.registerTool("get_user_form_schemes", {
617
+ description: WARNING +
618
+ "\n\n查询用户的个性化窗体方案。用户可自定义字段显示、列宽、冻结列等。数据来源: XDWmsCommon.dbo.UserFormSetHedTB + UserFormSetDetTB",
619
+ inputSchema: {
620
+ formId: z.string().max(128).optional().describe("窗体ID"),
621
+ userId: z.string().max(50).optional().describe("用户ID"),
622
+ schemeName: z.string().max(200).optional().describe("方案名称"),
623
+ page: z.number().int().min(1).default(1).describe("页码"),
624
+ pageSize: z
625
+ .number()
626
+ .int()
627
+ .min(1)
628
+ .max(200)
629
+ .default(50)
630
+ .describe("每页数量"),
631
+ },
632
+ }, async ({ formId, userId, schemeName, page = 1, pageSize = 50 }) => {
633
+ const warnings = [];
634
+ if (!(await tableExists(T("userFormHed")))) {
635
+ return ok(envelope({
636
+ items: [],
637
+ pagination: sqlPagination(page, pageSize, 0),
638
+ warnings: [
639
+ {
640
+ module: "get_user_form_schemes",
641
+ message: `环境库缺少 ${T("userFormHed")}`,
642
+ hint: "可用 get_capabilities 查看本环境支持的元数据表",
643
+ fallback: "get_capabilities",
644
+ },
645
+ ],
646
+ }));
647
+ }
648
+ const info = await getTableInfo(T("userFormHed"));
649
+ const rs = await resolveSelect(T("userFormHed"), [
650
+ "XDID",
651
+ "FormId",
652
+ "UserId",
653
+ "TableName",
654
+ "Remark",
655
+ "MakeDate",
656
+ "EditDate",
657
+ ]);
658
+ const groups = [];
659
+ if (formId)
660
+ groups.push({ filters: [{ col: "FormId", op: "eq", value: formId }] });
661
+ if (userId)
662
+ groups.push({ filters: [{ col: "UserId", op: "eq", value: userId }] });
663
+ if (schemeName)
664
+ groups.push({
665
+ filters: [{ col: "TableName", op: "like", value: schemeName }],
666
+ });
667
+ const { where, skipped } = buildWhere(info.columns, groups);
668
+ if (skipped.length > 0) {
669
+ warnings.push({
670
+ module: "get_user_form_schemes",
671
+ message: `以下列在本环境库不存在,条件已跳过: ${skipped.join(", ")}`,
672
+ });
673
+ }
674
+ const order = buildOrderBy(info.columns, [
675
+ "FormId",
676
+ { col: "EditDate", expr: "[EditDate] DESC" },
677
+ ]);
678
+ const q = buildPagedQuery({
679
+ table: T("userFormHed"),
680
+ cols: rs.present.length > 0 ? rs.present.map((c) => `[${c}]`) : ["[XDID]"],
681
+ where,
682
+ orderBy: order.orderBy,
683
+ page,
684
+ pageSize,
685
+ });
686
+ const cnt = await tryQuery("get_user_form_schemes.count", q.countSql, warnings);
687
+ const total = Number(cnt[0]?.Total ?? 0);
688
+ const schemes = total > 0
689
+ ? (await tryQuery("get_user_form_schemes", q.sql, warnings))
690
+ : [];
691
+ // 明细:逐方案查询(表缺失时降级)
692
+ const result = [];
693
+ for (const s of schemes) {
694
+ const schemeId = String(s.XDID ?? "");
695
+ result.push({
696
+ scheme: s,
697
+ fieldConfigs: await queryModule("get_user_form_schemes.detail", T("userFormDet"), [
698
+ "PXDID",
699
+ "FiledName",
700
+ "Remark",
701
+ "IsShow",
702
+ "Width",
703
+ "Index",
704
+ "SummaryType",
705
+ ], ` WHERE [PXDID]='${schemeId.replace(/'/g, "''")}'`, warnings, " ORDER BY [Index]"),
706
+ });
707
+ }
708
+ return ok(envelope({
709
+ items: result,
710
+ pagination: sqlPagination(page, pageSize, total),
711
+ warnings,
712
+ }));
713
+ });
714
+ }
715
+ //# sourceMappingURL=form-tools.js.map