@veltra/sheet 2.2.0 → 2.3.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/report/binding-badge.js +45 -21
- package/dist/components/report/designer/col-widths.js +18 -4
- package/dist/components/report/designer/conditional-rules/helpers.js +3 -3
- package/dist/components/report/designer/float-panel.js +73 -36
- package/dist/components/report/designer/rule-row.js +111 -127
- package/dist/components/report/designer/rules-dialog.js +5 -22
- package/dist/components/report/hub-dataset-editor.js +16 -1
- package/dist/components/report/preview-grid-size.js +32 -0
- package/dist/components/report/report-designer.js +75 -25
- package/dist/components/report/report-viewer.js +38 -25
- package/dist/components/report/style2.css +44 -39
- package/dist/components/report/use-report-designer.js +34 -12
- package/dist/components/report/use-report-viewer.js +6 -1
- package/dist/components/sheet/popups/border-popup.js +30 -2
- package/dist/components/sheet/popups/fill-color-popup.js +4 -3
- package/dist/components/sheet/popups/font-color-popup.js +2 -2
- package/dist/components/sheet/popups/font-size-popup.js +2 -2
- package/dist/components/sheet/sheet-context-menu.js +6 -3
- package/dist/components/sheet/sheet.js +8 -0
- package/dist/components/sheet/use-sheet-grid.js +14 -4
- package/dist/components/sheet/use-sheet-state.js +3 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/report/binding.d.ts +49 -11
- package/dist/report/binding.js +186 -29
- package/dist/report/connector.js +1 -1
- package/dist/report/export-xlsx.d.ts +3 -5
- package/dist/report/export-xlsx.js +7 -10
- package/dist/report/index.d.ts +2 -2
- package/dist/report/render/aggregate.js +20 -8
- package/dist/report/template.d.ts +8 -4
- package/dist/report/template.js +5 -2
- package/dist/tools/apply-style.js +29 -0
- package/dist/tools/builtin.js +17 -17
- package/dist/tools/context.d.ts +38 -5
- package/dist/tools/context.js +38 -1
- package/dist/types/report-designer.d.ts +2 -0
- package/dist/types/report-viewer.d.ts +2 -2
- package/dist/types/sheet.d.ts +4 -0
- package/package.json +15 -6
- package/src/components/report/__test__/conditional-rules-helpers.test.ts +1 -0
- package/src/components/report/__test__/preview-grid-size.test.ts +63 -0
- package/src/components/report/__test__/report-designer.test.ts +76 -0
- package/src/components/report/__test__/report-viewer.test.ts +24 -1
- package/src/components/report/__test__/use-report-designer.test.ts +142 -10
- package/src/components/report/binding-badge.ts +39 -20
- package/src/components/report/designer/col-widths.ts +34 -11
- package/src/components/report/designer/conditional-rules/helpers.ts +6 -3
- package/src/components/report/designer/float-panel.vue +71 -27
- package/src/components/report/designer/rule-row.vue +67 -67
- package/src/components/report/designer/rules-dialog.vue +3 -19
- package/src/components/report/hub-dataset-editor.vue +19 -1
- package/src/components/report/preview-grid-size.ts +33 -0
- package/src/components/report/report-designer.vue +79 -15
- package/src/components/report/report-viewer.vue +37 -29
- package/src/components/report/style-designer.scss +45 -41
- package/src/components/report/use-report-designer.ts +63 -14
- package/src/components/report/use-report-viewer.ts +11 -2
- package/src/components/sheet/__test__/sheet-component.test.ts +37 -0
- package/src/components/sheet/__test__/sheet-context-menu.test.ts +3 -2
- package/src/components/sheet/popups/border-popup.vue +31 -3
- package/src/components/sheet/popups/fill-color-popup.vue +5 -4
- package/src/components/sheet/popups/font-color-popup.vue +2 -2
- package/src/components/sheet/popups/font-size-popup.vue +2 -2
- package/src/components/sheet/sheet-context-menu.ts +8 -2
- package/src/components/sheet/sheet.vue +2 -0
- package/src/components/sheet/use-sheet-grid.ts +17 -3
- package/src/components/sheet/use-sheet-state.ts +8 -3
- package/src/report/__test__/binding.test.ts +103 -1
- package/src/report/__test__/connector.test.ts +21 -0
- package/src/report/__test__/export-xlsx.test.ts +4 -4
- package/src/report/__test__/render.test.ts +102 -0
- package/src/report/__test__/template.test.ts +11 -0
- package/src/report/binding.ts +278 -47
- package/src/report/connector.ts +3 -2
- package/src/report/export-xlsx.ts +9 -14
- package/src/report/render/aggregate.ts +29 -8
- package/src/report/template.ts +8 -4
- package/src/tools/__test__/apply-style.test.ts +129 -0
- package/src/tools/apply-style.ts +41 -0
- package/src/tools/builtin.ts +18 -18
- package/src/tools/context.ts +67 -4
- package/src/tools/index.ts +1 -0
- package/src/types/report-designer.ts +2 -0
- package/src/types/report-viewer.ts +2 -2
- package/src/types/sheet.ts +4 -0
|
@@ -18,13 +18,36 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
18
18
|
* 预设补丁由 core/style/border-presets 生成(含邻居格共享边同步,对齐
|
|
19
19
|
* Excel「写入时同步、最近设置生效」);面板打开期间的写入由
|
|
20
20
|
* use-tool-popup 事务包裹为一个 undo 单元。
|
|
21
|
+
* 整行/整列选区下,均匀预设(all/none/单侧)走 applyStyle → 行列默认样式。
|
|
21
22
|
*/
|
|
22
23
|
const props = __props;
|
|
23
24
|
const cls = bem("sheet");
|
|
24
25
|
/** 当前线型 / 颜色 */
|
|
25
26
|
const borderLineStyle = ref("thin");
|
|
26
27
|
const borderColor = ref("#000000");
|
|
27
|
-
/**
|
|
28
|
+
/** 均匀边框补丁(可写进行/列默认样式);outer/inner 几何相关 → null */
|
|
29
|
+
function uniformBorderPatch(preset, edge) {
|
|
30
|
+
switch (preset) {
|
|
31
|
+
case "all": return { border: {
|
|
32
|
+
top: edge,
|
|
33
|
+
right: edge,
|
|
34
|
+
bottom: edge,
|
|
35
|
+
left: edge
|
|
36
|
+
} };
|
|
37
|
+
case "none": return { border: {
|
|
38
|
+
top: null,
|
|
39
|
+
right: null,
|
|
40
|
+
bottom: null,
|
|
41
|
+
left: null
|
|
42
|
+
} };
|
|
43
|
+
case "top": return { border: { top: edge } };
|
|
44
|
+
case "bottom": return { border: { bottom: edge } };
|
|
45
|
+
case "left": return { border: { left: edge } };
|
|
46
|
+
case "right": return { border: { right: edge } };
|
|
47
|
+
default: return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/** 应用边框预设:整行/整列均匀预设走 applyStyle;其余逐格批量(含邻居同步) */
|
|
28
51
|
function applyBorderPreset(preset) {
|
|
29
52
|
const range = currentRange(props.context);
|
|
30
53
|
if (!range) return;
|
|
@@ -33,7 +56,12 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
33
56
|
width: BORDER_STYLE_WIDTH[borderLineStyle.value],
|
|
34
57
|
color: borderColor.value
|
|
35
58
|
};
|
|
36
|
-
const
|
|
59
|
+
const uniform = props.context.resolveStyleTarget(range) !== "cell" ? uniformBorderPatch(preset, edge) : null;
|
|
60
|
+
if (uniform) {
|
|
61
|
+
props.context.applyStyle(range, uniform);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const items = buildBorderPresetItems(range, preset, edge, (addr) => props.context.getEffectiveStyle(addr)).map(({ addr, patch }) => ({
|
|
37
65
|
addr,
|
|
38
66
|
partial: patch
|
|
39
67
|
}));
|
|
@@ -13,17 +13,18 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
13
13
|
*/
|
|
14
14
|
const props = __props;
|
|
15
15
|
/** 填充颜色('' = 无填充) */
|
|
16
|
-
const fillColor = ref(
|
|
16
|
+
const fillColor = ref();
|
|
17
17
|
onMounted(() => {
|
|
18
18
|
const active = props.context.getSelection().activeCell;
|
|
19
|
-
const style = active ? props.context.
|
|
19
|
+
const style = active ? props.context.getEffectiveStyle(active) : void 0;
|
|
20
20
|
fillColor.value = style?.fill?.color ?? "";
|
|
21
21
|
});
|
|
22
22
|
/** 填充颜色变化('' = 无填充:清除 fill 保留边框) */
|
|
23
23
|
function applyFillColor(color) {
|
|
24
|
+
fillColor.value = color;
|
|
24
25
|
const range = currentRange(props.context);
|
|
25
26
|
if (!range) return;
|
|
26
|
-
props.context.
|
|
27
|
+
props.context.applyStyle(range, color ? { fill: { color } } : { fill: {} });
|
|
27
28
|
}
|
|
28
29
|
return (_ctx, _cache) => {
|
|
29
30
|
return openBlock(), createBlock(unref(UPalette), {
|
|
@@ -16,14 +16,14 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
16
16
|
const fontColor = ref("");
|
|
17
17
|
onMounted(() => {
|
|
18
18
|
const active = props.context.getSelection().activeCell;
|
|
19
|
-
const style = active ? props.context.
|
|
19
|
+
const style = active ? props.context.getEffectiveStyle(active) : void 0;
|
|
20
20
|
fontColor.value = style?.font?.color ?? "";
|
|
21
21
|
});
|
|
22
22
|
/** 字体颜色变化('' = 清除 color) */
|
|
23
23
|
function applyFontColor(color) {
|
|
24
24
|
const range = currentRange(props.context);
|
|
25
25
|
if (!range) return;
|
|
26
|
-
props.context.
|
|
26
|
+
props.context.applyStyle(range, color ? { font: { color } } : { font: { color: null } });
|
|
27
27
|
}
|
|
28
28
|
return (_ctx, _cache) => {
|
|
29
29
|
return openBlock(), createBlock(unref(UPalette), {
|
|
@@ -32,14 +32,14 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
32
32
|
const currentSize = ref(void 0);
|
|
33
33
|
onMounted(() => {
|
|
34
34
|
const active = props.context.getSelection().activeCell;
|
|
35
|
-
const style = active ? props.context.
|
|
35
|
+
const style = active ? props.context.getEffectiveStyle(active) : void 0;
|
|
36
36
|
currentSize.value = style?.font?.size;
|
|
37
37
|
});
|
|
38
38
|
function applyFontSize(size) {
|
|
39
39
|
const range = currentRange(props.context);
|
|
40
40
|
if (!range) return;
|
|
41
41
|
currentSize.value = size;
|
|
42
|
-
props.context.
|
|
42
|
+
props.context.applyStyle(range, { font: { size } });
|
|
43
43
|
}
|
|
44
44
|
return (_ctx, _cache) => {
|
|
45
45
|
return openBlock(), createElementBlock(Fragment, null, [createCommentVNode(" 下拉排列:每行一个字号;滚动用 desktop UScroll(自定义滚动条) "), createVNode(unref(UScroll), {
|
|
@@ -38,11 +38,14 @@ function wholeColRange(col, rowCount) {
|
|
|
38
38
|
col
|
|
39
39
|
});
|
|
40
40
|
}
|
|
41
|
-
/**
|
|
41
|
+
/**
|
|
42
|
+
* 渲染尺寸:模型已声明时以模型为准(删行可低于 props);未声明时回落 props。
|
|
43
|
+
* 与 SheetGrid / useSheetGrid 一致——避免 ensureTableSize(props) 把删行结果撑回。
|
|
44
|
+
*/
|
|
42
45
|
function resolveRenderSize(propsRows, propsCols, sheetRows, sheetCols) {
|
|
43
46
|
return {
|
|
44
|
-
rows:
|
|
45
|
-
cols:
|
|
47
|
+
rows: sheetRows > 0 ? sheetRows : propsRows ?? 100,
|
|
48
|
+
cols: sheetCols > 0 ? sheetCols : propsCols ?? 26
|
|
46
49
|
};
|
|
47
50
|
}
|
|
48
51
|
function insertCountRender(options) {
|
|
@@ -39,6 +39,14 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
39
39
|
type: Boolean,
|
|
40
40
|
default: true
|
|
41
41
|
},
|
|
42
|
+
showRowHeader: {
|
|
43
|
+
type: Boolean,
|
|
44
|
+
default: true
|
|
45
|
+
},
|
|
46
|
+
showColHeader: {
|
|
47
|
+
type: Boolean,
|
|
48
|
+
default: true
|
|
49
|
+
},
|
|
42
50
|
readonly: {
|
|
43
51
|
type: Boolean,
|
|
44
52
|
default: false
|
|
@@ -57,12 +57,15 @@ function useSheetGrid(options) {
|
|
|
57
57
|
const el = document.createElement("div");
|
|
58
58
|
el.className = "u-sheet__grid-instance";
|
|
59
59
|
host.appendChild(el);
|
|
60
|
+
const { rows, cols } = resolveRenderSize(props.rows, props.cols, sheet.rows, sheet.cols);
|
|
60
61
|
const grid = new SheetGrid({
|
|
61
62
|
container: el,
|
|
62
63
|
sheet,
|
|
63
|
-
rows
|
|
64
|
-
cols
|
|
64
|
+
rows,
|
|
65
|
+
cols,
|
|
65
66
|
readonly: props.readonly,
|
|
67
|
+
showRowHeader: props.showRowHeader,
|
|
68
|
+
showColHeader: props.showColHeader,
|
|
66
69
|
resolveDisplayValue: props.resolveDisplayValue,
|
|
67
70
|
resolveCellStyle: props.resolveCellStyle,
|
|
68
71
|
resolveCellRenderer: props.resolveCellRenderer,
|
|
@@ -172,8 +175,15 @@ function useSheetGrid(options) {
|
|
|
172
175
|
watch(() => [
|
|
173
176
|
props.rows,
|
|
174
177
|
props.cols,
|
|
175
|
-
props.readonly
|
|
176
|
-
|
|
178
|
+
props.readonly,
|
|
179
|
+
props.showRowHeader,
|
|
180
|
+
props.showColHeader
|
|
181
|
+
], ([nextRows, nextCols]) => {
|
|
182
|
+
const sheet = getActiveSheet();
|
|
183
|
+
if (nextRows != null) sheet.ensureTableSize(nextRows, 0);
|
|
184
|
+
if (nextCols != null) sheet.ensureTableSize(0, nextCols);
|
|
185
|
+
rebuildGrid();
|
|
186
|
+
});
|
|
177
187
|
onBeforeUnmount(() => {
|
|
178
188
|
invalidateAll();
|
|
179
189
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { defaultToolRegistry } from "../../tools/registry.js";
|
|
2
2
|
import { createSheetContext } from "../../tools/context.js";
|
|
3
|
+
import { resolveRenderSize } from "./sheet-context-menu.js";
|
|
3
4
|
import { computed, onBeforeUnmount, onMounted, ref, shallowRef, watch } from "vue";
|
|
4
5
|
import { Workbook } from "@veltra/sheet-core/core/workbook";
|
|
5
6
|
//#region src/components/sheet/use-sheet-state.ts
|
|
@@ -19,8 +20,8 @@ function useSheetState(props, emit, hooks) {
|
|
|
19
20
|
/** sheet 列表(tabs 渲染;由 sheets-change 同步) */
|
|
20
21
|
const sheetList = shallowRef(workbook.value.getSheets());
|
|
21
22
|
const activeSheet = computed(() => sheetList.value[activeIndex.value] ?? workbook.value.activeSheet);
|
|
22
|
-
/** 工具上下文:动态解析活动 sheet
|
|
23
|
-
const context = createSheetContext(() => activeSheet.value, () => workbook.value);
|
|
23
|
+
/** 工具上下文:动态解析活动 sheet / 工作簿 / 渲染尺寸,tab 切换后自动指向最新值 */
|
|
24
|
+
const context = createSheetContext(() => activeSheet.value, () => workbook.value, { resolveGridSize: () => resolveRenderSize(props.rows, props.cols, activeSheet.value.rows, activeSheet.value.cols) });
|
|
24
25
|
/** 工具栏状态版本号:visible/disabled/active 是 (ctx) => boolean 纯函数,状态源变化时 bump 触发重算 */
|
|
25
26
|
const stateTick = ref(0);
|
|
26
27
|
const bump = () => {
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { SheetContext, createSheetContext } from "./tools/context.js";
|
|
|
5
5
|
import { SheetTool, SheetToolGroup, SheetToolPopupType, defaultToolRegistry, registerTool, unregisterTool } from "./tools/registry.js";
|
|
6
6
|
import { SheetEmits, SheetExposed, SheetProps, _SheetExposed } from "./types/sheet.js";
|
|
7
7
|
import { ConditionalOperator, ConditionalRule, DatasetCatalogItem, DatasetField, DatasetRecords, ParamValues, QueryParamDef, QueryParamOption, QueryParamType, ReportAggregate, ReportBinding, ReportExpand, ReportPreset, ReportSort } from "./report/types.js";
|
|
8
|
-
import { REPORT_META_NAMESPACE, applyReportPreset, createReportBinding, formatBindingPlaceholder, formatCellAddress, inferColParentCandidate, inferDropPreset, inferReportPreset, inferRowParentCandidate, isExpansionBandRow, isHorizontalExpandBinding, isVerticalExpandBinding, listColParentCandidates, listRowParentCandidates, parseCellAddress, presetBindingPatch, setBindingCatalog } from "./report/binding.js";
|
|
8
|
+
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 "./report/binding.js";
|
|
9
9
|
import { ConditionalEvalContext, evaluateCondition, evaluateConditionalStyle, resolveRuleCompareValue, toComparableNumber } from "./report/rules/evaluate.js";
|
|
10
10
|
import { buildParamDefs, extractParamIds, resolveBoundDatasetParams } from "./report/params.js";
|
|
11
11
|
import { ReportColWidthEntry, buildColumnDefs, exportFilledReportXlsx, pxToExcelColWidth } from "./report/export-xlsx.js";
|
|
@@ -18,4 +18,4 @@ import "./report/index.js";
|
|
|
18
18
|
import { ReportViewerExposed, ReportViewerProps, _ReportViewerExposed } from "./types/report-viewer.js";
|
|
19
19
|
import { ReportDesignerEmits, ReportDesignerExposed, ReportDesignerProps, _ReportDesignerExposed } from "./types/report-designer.js";
|
|
20
20
|
import "./types/index.js";
|
|
21
|
-
export { type ConditionalEvalContext, ConditionalOperator, ConditionalRule, ConnectionType, ConnectorError, CreateHttpConnectorOptions, DEFAULT_CONNECTION_PORTS, DataConnection, DataConnector, DatasetCatalogItem, DatasetField, DatasetRecords, IncompatibleTemplateVersionError, ParamValues, QueryParamDef, QueryParamOption, QueryParamType, QueryResult, REPORT_META_NAMESPACE, REPORT_TEMPLATE_VERSION, ReportAggregate, ReportBinding, ReportColWidthEntry, ReportDatasetDef, type ReportDesignerEmits, type ReportDesignerExposed, type ReportDesignerProps, ReportExpand, ReportPreset, ReportSort, ReportTemplate, type ReportViewerExposed, type ReportViewerProps, Result, type SheetContext, type SheetEmits, type SheetExposed, type SheetProps, type SheetTool, type SheetToolGroup, type SheetToolPopupType, _sfc_main as UReportDesigner, _sfc_main$1 as UReportViewer, _sfc_main$2 as USheet, type _ReportDesignerExposed, type _ReportViewerExposed, type _SheetExposed, applyReportPreset, assertCompatibleTemplateVersion, buildColumnDefs, buildParamDefs, createHttpConnector, createReportBinding, createReportTemplate, createSheetContext, defaultToolRegistry, evaluateCondition, evaluateConditionalStyle, exportFilledReportXlsx, extractParamIds, fetchTemplateRecords, formatBindingPlaceholder, formatCellAddress, getBoundDatasetIds, getTemplateDatasets, inferColParentCandidate, inferDropPreset, inferReportPreset, inferRowParentCandidate, isExpansionBandRow, isHorizontalExpandBinding, isVerticalExpandBinding, listColParentCandidates, listRowParentCandidates, mapFilledColWidths, parseCellAddress, parseDateRangeValue, patchParamValues, presetBindingPatch, pxToExcelColWidth, registerTool, renderReport, resolveBoundDatasetParams, resolveFilledColWidths, resolveNumberParamValue, resolveParamDefaults, resolvePortOnTypeChange, resolveRuleCompareValue, resolveTemplateParams, setBindingCatalog, toComparableNumber, unregisterTool };
|
|
21
|
+
export { type ConditionalEvalContext, ConditionalOperator, ConditionalRule, ConnectionType, ConnectorError, CreateHttpConnectorOptions, DEFAULT_CONNECTION_PORTS, DataConnection, DataConnector, DatasetCatalogItem, DatasetField, DatasetRecords, IncompatibleTemplateVersionError, InferParentOptions, ListParentCandidateOptions, ParamValues, QueryParamDef, QueryParamOption, QueryParamType, QueryResult, REPORT_META_NAMESPACE, REPORT_TEMPLATE_VERSION, ReportAggregate, ReportBinding, ReportColWidthEntry, ReportDatasetDef, type ReportDesignerEmits, type ReportDesignerExposed, type ReportDesignerProps, ReportExpand, ReportPreset, ReportSort, ReportTemplate, type ReportViewerExposed, type ReportViewerProps, Result, type SheetContext, type SheetEmits, type SheetExposed, type SheetProps, type SheetTool, type SheetToolGroup, type SheetToolPopupType, _sfc_main as UReportDesigner, _sfc_main$1 as UReportViewer, _sfc_main$2 as USheet, type _ReportDesignerExposed, type _ReportViewerExposed, type _SheetExposed, applyReportPreset, assertCompatibleTemplateVersion, buildColumnDefs, buildParamDefs, createHttpConnector, createReportBinding, createReportTemplate, createSheetContext, defaultToolRegistry, 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, prefersGroupParent, presetBindingPatch, presetStillApplies, pxToExcelColWidth, registerTool, renderReport, resolveBoundDatasetParams, resolveFilledColWidths, resolveNumberParamValue, resolveParamDefaults, resolvePortOnTypeChange, resolveRuleCompareValue, resolveTemplateParams, setBindingCatalog, toComparableNumber, unregisterTool };
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { createSheetContext } from "./tools/context.js";
|
|
|
4
4
|
import _sfc_main$2 from "./components/sheet/sheet.js";
|
|
5
5
|
import { buildColumnDefs, exportFilledReportXlsx, pxToExcelColWidth } from "./report/export-xlsx.js";
|
|
6
6
|
import { parseDateRangeValue, patchParamValues, resolveNumberParamValue } from "./report/filter-bar.js";
|
|
7
|
-
import { REPORT_META_NAMESPACE, applyReportPreset, createReportBinding, formatBindingPlaceholder, formatCellAddress, inferColParentCandidate, inferDropPreset, inferReportPreset, inferRowParentCandidate, isExpansionBandRow, isHorizontalExpandBinding, isVerticalExpandBinding, listColParentCandidates, listRowParentCandidates, parseCellAddress, presetBindingPatch, setBindingCatalog } from "./report/binding.js";
|
|
7
|
+
import { 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 "./report/binding.js";
|
|
8
8
|
import { evaluateCondition, evaluateConditionalStyle, resolveRuleCompareValue, toComparableNumber } from "./report/rules/evaluate.js";
|
|
9
9
|
import { mapFilledColWidths } from "./report/render/builder.js";
|
|
10
10
|
import { renderReport, resolveFilledColWidths } from "./report/render/index.js";
|
|
@@ -13,4 +13,4 @@ import { IncompatibleTemplateVersionError, REPORT_TEMPLATE_VERSION, assertCompat
|
|
|
13
13
|
import _sfc_main$1 from "./components/report/report-viewer.js";
|
|
14
14
|
import { DEFAULT_CONNECTION_PORTS, createHttpConnector, resolvePortOnTypeChange } from "./report/connector.js";
|
|
15
15
|
import _sfc_main from "./components/report/report-designer.js";
|
|
16
|
-
export { DEFAULT_CONNECTION_PORTS, IncompatibleTemplateVersionError, REPORT_META_NAMESPACE, REPORT_TEMPLATE_VERSION, _sfc_main as UReportDesigner, _sfc_main$1 as UReportViewer, _sfc_main$2 as USheet, applyReportPreset, assertCompatibleTemplateVersion, buildColumnDefs, buildParamDefs, createHttpConnector, createReportBinding, createReportTemplate, createSheetContext, defaultToolRegistry, evaluateCondition, evaluateConditionalStyle, exportFilledReportXlsx, extractParamIds, fetchTemplateRecords, formatBindingPlaceholder, formatCellAddress, getBoundDatasetIds, getTemplateDatasets, inferColParentCandidate, inferDropPreset, inferReportPreset, inferRowParentCandidate, isExpansionBandRow, isHorizontalExpandBinding, isVerticalExpandBinding, listColParentCandidates, listRowParentCandidates, mapFilledColWidths, parseCellAddress, parseDateRangeValue, patchParamValues, presetBindingPatch, pxToExcelColWidth, registerTool, renderReport, resolveBoundDatasetParams, resolveFilledColWidths, resolveNumberParamValue, resolveParamDefaults, resolvePortOnTypeChange, resolveRuleCompareValue, resolveTemplateParams, setBindingCatalog, toComparableNumber, unregisterTool };
|
|
16
|
+
export { DEFAULT_CONNECTION_PORTS, IncompatibleTemplateVersionError, REPORT_META_NAMESPACE, REPORT_TEMPLATE_VERSION, _sfc_main as UReportDesigner, _sfc_main$1 as UReportViewer, _sfc_main$2 as USheet, applyReportPreset, assertCompatibleTemplateVersion, buildColumnDefs, buildParamDefs, createHttpConnector, createReportBinding, createReportTemplate, createSheetContext, defaultToolRegistry, 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, prefersGroupParent, presetBindingPatch, presetStillApplies, pxToExcelColWidth, registerTool, renderReport, resolveBoundDatasetParams, resolveFilledColWidths, resolveNumberParamValue, resolveParamDefaults, resolvePortOnTypeChange, resolveRuleCompareValue, resolveTemplateParams, setBindingCatalog, toComparableNumber, unregisterTool };
|
package/dist/report/binding.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DatasetCatalogItem, ReportBinding, ReportPreset } from "./types.js";
|
|
1
|
+
import { DatasetCatalogItem, ReportAggregate, ReportBinding, ReportPreset } from "./types.js";
|
|
2
2
|
import { CellAddress } from "@veltra/sheet-core";
|
|
3
3
|
//#region src/report/binding.d.ts
|
|
4
4
|
declare function setBindingCatalog(catalog: DatasetCatalogItem[]): void;
|
|
@@ -13,24 +13,55 @@ declare function applyReportPreset(binding: ReportBinding, preset: ReportPreset,
|
|
|
13
13
|
}): ReportBinding;
|
|
14
14
|
declare function isVerticalExpandBinding(binding: ReportBinding): boolean;
|
|
15
15
|
declare function isHorizontalExpandBinding(binding: ReportBinding): boolean;
|
|
16
|
+
declare function isRowGroupBinding(binding: ReportBinding): boolean;
|
|
17
|
+
declare function isColGroupBinding(binding: ReportBinding): boolean;
|
|
18
|
+
declare function isReductionAggregate(aggregate: ReportAggregate): boolean;
|
|
19
|
+
/** 小计 / 汇总 / 交叉格的父格候选只列分组头 */
|
|
20
|
+
declare function prefersGroupParent(binding: ReportBinding): boolean;
|
|
21
|
+
/** 当前 expand / aggregate 是否仍属于已写入的预设族(同族内改聚合不掉到「自定义」) */
|
|
22
|
+
declare function presetStillApplies(binding: ReportBinding): boolean;
|
|
23
|
+
type GetBindingAt = (addr: CellAddress) => ReportBinding | undefined;
|
|
24
|
+
interface InferParentOptions {
|
|
25
|
+
/** 小计落格:必须优先分组头,禁止把同列/同行明细当成父格 */
|
|
26
|
+
preferGroup?: boolean;
|
|
27
|
+
}
|
|
16
28
|
/** 指定模板行是否含纵向扩展绑定(展开带行) */
|
|
17
|
-
declare function isExpansionBandRow(row: number, getBindingAt:
|
|
18
|
-
/**
|
|
19
|
-
declare function
|
|
29
|
+
declare function isExpansionBandRow(row: number, getBindingAt: GetBindingAt, scanCols?: number): boolean;
|
|
30
|
+
/** 指定模板列是否含横向扩展绑定(展开带列) */
|
|
31
|
+
declare function isExpansionBandCol(col: number, getBindingAt: GetBindingAt, scanRows?: number): boolean;
|
|
32
|
+
/** 落格时推断预设:默认明细;数值字段且位于展开带正下方或正右相邻 → 小计 */
|
|
33
|
+
declare function inferDropPreset(addr: CellAddress, fieldType: DatasetCatalogItem['fields'][number]['type'], getBindingAt: GetBindingAt): ReportPreset;
|
|
34
|
+
interface ListParentCandidateOptions {
|
|
35
|
+
preferGroup?: boolean;
|
|
36
|
+
}
|
|
20
37
|
/** 同数据集纵向扩展绑定格(行方向父格下拉候选) */
|
|
21
38
|
declare function listRowParentCandidates(binding: ReportBinding, entries: ReadonlyArray<{
|
|
22
39
|
addr: CellAddress;
|
|
23
40
|
binding: ReportBinding;
|
|
24
|
-
}
|
|
41
|
+
}>, options?: ListParentCandidateOptions): CellAddress[];
|
|
25
42
|
/** 同数据集横向扩展绑定格(列方向父格下拉候选) */
|
|
26
43
|
declare function listColParentCandidates(binding: ReportBinding, entries: ReadonlyArray<{
|
|
27
44
|
addr: CellAddress;
|
|
28
45
|
binding: ReportBinding;
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
46
|
+
}>, options?: ListParentCandidateOptions): CellAddress[];
|
|
47
|
+
/**
|
|
48
|
+
* 行方向父格推断:
|
|
49
|
+
* 1. 同行向左:先找分组头,否则最近纵向扩展格
|
|
50
|
+
* 2. 上方各行整行扫描:每行先找分组头,再退回任意纵向扩展格
|
|
51
|
+
* 小计(preferGroup)禁止把明细当成父格
|
|
52
|
+
*/
|
|
53
|
+
declare function inferRowParentCandidate(addr: CellAddress, getBindingAt: GetBindingAt, options?: InferParentOptions): CellAddress | null;
|
|
54
|
+
/**
|
|
55
|
+
* 列方向父格推断(与行方向对称):
|
|
56
|
+
* 1. 同列向上:先找列分组头,否则最近横向扩展格
|
|
57
|
+
* 2. 左侧各列整列扫描:每列先找列分组头
|
|
58
|
+
* 列小计(preferGroup)禁止把交叉格/明细当成列父格
|
|
59
|
+
*/
|
|
60
|
+
declare function inferColParentCandidate(addr: CellAddress, getBindingAt: GetBindingAt, options?: InferParentOptions): CellAddress | null;
|
|
61
|
+
/**
|
|
62
|
+
* 按预设写入落格父格:明细/分组/交叉双方向推断;小计按「下方行小计 / 右侧列小计」只挂对应轴。
|
|
63
|
+
*/
|
|
64
|
+
declare function inferParentsForPreset(addr: CellAddress, preset: ReportPreset, getBindingAt: GetBindingAt): Pick<ReportBinding, 'rowParent' | 'colParent'>;
|
|
34
65
|
/** 从绑定字段推断预设;不匹配任何预设时返回 null(自定义) */
|
|
35
66
|
declare function inferReportPreset(binding: ReportBinding): ReportPreset | null;
|
|
36
67
|
/** 默认明细 + 纵向扩展 */
|
|
@@ -39,7 +70,14 @@ declare function createReportBinding(dataset: DatasetCatalogItem, fieldName: str
|
|
|
39
70
|
declare function formatCellAddress(addr: CellAddress): string;
|
|
40
71
|
/** A1 标签 → 设计地址;非法输入返回 null */
|
|
41
72
|
declare function parseCellAddress(label: string): CellAddress | null;
|
|
73
|
+
/** Binding Placeholder 分段文案(聚合标签 + 字段标签),供徽章分色渲染等场景使用 */
|
|
74
|
+
declare function formatBindingPlaceholderParts(binding: ReportBinding, resolveLabel?: (datasetId: string, fieldName: string) => string): {
|
|
75
|
+
tag: string;
|
|
76
|
+
label: string;
|
|
77
|
+
};
|
|
42
78
|
/** Binding Placeholder 中文可读文案(如「分组 · 客户」) */
|
|
43
79
|
declare function formatBindingPlaceholder(binding: ReportBinding, resolveLabel?: (datasetId: string, fieldName: string) => string): string;
|
|
80
|
+
/** 父格下拉候选文案(如「分组 · 客户 (A2)」) */
|
|
81
|
+
declare function formatParentCandidateLabel(addr: CellAddress, binding: ReportBinding, resolveLabel?: (datasetId: string, fieldName: string) => string): string;
|
|
44
82
|
//#endregion
|
|
45
|
-
export { REPORT_META_NAMESPACE, applyReportPreset, createReportBinding, formatBindingPlaceholder, formatCellAddress, inferColParentCandidate, inferDropPreset, inferReportPreset, inferRowParentCandidate, isExpansionBandRow, isHorizontalExpandBinding, isVerticalExpandBinding, listColParentCandidates, listRowParentCandidates, parseCellAddress, presetBindingPatch, setBindingCatalog };
|
|
83
|
+
export { 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 };
|
package/dist/report/binding.js
CHANGED
|
@@ -65,10 +65,34 @@ function isVerticalExpandBinding(binding) {
|
|
|
65
65
|
return binding.expand === "down" && (binding.aggregate === "group" || binding.aggregate === "list");
|
|
66
66
|
}
|
|
67
67
|
function isHorizontalExpandBinding(binding) {
|
|
68
|
+
return binding.expand === "right" && (binding.aggregate === "group" || binding.aggregate === "list");
|
|
69
|
+
}
|
|
70
|
+
function isRowGroupBinding(binding) {
|
|
71
|
+
return binding.expand === "down" && binding.aggregate === "group";
|
|
72
|
+
}
|
|
73
|
+
function isColGroupBinding(binding) {
|
|
68
74
|
return binding.expand === "right" && binding.aggregate === "group";
|
|
69
75
|
}
|
|
76
|
+
function isReductionAggregate(aggregate) {
|
|
77
|
+
return aggregate === "sum" || aggregate === "avg" || aggregate === "count" || aggregate === "max" || aggregate === "min";
|
|
78
|
+
}
|
|
79
|
+
/** 小计 / 汇总 / 交叉格的父格候选只列分组头 */
|
|
80
|
+
function prefersGroupParent(binding) {
|
|
81
|
+
if (binding.preset === "subtotal" || binding.preset === "grandTotal" || binding.preset === "cross") return true;
|
|
82
|
+
return binding.expand === "none" && isReductionAggregate(binding.aggregate);
|
|
83
|
+
}
|
|
84
|
+
/** 当前 expand / aggregate 是否仍属于已写入的预设族(同族内改聚合不掉到「自定义」) */
|
|
85
|
+
function presetStillApplies(binding) {
|
|
86
|
+
const preset = binding.preset;
|
|
87
|
+
if (!preset) return false;
|
|
88
|
+
if (preset === "groupHeader") return binding.aggregate === "group" && (binding.expand === "down" || binding.expand === "right");
|
|
89
|
+
if (preset === "detail") return binding.aggregate === "list" && (binding.expand === "down" || binding.expand === "right");
|
|
90
|
+
return binding.expand === "none" && isReductionAggregate(binding.aggregate);
|
|
91
|
+
}
|
|
92
|
+
const DEFAULT_SCAN_COLS = 64;
|
|
93
|
+
const DEFAULT_SCAN_ROWS = 64;
|
|
70
94
|
/** 指定模板行是否含纵向扩展绑定(展开带行) */
|
|
71
|
-
function isExpansionBandRow(row, getBindingAt, scanCols =
|
|
95
|
+
function isExpansionBandRow(row, getBindingAt, scanCols = DEFAULT_SCAN_COLS) {
|
|
72
96
|
for (let col = 0; col < scanCols; col++) {
|
|
73
97
|
const binding = getBindingAt({
|
|
74
98
|
row,
|
|
@@ -78,65 +102,186 @@ function isExpansionBandRow(row, getBindingAt, scanCols = 64) {
|
|
|
78
102
|
}
|
|
79
103
|
return false;
|
|
80
104
|
}
|
|
81
|
-
/**
|
|
105
|
+
/** 指定模板列是否含横向扩展绑定(展开带列) */
|
|
106
|
+
function isExpansionBandCol(col, getBindingAt, scanRows = DEFAULT_SCAN_ROWS) {
|
|
107
|
+
for (let row = 0; row < scanRows; row++) {
|
|
108
|
+
const binding = getBindingAt({
|
|
109
|
+
row,
|
|
110
|
+
col
|
|
111
|
+
});
|
|
112
|
+
if (binding && isHorizontalExpandBinding(binding)) return true;
|
|
113
|
+
}
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
/** 落格时推断预设:默认明细;数值字段且位于展开带正下方或正右相邻 → 小计 */
|
|
82
117
|
function inferDropPreset(addr, fieldType, getBindingAt) {
|
|
83
|
-
if (fieldType
|
|
118
|
+
if (fieldType !== "number") return "detail";
|
|
119
|
+
if (addr.row > 0 && isExpansionBandRow(addr.row - 1, getBindingAt)) return "subtotal";
|
|
120
|
+
if (addr.col > 0 && isExpansionBandCol(addr.col - 1, getBindingAt)) return "subtotal";
|
|
84
121
|
return "detail";
|
|
85
122
|
}
|
|
86
123
|
/** 同数据集纵向扩展绑定格(行方向父格下拉候选) */
|
|
87
|
-
function listRowParentCandidates(binding, entries) {
|
|
124
|
+
function listRowParentCandidates(binding, entries, options) {
|
|
125
|
+
const preferGroup = options?.preferGroup === true;
|
|
88
126
|
const candidates = [];
|
|
89
127
|
for (const entry of entries) {
|
|
90
128
|
if (entry.binding.dataset !== binding.dataset) continue;
|
|
91
|
-
if (
|
|
129
|
+
if (preferGroup) {
|
|
130
|
+
if (!isRowGroupBinding(entry.binding)) continue;
|
|
131
|
+
} else if (!isVerticalExpandBinding(entry.binding)) continue;
|
|
92
132
|
candidates.push(entry.addr);
|
|
93
133
|
}
|
|
94
134
|
return candidates;
|
|
95
135
|
}
|
|
96
136
|
/** 同数据集横向扩展绑定格(列方向父格下拉候选) */
|
|
97
|
-
function listColParentCandidates(binding, entries) {
|
|
137
|
+
function listColParentCandidates(binding, entries, options) {
|
|
138
|
+
const preferGroup = options?.preferGroup === true;
|
|
98
139
|
const candidates = [];
|
|
99
140
|
for (const entry of entries) {
|
|
100
141
|
if (entry.binding.dataset !== binding.dataset) continue;
|
|
101
|
-
if (
|
|
142
|
+
if (preferGroup) {
|
|
143
|
+
if (!isColGroupBinding(entry.binding)) continue;
|
|
144
|
+
} else if (!isHorizontalExpandBinding(entry.binding)) continue;
|
|
102
145
|
candidates.push(entry.addr);
|
|
103
146
|
}
|
|
104
147
|
return candidates;
|
|
105
148
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
149
|
+
function betterHit(current, next) {
|
|
150
|
+
if (!current) return true;
|
|
151
|
+
if (next.distance !== current.distance) return next.distance < current.distance;
|
|
152
|
+
return next.addr.col + next.addr.row < current.addr.col + current.addr.row;
|
|
153
|
+
}
|
|
154
|
+
function pickExpandHit(hits, preferGroup) {
|
|
155
|
+
let group = null;
|
|
156
|
+
let expand = null;
|
|
157
|
+
for (const hit of hits) {
|
|
158
|
+
if (hit.group && betterHit(group, hit)) group = hit;
|
|
159
|
+
if (betterHit(expand, hit)) expand = hit;
|
|
160
|
+
}
|
|
161
|
+
if (preferGroup) return group?.addr ?? null;
|
|
162
|
+
return group?.addr ?? expand?.addr ?? null;
|
|
163
|
+
}
|
|
164
|
+
function scanVerticalOnRow(row, originCol, colStart, colEnd, getBindingAt) {
|
|
165
|
+
const hits = [];
|
|
166
|
+
for (let col = colStart; col < colEnd; col++) {
|
|
109
167
|
const binding = getBindingAt({
|
|
110
168
|
row,
|
|
111
|
-
col
|
|
169
|
+
col
|
|
170
|
+
});
|
|
171
|
+
if (!binding || !isVerticalExpandBinding(binding)) continue;
|
|
172
|
+
hits.push({
|
|
173
|
+
addr: {
|
|
174
|
+
row,
|
|
175
|
+
col
|
|
176
|
+
},
|
|
177
|
+
group: isRowGroupBinding(binding),
|
|
178
|
+
distance: Math.abs(col - originCol)
|
|
112
179
|
});
|
|
113
|
-
if (binding && isVerticalExpandBinding(binding)) return {
|
|
114
|
-
row,
|
|
115
|
-
col: addr.col
|
|
116
|
-
};
|
|
117
180
|
}
|
|
118
|
-
return
|
|
181
|
+
return hits;
|
|
119
182
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
for (let
|
|
183
|
+
function scanHorizontalOnCol(col, originRow, rowStart, rowEnd, getBindingAt) {
|
|
184
|
+
const hits = [];
|
|
185
|
+
for (let row = rowStart; row < rowEnd; row++) {
|
|
123
186
|
const binding = getBindingAt({
|
|
124
|
-
row
|
|
187
|
+
row,
|
|
125
188
|
col
|
|
126
189
|
});
|
|
127
|
-
if (binding
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
190
|
+
if (!binding || !isHorizontalExpandBinding(binding)) continue;
|
|
191
|
+
hits.push({
|
|
192
|
+
addr: {
|
|
193
|
+
row,
|
|
194
|
+
col
|
|
195
|
+
},
|
|
196
|
+
group: isColGroupBinding(binding),
|
|
197
|
+
distance: Math.abs(row - originRow)
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
return hits;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* 行方向父格推断:
|
|
204
|
+
* 1. 同行向左:先找分组头,否则最近纵向扩展格
|
|
205
|
+
* 2. 上方各行整行扫描:每行先找分组头,再退回任意纵向扩展格
|
|
206
|
+
* 小计(preferGroup)禁止把明细当成父格
|
|
207
|
+
*/
|
|
208
|
+
function inferRowParentCandidate(addr, getBindingAt, options) {
|
|
209
|
+
const preferGroup = options?.preferGroup === true;
|
|
210
|
+
const sameRow = pickExpandHit(scanVerticalOnRow(addr.row, addr.col, 0, addr.col, getBindingAt), preferGroup);
|
|
211
|
+
if (sameRow) return sameRow;
|
|
212
|
+
for (let row = addr.row - 1; row >= 0; row--) {
|
|
213
|
+
const found = pickExpandHit(scanVerticalOnRow(row, addr.col, 0, DEFAULT_SCAN_COLS, getBindingAt), preferGroup);
|
|
214
|
+
if (found) return found;
|
|
215
|
+
}
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* 列方向父格推断(与行方向对称):
|
|
220
|
+
* 1. 同列向上:先找列分组头,否则最近横向扩展格
|
|
221
|
+
* 2. 左侧各列整列扫描:每列先找列分组头
|
|
222
|
+
* 列小计(preferGroup)禁止把交叉格/明细当成列父格
|
|
223
|
+
*/
|
|
224
|
+
function inferColParentCandidate(addr, getBindingAt, options) {
|
|
225
|
+
const preferGroup = options?.preferGroup === true;
|
|
226
|
+
const sameCol = pickExpandHit(scanHorizontalOnCol(addr.col, addr.row, 0, addr.row, getBindingAt), preferGroup);
|
|
227
|
+
if (sameCol) return sameCol;
|
|
228
|
+
for (let col = addr.col - 1; col >= 0; col--) {
|
|
229
|
+
const found = pickExpandHit(scanHorizontalOnCol(col, addr.row, 0, DEFAULT_SCAN_ROWS, getBindingAt), preferGroup);
|
|
230
|
+
if (found) return found;
|
|
131
231
|
}
|
|
132
232
|
return null;
|
|
133
233
|
}
|
|
234
|
+
function suggestsColumnSubtotal(above) {
|
|
235
|
+
if (!above) return false;
|
|
236
|
+
return isHorizontalExpandBinding(above) || !!above.colParent || above.preset === "cross";
|
|
237
|
+
}
|
|
238
|
+
function suggestsRowSubtotal(left) {
|
|
239
|
+
if (!left) return false;
|
|
240
|
+
return isVerticalExpandBinding(left) || !!left.rowParent || left.preset === "cross";
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* 按预设写入落格父格:明细/分组/交叉双方向推断;小计按「下方行小计 / 右侧列小计」只挂对应轴。
|
|
244
|
+
*/
|
|
245
|
+
function inferParentsForPreset(addr, preset, getBindingAt) {
|
|
246
|
+
if (preset === "grandTotal") return {};
|
|
247
|
+
const preferGroup = preset === "subtotal" || preset === "cross";
|
|
248
|
+
const rowParent = inferRowParentCandidate(addr, getBindingAt, { preferGroup }) ?? void 0;
|
|
249
|
+
const colParent = inferColParentCandidate(addr, getBindingAt, { preferGroup }) ?? void 0;
|
|
250
|
+
if (preset !== "subtotal") return {
|
|
251
|
+
...rowParent ? { rowParent } : {},
|
|
252
|
+
...colParent ? { colParent } : {}
|
|
253
|
+
};
|
|
254
|
+
const above = addr.row > 0 ? getBindingAt({
|
|
255
|
+
row: addr.row - 1,
|
|
256
|
+
col: addr.col
|
|
257
|
+
}) : void 0;
|
|
258
|
+
const left = addr.col > 0 ? getBindingAt({
|
|
259
|
+
row: addr.row,
|
|
260
|
+
col: addr.col - 1
|
|
261
|
+
}) : void 0;
|
|
262
|
+
const belowBand = addr.row > 0 && isExpansionBandRow(addr.row - 1, getBindingAt);
|
|
263
|
+
const rightOfBand = addr.col > 0 && isExpansionBandCol(addr.col - 1, getBindingAt);
|
|
264
|
+
const columnSubtotal = suggestsColumnSubtotal(above) || rightOfBand && !suggestsRowSubtotal(left);
|
|
265
|
+
const rowSubtotal = suggestsRowSubtotal(left) || belowBand && !columnSubtotal;
|
|
266
|
+
const result = {};
|
|
267
|
+
if (rowSubtotal && rowParent) result.rowParent = rowParent;
|
|
268
|
+
if (columnSubtotal && colParent) result.colParent = colParent;
|
|
269
|
+
if (!rowSubtotal && !columnSubtotal) if (belowBand && rowParent) result.rowParent = rowParent;
|
|
270
|
+
else if (rightOfBand && colParent) result.colParent = colParent;
|
|
271
|
+
else {
|
|
272
|
+
if (rowParent) result.rowParent = rowParent;
|
|
273
|
+
if (colParent) result.colParent = colParent;
|
|
274
|
+
}
|
|
275
|
+
return result;
|
|
276
|
+
}
|
|
134
277
|
/** 从绑定字段推断预设;不匹配任何预设时返回 null(自定义) */
|
|
135
278
|
function inferReportPreset(binding) {
|
|
136
279
|
if (binding.preset) return binding.preset;
|
|
137
|
-
if (binding.expand === "none" && binding.aggregate
|
|
138
|
-
|
|
139
|
-
|
|
280
|
+
if (binding.expand === "none" && isReductionAggregate(binding.aggregate)) {
|
|
281
|
+
if (binding.rowParent && binding.colParent) return "cross";
|
|
282
|
+
if (binding.rowParent || binding.colParent) return "subtotal";
|
|
283
|
+
return "grandTotal";
|
|
284
|
+
}
|
|
140
285
|
if (binding.aggregate === "group" && (binding.expand === "down" || binding.expand === "right")) return "groupHeader";
|
|
141
286
|
if (binding.aggregate === "list" && (binding.expand === "down" || binding.expand === "right")) return "detail";
|
|
142
287
|
return null;
|
|
@@ -167,9 +312,21 @@ function resolveFieldLabel(datasetId, fieldName, resolveLabel) {
|
|
|
167
312
|
if (override) return override;
|
|
168
313
|
return (bindingCatalog.find((d) => d.id === datasetId)?.fields.find((f) => f.name === fieldName))?.label ?? fieldName;
|
|
169
314
|
}
|
|
315
|
+
/** Binding Placeholder 分段文案(聚合标签 + 字段标签),供徽章分色渲染等场景使用 */
|
|
316
|
+
function formatBindingPlaceholderParts(binding, resolveLabel) {
|
|
317
|
+
return {
|
|
318
|
+
tag: AGGREGATE_PLACEHOLDER_TAG[binding.aggregate],
|
|
319
|
+
label: resolveFieldLabel(binding.dataset, binding.field, resolveLabel)
|
|
320
|
+
};
|
|
321
|
+
}
|
|
170
322
|
/** Binding Placeholder 中文可读文案(如「分组 · 客户」) */
|
|
171
323
|
function formatBindingPlaceholder(binding, resolveLabel) {
|
|
172
|
-
|
|
324
|
+
const { tag, label } = formatBindingPlaceholderParts(binding, resolveLabel);
|
|
325
|
+
return `${tag} · ${label}`;
|
|
326
|
+
}
|
|
327
|
+
/** 父格下拉候选文案(如「分组 · 客户 (A2)」) */
|
|
328
|
+
function formatParentCandidateLabel(addr, binding, resolveLabel) {
|
|
329
|
+
return `${formatBindingPlaceholder(binding, resolveLabel)} (${formatCellAddress(addr)})`;
|
|
173
330
|
}
|
|
174
331
|
//#endregion
|
|
175
|
-
export { REPORT_META_NAMESPACE, applyReportPreset, createReportBinding, formatBindingPlaceholder, formatCellAddress, inferColParentCandidate, inferDropPreset, inferReportPreset, inferRowParentCandidate, isExpansionBandRow, isHorizontalExpandBinding, isVerticalExpandBinding, listColParentCandidates, listRowParentCandidates, parseCellAddress, presetBindingPatch, setBindingCatalog };
|
|
332
|
+
export { 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 };
|
package/dist/report/connector.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Sheet } from "@veltra/sheet-core";
|
|
2
2
|
import { ColumnDef } from "hucre";
|
|
3
3
|
//#region src/report/export-xlsx.d.ts
|
|
4
|
-
/** 列宽条目:模型列索引 →
|
|
4
|
+
/** 列宽条目:模型列索引 → 像素宽(与 SheetSnapshot.colWidths 同构) */
|
|
5
5
|
type ReportColWidthEntry = readonly [number, number];
|
|
6
6
|
/** VTable 像素列宽 → Excel 字符宽度(近似换算) */
|
|
7
7
|
declare function pxToExcelColWidth(px: number): number;
|
|
@@ -10,10 +10,8 @@ declare function buildColumnDefs(colWidths: ReadonlyArray<ReportColWidthEntry>):
|
|
|
10
10
|
/**
|
|
11
11
|
* 将已填充的 Sheet(Filled Report)导出为保真 XLSX(合并 / 样式 / 行高 / 列宽)。
|
|
12
12
|
* 条件样式颜色已在 renderReport 展开阶段打平进 StylePool(ADR-0001 决策 2)。
|
|
13
|
-
*
|
|
14
|
-
* 与 `exportWorkbookXlsx`(sheet-core)的差异:列宽未进 SheetSnapshot,
|
|
15
|
-
* 只能经 VTable 运行时读取,故这里接收显式列宽并写入 columns 定义。
|
|
13
|
+
* 列宽取自 sheet 模型(`getColWidths`)。
|
|
16
14
|
*/
|
|
17
|
-
declare function exportFilledReportXlsx(sheet: Sheet
|
|
15
|
+
declare function exportFilledReportXlsx(sheet: Sheet): Promise<Uint8Array>;
|
|
18
16
|
//#endregion
|
|
19
17
|
export { ReportColWidthEntry, buildColumnDefs, exportFilledReportXlsx, pxToExcelColWidth };
|