@agile-team/mach-report 2.8.3 → 2.9.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.
Files changed (95) hide show
  1. package/README.md +28 -10
  2. package/dist/ExcelBindingWizard-DiaxvWpQ.cjs +1 -0
  3. package/dist/ExcelBindingWizard-RLJIXKKG.js +816 -0
  4. package/dist/{ReportPreview-DRBAUkxj.js → ReportPreview-B5ZNEasW.js} +23 -22
  5. package/dist/ReportPreview-DRtVPUYo.cjs +6 -0
  6. package/dist/RuleEditor-N4qnMZ-Z.cjs +1 -0
  7. package/dist/RuleEditor-ynnUEK0s.js +1575 -0
  8. package/dist/TemplateReviewPanel-C_Lmzis6.cjs +1 -0
  9. package/dist/TemplateReviewPanel-Cn32OY4_.js +173 -0
  10. package/dist/{_plugin-vue_export-helper-DPbiz14D.js → _plugin-vue_export-helper-8SL1F89S.js} +2 -2
  11. package/dist/analytics.cjs +1 -1
  12. package/dist/analytics.d.cts +188 -5
  13. package/dist/analytics.d.ts +188 -5
  14. package/dist/analytics.js +68 -202
  15. package/dist/{assets-B9qJku3V.js → assets-DDsfEi8R.js} +3 -3
  16. package/dist/{assets-RZan7EyL.cjs → assets-ahTRUXRk.cjs} +1 -1
  17. package/dist/binding-preview-B5834rml.cjs +2 -0
  18. package/dist/binding-preview-ChXjN5L5.js +649 -0
  19. package/dist/{capabilities-joSutDF8.js → capabilities-Cm9hZ3uV.js} +5 -5
  20. package/dist/{capabilities-xGTpnPjJ.cjs → capabilities-DYzWL7KS.cjs} +1 -1
  21. package/dist/dataset-BkRmwgeJ.cjs +1 -0
  22. package/dist/dataset-H5pFuQGU.js +121 -0
  23. package/dist/defaults-DXhiM1ZD.js +10 -0
  24. package/dist/defaults-xhmcLLrf.cjs +1 -0
  25. package/dist/designer.cjs +2 -1
  26. package/dist/designer.d.cts +1391 -6
  27. package/dist/designer.d.ts +1391 -6
  28. package/dist/designer.js +2636 -673
  29. package/dist/grid-geometry-BNptEcMm.js +65 -0
  30. package/dist/grid-geometry-CZ_cYB6O.cjs +1 -0
  31. package/dist/import-template-CNMLJSQw.js +23030 -0
  32. package/dist/import-template-CpxunKVp.cjs +29 -0
  33. package/dist/index.cjs +7 -7
  34. package/dist/index.d.cts +202 -3
  35. package/dist/index.d.ts +202 -3
  36. package/dist/index.js +554 -535
  37. package/dist/matrix-CNPDJxED.js +745 -0
  38. package/dist/matrix-Div9Ilh3.cjs +1 -0
  39. package/dist/pdf.cjs +46 -46
  40. package/dist/pdf.d.cts +2 -0
  41. package/dist/pdf.d.ts +2 -0
  42. package/dist/pdf.js +17 -16
  43. package/dist/{plugin-BurDDMcd.js → plugin-BWwIgZXV.js} +1 -1
  44. package/dist/{plugin-DSFu51Ua.cjs → plugin-Dg-J1Rbm.cjs} +1 -1
  45. package/dist/progress-7OSZbFok.js +39 -0
  46. package/dist/progress-BnLiS5eH.cjs +1 -0
  47. package/dist/render-plan-7xpGrCEl.cjs +1 -0
  48. package/dist/render-plan-Ck6koX9L.js +13 -0
  49. package/dist/server/node.d.cts +62 -0
  50. package/dist/server/node.d.ts +62 -0
  51. package/dist/server-node.cjs +1 -1
  52. package/dist/server-node.js +373 -145
  53. package/dist/server.cjs +1 -1
  54. package/dist/server.d.cts +311 -0
  55. package/dist/server.d.ts +311 -0
  56. package/dist/server.js +590 -186
  57. package/dist/{style-Dv5o_x6b.js → style-CQ1PK8ZB.js} +5 -5
  58. package/dist/style-UgIJSA1F.cjs +1 -0
  59. package/dist/style.css +1 -1
  60. package/dist/template-registry-CHMYZ7SD.cjs +1 -0
  61. package/dist/template-registry-R61AMCr0.js +433 -0
  62. package/dist/template-review-hvWWQFsi.js +1027 -0
  63. package/dist/template-review-jEcOfmGr.cjs +1 -0
  64. package/dist/textwrap-CWHyzkBH.cjs +4 -0
  65. package/dist/{textwrap-DOl04hCQ.js → textwrap-DE1kgcJB.js} +1 -1
  66. package/dist/{validate-DfHPD8wX.cjs → validate-BDiMqkJC.cjs} +1 -1
  67. package/dist/{validate-S6CgIm5d.js → validate-DWPF7icl.js} +13 -13
  68. package/dist/vue/async.d.cts +186 -0
  69. package/dist/vue/async.d.ts +186 -0
  70. package/dist/vue/index.d.cts +271 -3
  71. package/dist/vue/index.d.ts +271 -3
  72. package/dist/vue-async.cjs +1 -1
  73. package/dist/vue-async.js +3 -3
  74. package/dist/vue.cjs +1 -1
  75. package/dist/vue.js +4 -4
  76. package/dist/worker.cjs +1 -1
  77. package/dist/worker.d.cts +2 -0
  78. package/dist/worker.d.ts +2 -0
  79. package/dist/worker.js +1 -1
  80. package/dist/xlsx.cjs +2 -30
  81. package/dist/xlsx.d.cts +268 -0
  82. package/dist/xlsx.d.ts +268 -0
  83. package/dist/xlsx.js +220 -23440
  84. package/package.json +1 -1
  85. package/dist/ReportPreview-DjGeWHY-.cjs +0 -6
  86. package/dist/progress-DD964VAB.js +0 -102
  87. package/dist/progress-KvhwXZ1Q.cjs +0 -1
  88. package/dist/render-plan-CckPEQyf.cjs +0 -1
  89. package/dist/render-plan-uzZYYSy1.js +0 -19
  90. package/dist/report-source-BXHNy_AD.js +0 -755
  91. package/dist/report-source-CCAvFE3t.cjs +0 -1
  92. package/dist/style-CpwiOPyB.cjs +0 -1
  93. package/dist/template-registry-DWExx0gU.cjs +0 -1
  94. package/dist/template-registry-NpOakidD.js +0 -354
  95. package/dist/textwrap-CnGsEum6.cjs +0 -4
