@veltra/sheet 2.0.1 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/report/binding-badge.js +76 -0
- package/dist/components/report/designer/cell-coords.js +46 -0
- package/dist/components/report/designer/col-widths.js +15 -0
- package/dist/components/report/designer/conditional-rules/helpers.js +139 -0
- package/dist/components/report/designer/drop-highlight-overlay.js +76 -0
- package/dist/components/report/designer/float-panel.js +385 -0
- package/dist/components/report/designer/role.js +17 -0
- package/dist/components/report/designer/rule-preview.js +33 -0
- package/dist/components/report/designer/rule-row.js +269 -0
- package/dist/components/report/designer/rules-dialog.js +135 -0
- package/dist/components/report/designer/topology-overlay.js +122 -0
- package/dist/components/report/designer/topology.js +64 -0
- package/dist/components/report/designer/use-grid-overlay.js +75 -0
- package/dist/components/report/designer-hub.js +177 -0
- package/dist/components/report/field-panel-helpers.js +33 -0
- package/dist/components/report/field-panel.js +132 -0
- package/dist/components/report/filter-bar.js +74 -0
- package/dist/components/report/hub-connection-form.js +145 -0
- package/dist/components/report/hub-dataset-editor.js +394 -0
- package/dist/components/report/report-designer.js +343 -0
- package/dist/components/report/report-viewer.js +111 -0
- package/dist/components/report/style.d.ts +17 -0
- package/dist/components/report/style.js +18 -0
- package/dist/components/report/style2.css +869 -0
- package/dist/components/report/use-report-designer.js +360 -0
- package/dist/components/report/use-report-viewer.js +50 -0
- package/dist/components/sheet/formula-bar.js +393 -0
- package/dist/components/sheet/formula-suggest-list.js +66 -0
- package/dist/components/sheet/import-file.js +140 -0
- package/dist/components/sheet/insert-count-menu-item.js +68 -0
- package/dist/components/sheet/insert-image.js +79 -0
- package/dist/components/sheet/popup-helpers.js +73 -0
- package/dist/components/sheet/popups/border-popup.js +75 -0
- package/dist/components/sheet/popups/border-preset-glyph.js +106 -0
- package/dist/components/sheet/popups/export-popup.js +51 -0
- package/dist/components/sheet/popups/fill-color-popup.js +37 -0
- package/dist/components/sheet/popups/find-popup.js +113 -0
- package/dist/components/sheet/popups/font-color-popup.js +37 -0
- package/dist/components/sheet/popups/font-size-popup.js +63 -0
- package/dist/components/sheet/popups/import.worker.d.ts +21 -0
- package/dist/components/sheet/popups/import.worker.js +41 -0
- package/dist/components/sheet/popups/insert-image-popup.js +38 -0
- package/dist/components/sheet/sheet-context-menu.js +200 -0
- package/dist/components/sheet/sheet-tabs.js +162 -0
- package/dist/components/sheet/sheet-toolbar.js +106 -0
- package/dist/components/sheet/sheet.js +198 -0
- package/dist/components/sheet/style.d.ts +11 -0
- package/dist/components/sheet/style.js +12 -0
- package/dist/components/sheet/style2.css +654 -0
- package/dist/components/sheet/use-find-replace.js +161 -0
- package/dist/components/sheet/use-formula-ref-select.js +37 -0
- package/dist/components/sheet/use-formula-suggest.js +126 -0
- package/dist/components/sheet/use-sheet-grid.js +188 -0
- package/dist/components/sheet/use-sheet-state.js +122 -0
- package/dist/components/sheet/use-sheet-tabs-bar.js +90 -0
- package/dist/components/sheet/use-tool-groups.js +42 -0
- package/dist/components/sheet/use-tool-popup.js +123 -0
- package/dist/components/sheet/use-toolbar-scroll.js +72 -0
- package/dist/index.d.ts +18 -26
- package/dist/index.js +14 -24
- package/dist/report/binding.d.ts +45 -0
- package/dist/report/binding.js +175 -0
- package/dist/report/connector.d.ts +66 -0
- package/dist/report/connector.js +159 -0
- package/dist/report/export-xlsx.d.ts +19 -0
- package/dist/report/export-xlsx.js +95 -0
- package/dist/report/filter-bar.d.ts +10 -0
- package/dist/report/filter-bar.js +31 -0
- package/dist/report/index.d.ts +12 -0
- package/dist/report/params.d.ts +13 -0
- package/dist/report/params.js +61 -0
- package/dist/report/render/aggregate.js +157 -0
- package/dist/report/render/builder.d.ts +12 -0
- package/dist/report/render/builder.js +139 -0
- package/dist/report/render/coordinate.d.ts +25 -0
- package/dist/report/render/coordinate.js +733 -0
- package/dist/report/render/index.d.ts +14 -0
- package/dist/report/render/index.js +21 -0
- package/dist/report/render/style-resolver.js +50 -0
- package/dist/report/render/template-index.d.ts +24 -0
- package/dist/report/render/template-index.js +137 -0
- package/dist/report/rules/evaluate.d.ts +25 -0
- package/dist/report/rules/evaluate.js +82 -0
- package/dist/report/rules/index.d.ts +2 -0
- package/dist/report/template.d.ts +59 -0
- package/dist/report/template.js +80 -0
- package/dist/report/types.d.ts +85 -0
- package/dist/tools/builtin.js +279 -8
- package/dist/tools/context.d.ts +54 -11
- package/dist/tools/context.js +28 -5
- package/dist/tools/download.js +68 -0
- package/dist/tools/export.worker.d.ts +16 -0
- package/dist/tools/export.worker.js +29 -0
- package/dist/tools/registry.d.ts +7 -4
- package/dist/tools/registry.js +1 -3
- package/dist/types/index.d.ts +3 -1
- package/dist/types/report-designer.d.ts +36 -0
- package/dist/types/report-viewer.d.ts +38 -0
- package/dist/types/sheet.d.ts +22 -5
- package/package.json +10 -7
- package/src/components/report/__test__/conditional-rules-helpers.test.ts +87 -0
- package/src/components/report/__test__/field-panel-helpers.test.ts +65 -0
- package/src/components/report/__test__/float-panel-position.test.ts +45 -0
- package/src/components/report/__test__/report-designer.test.ts +388 -0
- package/src/components/report/__test__/report-viewer.test.ts +334 -0
- package/src/components/report/__test__/topology.test.ts +143 -0
- package/src/components/report/__test__/use-report-designer.test.ts +565 -0
- package/src/components/report/binding-badge.ts +73 -0
- package/src/components/report/designer/cell-coords.ts +94 -0
- package/src/components/report/designer/col-widths.ts +33 -0
- package/src/components/report/designer/conditional-rules/helpers.ts +186 -0
- package/src/components/report/designer/drop-highlight-overlay.vue +74 -0
- package/src/components/report/designer/float-panel.vue +387 -0
- package/src/components/report/designer/role.ts +32 -0
- package/src/components/report/designer/rule-preview.vue +40 -0
- package/src/components/report/designer/rule-row.vue +252 -0
- package/src/components/report/designer/rules-dialog.vue +126 -0
- package/src/components/report/designer/topology-overlay.vue +127 -0
- package/src/components/report/designer/topology.ts +124 -0
- package/src/components/report/designer/use-grid-overlay.ts +113 -0
- package/src/components/report/designer-hub.vue +198 -0
- package/src/components/report/field-panel-helpers.ts +44 -0
- package/src/components/report/field-panel.vue +136 -0
- package/src/components/report/filter-bar.vue +77 -0
- package/src/components/report/hub-connection-form.vue +124 -0
- package/src/components/report/hub-dataset-editor.vue +369 -0
- package/src/components/report/index.ts +2 -0
- package/src/components/report/report-designer.vue +356 -0
- package/src/components/report/report-viewer.vue +128 -0
- package/src/components/report/style-designer.scss +583 -0
- package/src/components/report/style-hub.scss +292 -0
- package/src/components/report/style-viewer.scss +104 -0
- package/src/components/report/style.scss +3 -0
- package/src/components/report/style.ts +20 -0
- package/src/components/report/use-report-designer.ts +547 -0
- package/src/components/report/use-report-viewer.ts +79 -0
- package/src/components/sheet/__test__/formula-bar.test.ts +474 -0
- package/src/components/sheet/__test__/import-file.test.ts +183 -0
- package/src/components/sheet/__test__/insert-count-menu-item.test.ts +123 -0
- package/src/components/sheet/__test__/insert-image-popup.test.ts +89 -0
- package/src/components/sheet/__test__/insert-image.test.ts +100 -0
- package/src/components/sheet/__test__/sheet-component.test.ts +993 -0
- package/src/components/sheet/__test__/sheet-context-menu.test.ts +206 -0
- package/src/components/sheet/__test__/use-formula-ref-select.test.ts +35 -0
- package/src/components/sheet/__test__/use-formula-suggest.test.ts +83 -0
- package/src/components/sheet/formula-bar.vue +473 -0
- package/src/components/sheet/formula-suggest-list.vue +64 -0
- package/src/components/sheet/import-file.ts +173 -0
- package/src/components/sheet/insert-count-menu-item.vue +69 -0
- package/src/components/sheet/insert-image.ts +90 -0
- package/src/components/sheet/parsing.ts +11 -0
- package/src/components/sheet/popup-helpers.ts +50 -0
- package/src/components/sheet/popups/border-popup.vue +93 -0
- package/src/components/sheet/popups/border-preset-glyph.vue +111 -0
- package/src/components/sheet/popups/export-popup.vue +52 -0
- package/src/components/sheet/popups/fill-color-popup.vue +39 -0
- package/src/components/sheet/popups/find-popup.vue +111 -0
- package/src/components/sheet/popups/font-color-popup.vue +39 -0
- package/src/components/sheet/popups/font-size-popup.vue +52 -0
- package/src/components/sheet/popups/import.worker.ts +66 -0
- package/src/components/sheet/popups/insert-image-popup.vue +39 -0
- package/src/components/sheet/sheet-context-menu.ts +229 -0
- package/src/components/sheet/sheet-tabs.vue +162 -0
- package/src/components/sheet/sheet-toolbar.vue +91 -0
- package/src/components/sheet/sheet.vue +211 -0
- package/src/components/sheet/style.scss +737 -0
- package/src/components/sheet/style.ts +13 -0
- package/src/components/sheet/use-find-replace.ts +200 -0
- package/src/components/sheet/use-formula-ref-select.ts +34 -0
- package/src/components/sheet/use-formula-suggest.ts +150 -0
- package/src/components/sheet/use-sheet-grid.ts +247 -0
- package/src/components/sheet/use-sheet-state.ts +161 -0
- package/src/components/sheet/use-sheet-tabs-bar.ts +115 -0
- package/src/components/sheet/use-tool-groups.ts +61 -0
- package/src/components/sheet/use-tool-popup.ts +150 -0
- package/src/components/sheet/use-toolbar-scroll.ts +95 -0
- package/src/env.d.ts +11 -0
- package/src/index.ts +39 -14
- package/src/report/__test__/binding.test.ts +218 -0
- package/src/report/__test__/connector.test.ts +218 -0
- package/src/report/__test__/export-xlsx.test.ts +118 -0
- package/src/report/__test__/filter-bar.test.ts +58 -0
- package/src/report/__test__/params.test.ts +156 -0
- package/src/report/__test__/render.test.ts +728 -0
- package/src/report/__test__/rules.test.ts +131 -0
- package/src/report/__test__/template.test.ts +355 -0
- package/src/report/binding.ts +243 -0
- package/src/report/connector.ts +205 -0
- package/src/report/export-xlsx.ts +118 -0
- package/src/report/filter-bar.ts +36 -0
- package/src/report/index.ts +13 -0
- package/src/report/params.ts +96 -0
- package/src/report/render/__test__/aggregate.test.ts +16 -0
- package/src/report/render/__test__/coordinate.test.ts +405 -0
- package/src/report/render/aggregate.ts +240 -0
- package/src/report/render/builder.ts +211 -0
- package/src/report/render/coordinate.ts +1239 -0
- package/src/report/render/index.ts +30 -0
- package/src/report/render/style-resolver.ts +68 -0
- package/src/report/render/template-index.ts +200 -0
- package/src/report/rules/evaluate.ts +113 -0
- package/src/report/rules/index.ts +7 -0
- package/src/report/template.ts +141 -0
- package/src/report/types.ts +96 -0
- package/src/tools/__test__/builtin.test.ts +208 -66
- package/src/tools/__test__/context.test.ts +62 -2
- package/src/tools/builtin.ts +350 -6
- package/src/tools/context.ts +89 -11
- package/src/tools/download.ts +82 -0
- package/src/tools/export.worker.ts +61 -0
- package/src/tools/registry.ts +16 -1
- package/src/types/index.ts +2 -0
- package/src/types/report-designer.ts +36 -0
- package/src/types/report-viewer.ts +37 -0
- package/src/types/sheet.ts +26 -3
- package/dist/core/address.d.ts +0 -60
- package/dist/core/address.js +0 -142
- package/dist/core/address.js.map +0 -1
- package/dist/core/cell-store.d.ts +0 -61
- package/dist/core/cell-store.js +0 -135
- package/dist/core/cell-store.js.map +0 -1
- package/dist/core/command/default-registry.d.ts +0 -10
- package/dist/core/command/default-registry.js +0 -18
- package/dist/core/command/default-registry.js.map +0 -1
- package/dist/core/command/history.d.ts +0 -64
- package/dist/core/command/history.js +0 -127
- package/dist/core/command/history.js.map +0 -1
- package/dist/core/command/merge-cells.d.ts +0 -21
- package/dist/core/command/merge-cells.js +0 -74
- package/dist/core/command/merge-cells.js.map +0 -1
- package/dist/core/command/registry.d.ts +0 -17
- package/dist/core/command/registry.js +0 -26
- package/dist/core/command/registry.js.map +0 -1
- package/dist/core/command/set-cell-formula.d.ts +0 -17
- package/dist/core/command/set-cell-formula.js +0 -29
- package/dist/core/command/set-cell-formula.js.map +0 -1
- package/dist/core/command/set-cell-value.d.ts +0 -22
- package/dist/core/command/set-cell-value.js +0 -35
- package/dist/core/command/set-cell-value.js.map +0 -1
- package/dist/core/command/types.d.ts +0 -68
- package/dist/core/events.js +0 -29
- package/dist/core/events.js.map +0 -1
- package/dist/core/fill.d.ts +0 -34
- package/dist/core/fill.js +0 -320
- package/dist/core/fill.js.map +0 -1
- package/dist/core/formula/ast.d.ts +0 -58
- package/dist/core/formula/ast.js +0 -38
- package/dist/core/formula/ast.js.map +0 -1
- package/dist/core/formula/dependency-graph.d.ts +0 -70
- package/dist/core/formula/dependency-graph.js +0 -269
- package/dist/core/formula/dependency-graph.js.map +0 -1
- package/dist/core/formula/errors.d.ts +0 -25
- package/dist/core/formula/errors.js +0 -36
- package/dist/core/formula/errors.js.map +0 -1
- package/dist/core/formula/evaluator.d.ts +0 -41
- package/dist/core/formula/evaluator.js +0 -154
- package/dist/core/formula/evaluator.js.map +0 -1
- package/dist/core/formula/functions.d.ts +0 -30
- package/dist/core/formula/functions.js +0 -209
- package/dist/core/formula/functions.js.map +0 -1
- package/dist/core/formula/parser.d.ts +0 -7
- package/dist/core/formula/parser.js +0 -208
- package/dist/core/formula/parser.js.map +0 -1
- package/dist/core/formula/tokenizer.d.ts +0 -37
- package/dist/core/formula/tokenizer.js +0 -146
- package/dist/core/formula/tokenizer.js.map +0 -1
- package/dist/core/merge-manager.d.ts +0 -64
- package/dist/core/merge-manager.js +0 -111
- package/dist/core/merge-manager.js.map +0 -1
- package/dist/core/selection.d.ts +0 -31
- package/dist/core/selection.js +0 -62
- package/dist/core/selection.js.map +0 -1
- package/dist/core/sheet.d.ts +0 -116
- package/dist/core/sheet.js +0 -224
- package/dist/core/sheet.js.map +0 -1
- package/dist/core/workbook.d.ts +0 -43
- package/dist/core/workbook.js +0 -77
- package/dist/core/workbook.js.map +0 -1
- package/dist/grid/sheet-grid.d.ts +0 -81
- package/dist/grid/sheet-grid.js +0 -331
- package/dist/grid/sheet-grid.js.map +0 -1
- package/dist/grid/vtable-theme.js +0 -80
- package/dist/grid/vtable-theme.js.map +0 -1
- package/dist/tools/builtin.js.map +0 -1
- package/dist/tools/context.js.map +0 -1
- package/dist/tools/registry.js.map +0 -1
- package/dist/vue/index.d.ts +0 -2
- package/dist/vue/sheet.js +0 -211
- package/dist/vue/sheet.js.map +0 -1
- package/dist/vue/sheet.vue.d.ts +0 -24
- package/dist/vue/style.d.ts +0 -1
- package/dist/vue/style.js +0 -2
- package/dist/vue/style2.css +0 -93
- package/src/core/__test__/address.test.ts +0 -113
- package/src/core/__test__/cell-store.test.ts +0 -97
- package/src/core/__test__/command.test.ts +0 -377
- package/src/core/__test__/fill.test.ts +0 -140
- package/src/core/__test__/formula-adversarial.test.ts +0 -265
- package/src/core/__test__/formula-engine.test.ts +0 -470
- package/src/core/__test__/formula-functions.test.ts +0 -178
- package/src/core/__test__/formula-parser.test.ts +0 -160
- package/src/core/__test__/history.test.ts +0 -225
- package/src/core/__test__/merge-manager.test.ts +0 -106
- package/src/core/__test__/sheet.test.ts +0 -142
- package/src/core/address.ts +0 -166
- package/src/core/cell-store.ts +0 -173
- package/src/core/command/default-registry.ts +0 -15
- package/src/core/command/history.ts +0 -167
- package/src/core/command/index.ts +0 -7
- package/src/core/command/merge-cells.ts +0 -74
- package/src/core/command/registry.ts +0 -30
- package/src/core/command/set-cell-formula.ts +0 -29
- package/src/core/command/set-cell-value.ts +0 -38
- package/src/core/command/types.ts +0 -73
- package/src/core/events.ts +0 -37
- package/src/core/fill.ts +0 -314
- package/src/core/formula/ast.ts +0 -66
- package/src/core/formula/dependency-graph.ts +0 -329
- package/src/core/formula/errors.ts +0 -41
- package/src/core/formula/evaluator.ts +0 -219
- package/src/core/formula/functions.ts +0 -266
- package/src/core/formula/index.ts +0 -7
- package/src/core/formula/parser.ts +0 -198
- package/src/core/formula/tokenizer.ts +0 -160
- package/src/core/merge-manager.ts +0 -158
- package/src/core/selection.ts +0 -66
- package/src/core/sheet.ts +0 -282
- package/src/core/workbook.ts +0 -99
- package/src/grid/__test__/canvas-mock.ts +0 -49
- package/src/grid/__test__/setup.ts +0 -3
- package/src/grid/__test__/sheet-grid-formula.test.ts +0 -140
- package/src/grid/__test__/sheet-grid.test.ts +0 -275
- package/src/grid/sheet-grid.ts +0 -407
- package/src/grid/vtable-theme.ts +0 -61
- package/src/vue/__test__/sheet-component.test.ts +0 -267
- package/src/vue/sheet.vue +0 -235
- package/src/vue/style.scss +0 -94
- package/src/vue/style.ts +0 -2
- /package/src/{vue → components/sheet}/index.ts +0 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/// <reference lib="webworker" />
|
|
2
|
+
/**
|
|
3
|
+
* XLSX 导出 Worker:exportWorkbookXlsx(模型 → hucre 序列化 + ZIP 压缩,
|
|
4
|
+
* 大工作簿为秒级同步重活)移到独立线程,主线程保持空闲。
|
|
5
|
+
*
|
|
6
|
+
* 协议:主线程 postMessage({ sheets: [{ name, snapshot }], activeIndex })
|
|
7
|
+
* (快照为纯数据,可结构化克隆,行高随 SheetSnapshot.rowHeights 携带)→
|
|
8
|
+
* worker 返回 { ok: true, buffer }(精确拷贝后 transfer 回主线程);
|
|
9
|
+
* 失败返回 { ok: false, error }。
|
|
10
|
+
*
|
|
11
|
+
* 与 import.worker.ts 同一约束:必须用**运行时动态 import**——worker 顶层
|
|
12
|
+
* 静态 import 在 vite dev 的 worker 上下文中会因模块图加载顺序导致
|
|
13
|
+
* `Workbook is not defined`(实测)。
|
|
14
|
+
*/
|
|
15
|
+
import type { SheetSnapshot } from '@veltra/sheet-core/core/sheet'
|
|
16
|
+
|
|
17
|
+
export interface ExportWorkerPayload {
|
|
18
|
+
sheets: { name: string; snapshot: SheetSnapshot }[]
|
|
19
|
+
activeIndex: number
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ExportWorkerResponse {
|
|
23
|
+
ok: boolean
|
|
24
|
+
buffer?: Uint8Array
|
|
25
|
+
error?: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
self.onmessage = (e: MessageEvent<ExportWorkerPayload>): void => {
|
|
29
|
+
void Promise.all([
|
|
30
|
+
import('@veltra/sheet-core/core/io/export'),
|
|
31
|
+
import('@veltra/sheet-core/core/workbook')
|
|
32
|
+
])
|
|
33
|
+
.then(([{ exportWorkbookXlsx }, { Workbook }]) => {
|
|
34
|
+
const wb = new Workbook()
|
|
35
|
+
const sheets = e.data.sheets
|
|
36
|
+
for (let i = 0; i < sheets.length; i++) {
|
|
37
|
+
const { name, snapshot } = sheets[i]!
|
|
38
|
+
// 首个 sheet 复用 Workbook 自带的默认表:先改名对齐(空名/重名保持原名,
|
|
39
|
+
// 导出侧 hucre 1.0 会校验表名合法性)
|
|
40
|
+
const sheet = i === 0 ? wb.activeSheet : wb.addSheet(name)
|
|
41
|
+
if (i === 0 && sheet.name !== name) wb.renameSheet(sheet.name, name)
|
|
42
|
+
sheet.restore(snapshot)
|
|
43
|
+
}
|
|
44
|
+
wb.activateSheet(wb.getSheets()[Math.min(e.data.activeIndex, wb.sheetCount - 1)]!.name)
|
|
45
|
+
return exportWorkbookXlsx(wb)
|
|
46
|
+
})
|
|
47
|
+
.then((buffer) => {
|
|
48
|
+
// transfer 精确视图(writeXlsx 返回的 Uint8Array 理论上独占底层 buffer,
|
|
49
|
+
// slice 一份拷贝兜底偏移情形,避免 transfer 整个底层 buffer 带出冗余字节)
|
|
50
|
+
const exact = buffer.slice()
|
|
51
|
+
const response: ExportWorkerResponse = { ok: true, buffer: exact }
|
|
52
|
+
;(self as unknown as Worker).postMessage(response, [exact.buffer])
|
|
53
|
+
})
|
|
54
|
+
.catch((err: unknown) => {
|
|
55
|
+
const response: ExportWorkerResponse = {
|
|
56
|
+
ok: false,
|
|
57
|
+
error: err instanceof Error ? err.message : String(err)
|
|
58
|
+
}
|
|
59
|
+
;(self as unknown as Worker).postMessage(response)
|
|
60
|
+
})
|
|
61
|
+
}
|
package/src/tools/registry.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { TypedEventEmitter } from '
|
|
1
|
+
import { TypedEventEmitter } from '@veltra/sheet-core/core/events'
|
|
2
|
+
|
|
2
3
|
import type { SheetContext } from './context'
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -12,6 +13,16 @@ import type { SheetContext } from './context'
|
|
|
12
13
|
* (与 defaultCommandRegistry 同语义;每个实例的 SheetContext 各自绑定当前 sheet)
|
|
13
14
|
*/
|
|
14
15
|
|
|
16
|
+
/** 弹层型工具类型:vue 层按类型渲染弹层面板(面板交互走 SheetContext 命令入口) */
|
|
17
|
+
export type SheetToolPopupType =
|
|
18
|
+
| 'fill-color'
|
|
19
|
+
| 'border'
|
|
20
|
+
| 'font-color'
|
|
21
|
+
| 'font-size'
|
|
22
|
+
| 'find'
|
|
23
|
+
| 'insert-image'
|
|
24
|
+
| 'export'
|
|
25
|
+
|
|
15
26
|
/** 工具定义 */
|
|
16
27
|
export interface SheetTool {
|
|
17
28
|
/** 唯一 id;同 id 重复注册视为替换(保留原位置) */
|
|
@@ -30,6 +41,10 @@ export interface SheetTool {
|
|
|
30
41
|
visible?(ctx: SheetContext): boolean
|
|
31
42
|
/** 是否禁用(工具栏状态刷新时求值);缺省可用 */
|
|
32
43
|
disabled?(ctx: SheetContext): boolean
|
|
44
|
+
/** 是否处于激活/高亮状态(工具栏状态刷新时求值,vue 层渲染 is-active);缺省 false */
|
|
45
|
+
active?(ctx: SheetContext): boolean
|
|
46
|
+
/** 弹层型工具:vue 层渲染弹层面板,onClick 不执行(面板交互走 SheetContext) */
|
|
47
|
+
popup?: SheetToolPopupType
|
|
33
48
|
/** 点击执行;ctx 是唯一操作入口(写操作全走命令系统,天然可撤销) */
|
|
34
49
|
onClick(ctx: SheetContext): void
|
|
35
50
|
}
|
package/src/types/index.ts
CHANGED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Workbook } from '@veltra/sheet-core/core/workbook'
|
|
2
|
+
import type { DeconstructValue } from '@veltra/utils'
|
|
3
|
+
|
|
4
|
+
import type { DataConnection, DataConnector, ReportTemplate } from '../report'
|
|
5
|
+
|
|
6
|
+
/** 报表设计器组件属性(ADR-0003 决策 2) */
|
|
7
|
+
export interface ReportDesignerProps {
|
|
8
|
+
/** 数据连接器(如 `createHttpConnector({ endpoint })`):数据中枢的测试连接 / 字段解析 / 记录预览均经它 */
|
|
9
|
+
connector: DataConnector
|
|
10
|
+
/**
|
|
11
|
+
* 数据连接列表(`v-model:connections`):纯序列化对象,仅驻留内存;
|
|
12
|
+
* 凭据的持久化与安全存储完全由宿主掌控(ADR-0003 决策 4)
|
|
13
|
+
*/
|
|
14
|
+
connections?: DataConnection[]
|
|
15
|
+
/**
|
|
16
|
+
* 载入既有 Report Template 继续设计:恢复网格绑定与设计态数据集;
|
|
17
|
+
* 内嵌连接按 id 合并进 `v-model:connections`(仅缺省时追加,宿主列表是单一事实源)
|
|
18
|
+
*/
|
|
19
|
+
template?: ReportTemplate
|
|
20
|
+
/** 承载设计态的工作簿(USheet 先例:缺省内部自建单 sheet 工作簿) */
|
|
21
|
+
workbook?: Workbook
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** 报表设计器组件定义的事件 */
|
|
25
|
+
export interface ReportDesignerEmits {
|
|
26
|
+
(e: 'update:connections', value: DataConnection[]): void
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** 在组件内部引用 */
|
|
30
|
+
export interface _ReportDesignerExposed {
|
|
31
|
+
/** 取回含 meta 绑定与内嵌数据集定义的可序列化 Report Template */
|
|
32
|
+
getTemplate: () => ReportTemplate
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** 报表设计器组件暴露的方法 */
|
|
36
|
+
export type ReportDesignerExposed = DeconstructValue<_ReportDesignerExposed>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Workbook } from '@veltra/sheet-core/core/workbook'
|
|
2
|
+
import type { DeconstructValue } from '@veltra/utils'
|
|
3
|
+
|
|
4
|
+
import type { DataConnector, ReportTemplate } from '../report'
|
|
5
|
+
import type { ReportColWidthEntry } from '../report/export-xlsx'
|
|
6
|
+
|
|
7
|
+
/** 报表查看器组件属性(ADR-0003 决策 2) */
|
|
8
|
+
export interface ReportViewerProps {
|
|
9
|
+
/** 数据连接器(如 `createHttpConnector({ endpoint })`) */
|
|
10
|
+
connector: DataConnector
|
|
11
|
+
/**
|
|
12
|
+
* 自包含 Report Template(SheetSnapshot + 内嵌数据集定义,见 `ReportTemplate`):
|
|
13
|
+
* 查看器据此提取实际绑定数据集的查询参数并集生成 Filter Bar,并经连接器取数展开渲染
|
|
14
|
+
*/
|
|
15
|
+
template: ReportTemplate
|
|
16
|
+
/** 承载填充报表的工作簿(USheet 先例:缺省内部自建单 sheet 工作簿) */
|
|
17
|
+
workbook?: Workbook
|
|
18
|
+
/**
|
|
19
|
+
* 列宽(sheet-core 列宽未进 SheetSnapshot):载入填充结果后写入 VTable 运行时,
|
|
20
|
+
* 供 `exportXlsx()` 读取保真列宽(设计器预览态传入设计态捕获值)
|
|
21
|
+
*/
|
|
22
|
+
colWidths?: ReadonlyArray<ReportColWidthEntry>
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** 在组件内部引用 */
|
|
26
|
+
export interface _ReportViewerExposed {
|
|
27
|
+
/** 重新取数并展开渲染(外部状态变化后主动刷新报表) */
|
|
28
|
+
refresh: () => Promise<void>
|
|
29
|
+
/**
|
|
30
|
+
* 导出填充报表为 XLSX(取数完成前拒绝;内部读取填充 sheet 与运行时列宽)。
|
|
31
|
+
* 不内置导出按钮,工具栏由下游决定。
|
|
32
|
+
*/
|
|
33
|
+
exportXlsx: () => Promise<void>
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** 报表查看器组件暴露的方法 */
|
|
37
|
+
export type ReportViewerExposed = DeconstructValue<_ReportViewerExposed>
|
package/src/types/sheet.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
import type { Sheet } from '@veltra/sheet-core/core/sheet'
|
|
2
|
+
import type { Workbook } from '@veltra/sheet-core/core/workbook'
|
|
3
|
+
import type {
|
|
4
|
+
ResolveCellRenderer,
|
|
5
|
+
ResolveCellStyleHook,
|
|
6
|
+
ResolveDisplayValue,
|
|
7
|
+
SheetGrid
|
|
8
|
+
} from '@veltra/sheet-core/grid/sheet-grid'
|
|
1
9
|
import type { DeconstructValue } from '@veltra/utils'
|
|
2
10
|
import type { ComputedRef } from 'vue'
|
|
3
11
|
|
|
4
|
-
import type { Sheet } from '../core/sheet'
|
|
5
|
-
import type { Workbook } from '../core/workbook'
|
|
6
|
-
import type { SheetGrid } from '../grid/sheet-grid'
|
|
7
12
|
import type { SheetContext } from '../tools/context'
|
|
8
13
|
|
|
9
14
|
/** 电子表格组件属性 */
|
|
@@ -14,10 +19,28 @@ export interface SheetProps {
|
|
|
14
19
|
rows?: number
|
|
15
20
|
/** 渲染列数,默认 26(A..Z) */
|
|
16
21
|
cols?: number
|
|
22
|
+
/**
|
|
23
|
+
* 显示值覆盖(设计态 Binding Placeholder 等):覆盖 VTable record,不写 CellData.v
|
|
24
|
+
*/
|
|
25
|
+
resolveDisplayValue?: ResolveDisplayValue
|
|
26
|
+
/**
|
|
27
|
+
* 动态单元格样式:视口渲染时叠加条件样式补丁,不写 CellData.s / StylePool
|
|
28
|
+
*/
|
|
29
|
+
resolveCellStyle?: ResolveCellStyleHook
|
|
30
|
+
/**
|
|
31
|
+
* 动态单元格渲染(ADR-0004):视口布局时按格自定义渲染形态(VTable
|
|
32
|
+
* customLayout,布局构建用 sheet-core 导出的 CustomLayout),返回 undefined
|
|
33
|
+
* 回落默认渲染;不写模型、不进快照
|
|
34
|
+
*/
|
|
35
|
+
resolveCellRenderer?: ResolveCellRenderer
|
|
17
36
|
/** 是否显示工具栏,默认 true */
|
|
18
37
|
showToolbar?: boolean
|
|
38
|
+
/** 是否显示顶部公式栏(名称框 + fx 输入栏),默认 true */
|
|
39
|
+
showFormulaBar?: boolean
|
|
19
40
|
/** 是否显示底部 sheet 标签栏,默认 true */
|
|
20
41
|
showTabs?: boolean
|
|
42
|
+
/** 只读预览(关闭编辑回写、填充柄等写入口) */
|
|
43
|
+
readonly?: boolean
|
|
21
44
|
}
|
|
22
45
|
|
|
23
46
|
export interface SheetEmits {
|
package/dist/core/address.d.ts
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
//#region src/core/address.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* A1 地址系统(纯函数)。
|
|
4
|
-
*
|
|
5
|
-
* 坐标统一 0-based:`{ row: 0, col: 0 }` 即 A1。
|
|
6
|
-
* 区域为闭区间,且经过规范化:start 恒为左上角,end 恒为右下角。
|
|
7
|
-
*/
|
|
8
|
-
/** 单元格地址(0-based) */
|
|
9
|
-
interface CellAddress {
|
|
10
|
-
row: number;
|
|
11
|
-
col: number;
|
|
12
|
-
}
|
|
13
|
-
/** 单元格区域(闭区间,start 左上角,end 右下角) */
|
|
14
|
-
interface CellRange {
|
|
15
|
-
start: CellAddress;
|
|
16
|
-
end: CellAddress;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* cellKey 的列基数(2^20)。
|
|
20
|
-
* key = row * COL_KEY_BASE + col,要求 col < COL_KEY_BASE;
|
|
21
|
-
* JS 安全整数范围内可容纳约 8.5e9 行,远超实际使用。
|
|
22
|
-
*/
|
|
23
|
-
declare const COL_KEY_BASE: number;
|
|
24
|
-
/** 地址 → 数值 key(Map 索引用) */
|
|
25
|
-
declare function cellKey(addr: CellAddress): number;
|
|
26
|
-
/** 数值 key → 地址 */
|
|
27
|
-
declare function addressFromKey(key: number): CellAddress;
|
|
28
|
-
/** 列号(0-based)→ 列名:0 → 'A',25 → 'Z',26 → 'AA' */
|
|
29
|
-
declare function colIndexToName(col: number): string;
|
|
30
|
-
/** 列名 → 列号(0-based):'A' → 0,'AA' → 26;非法列名返回 -1 */
|
|
31
|
-
declare function colNameToIndex(name: string): number;
|
|
32
|
-
/** 解析 A1 记法(兼容 `$A$1` 绝对引用写法)→ 地址;非法返回 null */
|
|
33
|
-
declare function parseAddress(text: string): CellAddress | null;
|
|
34
|
-
/** 地址 → A1 记法:{ row: 1, col: 1 } → 'B2' */
|
|
35
|
-
declare function formatAddress(addr: CellAddress): string;
|
|
36
|
-
/** 由两个角点构造规范化区域(start ≤ end) */
|
|
37
|
-
declare function createRange(a: CellAddress, b: CellAddress): CellRange;
|
|
38
|
-
/** 解析区域记法:'B2' 或 'B2:D5'(兼容绝对引用);非法返回 null */
|
|
39
|
-
declare function parseRange(text: string): CellRange | null;
|
|
40
|
-
/** 区域 → 记法:单格 → 'B2',多格 → 'B2:D5' */
|
|
41
|
-
declare function formatRange(range: CellRange): string;
|
|
42
|
-
/** 地址相等 */
|
|
43
|
-
declare function addressesEqual(a: CellAddress, b: CellAddress): boolean;
|
|
44
|
-
/** 区域相等 */
|
|
45
|
-
declare function rangesEqual(a: CellRange, b: CellRange): boolean;
|
|
46
|
-
/** 两区域是否相交 */
|
|
47
|
-
declare function rangesIntersect(a: CellRange, b: CellRange): boolean;
|
|
48
|
-
/** 区域是否包含地址 */
|
|
49
|
-
declare function rangeContainsAddress(range: CellRange, addr: CellAddress): boolean;
|
|
50
|
-
/** 区域是否完整包含另一区域 */
|
|
51
|
-
declare function rangeContainsRange(outer: CellRange, inner: CellRange): boolean;
|
|
52
|
-
/** 一组区域的最小包围盒(至少传入一个区域) */
|
|
53
|
-
declare function boundingBox(ranges: readonly [CellRange, ...CellRange[]]): CellRange;
|
|
54
|
-
/** 按行主序遍历区域内的所有地址 */
|
|
55
|
-
declare function iterateRange(range: CellRange): Generator<CellAddress, void, undefined>;
|
|
56
|
-
/** 区域内的单元格数量 */
|
|
57
|
-
declare function rangeSize(range: CellRange): number;
|
|
58
|
-
//#endregion
|
|
59
|
-
export { COL_KEY_BASE, CellAddress, CellRange, addressFromKey, addressesEqual, boundingBox, cellKey, colIndexToName, colNameToIndex, createRange, formatAddress, formatRange, iterateRange, parseAddress, parseRange, rangeContainsAddress, rangeContainsRange, rangeSize, rangesEqual, rangesIntersect };
|
|
60
|
-
//# sourceMappingURL=address.d.ts.map
|
package/dist/core/address.js
DELETED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
//#region src/core/address.ts
|
|
2
|
-
/**
|
|
3
|
-
* cellKey 的列基数(2^20)。
|
|
4
|
-
* key = row * COL_KEY_BASE + col,要求 col < COL_KEY_BASE;
|
|
5
|
-
* JS 安全整数范围内可容纳约 8.5e9 行,远超实际使用。
|
|
6
|
-
*/
|
|
7
|
-
const COL_KEY_BASE = 2 ** 20;
|
|
8
|
-
/** 地址 → 数值 key(Map 索引用) */
|
|
9
|
-
function cellKey(addr) {
|
|
10
|
-
return addr.row * COL_KEY_BASE + addr.col;
|
|
11
|
-
}
|
|
12
|
-
/** 数值 key → 地址 */
|
|
13
|
-
function addressFromKey(key) {
|
|
14
|
-
return {
|
|
15
|
-
row: Math.floor(key / COL_KEY_BASE),
|
|
16
|
-
col: key % COL_KEY_BASE
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
/** 列号(0-based)→ 列名:0 → 'A',25 → 'Z',26 → 'AA' */
|
|
20
|
-
function colIndexToName(col) {
|
|
21
|
-
if (!Number.isInteger(col) || col < 0) throw new RangeError(`列号必须是非负整数: ${col}`);
|
|
22
|
-
let name = "";
|
|
23
|
-
let n = col;
|
|
24
|
-
do {
|
|
25
|
-
name = String.fromCharCode(65 + n % 26) + name;
|
|
26
|
-
n = Math.floor(n / 26) - 1;
|
|
27
|
-
} while (n >= 0);
|
|
28
|
-
return name;
|
|
29
|
-
}
|
|
30
|
-
/** 列名 → 列号(0-based):'A' → 0,'AA' → 26;非法列名返回 -1 */
|
|
31
|
-
function colNameToIndex(name) {
|
|
32
|
-
if (!/^[A-Za-z]+$/.test(name)) return -1;
|
|
33
|
-
let index = 0;
|
|
34
|
-
for (const ch of name.toUpperCase()) index = index * 26 + (ch.charCodeAt(0) - 64);
|
|
35
|
-
return index - 1;
|
|
36
|
-
}
|
|
37
|
-
const ADDRESS_RE = /^\$?([A-Za-z]+)\$?([1-9]\d*)$/;
|
|
38
|
-
/** 解析 A1 记法(兼容 `$A$1` 绝对引用写法)→ 地址;非法返回 null */
|
|
39
|
-
function parseAddress(text) {
|
|
40
|
-
const match = ADDRESS_RE.exec(text.trim());
|
|
41
|
-
if (!match) return null;
|
|
42
|
-
const col = colNameToIndex(match[1]);
|
|
43
|
-
return {
|
|
44
|
-
row: Number.parseInt(match[2], 10) - 1,
|
|
45
|
-
col
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
/** 地址 → A1 记法:{ row: 1, col: 1 } → 'B2' */
|
|
49
|
-
function formatAddress(addr) {
|
|
50
|
-
return `${colIndexToName(addr.col)}${addr.row + 1}`;
|
|
51
|
-
}
|
|
52
|
-
/** 由两个角点构造规范化区域(start ≤ end) */
|
|
53
|
-
function createRange(a, b) {
|
|
54
|
-
return {
|
|
55
|
-
start: {
|
|
56
|
-
row: Math.min(a.row, b.row),
|
|
57
|
-
col: Math.min(a.col, b.col)
|
|
58
|
-
},
|
|
59
|
-
end: {
|
|
60
|
-
row: Math.max(a.row, b.row),
|
|
61
|
-
col: Math.max(a.col, b.col)
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
/** 解析区域记法:'B2' 或 'B2:D5'(兼容绝对引用);非法返回 null */
|
|
66
|
-
function parseRange(text) {
|
|
67
|
-
const parts = text.trim().split(":");
|
|
68
|
-
if (parts.length > 2) return null;
|
|
69
|
-
const start = parseAddress(parts[0]);
|
|
70
|
-
if (!start) return null;
|
|
71
|
-
if (parts.length === 1) return {
|
|
72
|
-
start,
|
|
73
|
-
end: { ...start }
|
|
74
|
-
};
|
|
75
|
-
const end = parseAddress(parts[1]);
|
|
76
|
-
if (!end) return null;
|
|
77
|
-
return createRange(start, end);
|
|
78
|
-
}
|
|
79
|
-
/** 区域 → 记法:单格 → 'B2',多格 → 'B2:D5' */
|
|
80
|
-
function formatRange(range) {
|
|
81
|
-
const start = formatAddress(range.start);
|
|
82
|
-
if (range.start.row === range.end.row && range.start.col === range.end.col) return start;
|
|
83
|
-
return `${start}:${formatAddress(range.end)}`;
|
|
84
|
-
}
|
|
85
|
-
/** 地址相等 */
|
|
86
|
-
function addressesEqual(a, b) {
|
|
87
|
-
return a.row === b.row && a.col === b.col;
|
|
88
|
-
}
|
|
89
|
-
/** 区域相等 */
|
|
90
|
-
function rangesEqual(a, b) {
|
|
91
|
-
return addressesEqual(a.start, b.start) && addressesEqual(a.end, b.end);
|
|
92
|
-
}
|
|
93
|
-
/** 两区域是否相交 */
|
|
94
|
-
function rangesIntersect(a, b) {
|
|
95
|
-
return a.start.row <= b.end.row && a.end.row >= b.start.row && a.start.col <= b.end.col && a.end.col >= b.start.col;
|
|
96
|
-
}
|
|
97
|
-
/** 区域是否包含地址 */
|
|
98
|
-
function rangeContainsAddress(range, addr) {
|
|
99
|
-
return addr.row >= range.start.row && addr.row <= range.end.row && addr.col >= range.start.col && addr.col <= range.end.col;
|
|
100
|
-
}
|
|
101
|
-
/** 区域是否完整包含另一区域 */
|
|
102
|
-
function rangeContainsRange(outer, inner) {
|
|
103
|
-
return rangeContainsAddress(outer, inner.start) && rangeContainsAddress(outer, inner.end);
|
|
104
|
-
}
|
|
105
|
-
/** 一组区域的最小包围盒(至少传入一个区域) */
|
|
106
|
-
function boundingBox(ranges) {
|
|
107
|
-
let minRow = Infinity;
|
|
108
|
-
let minCol = Infinity;
|
|
109
|
-
let maxRow = -Infinity;
|
|
110
|
-
let maxCol = -Infinity;
|
|
111
|
-
for (const range of ranges) {
|
|
112
|
-
minRow = Math.min(minRow, range.start.row);
|
|
113
|
-
minCol = Math.min(minCol, range.start.col);
|
|
114
|
-
maxRow = Math.max(maxRow, range.end.row);
|
|
115
|
-
maxCol = Math.max(maxCol, range.end.col);
|
|
116
|
-
}
|
|
117
|
-
return {
|
|
118
|
-
start: {
|
|
119
|
-
row: minRow,
|
|
120
|
-
col: minCol
|
|
121
|
-
},
|
|
122
|
-
end: {
|
|
123
|
-
row: maxRow,
|
|
124
|
-
col: maxCol
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
/** 按行主序遍历区域内的所有地址 */
|
|
129
|
-
function* iterateRange(range) {
|
|
130
|
-
for (let row = range.start.row; row <= range.end.row; row++) for (let col = range.start.col; col <= range.end.col; col++) yield {
|
|
131
|
-
row,
|
|
132
|
-
col
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
/** 区域内的单元格数量 */
|
|
136
|
-
function rangeSize(range) {
|
|
137
|
-
return (range.end.row - range.start.row + 1) * (range.end.col - range.start.col + 1);
|
|
138
|
-
}
|
|
139
|
-
//#endregion
|
|
140
|
-
export { COL_KEY_BASE, addressFromKey, addressesEqual, boundingBox, cellKey, colIndexToName, colNameToIndex, createRange, formatAddress, formatRange, iterateRange, parseAddress, parseRange, rangeContainsAddress, rangeContainsRange, rangeSize, rangesEqual, rangesIntersect };
|
|
141
|
-
|
|
142
|
-
//# sourceMappingURL=address.js.map
|
package/dist/core/address.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"address.js","names":[],"sources":["../../src/core/address.ts"],"sourcesContent":["/**\n * A1 地址系统(纯函数)。\n *\n * 坐标统一 0-based:`{ row: 0, col: 0 }` 即 A1。\n * 区域为闭区间,且经过规范化:start 恒为左上角,end 恒为右下角。\n */\n\n/** 单元格地址(0-based) */\nexport interface CellAddress {\n row: number\n col: number\n}\n\n/** 单元格区域(闭区间,start 左上角,end 右下角) */\nexport interface CellRange {\n start: CellAddress\n end: CellAddress\n}\n\n/**\n * cellKey 的列基数(2^20)。\n * key = row * COL_KEY_BASE + col,要求 col < COL_KEY_BASE;\n * JS 安全整数范围内可容纳约 8.5e9 行,远超实际使用。\n */\nexport const COL_KEY_BASE = 2 ** 20\n\n/** 地址 → 数值 key(Map 索引用) */\nexport function cellKey(addr: CellAddress): number {\n return addr.row * COL_KEY_BASE + addr.col\n}\n\n/** 数值 key → 地址 */\nexport function addressFromKey(key: number): CellAddress {\n return { row: Math.floor(key / COL_KEY_BASE), col: key % COL_KEY_BASE }\n}\n\n/** 列号(0-based)→ 列名:0 → 'A',25 → 'Z',26 → 'AA' */\nexport function colIndexToName(col: number): string {\n if (!Number.isInteger(col) || col < 0) {\n throw new RangeError(`列号必须是非负整数: ${col}`)\n }\n let name = ''\n let n = col\n do {\n name = String.fromCharCode(65 + (n % 26)) + name\n n = Math.floor(n / 26) - 1\n } while (n >= 0)\n return name\n}\n\n/** 列名 → 列号(0-based):'A' → 0,'AA' → 26;非法列名返回 -1 */\nexport function colNameToIndex(name: string): number {\n if (!/^[A-Za-z]+$/.test(name)) return -1\n let index = 0\n for (const ch of name.toUpperCase()) {\n index = index * 26 + (ch.charCodeAt(0) - 64)\n }\n return index - 1\n}\n\nconst ADDRESS_RE = /^\\$?([A-Za-z]+)\\$?([1-9]\\d*)$/\n\n/** 解析 A1 记法(兼容 `$A$1` 绝对引用写法)→ 地址;非法返回 null */\nexport function parseAddress(text: string): CellAddress | null {\n const match = ADDRESS_RE.exec(text.trim())\n if (!match) return null\n const col = colNameToIndex(match[1]!)\n const row = Number.parseInt(match[2]!, 10) - 1\n return { row, col }\n}\n\n/** 地址 → A1 记法:{ row: 1, col: 1 } → 'B2' */\nexport function formatAddress(addr: CellAddress): string {\n return `${colIndexToName(addr.col)}${addr.row + 1}`\n}\n\n/** 由两个角点构造规范化区域(start ≤ end) */\nexport function createRange(a: CellAddress, b: CellAddress): CellRange {\n return {\n start: { row: Math.min(a.row, b.row), col: Math.min(a.col, b.col) },\n end: { row: Math.max(a.row, b.row), col: Math.max(a.col, b.col) }\n }\n}\n\n/** 解析区域记法:'B2' 或 'B2:D5'(兼容绝对引用);非法返回 null */\nexport function parseRange(text: string): CellRange | null {\n const parts = text.trim().split(':')\n if (parts.length > 2) return null\n const start = parseAddress(parts[0]!)\n if (!start) return null\n if (parts.length === 1) return { start, end: { ...start } }\n const end = parseAddress(parts[1]!)\n if (!end) return null\n return createRange(start, end)\n}\n\n/** 区域 → 记法:单格 → 'B2',多格 → 'B2:D5' */\nexport function formatRange(range: CellRange): string {\n const start = formatAddress(range.start)\n if (range.start.row === range.end.row && range.start.col === range.end.col) return start\n return `${start}:${formatAddress(range.end)}`\n}\n\n/** 地址相等 */\nexport function addressesEqual(a: CellAddress, b: CellAddress): boolean {\n return a.row === b.row && a.col === b.col\n}\n\n/** 区域相等 */\nexport function rangesEqual(a: CellRange, b: CellRange): boolean {\n return addressesEqual(a.start, b.start) && addressesEqual(a.end, b.end)\n}\n\n/** 两区域是否相交 */\nexport function rangesIntersect(a: CellRange, b: CellRange): boolean {\n return (\n a.start.row <= b.end.row &&\n a.end.row >= b.start.row &&\n a.start.col <= b.end.col &&\n a.end.col >= b.start.col\n )\n}\n\n/** 区域是否包含地址 */\nexport function rangeContainsAddress(range: CellRange, addr: CellAddress): boolean {\n return (\n addr.row >= range.start.row &&\n addr.row <= range.end.row &&\n addr.col >= range.start.col &&\n addr.col <= range.end.col\n )\n}\n\n/** 区域是否完整包含另一区域 */\nexport function rangeContainsRange(outer: CellRange, inner: CellRange): boolean {\n return rangeContainsAddress(outer, inner.start) && rangeContainsAddress(outer, inner.end)\n}\n\n/** 一组区域的最小包围盒(至少传入一个区域) */\nexport function boundingBox(ranges: readonly [CellRange, ...CellRange[]]): CellRange {\n let minRow = Infinity\n let minCol = Infinity\n let maxRow = -Infinity\n let maxCol = -Infinity\n for (const range of ranges) {\n minRow = Math.min(minRow, range.start.row)\n minCol = Math.min(minCol, range.start.col)\n maxRow = Math.max(maxRow, range.end.row)\n maxCol = Math.max(maxCol, range.end.col)\n }\n return { start: { row: minRow, col: minCol }, end: { row: maxRow, col: maxCol } }\n}\n\n/** 按行主序遍历区域内的所有地址 */\nexport function* iterateRange(range: CellRange): Generator<CellAddress, void, undefined> {\n for (let row = range.start.row; row <= range.end.row; row++) {\n for (let col = range.start.col; col <= range.end.col; col++) {\n yield { row, col }\n }\n }\n}\n\n/** 区域内的单元格数量 */\nexport function rangeSize(range: CellRange): number {\n return (range.end.row - range.start.row + 1) * (range.end.col - range.start.col + 1)\n}\n"],"mappings":"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"}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { CellAddress, CellRange } from "./address.js";
|
|
2
|
-
//#region src/core/cell-store.d.ts
|
|
3
|
-
/**
|
|
4
|
-
* 稀疏矩阵存储:`Map<row, Map<col, CellData>>`。
|
|
5
|
-
* 空单元格 = 存储中不存在该 key(稀疏的第一原则);
|
|
6
|
-
* rowCount/colCount 只是高水位,用于渲染行数,不分配空间。
|
|
7
|
-
*/
|
|
8
|
-
/** 单元格值类型:n=数字 s=字符串 b=布尔 str=公式结果字符串 e=错误 d=日期(序列数) */
|
|
9
|
-
type CellType = 'n' | 's' | 'b' | 'str' | 'e' | 'd';
|
|
10
|
-
/** 单元格原始值 */
|
|
11
|
-
type CellValue = string | number | boolean | null;
|
|
12
|
-
/** 单元格数据(参考 univer ICellData 裁剪版) */
|
|
13
|
-
interface CellData {
|
|
14
|
-
/** 原始值(公式格为计算缓存值) */
|
|
15
|
-
v?: CellValue;
|
|
16
|
-
/** 值类型,缺省按 v 推断 */
|
|
17
|
-
t?: CellType;
|
|
18
|
-
/** 公式文本(不含 '='),如 'SUM(A1:B2)+Sheet2!C3' */
|
|
19
|
-
f?: string;
|
|
20
|
-
}
|
|
21
|
-
/** 序列化条目(snapshot/restore 用) */
|
|
22
|
-
interface CellSnapshotItem extends CellData {
|
|
23
|
-
row: number;
|
|
24
|
-
col: number;
|
|
25
|
-
}
|
|
26
|
-
/** 按原始值推断类型 */
|
|
27
|
-
declare function inferCellType(v: CellValue): CellType | undefined;
|
|
28
|
-
/** 判定为空:无公式且值为 null/undefined/'' */
|
|
29
|
-
declare function isEmptyCellData(data: CellData | undefined): boolean;
|
|
30
|
-
/** CellData 相等(v/t/f 三字段逐一比较;命令系统据此跳过无实际变更的补丁) */
|
|
31
|
-
declare function cellDataEqual(a: CellData | undefined, b: CellData | undefined): boolean;
|
|
32
|
-
declare class CellStore {
|
|
33
|
-
private cells;
|
|
34
|
-
private _rowCount;
|
|
35
|
-
private _colCount;
|
|
36
|
-
/** 行数高水位(只增不减,restore 时重算) */
|
|
37
|
-
get rowCount(): number;
|
|
38
|
-
/** 列数高水位 */
|
|
39
|
-
get colCount(): number;
|
|
40
|
-
/** 真实存在的单元格数量 */
|
|
41
|
-
get size(): number;
|
|
42
|
-
/** 读取(返回副本,外部修改不影响存储) */
|
|
43
|
-
getCell(addr: CellAddress): CellData | undefined;
|
|
44
|
-
/** 写入(存储副本);空数据等价于删除 */
|
|
45
|
-
setCell(addr: CellAddress, data?: CellData): void;
|
|
46
|
-
/** 便捷写入原始值,类型自动推断;空值等价于删除 */
|
|
47
|
-
setCellValue(addr: CellAddress, value: CellValue): void;
|
|
48
|
-
deleteCell(addr: CellAddress): boolean;
|
|
49
|
-
/** 只遍历真实存在的单元格(行主序) */
|
|
50
|
-
entries(): Generator<[CellAddress, CellData], void, undefined>;
|
|
51
|
-
/** 只遍历区域内真实存在的单元格(行主序;公式区域展开用,空行/空格不分配不访问) */
|
|
52
|
-
entriesInRange(range: CellRange): Generator<[CellAddress, CellData], void, undefined>;
|
|
53
|
-
/** 序列化(只含真实存在的格) */
|
|
54
|
-
snapshot(): CellSnapshotItem[];
|
|
55
|
-
/** 从序列化恢复(清空重建,重算高水位) */
|
|
56
|
-
restore(items: readonly CellSnapshotItem[]): void;
|
|
57
|
-
clear(): void;
|
|
58
|
-
}
|
|
59
|
-
//#endregion
|
|
60
|
-
export { CellData, CellSnapshotItem, CellStore, CellType, CellValue, cellDataEqual, inferCellType, isEmptyCellData };
|
|
61
|
-
//# sourceMappingURL=cell-store.d.ts.map
|
package/dist/core/cell-store.js
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
//#region src/core/cell-store.ts
|
|
2
|
-
/** 按原始值推断类型 */
|
|
3
|
-
function inferCellType(v) {
|
|
4
|
-
switch (typeof v) {
|
|
5
|
-
case "number": return "n";
|
|
6
|
-
case "boolean": return "b";
|
|
7
|
-
case "string": return "s";
|
|
8
|
-
default: return;
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
/** 判定为空:无公式且值为 null/undefined/'' */
|
|
12
|
-
function isEmptyCellData(data) {
|
|
13
|
-
if (!data) return true;
|
|
14
|
-
if (data.f != null && data.f !== "") return false;
|
|
15
|
-
return data.v == null || data.v === "";
|
|
16
|
-
}
|
|
17
|
-
/** CellData 相等(v/t/f 三字段逐一比较;命令系统据此跳过无实际变更的补丁) */
|
|
18
|
-
function cellDataEqual(a, b) {
|
|
19
|
-
if (a === b) return true;
|
|
20
|
-
if (!a || !b) return false;
|
|
21
|
-
return a.v === b.v && a.t === b.t && a.f === b.f;
|
|
22
|
-
}
|
|
23
|
-
var CellStore = class {
|
|
24
|
-
cells = /* @__PURE__ */ new Map();
|
|
25
|
-
_rowCount = 0;
|
|
26
|
-
_colCount = 0;
|
|
27
|
-
/** 行数高水位(只增不减,restore 时重算) */
|
|
28
|
-
get rowCount() {
|
|
29
|
-
return this._rowCount;
|
|
30
|
-
}
|
|
31
|
-
/** 列数高水位 */
|
|
32
|
-
get colCount() {
|
|
33
|
-
return this._colCount;
|
|
34
|
-
}
|
|
35
|
-
/** 真实存在的单元格数量 */
|
|
36
|
-
get size() {
|
|
37
|
-
let size = 0;
|
|
38
|
-
for (const rowMap of this.cells.values()) size += rowMap.size;
|
|
39
|
-
return size;
|
|
40
|
-
}
|
|
41
|
-
/** 读取(返回副本,外部修改不影响存储) */
|
|
42
|
-
getCell(addr) {
|
|
43
|
-
const data = this.cells.get(addr.row)?.get(addr.col);
|
|
44
|
-
return data ? { ...data } : void 0;
|
|
45
|
-
}
|
|
46
|
-
/** 写入(存储副本);空数据等价于删除 */
|
|
47
|
-
setCell(addr, data) {
|
|
48
|
-
if (isEmptyCellData(data)) {
|
|
49
|
-
this.deleteCell(addr);
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
let rowMap = this.cells.get(addr.row);
|
|
53
|
-
if (!rowMap) {
|
|
54
|
-
rowMap = /* @__PURE__ */ new Map();
|
|
55
|
-
this.cells.set(addr.row, rowMap);
|
|
56
|
-
}
|
|
57
|
-
rowMap.set(addr.col, { ...data });
|
|
58
|
-
this._rowCount = Math.max(this._rowCount, addr.row + 1);
|
|
59
|
-
this._colCount = Math.max(this._colCount, addr.col + 1);
|
|
60
|
-
}
|
|
61
|
-
/** 便捷写入原始值,类型自动推断;空值等价于删除 */
|
|
62
|
-
setCellValue(addr, value) {
|
|
63
|
-
if (value == null || value === "") {
|
|
64
|
-
this.deleteCell(addr);
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
this.setCell(addr, {
|
|
68
|
-
v: value,
|
|
69
|
-
t: inferCellType(value)
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
deleteCell(addr) {
|
|
73
|
-
const rowMap = this.cells.get(addr.row);
|
|
74
|
-
if (!rowMap) return false;
|
|
75
|
-
const deleted = rowMap.delete(addr.col);
|
|
76
|
-
if (rowMap.size === 0) this.cells.delete(addr.row);
|
|
77
|
-
return deleted;
|
|
78
|
-
}
|
|
79
|
-
/** 只遍历真实存在的单元格(行主序) */
|
|
80
|
-
*entries() {
|
|
81
|
-
for (const [row, rowMap] of this.cells) for (const [col, data] of rowMap) yield [{
|
|
82
|
-
row,
|
|
83
|
-
col
|
|
84
|
-
}, { ...data }];
|
|
85
|
-
}
|
|
86
|
-
/** 只遍历区域内真实存在的单元格(行主序;公式区域展开用,空行/空格不分配不访问) */
|
|
87
|
-
*entriesInRange(range) {
|
|
88
|
-
for (let row = range.start.row; row <= range.end.row; row++) {
|
|
89
|
-
const rowMap = this.cells.get(row);
|
|
90
|
-
if (!rowMap) continue;
|
|
91
|
-
for (let col = range.start.col; col <= range.end.col; col++) {
|
|
92
|
-
const data = rowMap.get(col);
|
|
93
|
-
if (data) yield [{
|
|
94
|
-
row,
|
|
95
|
-
col
|
|
96
|
-
}, { ...data }];
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
/** 序列化(只含真实存在的格) */
|
|
101
|
-
snapshot() {
|
|
102
|
-
const items = [];
|
|
103
|
-
for (const [addr, data] of this.entries()) items.push({
|
|
104
|
-
row: addr.row,
|
|
105
|
-
col: addr.col,
|
|
106
|
-
...data
|
|
107
|
-
});
|
|
108
|
-
return items;
|
|
109
|
-
}
|
|
110
|
-
/** 从序列化恢复(清空重建,重算高水位) */
|
|
111
|
-
restore(items) {
|
|
112
|
-
this.clear();
|
|
113
|
-
for (const item of items) {
|
|
114
|
-
const { row, col, ...data } = item;
|
|
115
|
-
if (isEmptyCellData(data)) continue;
|
|
116
|
-
let rowMap = this.cells.get(row);
|
|
117
|
-
if (!rowMap) {
|
|
118
|
-
rowMap = /* @__PURE__ */ new Map();
|
|
119
|
-
this.cells.set(row, rowMap);
|
|
120
|
-
}
|
|
121
|
-
rowMap.set(col, { ...data });
|
|
122
|
-
this._rowCount = Math.max(this._rowCount, row + 1);
|
|
123
|
-
this._colCount = Math.max(this._colCount, col + 1);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
clear() {
|
|
127
|
-
this.cells.clear();
|
|
128
|
-
this._rowCount = 0;
|
|
129
|
-
this._colCount = 0;
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
//#endregion
|
|
133
|
-
export { CellStore, cellDataEqual, inferCellType, isEmptyCellData };
|
|
134
|
-
|
|
135
|
-
//# sourceMappingURL=cell-store.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cell-store.js","names":[],"sources":["../../src/core/cell-store.ts"],"sourcesContent":["import type { CellAddress, CellRange } from './address'\n\n/**\n * 稀疏矩阵存储:`Map<row, Map<col, CellData>>`。\n * 空单元格 = 存储中不存在该 key(稀疏的第一原则);\n * rowCount/colCount 只是高水位,用于渲染行数,不分配空间。\n */\n\n/** 单元格值类型:n=数字 s=字符串 b=布尔 str=公式结果字符串 e=错误 d=日期(序列数) */\nexport type CellType = 'n' | 's' | 'b' | 'str' | 'e' | 'd'\n\n/** 单元格原始值 */\nexport type CellValue = string | number | boolean | null\n\n/** 单元格数据(参考 univer ICellData 裁剪版) */\nexport interface CellData {\n /** 原始值(公式格为计算缓存值) */\n v?: CellValue\n /** 值类型,缺省按 v 推断 */\n t?: CellType\n /** 公式文本(不含 '='),如 'SUM(A1:B2)+Sheet2!C3' */\n f?: string\n // s?: StyleId —— 预留样式位,本期不实现\n}\n\n/** 序列化条目(snapshot/restore 用) */\nexport interface CellSnapshotItem extends CellData {\n row: number\n col: number\n}\n\n/** 按原始值推断类型 */\nexport function inferCellType(v: CellValue): CellType | undefined {\n switch (typeof v) {\n case 'number':\n return 'n'\n case 'boolean':\n return 'b'\n case 'string':\n return 's'\n default:\n return undefined\n }\n}\n\n/** 判定为空:无公式且值为 null/undefined/'' */\nexport function isEmptyCellData(data: CellData | undefined): boolean {\n if (!data) return true\n if (data.f != null && data.f !== '') return false\n return data.v == null || data.v === ''\n}\n\n/** CellData 相等(v/t/f 三字段逐一比较;命令系统据此跳过无实际变更的补丁) */\nexport function cellDataEqual(a: CellData | undefined, b: CellData | undefined): boolean {\n if (a === b) return true\n if (!a || !b) return false\n return a.v === b.v && a.t === b.t && a.f === b.f\n}\n\nexport class CellStore {\n private cells = new Map<number, Map<number, CellData>>()\n private _rowCount = 0\n private _colCount = 0\n\n /** 行数高水位(只增不减,restore 时重算) */\n get rowCount(): number {\n return this._rowCount\n }\n\n /** 列数高水位 */\n get colCount(): number {\n return this._colCount\n }\n\n /** 真实存在的单元格数量 */\n get size(): number {\n let size = 0\n for (const rowMap of this.cells.values()) size += rowMap.size\n return size\n }\n\n /** 读取(返回副本,外部修改不影响存储) */\n getCell(addr: CellAddress): CellData | undefined {\n const data = this.cells.get(addr.row)?.get(addr.col)\n return data ? { ...data } : undefined\n }\n\n /** 写入(存储副本);空数据等价于删除 */\n setCell(addr: CellAddress, data?: CellData): void {\n if (isEmptyCellData(data)) {\n this.deleteCell(addr)\n return\n }\n let rowMap = this.cells.get(addr.row)\n if (!rowMap) {\n rowMap = new Map()\n this.cells.set(addr.row, rowMap)\n }\n rowMap.set(addr.col, { ...data })\n this._rowCount = Math.max(this._rowCount, addr.row + 1)\n this._colCount = Math.max(this._colCount, addr.col + 1)\n }\n\n /** 便捷写入原始值,类型自动推断;空值等价于删除 */\n setCellValue(addr: CellAddress, value: CellValue): void {\n if (value == null || value === '') {\n this.deleteCell(addr)\n return\n }\n this.setCell(addr, { v: value, t: inferCellType(value) })\n }\n\n deleteCell(addr: CellAddress): boolean {\n const rowMap = this.cells.get(addr.row)\n if (!rowMap) return false\n const deleted = rowMap.delete(addr.col)\n if (rowMap.size === 0) this.cells.delete(addr.row)\n return deleted\n }\n\n /** 只遍历真实存在的单元格(行主序) */\n *entries(): Generator<[CellAddress, CellData], void, undefined> {\n for (const [row, rowMap] of this.cells) {\n for (const [col, data] of rowMap) {\n yield [{ row, col }, { ...data }]\n }\n }\n }\n\n /** 只遍历区域内真实存在的单元格(行主序;公式区域展开用,空行/空格不分配不访问) */\n *entriesInRange(range: CellRange): Generator<[CellAddress, CellData], void, undefined> {\n for (let row = range.start.row; row <= range.end.row; row++) {\n const rowMap = this.cells.get(row)\n if (!rowMap) continue\n for (let col = range.start.col; col <= range.end.col; col++) {\n const data = rowMap.get(col)\n if (data) yield [{ row, col }, { ...data }]\n }\n }\n }\n\n /** 序列化(只含真实存在的格) */\n snapshot(): CellSnapshotItem[] {\n const items: CellSnapshotItem[] = []\n for (const [addr, data] of this.entries()) {\n items.push({ row: addr.row, col: addr.col, ...data })\n }\n return items\n }\n\n /** 从序列化恢复(清空重建,重算高水位) */\n restore(items: readonly CellSnapshotItem[]): void {\n this.clear()\n for (const item of items) {\n const { row, col, ...data } = item\n if (isEmptyCellData(data)) continue\n let rowMap = this.cells.get(row)\n if (!rowMap) {\n rowMap = new Map()\n this.cells.set(row, rowMap)\n }\n rowMap.set(col, { ...data })\n this._rowCount = Math.max(this._rowCount, row + 1)\n this._colCount = Math.max(this._colCount, col + 1)\n }\n }\n\n clear(): void {\n this.cells.clear()\n this._rowCount = 0\n this._colCount = 0\n }\n}\n"],"mappings":"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"}
|