@veltra/sheet 2.4.0 → 2.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/dist/components/sheet/formula-bar.js +50 -7
- package/dist/components/sheet/style2.css +2 -2
- package/dist/index.d.ts +2 -19
- package/dist/index.js +2 -15
- package/dist/types/index.d.ts +1 -3
- package/package.json +5 -6
- package/src/components/sheet/__test__/formula-bar.test.ts +29 -0
- package/src/components/sheet/formula-bar.vue +67 -6
- package/src/components/sheet/style.scss +1 -1
- package/src/index.ts +1 -27
- package/src/types/index.ts +0 -2
- package/dist/components/report/binding-badge.js +0 -118
- package/dist/components/report/designer/cell-coords.js +0 -46
- package/dist/components/report/designer/col-widths.js +0 -29
- package/dist/components/report/designer/conditional-rules/helpers.js +0 -139
- package/dist/components/report/designer/drill-dialog.js +0 -258
- package/dist/components/report/designer/drop-highlight-overlay.js +0 -76
- package/dist/components/report/designer/float-panel.js +0 -434
- package/dist/components/report/designer/role.js +0 -17
- package/dist/components/report/designer/rule-preview.js +0 -33
- package/dist/components/report/designer/rule-row.js +0 -253
- package/dist/components/report/designer/rules-dialog.js +0 -118
- package/dist/components/report/designer/topology-overlay.js +0 -122
- package/dist/components/report/designer/topology.js +0 -64
- package/dist/components/report/designer/use-grid-overlay.js +0 -75
- package/dist/components/report/designer-hub.js +0 -177
- package/dist/components/report/field-panel-helpers.js +0 -33
- package/dist/components/report/field-panel.js +0 -132
- package/dist/components/report/filter-bar.js +0 -74
- package/dist/components/report/hub-connection-form.js +0 -145
- package/dist/components/report/hub-dataset-editor.js +0 -409
- package/dist/components/report/preview-grid-size.js +0 -32
- package/dist/components/report/print.js +0 -39
- package/dist/components/report/report-designer.js +0 -428
- package/dist/components/report/report-viewer.js +0 -253
- package/dist/components/report/style.d.ts +0 -17
- package/dist/components/report/style.js +0 -18
- package/dist/components/report/style2.css +0 -965
- package/dist/components/report/use-report-designer.js +0 -387
- package/dist/components/report/use-report-viewer.js +0 -140
- package/dist/report/binding.d.ts +0 -83
- package/dist/report/binding.js +0 -334
- package/dist/report/connector.d.ts +0 -66
- package/dist/report/connector.js +0 -159
- package/dist/report/drill.d.ts +0 -48
- package/dist/report/drill.js +0 -78
- package/dist/report/export-xlsx.d.ts +0 -13
- package/dist/report/export-xlsx.js +0 -13
- package/dist/report/filter-bar.d.ts +0 -10
- package/dist/report/filter-bar.js +0 -31
- package/dist/report/index.d.ts +0 -14
- package/dist/report/params.d.ts +0 -13
- package/dist/report/params.js +0 -61
- package/dist/report/print.d.ts +0 -23
- package/dist/report/print.js +0 -197
- package/dist/report/render/aggregate.js +0 -193
- package/dist/report/render/builder.d.ts +0 -12
- package/dist/report/render/builder.js +0 -139
- package/dist/report/render/coordinate.d.ts +0 -25
- package/dist/report/render/coordinate.js +0 -733
- package/dist/report/render/index.d.ts +0 -14
- package/dist/report/render/index.js +0 -21
- package/dist/report/render/style-resolver.js +0 -50
- package/dist/report/render/template-index.d.ts +0 -24
- package/dist/report/render/template-index.js +0 -137
- package/dist/report/rules/evaluate.d.ts +0 -25
- package/dist/report/rules/evaluate.js +0 -82
- package/dist/report/rules/index.d.ts +0 -2
- package/dist/report/template.d.ts +0 -63
- package/dist/report/template.js +0 -83
- package/dist/report/types.d.ts +0 -103
- package/dist/types/report-designer.d.ts +0 -51
- package/dist/types/report-viewer.d.ts +0 -57
- package/src/components/report/__test__/binding-badge.test.ts +0 -92
- package/src/components/report/__test__/conditional-rules-helpers.test.ts +0 -88
- package/src/components/report/__test__/field-panel-helpers.test.ts +0 -65
- package/src/components/report/__test__/float-panel-position.test.ts +0 -45
- package/src/components/report/__test__/preview-grid-size.test.ts +0 -63
- package/src/components/report/__test__/report-designer.test.ts +0 -559
- package/src/components/report/__test__/report-drill.test.ts +0 -692
- package/src/components/report/__test__/report-viewer.test.ts +0 -400
- package/src/components/report/__test__/topology.test.ts +0 -143
- package/src/components/report/__test__/use-report-designer.test.ts +0 -804
- package/src/components/report/binding-badge.ts +0 -122
- package/src/components/report/designer/cell-coords.ts +0 -95
- package/src/components/report/designer/col-widths.ts +0 -56
- package/src/components/report/designer/conditional-rules/helpers.ts +0 -189
- package/src/components/report/designer/drill-dialog.vue +0 -245
- package/src/components/report/designer/drop-highlight-overlay.vue +0 -75
- package/src/components/report/designer/float-panel.vue +0 -444
- package/src/components/report/designer/role.ts +0 -32
- package/src/components/report/designer/rule-preview.vue +0 -40
- package/src/components/report/designer/rule-row.vue +0 -252
- package/src/components/report/designer/rules-dialog.vue +0 -110
- package/src/components/report/designer/topology-overlay.vue +0 -128
- package/src/components/report/designer/topology.ts +0 -124
- package/src/components/report/designer/use-grid-overlay.ts +0 -114
- package/src/components/report/designer-hub.vue +0 -198
- package/src/components/report/field-panel-helpers.ts +0 -44
- package/src/components/report/field-panel.vue +0 -136
- package/src/components/report/filter-bar.vue +0 -77
- package/src/components/report/hub-connection-form.vue +0 -124
- package/src/components/report/hub-dataset-editor.vue +0 -387
- package/src/components/report/index.ts +0 -2
- package/src/components/report/preview-grid-size.ts +0 -33
- package/src/components/report/print.ts +0 -44
- package/src/components/report/report-designer.vue +0 -454
- package/src/components/report/report-viewer.vue +0 -289
- package/src/components/report/style-designer.scss +0 -653
- package/src/components/report/style-hub.scss +0 -292
- package/src/components/report/style-viewer.scss +0 -144
- package/src/components/report/style.scss +0 -3
- package/src/components/report/style.ts +0 -20
- package/src/components/report/use-report-designer.ts +0 -603
- package/src/components/report/use-report-viewer.ts +0 -227
- package/src/report/__test__/binding.test.ts +0 -320
- package/src/report/__test__/connector.test.ts +0 -239
- package/src/report/__test__/drill.test.ts +0 -194
- package/src/report/__test__/export-xlsx.test.ts +0 -96
- package/src/report/__test__/filter-bar.test.ts +0 -58
- package/src/report/__test__/params.test.ts +0 -156
- package/src/report/__test__/print.test.ts +0 -170
- package/src/report/__test__/render.test.ts +0 -856
- package/src/report/__test__/rules.test.ts +0 -131
- package/src/report/__test__/template.test.ts +0 -366
- package/src/report/binding.ts +0 -474
- package/src/report/connector.ts +0 -206
- package/src/report/drill.ts +0 -112
- package/src/report/export-xlsx.ts +0 -15
- package/src/report/filter-bar.ts +0 -36
- package/src/report/index.ts +0 -16
- package/src/report/params.ts +0 -96
- package/src/report/print.ts +0 -234
- package/src/report/render/__test__/aggregate.test.ts +0 -16
- package/src/report/render/__test__/coordinate.test.ts +0 -405
- package/src/report/render/aggregate.ts +0 -289
- package/src/report/render/builder.ts +0 -211
- package/src/report/render/coordinate.ts +0 -1239
- package/src/report/render/index.ts +0 -30
- package/src/report/render/style-resolver.ts +0 -68
- package/src/report/render/template-index.ts +0 -200
- package/src/report/rules/evaluate.ts +0 -113
- package/src/report/rules/index.ts +0 -7
- package/src/report/template.ts +0 -145
- package/src/report/types.ts +0 -116
- package/src/types/report-designer.ts +0 -55
- package/src/types/report-viewer.ts +0 -54
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { Sheet } from "@veltra/sheet-core";
|
|
2
|
-
//#region src/report/export-xlsx.d.ts
|
|
3
|
-
/** 列宽条目:模型列索引 → 像素宽(与 SheetSnapshot.colWidths 同构) */
|
|
4
|
-
type ReportColWidthEntry = readonly [number, number];
|
|
5
|
-
/**
|
|
6
|
-
* 将已填充的 Sheet(Filled Report)导出为保真 XLSX(合并 / 样式 / 行高 / 列宽 / 浮动图)。
|
|
7
|
-
* 组装与序列化委托 sheet-core `exportSheetXlsx`(与 `exportWorkbookXlsx` 同一套单表逻辑);
|
|
8
|
-
* 条件样式颜色已在 renderReport 展开阶段打平进 StylePool(ADR-0001 决策 2)。
|
|
9
|
-
* 列宽取自 sheet 模型(`getColWidths`)。
|
|
10
|
-
*/
|
|
11
|
-
declare function exportFilledReportXlsx(sheet: Sheet): Promise<Uint8Array>;
|
|
12
|
-
//#endregion
|
|
13
|
-
export { ReportColWidthEntry, exportFilledReportXlsx };
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { exportSheetXlsx } from "@veltra/sheet-core/core/io/export";
|
|
2
|
-
//#region src/report/export-xlsx.ts
|
|
3
|
-
/**
|
|
4
|
-
* 将已填充的 Sheet(Filled Report)导出为保真 XLSX(合并 / 样式 / 行高 / 列宽 / 浮动图)。
|
|
5
|
-
* 组装与序列化委托 sheet-core `exportSheetXlsx`(与 `exportWorkbookXlsx` 同一套单表逻辑);
|
|
6
|
-
* 条件样式颜色已在 renderReport 展开阶段打平进 StylePool(ADR-0001 决策 2)。
|
|
7
|
-
* 列宽取自 sheet 模型(`getColWidths`)。
|
|
8
|
-
*/
|
|
9
|
-
function exportFilledReportXlsx(sheet) {
|
|
10
|
-
return exportSheetXlsx(sheet, { fallbackName: "报表" });
|
|
11
|
-
}
|
|
12
|
-
//#endregion
|
|
13
|
-
export { exportFilledReportXlsx };
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { ParamValues } from "./types.js";
|
|
2
|
-
//#region src/report/filter-bar.d.ts
|
|
3
|
-
/** 将运行时 date-range 参数值规范为 [from, to] 字符串元组 */
|
|
4
|
-
declare function parseDateRangeValue(raw: unknown): [string, string];
|
|
5
|
-
/** 将运行时 number 参数值规范为 UNumberInput 可接受的 number | undefined */
|
|
6
|
-
declare function resolveNumberParamValue(raw: unknown): number | undefined;
|
|
7
|
-
/** 合并单参数变更,保持其余参数值不变 */
|
|
8
|
-
declare function patchParamValues(values: ParamValues, id: string, value: unknown): ParamValues;
|
|
9
|
-
//#endregion
|
|
10
|
-
export { parseDateRangeValue, patchParamValues, resolveNumberParamValue };
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
//#region src/report/filter-bar.ts
|
|
2
|
-
function toParamString(value) {
|
|
3
|
-
if (value == null || value === "") return "";
|
|
4
|
-
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return String(value);
|
|
5
|
-
return "";
|
|
6
|
-
}
|
|
7
|
-
/** 将运行时 date-range 参数值规范为 [from, to] 字符串元组 */
|
|
8
|
-
function parseDateRangeValue(raw) {
|
|
9
|
-
if (Array.isArray(raw)) return [toParamString(raw[0]), toParamString(raw[1])];
|
|
10
|
-
if (raw && typeof raw === "object") {
|
|
11
|
-
const obj = raw;
|
|
12
|
-
return [toParamString(obj.from ?? obj.start), toParamString(obj.to ?? obj.end)];
|
|
13
|
-
}
|
|
14
|
-
return ["", ""];
|
|
15
|
-
}
|
|
16
|
-
/** 将运行时 number 参数值规范为 UNumberInput 可接受的 number | undefined */
|
|
17
|
-
function resolveNumberParamValue(raw) {
|
|
18
|
-
if (raw === "" || raw == null) return void 0;
|
|
19
|
-
if (typeof raw === "number" && Number.isFinite(raw)) return raw;
|
|
20
|
-
const parsed = Number(raw);
|
|
21
|
-
return Number.isFinite(parsed) ? parsed : void 0;
|
|
22
|
-
}
|
|
23
|
-
/** 合并单参数变更,保持其余参数值不变 */
|
|
24
|
-
function patchParamValues(values, id, value) {
|
|
25
|
-
return {
|
|
26
|
-
...values,
|
|
27
|
-
[id]: value
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
//#endregion
|
|
31
|
-
export { parseDateRangeValue, patchParamValues, resolveNumberParamValue };
|
package/dist/report/index.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { ConditionalOperator, ConditionalRule, DatasetCatalogItem, DatasetField, DatasetRecords, ParamValues, QueryParamDef, QueryParamOption, QueryParamType, ReportAggregate, ReportBinding, ReportDrillConfig, ReportExpand, ReportPreset, ReportSort, ReportTemplateListItem } from "./types.js";
|
|
2
|
-
import { InferParentOptions, ListParentCandidateOptions, REPORT_META_NAMESPACE, applyReportPreset, createReportBinding, formatBindingPlaceholder, formatBindingPlaceholderParts, formatCellAddress, formatParentCandidateLabel, inferColParentCandidate, inferDropPreset, inferParentsForPreset, inferReportPreset, inferRowParentCandidate, isColGroupBinding, isExpansionBandCol, isExpansionBandRow, isHorizontalExpandBinding, isReductionAggregate, isRowGroupBinding, isVerticalExpandBinding, listColParentCandidates, listRowParentCandidates, parseCellAddress, prefersGroupParent, presetBindingPatch, presetStillApplies, setBindingCatalog } from "./binding.js";
|
|
3
|
-
import { ConditionalEvalContext, evaluateCondition, evaluateConditionalStyle, resolveRuleCompareValue, toComparableNumber } from "./rules/evaluate.js";
|
|
4
|
-
import "./rules/index.js";
|
|
5
|
-
import { buildParamDefs, extractParamIds, resolveBoundDatasetParams } from "./params.js";
|
|
6
|
-
import { ReportColWidthEntry, exportFilledReportXlsx } from "./export-xlsx.js";
|
|
7
|
-
import { mapFilledColWidths } from "./render/builder.js";
|
|
8
|
-
import { renderReport, resolveFilledColWidths } from "./render/index.js";
|
|
9
|
-
import { ConnectionType, ConnectorError, CreateHttpConnectorOptions, DEFAULT_CONNECTION_PORTS, DataConnection, DataConnector, QueryResult, Result, createHttpConnector, resolvePortOnTypeChange } from "./connector.js";
|
|
10
|
-
import { IncompatibleTemplateVersionError, REPORT_TEMPLATE_VERSION, ReportDatasetDef, ReportTemplate, assertCompatibleTemplateVersion, createReportTemplate, fetchTemplateRecords, getBoundDatasetIds, getTemplateDatasets, resolveParamDefaults, resolveTemplateParams } from "./template.js";
|
|
11
|
-
import { parseDateRangeValue, patchParamValues, resolveNumberParamValue } from "./filter-bar.js";
|
|
12
|
-
import { DrillHit, DrillStack, DrillStackLayer, ResolveReportTemplate, buildDrillHitMap, createDrillStack, currentDrillLayer, popDrillLayer, pushDrillLayer, resolveDrillParams } from "./drill.js";
|
|
13
|
-
import { ReportPrintOptions, buildFilledReportPrintHtml } from "./print.js";
|
|
14
|
-
export { type ConditionalEvalContext, ConditionalOperator, ConditionalRule, ConnectionType, ConnectorError, CreateHttpConnectorOptions, DEFAULT_CONNECTION_PORTS, DataConnection, DataConnector, DatasetCatalogItem, DatasetField, DatasetRecords, DrillHit, DrillStack, DrillStackLayer, IncompatibleTemplateVersionError, InferParentOptions, ListParentCandidateOptions, ParamValues, QueryParamDef, QueryParamOption, QueryParamType, QueryResult, REPORT_META_NAMESPACE, REPORT_TEMPLATE_VERSION, ReportAggregate, ReportBinding, ReportColWidthEntry, ReportDatasetDef, ReportDrillConfig, ReportExpand, ReportPreset, ReportPrintOptions, ReportSort, ReportTemplate, ReportTemplateListItem, ResolveReportTemplate, Result, applyReportPreset, assertCompatibleTemplateVersion, buildDrillHitMap, buildFilledReportPrintHtml, buildParamDefs, createDrillStack, createHttpConnector, createReportBinding, createReportTemplate, currentDrillLayer, evaluateCondition, evaluateConditionalStyle, exportFilledReportXlsx, extractParamIds, fetchTemplateRecords, formatBindingPlaceholder, formatBindingPlaceholderParts, formatCellAddress, formatParentCandidateLabel, getBoundDatasetIds, getTemplateDatasets, inferColParentCandidate, inferDropPreset, inferParentsForPreset, inferReportPreset, inferRowParentCandidate, isColGroupBinding, isExpansionBandCol, isExpansionBandRow, isHorizontalExpandBinding, isReductionAggregate, isRowGroupBinding, isVerticalExpandBinding, listColParentCandidates, listRowParentCandidates, mapFilledColWidths, parseCellAddress, parseDateRangeValue, patchParamValues, popDrillLayer, prefersGroupParent, presetBindingPatch, presetStillApplies, pushDrillLayer, renderReport, resolveBoundDatasetParams, resolveDrillParams, resolveFilledColWidths, resolveNumberParamValue, resolveParamDefaults, resolvePortOnTypeChange, resolveRuleCompareValue, resolveTemplateParams, setBindingCatalog, toComparableNumber };
|
package/dist/report/params.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { QueryParamDef } from "./types.js";
|
|
2
|
-
//#region src/report/params.d.ts
|
|
3
|
-
/** 从 SQL 提取 `${param}` 占位符 id(ADR-0002 决策 2:前端纯函数) */
|
|
4
|
-
declare function extractParamIds(sql: string): string[];
|
|
5
|
-
/**
|
|
6
|
-
* 从 SQL 构建查询参数定义:提取 `${param}` 占位符 + 上下文类型推断,
|
|
7
|
-
* 再叠加数据集编辑器的元数据覆盖(label / 类型 / 默认值 / 选项)。
|
|
8
|
-
*/
|
|
9
|
-
declare function buildParamDefs(sql: string, overrides?: Record<string, Partial<Omit<QueryParamDef, 'id'>>>): QueryParamDef[];
|
|
10
|
-
/** 按绑定的数据集 id 合并查询参数(同名参数先见为准) */
|
|
11
|
-
declare function resolveBoundDatasetParams(queryParams: QueryParamDef[], boundDatasetIds: readonly string[], getDatasetParams: (datasetId: string) => QueryParamDef[]): QueryParamDef[];
|
|
12
|
-
//#endregion
|
|
13
|
-
export { buildParamDefs, extractParamIds, resolveBoundDatasetParams };
|
package/dist/report/params.js
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
//#region src/report/params.ts
|
|
2
|
-
/** 从 SQL 提取 `${param}` 占位符 id(ADR-0002 决策 2:前端纯函数) */
|
|
3
|
-
function extractParamIds(sql) {
|
|
4
|
-
const ids = [];
|
|
5
|
-
const re = /\$\{([^}]+)\}/g;
|
|
6
|
-
let match;
|
|
7
|
-
while ((match = re.exec(sql)) !== null) {
|
|
8
|
-
const id = match[1].trim();
|
|
9
|
-
if (id && !ids.includes(id)) ids.push(id);
|
|
10
|
-
}
|
|
11
|
-
return ids;
|
|
12
|
-
}
|
|
13
|
-
function escapeRegExp(value) {
|
|
14
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
15
|
-
}
|
|
16
|
-
/** 从 SQL 上下文推断参数控件类型(BETWEEN/LIKE/数值比较) */
|
|
17
|
-
function inferParamTypeFromSql(sql, paramId) {
|
|
18
|
-
if (new RegExp(`\\bBETWEEN\\s+\\$\\{${escapeRegExp(paramId)}\\}(?!\\s+AND)`, "i").test(sql)) return "date-range";
|
|
19
|
-
const pairMatch = new RegExp(`\\bBETWEEN\\s+\\$\\{${escapeRegExp(paramId)}\\}\\s+AND\\s+\\$\\{([^}]+)\\}`, "i").exec(sql);
|
|
20
|
-
if (pairMatch && pairMatch[1].trim() !== paramId) return "date";
|
|
21
|
-
if (new RegExp(`\\bLIKE\\s+\\$\\{${escapeRegExp(paramId)}\\}`, "i").test(sql)) return "text";
|
|
22
|
-
if (new RegExp(`[<>=]+\\s+\\$\\{${escapeRegExp(paramId)}\\}|\\$\\{${escapeRegExp(paramId)}\\}\\s*[<>=]+`, "i").test(sql)) return "number";
|
|
23
|
-
return "text";
|
|
24
|
-
}
|
|
25
|
-
function defaultValueForType(type) {
|
|
26
|
-
switch (type) {
|
|
27
|
-
case "number": return 0;
|
|
28
|
-
case "date-range": return ["", ""];
|
|
29
|
-
case "select": return "";
|
|
30
|
-
default: return "";
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* 从 SQL 构建查询参数定义:提取 `${param}` 占位符 + 上下文类型推断,
|
|
35
|
-
* 再叠加数据集编辑器的元数据覆盖(label / 类型 / 默认值 / 选项)。
|
|
36
|
-
*/
|
|
37
|
-
function buildParamDefs(sql, overrides) {
|
|
38
|
-
return extractParamIds(sql).map((id) => {
|
|
39
|
-
const inferred = inferParamTypeFromSql(sql, id);
|
|
40
|
-
const override = overrides?.[id];
|
|
41
|
-
return {
|
|
42
|
-
id,
|
|
43
|
-
label: override?.label ?? id,
|
|
44
|
-
type: override?.type ?? inferred,
|
|
45
|
-
defaultValue: override?.defaultValue ?? defaultValueForType(override?.type ?? inferred),
|
|
46
|
-
options: override?.options
|
|
47
|
-
};
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
/** 按绑定的数据集 id 合并查询参数(同名参数先见为准) */
|
|
51
|
-
function resolveBoundDatasetParams(queryParams, boundDatasetIds, getDatasetParams) {
|
|
52
|
-
const map = /* @__PURE__ */ new Map();
|
|
53
|
-
for (const datasetId of boundDatasetIds) {
|
|
54
|
-
const params = getDatasetParams(datasetId);
|
|
55
|
-
for (const param of params) if (!map.has(param.id)) map.set(param.id, param);
|
|
56
|
-
}
|
|
57
|
-
if (map.size > 0) return Array.from(map.values());
|
|
58
|
-
return queryParams;
|
|
59
|
-
}
|
|
60
|
-
//#endregion
|
|
61
|
-
export { buildParamDefs, extractParamIds, resolveBoundDatasetParams };
|
package/dist/report/print.d.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { Sheet } from "@veltra/sheet-core";
|
|
2
|
-
//#region src/report/print.d.ts
|
|
3
|
-
/** 报表打印选项 */
|
|
4
|
-
interface ReportPrintOptions {
|
|
5
|
-
/** 打印文档标题(打印对话框标题 / 另存 PDF 文件名);缺省取 sheet 名,再回落「报表」 */
|
|
6
|
-
title?: string;
|
|
7
|
-
/** 纸张方向(@page size),默认 portrait */
|
|
8
|
-
orientation?: 'portrait' | 'landscape';
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* 将已填充的 Sheet(Filled Report)构建为打印专用 HTML 文档(纯 TS、headless、无 DOM)。
|
|
12
|
-
*
|
|
13
|
-
* 路线说明:网格渲染层是 canvas + 虚拟滚动(视口外不绘制),无法直接 window.print;
|
|
14
|
-
* 这里从模型单一事实源(与 exportFilledReportXlsx 同一读取路径)重建 `<table>`——
|
|
15
|
-
* 矢量文字清晰、浏览器原生分页、合并格天然映射 rowspan/colspan。
|
|
16
|
-
*
|
|
17
|
-
* 保真范围:值 / 合并 / 有效样式(fill + border + font + align/wrap,条件样式已在
|
|
18
|
-
* 展开阶段打平进 StylePool)/ 行高 / 列宽 / 浮动图(data URL 内嵌,跨页被裁剪属预期)。
|
|
19
|
-
* 与 Excel 默认一致:不打印屏幕网格线(仅模型显式边框)。
|
|
20
|
-
*/
|
|
21
|
-
declare function buildFilledReportPrintHtml(sheet: Sheet, options?: ReportPrintOptions): string;
|
|
22
|
-
//#endregion
|
|
23
|
-
export { ReportPrintOptions, buildFilledReportPrintHtml };
|
package/dist/report/print.js
DELETED
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
import { BORDER_SIDES } from "@veltra/sheet-core";
|
|
2
|
-
//#region src/report/print.ts
|
|
3
|
-
/**
|
|
4
|
-
* 默认列宽 / 行高(px):与 grid 层 vtable-theme 的
|
|
5
|
-
* SHEET_DEFAULT_COL_WIDTH / SHEET_DEFAULT_ROW_HEIGHT 对齐;
|
|
6
|
-
* report 内核保持 headless,不引 grid 入口。
|
|
7
|
-
*/
|
|
8
|
-
const PRINT_DEFAULT_COL_WIDTH = 80;
|
|
9
|
-
const PRINT_DEFAULT_ROW_HEIGHT = 28;
|
|
10
|
-
const IMAGE_MIME = {
|
|
11
|
-
png: "image/png",
|
|
12
|
-
jpeg: "image/jpeg",
|
|
13
|
-
gif: "image/gif",
|
|
14
|
-
svg: "image/svg+xml",
|
|
15
|
-
webp: "image/webp"
|
|
16
|
-
};
|
|
17
|
-
/** 模型边框线型 → CSS 线型(thin/medium/thick 为实线粗细分级,宽度由 edge.width 表达) */
|
|
18
|
-
const BORDER_CSS_LINE = {
|
|
19
|
-
thin: "solid",
|
|
20
|
-
medium: "solid",
|
|
21
|
-
thick: "solid",
|
|
22
|
-
dashed: "dashed",
|
|
23
|
-
dotted: "dotted"
|
|
24
|
-
};
|
|
25
|
-
function escapeHtml(text) {
|
|
26
|
-
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
27
|
-
}
|
|
28
|
-
function escapeAttr(text) {
|
|
29
|
-
return escapeHtml(text).replace(/"/g, """);
|
|
30
|
-
}
|
|
31
|
-
/** Uint8Array → base64(分块避免栈溢出;btoa 在浏览器 / Node >=16 / Bun / happy-dom 均可用) */
|
|
32
|
-
function bytesToBase64(data) {
|
|
33
|
-
let binary = "";
|
|
34
|
-
const CHUNK = 32768;
|
|
35
|
-
for (let i = 0; i < data.length; i += CHUNK) binary += String.fromCharCode(...data.subarray(i, i + CHUNK));
|
|
36
|
-
return btoa(binary);
|
|
37
|
-
}
|
|
38
|
-
/** 模型有效样式 → td 内联 CSS(字号 pt 直出,与屏幕 px ×4/3 物理尺寸一致) */
|
|
39
|
-
function styleToCss(style) {
|
|
40
|
-
const decls = [];
|
|
41
|
-
if (style.fill?.color) decls.push(`background-color:${style.fill.color}`);
|
|
42
|
-
for (const side of BORDER_SIDES) {
|
|
43
|
-
const edge = style.border?.[side];
|
|
44
|
-
if (edge) decls.push(`border-${side}:${edge.width}px ${BORDER_CSS_LINE[edge.style]} ${edge.color}`);
|
|
45
|
-
}
|
|
46
|
-
const font = style.font;
|
|
47
|
-
if (font) {
|
|
48
|
-
if (font.color) decls.push(`color:${font.color}`);
|
|
49
|
-
if (font.bold) decls.push("font-weight:bold");
|
|
50
|
-
if (font.italic) decls.push("font-style:italic");
|
|
51
|
-
const decoration = [font.underline ? "underline" : "", font.strikethrough ? "line-through" : ""].filter(Boolean).join(" ");
|
|
52
|
-
if (decoration) decls.push(`text-decoration:${decoration}`);
|
|
53
|
-
if (typeof font.size === "number") decls.push(`font-size:${font.size}pt`);
|
|
54
|
-
}
|
|
55
|
-
const align = style.align;
|
|
56
|
-
if (align) {
|
|
57
|
-
if (align.horizontal) decls.push(`text-align:${align.horizontal}`);
|
|
58
|
-
if (align.vertical) decls.push(`vertical-align:${align.vertical}`);
|
|
59
|
-
if (align.wrap) decls.push("white-space:normal;word-break:break-all");
|
|
60
|
-
}
|
|
61
|
-
return decls.join(";");
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* 浮动图打印定位(镜像 grid image-layer `computeImageRect`):
|
|
65
|
-
* left/top = from 格左上 + 格内像素偏移;宽高优先 image.width/height(两者都有才用),
|
|
66
|
-
* 缺失且有 to 时按 from→to 跨度兜底,都缺失则省略尺寸(浏览器取自然尺寸)。
|
|
67
|
-
*/
|
|
68
|
-
function computePrintImageRect(image, colWidths, rowHeights) {
|
|
69
|
-
const { from, to } = image.anchor;
|
|
70
|
-
let left = from.offsetX ?? 0;
|
|
71
|
-
for (let c = 0; c < from.col; c++) left += colWidths[c] ?? PRINT_DEFAULT_COL_WIDTH;
|
|
72
|
-
let top = from.offsetY ?? 0;
|
|
73
|
-
for (let r = 0; r < from.row; r++) top += rowHeights[r] ?? PRINT_DEFAULT_ROW_HEIGHT;
|
|
74
|
-
if (image.width != null && image.height != null) return {
|
|
75
|
-
left,
|
|
76
|
-
top,
|
|
77
|
-
width: image.width,
|
|
78
|
-
height: image.height
|
|
79
|
-
};
|
|
80
|
-
if (to) {
|
|
81
|
-
let width = 0;
|
|
82
|
-
for (let c = from.col; c <= to.col; c++) width += colWidths[c] ?? PRINT_DEFAULT_COL_WIDTH;
|
|
83
|
-
let height = 0;
|
|
84
|
-
for (let r = from.row; r <= to.row; r++) height += rowHeights[r] ?? PRINT_DEFAULT_ROW_HEIGHT;
|
|
85
|
-
return {
|
|
86
|
-
left,
|
|
87
|
-
top,
|
|
88
|
-
width,
|
|
89
|
-
height
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
return {
|
|
93
|
-
left,
|
|
94
|
-
top
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* 将已填充的 Sheet(Filled Report)构建为打印专用 HTML 文档(纯 TS、headless、无 DOM)。
|
|
99
|
-
*
|
|
100
|
-
* 路线说明:网格渲染层是 canvas + 虚拟滚动(视口外不绘制),无法直接 window.print;
|
|
101
|
-
* 这里从模型单一事实源(与 exportFilledReportXlsx 同一读取路径)重建 `<table>`——
|
|
102
|
-
* 矢量文字清晰、浏览器原生分页、合并格天然映射 rowspan/colspan。
|
|
103
|
-
*
|
|
104
|
-
* 保真范围:值 / 合并 / 有效样式(fill + border + font + align/wrap,条件样式已在
|
|
105
|
-
* 展开阶段打平进 StylePool)/ 行高 / 列宽 / 浮动图(data URL 内嵌,跨页被裁剪属预期)。
|
|
106
|
-
* 与 Excel 默认一致:不打印屏幕网格线(仅模型显式边框)。
|
|
107
|
-
*/
|
|
108
|
-
function buildFilledReportPrintHtml(sheet, options) {
|
|
109
|
-
const title = options?.title ?? sheet.name ?? "";
|
|
110
|
-
const orientation = options?.orientation ?? "portrait";
|
|
111
|
-
let maxRow = -1;
|
|
112
|
-
let maxCol = -1;
|
|
113
|
-
const grow = (row, col) => {
|
|
114
|
-
if (row > maxRow) maxRow = row;
|
|
115
|
-
if (col > maxCol) maxCol = col;
|
|
116
|
-
};
|
|
117
|
-
for (const [addr] of sheet.store.peekEntries()) grow(addr.row, addr.col);
|
|
118
|
-
for (const [row] of sheet.getRowHeights()) grow(row, 0);
|
|
119
|
-
for (const [col] of sheet.getColWidths()) grow(0, col);
|
|
120
|
-
const merges = sheet.merges.getMerges();
|
|
121
|
-
for (const range of merges) grow(range.end.row, range.end.col);
|
|
122
|
-
const images = sheet.getImages();
|
|
123
|
-
for (const image of images) {
|
|
124
|
-
grow(image.anchor.from.row, image.anchor.from.col);
|
|
125
|
-
if (image.anchor.to) grow(image.anchor.to.row, image.anchor.to.col);
|
|
126
|
-
}
|
|
127
|
-
const colWidths = [];
|
|
128
|
-
for (let c = 0; c <= maxCol; c++) colWidths.push(sheet.getColWidth(c) ?? PRINT_DEFAULT_COL_WIDTH);
|
|
129
|
-
const rowHeights = [];
|
|
130
|
-
for (let r = 0; r <= maxRow; r++) rowHeights.push(sheet.getRowHeight(r) ?? PRINT_DEFAULT_ROW_HEIGHT);
|
|
131
|
-
const spanByAnchor = /* @__PURE__ */ new Map();
|
|
132
|
-
const covered = /* @__PURE__ */ new Set();
|
|
133
|
-
for (const range of merges) {
|
|
134
|
-
const rowSpan = range.end.row - range.start.row + 1;
|
|
135
|
-
const colSpan = range.end.col - range.start.col + 1;
|
|
136
|
-
spanByAnchor.set(`${range.start.row},${range.start.col}`, {
|
|
137
|
-
rowSpan,
|
|
138
|
-
colSpan
|
|
139
|
-
});
|
|
140
|
-
for (let r = range.start.row; r <= range.end.row; r++) for (let c = range.start.col; c <= range.end.col; c++) if (r !== range.start.row || c !== range.start.col) covered.add(`${r},${c}`);
|
|
141
|
-
}
|
|
142
|
-
const css = [
|
|
143
|
-
`@page { size: A4 ${orientation}; margin: 12mm; }`,
|
|
144
|
-
"html, body { margin: 0; padding: 0; }",
|
|
145
|
-
"body { font-family: Arial, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif; font-size: 12px; color: #1f2329; -webkit-print-color-adjust: exact; print-color-adjust: exact; }",
|
|
146
|
-
".sheet-print-root { position: relative; }",
|
|
147
|
-
"table { border-collapse: collapse; table-layout: fixed; }",
|
|
148
|
-
"tr { break-inside: avoid; }",
|
|
149
|
-
"td { box-sizing: border-box; padding: 2px 6px; overflow: hidden; white-space: nowrap; vertical-align: middle; text-align: left; }",
|
|
150
|
-
".sheet-print-root img { position: absolute; }"
|
|
151
|
-
].join("\n");
|
|
152
|
-
const parts = [];
|
|
153
|
-
parts.push("<!doctype html><html><head><meta charset=\"utf-8\">");
|
|
154
|
-
parts.push(`<title>${escapeHtml(title || "报表")}</title>`);
|
|
155
|
-
parts.push(`<style>\n${css}\n</style></head><body>`);
|
|
156
|
-
parts.push("<div class=\"sheet-print-root\">");
|
|
157
|
-
parts.push("<table>");
|
|
158
|
-
if (colWidths.length > 0) {
|
|
159
|
-
parts.push("<colgroup>");
|
|
160
|
-
for (const width of colWidths) parts.push(`<col style="width:${width}px">`);
|
|
161
|
-
parts.push("</colgroup>");
|
|
162
|
-
}
|
|
163
|
-
for (let r = 0; r <= maxRow; r++) {
|
|
164
|
-
parts.push(`<tr style="height:${rowHeights[r]}px">`);
|
|
165
|
-
for (let c = 0; c <= maxCol; c++) {
|
|
166
|
-
if (covered.has(`${r},${c}`)) continue;
|
|
167
|
-
const attrs = [];
|
|
168
|
-
const span = spanByAnchor.get(`${r},${c}`);
|
|
169
|
-
if (span && span.colSpan > 1) attrs.push(`colspan="${span.colSpan}"`);
|
|
170
|
-
if (span && span.rowSpan > 1) attrs.push(`rowspan="${span.rowSpan}"`);
|
|
171
|
-
const style = sheet.getEffectiveStyle({
|
|
172
|
-
row: r,
|
|
173
|
-
col: c
|
|
174
|
-
});
|
|
175
|
-
const cellCss = style ? styleToCss(style) : "";
|
|
176
|
-
if (cellCss) attrs.push(`style="${escapeAttr(cellCss)}"`);
|
|
177
|
-
const value = sheet.getDisplayValue({
|
|
178
|
-
row: r,
|
|
179
|
-
col: c
|
|
180
|
-
});
|
|
181
|
-
const text = value == null ? "" : escapeHtml(String(value));
|
|
182
|
-
parts.push(`<td${attrs.length > 0 ? ` ${attrs.join(" ")}` : ""}>${text}</td>`);
|
|
183
|
-
}
|
|
184
|
-
parts.push("</tr>");
|
|
185
|
-
}
|
|
186
|
-
parts.push("</table>");
|
|
187
|
-
for (const image of images) {
|
|
188
|
-
const rect = computePrintImageRect(image, colWidths, rowHeights);
|
|
189
|
-
const size = rect.width != null && rect.height != null ? `width:${rect.width}px;height:${rect.height}px;` : "";
|
|
190
|
-
const src = `data:${IMAGE_MIME[image.type]};base64,${bytesToBase64(image.data)}`;
|
|
191
|
-
parts.push(`<img src="${src}" style="left:${rect.left}px;top:${rect.top}px;${size}" alt="${escapeAttr(image.altText ?? "")}">`);
|
|
192
|
-
}
|
|
193
|
-
parts.push("</div></body></html>");
|
|
194
|
-
return parts.join("");
|
|
195
|
-
}
|
|
196
|
-
//#endregion
|
|
197
|
-
export { buildFilledReportPrintHtml };
|
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
import { enumerateExpansionInstances } from "./coordinate.js";
|
|
2
|
-
//#region src/report/render/aggregate.ts
|
|
3
|
-
function filterRows(rows, filter) {
|
|
4
|
-
if (Object.keys(filter).length === 0) return rows;
|
|
5
|
-
return rows.filter((row) => Object.entries(filter).every(([field, value]) => row[field] === value));
|
|
6
|
-
}
|
|
7
|
-
/** 对数值集求聚合;`avg` 空集返回 `undefined`,`sum` 空集仍为 `0` */
|
|
8
|
-
function aggregateField(rows, field, aggregate) {
|
|
9
|
-
if (aggregate === "count") return rows.length;
|
|
10
|
-
if (aggregate === "list" || aggregate === "group") return rows[0]?.[field];
|
|
11
|
-
const numbers = rows.map((row) => row[field]).map((value) => typeof value === "number" ? value : Number(value)).filter((value) => Number.isFinite(value));
|
|
12
|
-
if (numbers.length === 0) {
|
|
13
|
-
if (aggregate === "avg") return void 0;
|
|
14
|
-
return 0;
|
|
15
|
-
}
|
|
16
|
-
const sum = numbers.reduce((acc, value) => acc + value, 0);
|
|
17
|
-
if (aggregate === "avg") return sum / numbers.length;
|
|
18
|
-
if (aggregate === "max") return Math.max(...numbers);
|
|
19
|
-
if (aggregate === "min") return Math.min(...numbers);
|
|
20
|
-
return sum;
|
|
21
|
-
}
|
|
22
|
-
function isRowExpanding(binding) {
|
|
23
|
-
return binding.expand === "down" && (binding.aggregate === "group" || binding.aggregate === "list");
|
|
24
|
-
}
|
|
25
|
-
function isColExpanding(binding) {
|
|
26
|
-
return binding.expand === "right" && (binding.aggregate === "group" || binding.aggregate === "list");
|
|
27
|
-
}
|
|
28
|
-
function isReductionAggregate(aggregate) {
|
|
29
|
-
return aggregate === "sum" || aggregate === "avg" || aggregate === "count" || aggregate === "max" || aggregate === "min";
|
|
30
|
-
}
|
|
31
|
-
function rowExpandingAncestors(binding, index, groupsOnly) {
|
|
32
|
-
const chain = [];
|
|
33
|
-
let current = binding.rowParent;
|
|
34
|
-
while (current) {
|
|
35
|
-
const parentBinding = index.bindingAt(current);
|
|
36
|
-
if (parentBinding) chain.unshift({
|
|
37
|
-
addr: current,
|
|
38
|
-
binding: parentBinding
|
|
39
|
-
});
|
|
40
|
-
current = parentBinding?.rowParent;
|
|
41
|
-
}
|
|
42
|
-
return chain.filter((item) => {
|
|
43
|
-
if (!isRowExpanding(item.binding)) return false;
|
|
44
|
-
if (groupsOnly && item.binding.aggregate !== "group") return false;
|
|
45
|
-
return true;
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
function colExpandingAncestors(binding, index, groupsOnly) {
|
|
49
|
-
const chain = [];
|
|
50
|
-
let current = binding.colParent;
|
|
51
|
-
while (current) {
|
|
52
|
-
const parentBinding = index.bindingAt(current);
|
|
53
|
-
if (parentBinding) chain.unshift({
|
|
54
|
-
addr: current,
|
|
55
|
-
binding: parentBinding
|
|
56
|
-
});
|
|
57
|
-
current = parentBinding?.colParent;
|
|
58
|
-
}
|
|
59
|
-
return chain.filter((item) => {
|
|
60
|
-
if (!isColExpanding(item.binding)) return false;
|
|
61
|
-
if (groupsOnly && item.binding.aggregate !== "group") return false;
|
|
62
|
-
return true;
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
function mergeFilters(rowFilter, colFilter) {
|
|
66
|
-
return {
|
|
67
|
-
...rowFilter,
|
|
68
|
-
...colFilter
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
function resolveAncestorFilters(binding, placement, index, data) {
|
|
72
|
-
const rowFilter = {};
|
|
73
|
-
const colFilter = {};
|
|
74
|
-
let parentFilter = {};
|
|
75
|
-
const groupsOnly = isReductionAggregate(binding.aggregate);
|
|
76
|
-
const rowAncestors = rowExpandingAncestors(binding, index, groupsOnly);
|
|
77
|
-
for (let i = 0; i < rowAncestors.length; i++) {
|
|
78
|
-
const ancestor = rowAncestors[i];
|
|
79
|
-
if (ancestor.binding.dataset !== binding.dataset) continue;
|
|
80
|
-
const instances = enumerateExpansionInstances(ancestor.binding, data, parentFilter);
|
|
81
|
-
const pathIndex = placement.rowPath[i];
|
|
82
|
-
if (pathIndex === void 0) continue;
|
|
83
|
-
const instance = instances[pathIndex];
|
|
84
|
-
if (!instance) continue;
|
|
85
|
-
Object.assign(rowFilter, instance.filter);
|
|
86
|
-
parentFilter = instance.filter;
|
|
87
|
-
}
|
|
88
|
-
parentFilter = {};
|
|
89
|
-
const colAncestors = colExpandingAncestors(binding, index, groupsOnly);
|
|
90
|
-
for (let i = 0; i < colAncestors.length; i++) {
|
|
91
|
-
const ancestor = colAncestors[i];
|
|
92
|
-
if (ancestor.binding.dataset !== binding.dataset) continue;
|
|
93
|
-
const instances = enumerateExpansionInstances(ancestor.binding, data, parentFilter);
|
|
94
|
-
const pathIndex = placement.colPath[i];
|
|
95
|
-
if (pathIndex === void 0) continue;
|
|
96
|
-
const instance = instances[pathIndex];
|
|
97
|
-
if (!instance) continue;
|
|
98
|
-
Object.assign(colFilter, instance.filter);
|
|
99
|
-
parentFilter = instance.filter;
|
|
100
|
-
}
|
|
101
|
-
return mergeFilters(rowFilter, colFilter);
|
|
102
|
-
}
|
|
103
|
-
function resolveOwnGroupValue(binding, placement, index, data) {
|
|
104
|
-
const rowAncestors = rowExpandingAncestors(binding, index, false);
|
|
105
|
-
const colAncestors = colExpandingAncestors(binding, index, false);
|
|
106
|
-
let parentFilter = {};
|
|
107
|
-
for (let i = 0; i < rowAncestors.length; i++) {
|
|
108
|
-
const ancestor = rowAncestors[i];
|
|
109
|
-
if (ancestor.binding.dataset !== binding.dataset) continue;
|
|
110
|
-
const instances = enumerateExpansionInstances(ancestor.binding, data, parentFilter);
|
|
111
|
-
const pathIndex = placement.rowPath[i];
|
|
112
|
-
if (pathIndex === void 0) continue;
|
|
113
|
-
const instance = instances[pathIndex];
|
|
114
|
-
if (instance) parentFilter = instance.filter;
|
|
115
|
-
}
|
|
116
|
-
for (let i = 0; i < colAncestors.length; i++) {
|
|
117
|
-
const ancestor = colAncestors[i];
|
|
118
|
-
if (ancestor.binding.dataset !== binding.dataset) continue;
|
|
119
|
-
const instances = enumerateExpansionInstances(ancestor.binding, data, parentFilter);
|
|
120
|
-
const pathIndex = placement.colPath[i];
|
|
121
|
-
if (pathIndex === void 0) continue;
|
|
122
|
-
const instance = instances[pathIndex];
|
|
123
|
-
if (instance) parentFilter = instance.filter;
|
|
124
|
-
}
|
|
125
|
-
const instances = enumerateExpansionInstances(binding, data, parentFilter);
|
|
126
|
-
const pathIndex = isRowExpanding(binding) ? placement.rowPath.at(-1) : placement.colPath.at(-1);
|
|
127
|
-
if (pathIndex === void 0) return void 0;
|
|
128
|
-
return instances[pathIndex]?.value;
|
|
129
|
-
}
|
|
130
|
-
/** 按分组字段建索引,避免交叉展开重复 filterRows */
|
|
131
|
-
var AggregateIndex = class {
|
|
132
|
-
datasets = /* @__PURE__ */ new Map();
|
|
133
|
-
filterCache = /* @__PURE__ */ new Map();
|
|
134
|
-
constructor(data) {
|
|
135
|
-
for (const [datasetId, rows] of Object.entries(data)) this.datasets.set(datasetId, rows);
|
|
136
|
-
}
|
|
137
|
-
rowsFor(dataset, filter) {
|
|
138
|
-
const cacheKey = `${dataset}:${JSON.stringify(filter)}`;
|
|
139
|
-
const cached = this.filterCache.get(cacheKey);
|
|
140
|
-
if (cached) return cached;
|
|
141
|
-
const rows = filterRows(this.datasets.get(dataset) ?? [], filter);
|
|
142
|
-
this.filterCache.set(cacheKey, rows);
|
|
143
|
-
return rows;
|
|
144
|
-
}
|
|
145
|
-
aggregate(dataset, filter, field, aggregate) {
|
|
146
|
-
const rows = this.rowsFor(dataset, filter);
|
|
147
|
-
if (aggregate === "list") return rows[0]?.[field];
|
|
148
|
-
return aggregateField(rows, field, aggregate);
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
/** 解析单个物理落点的绑定取值 */
|
|
152
|
-
function resolvePlacementValue(placement, index, data, aggregateIndex) {
|
|
153
|
-
const binding = placement.binding;
|
|
154
|
-
if (!binding) return void 0;
|
|
155
|
-
const filter = resolveAncestorFilters(binding, placement, index, data);
|
|
156
|
-
const rows = aggregateIndex.rowsFor(binding.dataset, filter);
|
|
157
|
-
if (binding.aggregate === "group") return filter[binding.field] ?? resolveOwnGroupValue(binding, placement, index, data);
|
|
158
|
-
if (binding.aggregate === "list") return rows[placement.listIndex]?.[binding.field];
|
|
159
|
-
return aggregateField(rows, binding.field, binding.aggregate);
|
|
160
|
-
}
|
|
161
|
-
/** 解析 `list` 明细落点对应的源数据行;非 list 绑定无单条记录上下文 */
|
|
162
|
-
function resolvePlacementRecord(placement, index, data, aggregateIndex) {
|
|
163
|
-
const binding = placement.binding;
|
|
164
|
-
if (!binding || binding.aggregate !== "list") return void 0;
|
|
165
|
-
const filter = resolveAncestorFilters(binding, placement, index, data);
|
|
166
|
-
return aggregateIndex.rowsFor(binding.dataset, filter)[placement.listIndex];
|
|
167
|
-
}
|
|
168
|
-
/**
|
|
169
|
-
* 解析落点的上下文记录(下钻字段映射用):
|
|
170
|
-
* `list` 明细取源数据行;分组/汇总格取祖先分组过滤值合成的上下文
|
|
171
|
-
* (分组格含自身分组值,如地区分组格 → `{ region: '华东' }`;
|
|
172
|
-
* 汇总聚合格如 sum/avg/count/max/min 也将本格聚合计算值并入上下文,如 `{ region: '华东', total: 300 }`)。
|
|
173
|
-
*/
|
|
174
|
-
function resolvePlacementContext(placement, index, data, aggregateIndex) {
|
|
175
|
-
const binding = placement.binding;
|
|
176
|
-
if (!binding) return void 0;
|
|
177
|
-
if (binding.aggregate === "list") return resolvePlacementRecord(placement, index, data, aggregateIndex);
|
|
178
|
-
const filter = resolveAncestorFilters(binding, placement, index, data);
|
|
179
|
-
if (binding.aggregate === "group") {
|
|
180
|
-
const value = filter[binding.field] ?? resolveOwnGroupValue(binding, placement, index, data);
|
|
181
|
-
return value === void 0 ? filter : {
|
|
182
|
-
...filter,
|
|
183
|
-
[binding.field]: value
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
const value = resolvePlacementValue(placement, index, data, aggregateIndex);
|
|
187
|
-
return value === void 0 ? filter : {
|
|
188
|
-
...filter,
|
|
189
|
-
[binding.field]: value
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
//#endregion
|
|
193
|
-
export { AggregateIndex, aggregateField, resolvePlacementContext, resolvePlacementRecord, resolvePlacementValue };
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import "../types.js";
|
|
2
|
-
import { ReportColWidthEntry } from "../export-xlsx.js";
|
|
3
|
-
import { TemplateIndex } from "./template-index.js";
|
|
4
|
-
import { ExpansionLayout } from "./coordinate.js";
|
|
5
|
-
import { SheetSnapshot } from "@veltra/sheet-core";
|
|
6
|
-
//#region src/report/render/builder.d.ts
|
|
7
|
-
/**
|
|
8
|
-
* 将模板列宽映射到填充报表物理列:横向展开列继承列方向父格所在模板列宽。
|
|
9
|
-
*/
|
|
10
|
-
declare function mapFilledColWidths(templateColWidths: ReadonlyArray<ReportColWidthEntry>, layout: ExpansionLayout, _index: TemplateIndex): ReportColWidthEntry[];
|
|
11
|
-
//#endregion
|
|
12
|
-
export { mapFilledColWidths };
|