package/dist/index.d.ts CHANGED
@@ -1,3 +1,15 @@
1
+ declare interface AggregateDefinition {
2
+ /** Output column; valueField defaults to this field. */
3
+ field: string;
4
+ op: AggregateOperation;
5
+ valueField?: string;
6
+ weightField?: string;
7
+ numeric?: "number" | "decimal";
8
+ digits?: number;
9
+ }
10
+
11
+ declare type AggregateOperation = "sum" | "count" | "avg" | "min" | "max" | "weightedAvg";
12
+
1
13
  /** 复制发生变化的页/组件/行;原计划保持不变,并拒绝覆盖已改变的单元格。 */
2
14
  export declare function applyReportCellEdit(plan: RenderPlan, edit: ReportCellEdit): RenderPlan;
3
15
 
@@ -158,9 +170,22 @@ export declare interface ComponentStyle {
158
170
  rotateDeg?: number;
159
171
  }
160
172
 
173
+ declare interface ComputedField extends ExpressionOptions {
174
+ field: string;
175
+ expression: ReportExpression | string;
176
+ /** Scope controls aggregate inputs; row expressions may reference the current row in any scope. */
177
+ scope?: "row" | "group" | "dataset";
178
+ groupBy?: readonly string[];
179
+ /** String adapter expressions cannot be inspected; declare dependencies explicitly. */
180
+ dependsOn?: readonly string[];
181
+ }
182
+
161
183
  /** 页级视口虚拟化;单次计算入口保留兼容,预览内部复用已建立的几何索引。 */
162
184
  export declare function computePageWindow(input: PageWindowInput): PageWindow;
163
185
 
