@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,57 +0,0 @@
|
|
|
1
|
-
import { ParamValues } from "../report/types.js";
|
|
2
|
-
import { ReportColWidthEntry } from "../report/export-xlsx.js";
|
|
3
|
-
import { DataConnector } from "../report/connector.js";
|
|
4
|
-
import { ReportTemplate } from "../report/template.js";
|
|
5
|
-
import { ResolveReportTemplate } from "../report/drill.js";
|
|
6
|
-
import { ReportPrintOptions } from "../report/print.js";
|
|
7
|
-
import "../report/index.js";
|
|
8
|
-
import { DeconstructValue } from "@veltra/utils";
|
|
9
|
-
import { Workbook } from "@veltra/sheet-core/core/workbook";
|
|
10
|
-
//#region src/types/report-viewer.d.ts
|
|
11
|
-
/** 报表查看器组件属性(ADR-0003 决策 2) */
|
|
12
|
-
interface ReportViewerProps {
|
|
13
|
-
/** 数据连接器(如 `createHttpConnector({ endpoint })`) */
|
|
14
|
-
connector: DataConnector;
|
|
15
|
-
/**
|
|
16
|
-
* 自包含 Report Template(SheetSnapshot + 内嵌数据集定义,见 `ReportTemplate`):
|
|
17
|
-
* 查看器据此提取实际绑定数据集的查询参数并集生成 Filter Bar,并经连接器取数展开渲染
|
|
18
|
-
*/
|
|
19
|
-
template: ReportTemplate;
|
|
20
|
-
/** 承载填充报表的工作簿(USheet 先例:缺省内部自建单 sheet 工作簿) */
|
|
21
|
-
workbook?: Workbook;
|
|
22
|
-
/**
|
|
23
|
-
* 列宽显式覆盖(可选):优先于模板 `colWidths` / 展开映射结果写入模型与网格。
|
|
24
|
-
* 列宽已进 `SheetSnapshot.colWidths`,通常无需再传。
|
|
25
|
-
*/
|
|
26
|
-
colWidths?: ReadonlyArray<ReportColWidthEntry>;
|
|
27
|
-
/**
|
|
28
|
-
* 下钻目标模板解析契约(可选,内核共享类型):单击配了下钻的绑定格时按 `target` 引用取目标模板。
|
|
29
|
-
* 解析失败(抛错 / reject,或宿主实现返回空值)时查看器给出可读提示并停留当前报。
|
|
30
|
-
* 缺省时下钻不生效(无点击行为与可点视觉提示)。
|
|
31
|
-
*/
|
|
32
|
-
resolveTemplate?: ResolveReportTemplate;
|
|
33
|
-
/**
|
|
34
|
-
* Filter Bar 初值(可选):与当前模板参数默认值合并,显式键覆盖默认值。
|
|
35
|
-
* 仅在根模板载入时播种(下钻弹框传入映射参数);缺省则只用参数默认值。
|
|
36
|
-
*/
|
|
37
|
-
initialValues?: ParamValues;
|
|
38
|
-
}
|
|
39
|
-
/** 在组件内部引用 */
|
|
40
|
-
interface _ReportViewerExposed {
|
|
41
|
-
/** 重新取数并展开渲染(外部状态变化后主动刷新报表) */
|
|
42
|
-
refresh: () => Promise<void>;
|
|
43
|
-
/**
|
|
44
|
-
* 导出填充报表为 XLSX(取数完成前拒绝;内部读取填充 sheet 与运行时列宽)。
|
|
45
|
-
* 不内置导出按钮,工具栏由下游决定。
|
|
46
|
-
*/
|
|
47
|
-
exportXlsx: () => Promise<void>;
|
|
48
|
-
/**
|
|
49
|
-
* 打印填充报表(纯前端:模型 → 打印 HTML → 隐藏 iframe 调起浏览器打印;
|
|
50
|
-
* 取数完成前拒绝)。不内置打印按钮,工具栏由下游决定。
|
|
51
|
-
*/
|
|
52
|
-
print: (options?: ReportPrintOptions) => void;
|
|
53
|
-
}
|
|
54
|
-
/** 报表查看器组件暴露的方法 */
|
|
55
|
-
type ReportViewerExposed = DeconstructValue<_ReportViewerExposed>;
|
|
56
|
-
//#endregion
|
|
57
|
-
export { ReportViewerExposed, ReportViewerProps, _ReportViewerExposed };
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { Sheet } from '@veltra/sheet-core'
|
|
2
|
-
import type { CellAddress } from '@veltra/sheet-core'
|
|
3
|
-
import { describe, expect, it } from 'vitest'
|
|
4
|
-
|
|
5
|
-
import { REPORT_META_NAMESPACE, createReportBinding } from '../../../report/binding'
|
|
6
|
-
import type { DatasetCatalogItem, ReportBinding } from '../../../report/types'
|
|
7
|
-
import { badgeLayoutProps, createBindingBadgeRenderer } from '../binding-badge'
|
|
8
|
-
|
|
9
|
-
// ---- 内联 fixtures ----
|
|
10
|
-
|
|
11
|
-
const ORDERS_DATASET: DatasetCatalogItem = {
|
|
12
|
-
id: 'orders',
|
|
13
|
-
label: '销售明细',
|
|
14
|
-
fields: [
|
|
15
|
-
{ name: 'customer', label: '客户', type: 'string' },
|
|
16
|
-
{ name: 'amount', label: '金额', type: 'number' }
|
|
17
|
-
]
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const ADDR = { row: 1, col: 3 }
|
|
21
|
-
|
|
22
|
-
function bindingMap(entries: Array<{ addr: CellAddress; binding: ReportBinding }>) {
|
|
23
|
-
const map = new Map<string, ReportBinding>()
|
|
24
|
-
for (const { addr, binding } of entries) map.set(`${addr.row},${addr.col}`, binding)
|
|
25
|
-
return (addr: CellAddress) => map.get(`${addr.row},${addr.col}`)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
describe('badgeLayoutProps(单元格对齐 → 徽章容器 flex 映射)', () => {
|
|
29
|
-
it('缺省对齐 → 主轴起点 + 交叉轴居中(向后兼容)', () => {
|
|
30
|
-
expect(badgeLayoutProps(undefined)).toEqual({
|
|
31
|
-
justifyContent: 'flex-start',
|
|
32
|
-
alignItems: 'center'
|
|
33
|
-
})
|
|
34
|
-
expect(badgeLayoutProps({})).toEqual({ justifyContent: 'flex-start', alignItems: 'center' })
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
it('horizontal center / right / left → justifyContent', () => {
|
|
38
|
-
expect(badgeLayoutProps({ horizontal: 'center' }).justifyContent).toBe('center')
|
|
39
|
-
expect(badgeLayoutProps({ horizontal: 'right' }).justifyContent).toBe('flex-end')
|
|
40
|
-
expect(badgeLayoutProps({ horizontal: 'left' }).justifyContent).toBe('flex-start')
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
it('vertical bottom / top / middle → alignItems', () => {
|
|
44
|
-
expect(badgeLayoutProps({ vertical: 'bottom' }).alignItems).toBe('flex-end')
|
|
45
|
-
expect(badgeLayoutProps({ vertical: 'top' }).alignItems).toBe('flex-start')
|
|
46
|
-
expect(badgeLayoutProps({ vertical: 'middle' }).alignItems).toBe('center')
|
|
47
|
-
})
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
describe('createBindingBadgeRenderer', () => {
|
|
51
|
-
it('未绑定格返回 undefined 回落默认渲染', () => {
|
|
52
|
-
const renderer = createBindingBadgeRenderer(bindingMap([]))
|
|
53
|
-
expect(renderer(ADDR, undefined)).toBeUndefined()
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
it('绑定格不传 resolveAlign 保持左对齐徽章(向后兼容)', () => {
|
|
57
|
-
const binding = createReportBinding(ORDERS_DATASET, 'amount')
|
|
58
|
-
const renderer = createBindingBadgeRenderer(bindingMap([{ addr: ADDR, binding }]))
|
|
59
|
-
const layout = renderer(ADDR, undefined)
|
|
60
|
-
expect(layout?.renderDefault).toBe(false)
|
|
61
|
-
expect(layout?.rootContainer.attribute.justifyContent).toBe('flex-start')
|
|
62
|
-
expect(layout?.rootContainer.attribute.alignItems).toBe('center')
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
it('绑定格容器跟随 resolveAlign 的水平 / 垂直对齐', () => {
|
|
66
|
-
const binding = createReportBinding(ORDERS_DATASET, 'amount')
|
|
67
|
-
const renderer = createBindingBadgeRenderer(
|
|
68
|
-
bindingMap([{ addr: ADDR, binding }]),
|
|
69
|
-
undefined,
|
|
70
|
-
() => ({ horizontal: 'center', vertical: 'bottom' })
|
|
71
|
-
)
|
|
72
|
-
const layout = renderer(ADDR, undefined)
|
|
73
|
-
expect(layout?.rootContainer.attribute.justifyContent).toBe('center')
|
|
74
|
-
expect(layout?.rootContainer.attribute.alignItems).toBe('flex-end')
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
it('接线冒烟:经 Sheet.getEffectiveStyle 读取有效样式对齐(含行默认样式叠加)', () => {
|
|
78
|
-
const sheet = new Sheet()
|
|
79
|
-
sheet.setCellMeta(ADDR, REPORT_META_NAMESPACE, createReportBinding(ORDERS_DATASET, 'amount'))
|
|
80
|
-
sheet.setCellStyle({ start: ADDR, end: ADDR }, { align: { horizontal: 'center' } })
|
|
81
|
-
sheet.setRowStyle(ADDR.row, { align: { vertical: 'bottom' } })
|
|
82
|
-
|
|
83
|
-
const renderer = createBindingBadgeRenderer(
|
|
84
|
-
(addr) => sheet.getCellMeta<ReportBinding>(addr, REPORT_META_NAMESPACE),
|
|
85
|
-
undefined,
|
|
86
|
-
(addr) => sheet.getEffectiveStyle(addr)?.align
|
|
87
|
-
)
|
|
88
|
-
const layout = renderer(ADDR, undefined)
|
|
89
|
-
expect(layout?.rootContainer.attribute.justifyContent).toBe('center')
|
|
90
|
-
expect(layout?.rootContainer.attribute.alignItems).toBe('flex-end')
|
|
91
|
-
})
|
|
92
|
-
})
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest'
|
|
2
|
-
|
|
3
|
-
import type { ConditionalRule } from '../../../report/types'
|
|
4
|
-
import {
|
|
5
|
-
cloneRulesFromDraft,
|
|
6
|
-
coerceValueForOperator,
|
|
7
|
-
createDraftItem,
|
|
8
|
-
defaultRuleValue,
|
|
9
|
-
initDraftFromRules,
|
|
10
|
-
operatorsForFieldType,
|
|
11
|
-
readBetweenValue,
|
|
12
|
-
resolveEvalFieldType,
|
|
13
|
-
ruleEvalFieldOptions,
|
|
14
|
-
RULE_SCOPE_OPTIONS,
|
|
15
|
-
writeBetweenValue
|
|
16
|
-
} from '../designer/conditional-rules/helpers'
|
|
17
|
-
|
|
18
|
-
describe('conditional-rules helpers', () => {
|
|
19
|
-
it('按字段类型返回运算符列表', () => {
|
|
20
|
-
expect(operatorsForFieldType('number').map((o) => o.value)).toEqual([
|
|
21
|
-
'gt',
|
|
22
|
-
'gte',
|
|
23
|
-
'lt',
|
|
24
|
-
'lte',
|
|
25
|
-
'eq',
|
|
26
|
-
'between'
|
|
27
|
-
])
|
|
28
|
-
expect(operatorsForFieldType('string').map((o) => o.value)).toEqual(['eq', 'contains'])
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
it('运算符切换时重置比较值', () => {
|
|
32
|
-
expect(coerceValueForOperator('between', 'number', 42)).toEqual([0, 100])
|
|
33
|
-
expect(coerceValueForOperator('contains', 'string', 42)).toBe('')
|
|
34
|
-
expect(coerceValueForOperator('gt', 'number', '12')).toBe(12)
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
it('between 读写辅助', () => {
|
|
38
|
-
const value = defaultRuleValue('between', 'number')
|
|
39
|
-
expect(readBetweenValue(value, 0, 'number')).toBe(0)
|
|
40
|
-
expect(readBetweenValue(value, 1, 'number')).toBe(100)
|
|
41
|
-
expect(writeBetweenValue(value, 1, 250, 'number')).toEqual([0, 250])
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
it('草稿与规则互转保持深拷贝', () => {
|
|
45
|
-
const rules: ConditionalRule[] = [
|
|
46
|
-
{ operator: 'gt', value: 10, style: { fill: { color: '#FFCCCC' }, font: { bold: true } } }
|
|
47
|
-
]
|
|
48
|
-
const draft = initDraftFromRules(rules, 'number')
|
|
49
|
-
expect(draft).toHaveLength(1)
|
|
50
|
-
|
|
51
|
-
const cloned = cloneRulesFromDraft(draft)
|
|
52
|
-
expect(cloned[0]).toEqual(rules[0])
|
|
53
|
-
expect(cloned[0]).not.toBe(rules[0])
|
|
54
|
-
|
|
55
|
-
draft[0]!.rule.style.fill!.color = '#000000'
|
|
56
|
-
expect(rules[0]!.style.fill!.color).toBe('#FFCCCC')
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
it('新建草稿项带默认样式', () => {
|
|
60
|
-
const item = createDraftItem(undefined, 'string')
|
|
61
|
-
expect(item.rule.operator).toBe('eq')
|
|
62
|
-
expect(item.rule.value).toBe('')
|
|
63
|
-
expect(item.rule.style.fill?.color).toBeTruthy()
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
it('求值字段与作用范围选项', () => {
|
|
67
|
-
const fields = [
|
|
68
|
-
{ name: 'amount', label: '金额', type: 'number' as const },
|
|
69
|
-
{ name: 'region', label: '地区', type: 'string' as const }
|
|
70
|
-
]
|
|
71
|
-
expect(ruleEvalFieldOptions('amount', fields).map((item) => item.label)).toEqual([
|
|
72
|
-
'本格字段',
|
|
73
|
-
'地区'
|
|
74
|
-
])
|
|
75
|
-
expect(ruleEvalFieldOptions('amount', fields).map((item) => item.value)).toEqual(['', 'region'])
|
|
76
|
-
expect(RULE_SCOPE_OPTIONS.map((item) => item.label)).toEqual(['本格', '整行'])
|
|
77
|
-
expect(resolveEvalFieldType({ operator: 'eq', value: '', style: {} }, 'amount', fields)).toBe(
|
|
78
|
-
'number'
|
|
79
|
-
)
|
|
80
|
-
expect(
|
|
81
|
-
resolveEvalFieldType(
|
|
82
|
-
{ operator: 'eq', value: '', style: {}, field: 'region' },
|
|
83
|
-
'amount',
|
|
84
|
-
fields
|
|
85
|
-
)
|
|
86
|
-
).toBe('string')
|
|
87
|
-
})
|
|
88
|
-
})
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest'
|
|
2
|
-
|
|
3
|
-
import type { DatasetCatalogItem } from '../../../report/types'
|
|
4
|
-
import {
|
|
5
|
-
fieldTypeGlyph,
|
|
6
|
-
filterDatasetsByQuery,
|
|
7
|
-
formatFieldDragPayload,
|
|
8
|
-
parseFieldDragPayload
|
|
9
|
-
} from '../field-panel-helpers'
|
|
10
|
-
|
|
11
|
-
// ---- 内联 fixtures ----
|
|
12
|
-
|
|
13
|
-
const ORDERS: DatasetCatalogItem = {
|
|
14
|
-
id: 'orders',
|
|
15
|
-
label: '销售明细',
|
|
16
|
-
fields: [
|
|
17
|
-
{ name: 'customer', label: '客户', type: 'string' },
|
|
18
|
-
{ name: 'amount', label: '金额', type: 'number' }
|
|
19
|
-
]
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const INVENTORY: DatasetCatalogItem = {
|
|
23
|
-
id: 'inventory',
|
|
24
|
-
label: '库存',
|
|
25
|
-
fields: [
|
|
26
|
-
{ name: 'sku', label: 'SKU', type: 'string' },
|
|
27
|
-
{ name: 'qty', label: '数量', type: 'number' }
|
|
28
|
-
]
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
describe('field-panel helpers', () => {
|
|
32
|
-
it('fieldTypeGlyph 按字段类型返回短标识', () => {
|
|
33
|
-
expect(fieldTypeGlyph('string')).toBe('文')
|
|
34
|
-
expect(fieldTypeGlyph('number')).toBe('#')
|
|
35
|
-
expect(fieldTypeGlyph('date')).toBe('日')
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
it('filterDatasetsByQuery 按中文名或英文字段名过滤', () => {
|
|
39
|
-
const datasets = [ORDERS, INVENTORY]
|
|
40
|
-
|
|
41
|
-
expect(filterDatasetsByQuery(datasets, '客户')).toEqual([
|
|
42
|
-
{ ...ORDERS, fields: [ORDERS.fields[0]!] }
|
|
43
|
-
])
|
|
44
|
-
|
|
45
|
-
expect(filterDatasetsByQuery(datasets, 'qty')).toEqual([
|
|
46
|
-
{ ...INVENTORY, fields: [INVENTORY.fields[1]!] }
|
|
47
|
-
])
|
|
48
|
-
|
|
49
|
-
expect(filterDatasetsByQuery(datasets, ' ')).toEqual(datasets)
|
|
50
|
-
expect(filterDatasetsByQuery(datasets, '不存在')).toEqual([])
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
it('字段拖拽负载编解码往返;非法负载返回 null', () => {
|
|
54
|
-
const payload = formatFieldDragPayload('orders', 'customer')
|
|
55
|
-
expect(payload).toBe('orders:customer')
|
|
56
|
-
expect(parseFieldDragPayload(payload)).toEqual({ datasetId: 'orders', fieldName: 'customer' })
|
|
57
|
-
|
|
58
|
-
// 字段名含冒号时按首个分隔符切分
|
|
59
|
-
expect(parseFieldDragPayload('orders:a:b')).toEqual({ datasetId: 'orders', fieldName: 'a:b' })
|
|
60
|
-
|
|
61
|
-
expect(parseFieldDragPayload('')).toBeNull()
|
|
62
|
-
expect(parseFieldDragPayload(':customer')).toBeNull()
|
|
63
|
-
expect(parseFieldDragPayload('orders:')).toBeNull()
|
|
64
|
-
})
|
|
65
|
-
})
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest'
|
|
2
|
-
|
|
3
|
-
import type { CellOverlayRect, GridOverlayLayout } from '../designer/cell-coords'
|
|
4
|
-
import { resolveBindingFloatPanelPosition } from '../designer/use-grid-overlay'
|
|
5
|
-
|
|
6
|
-
function cellRect(top: number, height = 24): CellOverlayRect {
|
|
7
|
-
const bottom = top + height
|
|
8
|
-
return {
|
|
9
|
-
left: 100,
|
|
10
|
-
top,
|
|
11
|
-
right: 180,
|
|
12
|
-
bottom,
|
|
13
|
-
width: 80,
|
|
14
|
-
height,
|
|
15
|
-
centerX: 140,
|
|
16
|
-
centerY: top + height / 2
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const layout: GridOverlayLayout = { offsetX: 0, offsetY: 77, viewW: 640, viewH: 400 }
|
|
21
|
-
|
|
22
|
-
describe('resolveBindingFloatPanelPosition', () => {
|
|
23
|
-
it('顶行格空间不足时改在单元格下方', () => {
|
|
24
|
-
const rect = cellRect(101)
|
|
25
|
-
const position = resolveBindingFloatPanelPosition(rect, layout, 320, 68, 640)
|
|
26
|
-
|
|
27
|
-
expect(position.placement).toBe('below')
|
|
28
|
-
expect(position.top).toBe(rect.bottom + 8)
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
it('中部格优先在单元格上方', () => {
|
|
32
|
-
const rect = cellRect(200)
|
|
33
|
-
const position = resolveBindingFloatPanelPosition(rect, layout, 320, 68, 640)
|
|
34
|
-
|
|
35
|
-
expect(position.placement).toBe('above')
|
|
36
|
-
expect(position.top).toBe(rect.top - 8)
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
it('水平居中并限制在宿主宽度内', () => {
|
|
40
|
-
const rect = cellRect(200)
|
|
41
|
-
const position = resolveBindingFloatPanelPosition(rect, layout, 320, 68, 340)
|
|
42
|
-
|
|
43
|
-
expect(position.left).toBe(170)
|
|
44
|
-
})
|
|
45
|
-
})
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import type { SheetSnapshot } from '@veltra/sheet-core'
|
|
2
|
-
import { describe, expect, it } from 'vitest'
|
|
3
|
-
|
|
4
|
-
import { previewGridSize } from '../preview-grid-size'
|
|
5
|
-
|
|
6
|
-
function snap(
|
|
7
|
-
partial: Partial<SheetSnapshot> & Pick<SheetSnapshot, 'cells'>
|
|
8
|
-
): Pick<SheetSnapshot, 'cells' | 'merges' | 'meta' | 'rows'> {
|
|
9
|
-
return { merges: [], rows: 0, ...partial }
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
describe('previewGridSize', () => {
|
|
13
|
-
it('template 模式用内容包围盒,忽略设计态 canvas 尺寸', () => {
|
|
14
|
-
expect(
|
|
15
|
-
previewGridSize(
|
|
16
|
-
snap({
|
|
17
|
-
cells: [
|
|
18
|
-
{ row: 0, col: 0, v: '客户' },
|
|
19
|
-
{ row: 0, col: 1, v: '金额' }
|
|
20
|
-
],
|
|
21
|
-
rows: 24,
|
|
22
|
-
cols: 10
|
|
23
|
-
}),
|
|
24
|
-
'template'
|
|
25
|
-
)
|
|
26
|
-
).toEqual({ rows: 1, cols: 2 })
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
it('filled 模式行保留展开布局尺寸,列按包围盒收敛(去掉设计态撑大的列)', () => {
|
|
30
|
-
expect(
|
|
31
|
-
previewGridSize(
|
|
32
|
-
snap({
|
|
33
|
-
cells: [
|
|
34
|
-
{ row: 0, col: 0, v: '客户' },
|
|
35
|
-
{ row: 3, col: 1, v: 300 }
|
|
36
|
-
],
|
|
37
|
-
rows: 4,
|
|
38
|
-
cols: 10
|
|
39
|
-
}),
|
|
40
|
-
'filled'
|
|
41
|
-
)
|
|
42
|
-
).toEqual({ rows: 4, cols: 2 })
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
it('空快照至少 1×1(VTable 需要非零网格)', () => {
|
|
46
|
-
expect(previewGridSize(snap({ cells: [] }), 'template')).toEqual({ rows: 1, cols: 1 })
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
it('包围盒计入合并区终点与 meta 绑定格', () => {
|
|
50
|
-
expect(
|
|
51
|
-
previewGridSize(
|
|
52
|
-
snap({
|
|
53
|
-
cells: [{ row: 0, col: 0, v: '标题' }],
|
|
54
|
-
merges: [{ start: { row: 0, col: 0 }, end: { row: 0, col: 2 } }],
|
|
55
|
-
meta: [{ row: 2, col: 1, namespace: 'report', payload: {} }],
|
|
56
|
-
rows: 24,
|
|
57
|
-
cols: 10
|
|
58
|
-
}),
|
|
59
|
-
'template'
|
|
60
|
-
)
|
|
61
|
-
).toEqual({ rows: 3, cols: 3 })
|
|
62
|
-
})
|
|
63
|
-
})
|