186
+ /** Counting pass does not keep page grids, components or a RenderPlan alive. */
187
+ export declare function countTemplatePages(template: ReportTemplate, datasets: DatasetRows, options?: PaginateOptions): number;
188
+
164
189
  /**
165
190
  * 浏览器 Canvas 测量器:用真实字体 metrics 校准宽度(可选注入)。
166
191
  * 无 2D 环境时自动回退启发式(Node/SSR 安全)。
@@ -204,6 +229,7 @@ export declare function createReportSource(reports: ReportRegistry, options?: {
204
229
  onWarning?: (message: string) => void;
205
230
  onDatasets?: (reportId: string, datasets: DatasetRows, template: ReportTemplate) => void;
206
231
  maxPages?: number;
232
+ maxCells?: number;
207
233
  }): ReportSource;
208
234
 
209
235
  /**
@@ -218,6 +244,12 @@ export declare function createTemplate(): TemplateBuilder;
218
244
  export declare function createTemplateManager(store: ReportTemplateStore, options?: {
219
245
  migrate?: (input: unknown) => unknown | Promise<unknown>;
220
246
  now?: () => Date;
247
+ /** Optional publication gate; receives explicit draft snapshots and never replaces CAS. */
248
+ beforePublish?: (context: {
249
+ document: ReportTemplateDocument;
250
+ previous?: ReportTemplateDocument;
251
+ signal?: AbortSignal;
252
+ }) => ReportTemplateReview | Promise<ReportTemplateReview>;
221
253
  }): ReportTemplateManager;
222
254
 
223
255
  /** 存储无关的模板目录;后台 CRUD、权限、发布审批与持久化由宿主接入。 */
@@ -275,6 +307,14 @@ export declare function defineReportTemplate(document: Omit<ReportTemplateDocume
275
307
  schemaVersion?: typeof REPORT_TEMPLATE_DOCUMENT_VERSION;
276
308
  }): ReportTemplateDocument;
277
309
 
310
+ /** Semantic column identities keep a reorder distinct from deleting or rebinding a field. */
311
+ export declare function diffReportTemplates(previous: ReportTemplateDocument, next: ReportTemplateDocument, options?: {
312
+ maxChanges?: number;
313
+ }): ReportTemplateDiff;
314
+
315
+ /** Conservative cell allocation estimate; relation validation rejects duplicate master keys before rendering. */
316
+ export declare function estimateListLayoutCells(list: ListComponent, datasets: DatasetRows, options?: Pick<PaginateOptions, "formula" | "signal">): number;
317
+
278
318
  /**
279
319
  * 规则求值语义:
280
320
  * - 空值(null/undefined/"")永不命中(避免 Number("")===0 把空当 0 的隐式陷阱)
@@ -285,6 +325,13 @@ export declare function evalStyleRule(row: Record<string, unknown>, when: StyleR
285
325
  /** A tiny arithmetic parser: no functions, property access, globals, assignments or executable source. */
286
326
  export declare function evaluateReportAggregateExpression(expression: string, values: Readonly<Record<string, number>>): number;
287
327
 
328
+ declare interface ExpressionOptions {
329
+ numeric?: "number" | "decimal";
330
+ digits?: number;
331
+ nulls?: "propagate" | "error";
332
+ divisionByZero?: "null" | "error";
333
+ }
334
+
288
335
  /** 同步 text/raw value,所有输出后端读取同一份更新后的 RenderPlan。 */
289
336
  export declare function formatReportCellEdit(context: ReportCellContext, value: ReportCellValue): string;
290
337
 
@@ -299,6 +346,15 @@ export declare function formatReportClipboard(rows: readonly (readonly string[])
299
346
  */
300
347
  export declare function formatValue(value: unknown, format?: ColumnFormat): string;
301
348
 
349
+ declare interface FormulaAdapter {
350
+ /** Explicit trusted engine; core never evaluates source code/macros/external workbook references. */
351
+ evaluate(expression: string, context: {
352
+ row: Readonly<Record<string, unknown>>;
353
+ rowIndex: number;
354
+ rows: readonly Record<string, unknown>[];
355
+ }): unknown;
356
+ }
357
+
302
358
  declare type Geometry = Partial<Pick<PlanComponent, "leftMm" | "topMm" | "widthMm" | "heightMm">>;
303
359
 
304
360
  export declare function getReportCellContext(plan: RenderPlan, address: ReportCellAddress): ReportCellContext | null;
@@ -408,6 +464,9 @@ export declare interface ListColumn {
408
464
  valueType?: GridCell["valueType"];
409
465
  /** 字段语义用于 auto 对齐;明确声明编号,避免把数字编号当成度量。 */
410
466
  semanticRole?: "identifier" | "dimension" | "measure" | "date" | "text";
467
+ hidden?: boolean;
468
+ /** Condition hides cell content, preserving its physical layout in preview and exports. */
469
+ visibleWhen?: StyleRule["when"];
411
470
  }
412
471
 
413
472
  export declare interface ListComponent {
@@ -442,15 +501,38 @@ export declare interface ListComponent {
442
501
  border?: boolean;
443
502
  /** 分组小计(组头/组尾小计/组头防孤行) */
444
503
  groupBy?: ListGroupBy;
504
+ /** Ordered outer-to-inner grouping; groupBy remains the single-level shorthand. */
505
+ groups?: ListGroupBy[];
506
+ computed?: ComputedField[];
507
+ /** Dynamic pivot of the current source dataset, with read-only derived identities. */
508
+ matrix?: MatrixTableOptions;
509
+ /** Explicit row visibility; hidden rows do not participate in summaries. */
510
+ rowVisibleWhen?: StyleRule["when"];
511
+ /** Master/detail relation is keyed by business identity, never by display row index. */
512
+ detail?: ListDetail;
445
513
  /** 末尾总合计行(依赖 groupBy.subtotal 或显式 fields) */
446
514
  grandTotal?: ListGrandTotal;
447
515
  }
448
516
 
517
+ export declare interface ListDetail {
518
+ dataset: string;
519
+ parentKey: string;
520
+ foreignKey: string;
521
+ rowKey?: string;
522
+ columns: ListColumn[];
523
+ rowHeightMm?: number;
524
+ header?: boolean;
525
+ label?: string;
526
+ /** Unmatched children fail by default; opt-in ignore is explicit. */
527
+ unmatched?: "error" | "ignore";
528
+ }
529
+
449
530
  export declare type ListGrandTotal = boolean | {
450
531
  label?: string;
451
532
  style?: ComponentStyle;
452
533
  /** 合计列(缺省沿用 groupBy.subtotal) */
453
534
  fields?: string[];
535
+ aggregates?: AggregateDefinition[];
454
536
  };
455
537
 
456
538
  /** 分组小计配置(声明式,见 ListComponent.groupBy) */
@@ -466,6 +548,25 @@ export declare interface ListGroupBy {
466
548
  subtotalLabel?: string;
467
549
  /** 组头防孤行(默认 true:页尾放不下"组头+首行"时整体换页) */
468
550
  keepWithNext?: boolean;
551
+ aggregates?: AggregateDefinition[];
552
+ /** Repeat this group heading after page breaks within the group. */
553
+ repeatHeader?: boolean;
554
+ }
555
+
556
+ declare interface MatrixTableOptions {
557
+ rowFields: readonly string[];
558
+ columnFields: readonly string[];
559
+ measures: readonly (AggregateDefinition & {
560
+ label?: string;
561
+ })[];
562
+ totals?: boolean;
563
+ rowHeader?: string;
564
+ columnWidthMm?: number;
565
+ rowWidthMm?: number;
566
+ maxRows?: number;
567
+ maxColumns?: number;
568
+ maxInputRows?: number;
569
+ maxCells?: number;
469
570
  }
470
571
 
471
572
  export declare function measurePageSizePx(page: Pick<PlanPage, "pageWidthMm" | "pageHeightMm">, dpi?: number): {
@@ -564,6 +665,13 @@ export declare interface PageWindowInput {
564
665
  gapPx?: number;
565
666
  }
566
667
 
668
+ export declare class PaginateCellLimitError extends Error {
669
+ readonly limit: number;
670
+ readonly actual: number;
671
+ readonly code = "cell-limit";
672
+ constructor(limit: number, actual: number);
673
+ }
674
+
567
675
  export declare interface PaginateOptions {
568
676
  /** 每行额外占高(mm),压测专用钩子 */
569
677
  mmPerRow?: number;
@@ -571,6 +679,14 @@ export declare interface PaginateOptions {
571
679
  measurer?: TextMeasurer;
572
680
  /** 可选页数上限;在追加超限页前终止,避免先分配全部页面再检查。 */
573
681
  maxPages?: number;
682
+ /** Actual grid cells, including repeated furniture and nested children; checked before each page is appended. */
683
+ maxCells?: number;
684
+ signal?: AbortSignal;
685
+ /** Streaming total-page anchors can skip the bounded counting pass when known. */
686
+ knownTotalPages?: number;
687
+ onWarning?: (warning: string) => void;
688
+ /** Trusted formula adapter is passed at execution time; it is never serialized in templates. */
689
+ formula?: FormulaAdapter;
574
690
  }
575
691
 
576
692
  export declare class PaginatePageLimitError extends Error {
@@ -585,9 +701,12 @@ export declare interface PaginateResult {
585
701
  warnings: string[];
586
702
  }
587
703
 
588
- /** 模板遍历只编排静态组件和列表;行测量、分组、换页与汇总各自独立。 */
704
+ /** Compatibility collector: the pagination engine is shared with the bounded page iterator. */
589
705
  export declare function paginateTemplate(template: ReportTemplate, datasets: DatasetRows, optionsOrMmPerRow?: number | PaginateOptions): PaginateResult;
590
706
 
707
+ /** Genuine page-level layout. With total-page anchors, use knownTotalPages or a bounded counting pass. */
708
+ export declare function paginateTemplatePages(template: ReportTemplate, datasets: DatasetRows, options?: PaginateOptions): Generator<PlanPage>;
709
+
591
710
  export declare const PAPER_SIZES: Record<string, {
592
711
  widthMm: number;
593
712
  heightMm: number;
@@ -612,6 +731,8 @@ export declare function parseReportClipboard(text: string, maxCells?: number): s
612
731
  export declare function parseReportTemplate(input: unknown): ReportTemplateDocument;
613
732
 
614
733
  export declare interface PlanComponent {
734
+ /** Template page furniture repeats per page and reserves its vertical band. */
735
+ pageAnchor?: "header" | "footer";
615
736
  kind: ComponentKind;
616
737
  leftMm: number;
617
738
  topMm: number;
@@ -679,6 +800,9 @@ export declare interface PlanTableFragment {
679
800
  };
680
801
  }
681
802
 
803
+ /** Hides physical columns and projects merged headers using the same geometry in every output. */
804
+ export declare function projectListColumns(list: ListComponent): ListComponent;
805
+
682
806
  export declare function ptToPx(pt: number, dpi?: number): number;
683
807
 
684
808
  export declare function pxToMm(value: number, dpi?: number): number;
@@ -899,6 +1023,19 @@ export declare interface ReportEditResult {
899
1023
  conflicts?: readonly ReportEditConflict[];
900
1024
  }
901
1025
 
1026
+ declare type ReportExpression = {
1027
+ field: string;
1028
+ } | {
1029
+ value: string | number | boolean | null;
1030
+ } | {
1031
+ aggregate: AggregateOperation;
1032
+ field?: string;
1033
+ weightField?: string;
1034
+ } | {
1035
+ op: "add" | "subtract" | "multiply" | "divide" | "coalesce";
1036
+ args: readonly ReportExpression[];
1037
+ };
1038
+
902
1039
  /** 保持 Promise<RenderPlan> 契约;元数据为可选,旧业务 fetcher 无需改造。 */
903
1040
  export declare interface ReportFetcher {
904
1041
  (input: ReportFetchInput): Promise<RenderPlan>;
@@ -1092,6 +1229,22 @@ export declare interface ReportTemplate {
1092
1229
  pages: TemplatePage[];
1093
1230
  }
1094
1231
 
1232
+ export declare interface ReportTemplateChange {
1233
+ kind: "added" | "removed" | "modified" | "moved";
1234
+ category: "metadata" | "structure" | "binding" | "calculation" | "format";
1235
+ path: string;
1236
+ before?: string;
1237
+ after?: string;
1238
+ breaking: boolean;
1239
+ }
1240
+
1241
+ export declare interface ReportTemplateDiff {
1242
+ changes: ReportTemplateChange[];
1243
+ totalChanges: number;
1244
+ truncated: boolean;
1245
+ breakingChanges: number;
1246
+ }
1247
+
1095
1248
  /** 可存入数据库/文件的纯 JSON 模板;数据、接口与鉴权仍由宿主提供。 */
1096
1249
  export declare interface ReportTemplateDocument {
1097
1250
  schemaVersion: "1.0";
@@ -1108,6 +1261,12 @@ export declare class ReportTemplateError extends Error {
1108
1261
  constructor(errors: readonly ValidationError[]);
1109
1262
  }
1110
1263
 
1264
+ export declare interface ReportTemplateFixture {
1265
+ name: string;
1266
+ datasets: DatasetRows;
1267
+ params?: Record<string, string>;
1268
+ }
1269
+
1111
1270
  export declare type ReportTemplateLoader = (context: ReportLoadContext) => ReportTemplate | Promise<ReportTemplate>;
1112
1271
 
1113
1272
  export declare interface ReportTemplateManager {
@@ -1150,6 +1309,41 @@ export declare interface ReportTemplateRegistry {
1150
1309
  remove(id: string): boolean;
1151
1310
  }
1152
1311
 
1312
+ export declare interface ReportTemplateReview {
1313
+ ok: boolean;
1314
+ changes?: ReportTemplateDiff;
1315
+ issues: ReportTemplateReviewIssue[];
1316
+ samples: Array<{
1317
+ name: string;
1318
+ pages: number;
1319
+ rows: number;
1320
+ diagnostics: OutputDiagnostic[];
1321
+ }>;
1322
+ }
1323
+
1324
+ export declare interface ReportTemplateReviewIssue {
1325
+ code: "template" | "compatibility" | "dataset" | "field" | "sample" | "layout" | "output";
1326
+ severity: "error" | "warning";
1327
+ path: string;
1328
+ message: string;
1329
+ fixture?: string;
1330
+ pageIndex?: number;
1331
+ componentIndex?: number;
1332
+ field?: string;
1333
+ }
1334
+
1335
+ export declare interface ReportTemplateReviewOptions {
1336
+ previous?: ReportTemplateDocument;
1337
+ dataSchemas?: Readonly<Record<string, DatasetContract>>;
1338
+ fixtures?: readonly ReportTemplateFixture[];
1339
+ formats?: readonly OutputFormat[];
1340
+ maxPages?: number;
1341
+ maxCells?: number;
1342
+ maxSampleRows?: number;
1343
+ allowBreakingChanges?: boolean;
1344
+ strictOutputs?: boolean;
1345
+ }
1346
+
1153
1347
  /** compareAndSwap 必须由宿主数据库/文件适配器保证原子性,不能用先读再无条件写替代。 */
1154
1348
  export declare interface ReportTemplateStore {
1155
1349
  read(id: string, signal?: AbortSignal): Promise<ReportTemplateRecord | undefined>;
@@ -1165,8 +1359,8 @@ export declare interface ReportTemplateStore {
1165
1359
  }
1166
1360
 
1167
1361
  export declare class ReportTemplateStoreError extends Error {
1168
- readonly code: "conflict" | "missing" | "draft" | "history";
1169
- constructor(code: "conflict" | "missing" | "draft" | "history", message: string);
1362
+ readonly code: "conflict" | "missing" | "draft" | "history" | "review";
1363
+ constructor(code: "conflict" | "missing" | "draft" | "history" | "review", message: string);
1170
1364
  }
1171
1365
 
1172
1366
  export declare type ReportTemplateSummary = Omit<ReportTemplateDocument, "template">;
@@ -1240,6 +1434,9 @@ export declare function resolveStroke(style: Pick<ComponentStyle, "borderColor"
1240
1434
  /** 文本颜色解析 */
1241
1435
  export declare function resolveTextColor(style: Pick<ComponentStyle, "color"> | undefined, fallback?: string): string;
1242
1436
 
1437
+ /** Pure preflight uses explicit samples only; it never fetches business data or publishes a draft. */
1438
+ export declare function reviewReportTemplate(input: unknown, options?: ReportTemplateReviewOptions): ReportTemplateReview;
1439
+
1243
1440
  export declare interface RichParagraph {
1244
1441
  segments: RichSegment[];
1245
1442
  align?: ComponentStyle["align"];
@@ -1270,6 +1467,8 @@ export declare interface StyleRule {
1270
1467
  field: string;
1271
1468
  op: ">" | ">=" | "<" | "<=" | "==" | "!=";
1272
1469
  value: number | string;
1470
+ /** Explicit decimal comparisons retain decimal thresholds as text. */
1471
+ numeric?: "number" | "decimal";
1273
1472
  };
1274
1473
  /** 命中时合并进单元格样式(color/bold/backgroundColor 等) */
1275
1474
  style: Record<string, unknown>;