Skip to content

Commit 2c74976

Browse files
committed
Merge branch develop into feat/filter-plugin-for-business
2 parents 6890322 + aa26cb1 commit 2c74976

59 files changed

Lines changed: 5314 additions & 509 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CLAUDE.md

Lines changed: 99 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,13 @@ git commit -m "type: description"
6464
- **packages/vtable-search**: Search capabilities
6565
- **packages/vtable-calendar**: Calendar component
6666
- **packages/vtable-sheet**: Spreadsheet functionality (current development branch)
67+
- **项目特性**: 电子表格组件,支持多sheet tab页签管理
68+
- **核心架构**:
69+
- `workSheetInstances`: 管理所有sheet tab实例的核心容器
70+
- `work-sheet`: 单个sheet页签的实现,包含对应vtable实例
71+
- **依赖关系**: 依赖vtable核心插件系统,需先安装vtable插件
72+
- **当前开发重点**: 跨sheet tab公式计算支持
73+
- **技术实现**: 基于VTable核心库扩展,每个sheet对应独立的VTable实例
6774
- **packages/react-vtable**: React wrapper
6875
- **packages/vue-vtable**: Vue wrapper
6976
- **packages/openinula-vtable**: OpenInula wrapper
@@ -107,5 +114,95 @@ The library is built on a canvas-based rendering system using VRender:
107114
- Current branch: `feat/vtable-sheet` (spreadsheet functionality)
108115
- Main branches: `main`, `develop`
109116
- Node.js versions supported: 14.15.0+, 16.13.0+, 18.15.0+
110-
- to memorize
111-
- to memorize
117+
118+
## vtable-sheet 项目详细信息
119+
120+
### 项目路径
121+
`/Users/bytedance/VisActor/VTable/packages/vtable-sheet`
122+
123+
### 核心功能需求
124+
- **跨sheet tab公式计算支持**: 实现不同sheet页签间的公式引用和计算
125+
- **多页签管理**: 支持创建、切换、删除sheet页签
126+
- **数据同步**: 确保跨sheet数据引用的实时更新
127+
128+
### 技术架构
129+
- **核心入口**: vtable-sheet文件是整个组件的入口点
130+
- **实例管理**: workSheetInstances负责管理所有sheet实例
131+
- **单sheet实现**: 每个work-sheet包含独立的VTable实例
132+
- **插件依赖**: 依赖VTable核心插件系统提供基础功能
133+
134+
### 跨Sheet公式功能实现
135+
136+
#### 新增核心组件
137+
1. **CrossSheetFormulaManager** (`src/formula/cross-sheet-formula-manager.ts`)
138+
- 管理跨Sheet公式引用关系
139+
- 处理依赖关系映射和缓存
140+
- 支持公式验证和错误处理
141+
142+
2. **CrossSheetDataSynchronizer** (`src/formula/cross-sheet-data-synchronizer.ts`)
143+
- 处理跨Sheet数据同步
144+
- 支持批量数据更新
145+
- 提供实时更新通知机制
146+
147+
3. **CrossSheetFormulaValidator** (`src/formula/cross-sheet-formula-validator.ts`)
148+
- 验证跨Sheet公式语法
149+
- 检测循环依赖
150+
- 提供详细的错误信息
151+
152+
4. **CrossSheetFormulaHandler** (`src/formula/cross-sheet-formula-handler.ts`)
153+
- 统一的跨Sheet公式处理接口
154+
- 集成缓存、验证、同步功能
155+
- 提供高性能的计算引擎
156+
157+
#### 支持的公式类型
158+
- **基本引用**: `=Sheet1!A1`, `=Sheet2!B2:C4`
159+
- **函数计算**: `=SUM(Sheet1!A1:A10)`, `=AVERAGE(Sheet1!B1:B10)`
160+
- **跨表运算**: `=Sheet1!A1 + Sheet2!B1`
161+
- **条件判断**: `=IF(Sheet1!A1>100, "达标", "未达标")`
162+
- **复杂嵌套**: `=IF(AVERAGE(Sheet1!A1:A10)>50, SUM(Sheet1!B1:B10)*1.1, SUM(Sheet1!B1:B10))`
163+
164+
#### 核心功能特性
165+
-**实时计算**: 源数据变化时自动更新依赖公式
166+
-**智能缓存**: 1秒TTL缓存机制,平衡性能与实时性
167+
-**错误处理**: 完善的错误检测和提示机制
168+
-**依赖管理**: 自动识别和管理跨Sheet依赖关系
169+
-**批量处理**: 支持批量公式计算和数据更新
170+
-**性能优化**: 异步处理,避免阻塞UI
171+
172+
#### 使用示例
173+
```typescript
174+
// 设置跨Sheet公式
175+
const cell = { sheet: 'Summary', row: 1, col: 1 };
176+
const formula = '=SUM(SalesData!B2:E4)';
177+
await formulaManager.setCrossSheetFormula(cell, formula);
178+
179+
// 获取计算结果
180+
const result = await formulaManager.getCrossSheetValue(cell);
181+
console.log(result.value); // 计算结果
182+
console.log(result.calculationTime); // 计算耗时
183+
184+
// 验证公式
185+
const validation = formulaManager.validateCrossSheetFormula(cell);
186+
console.log(validation.valid); // 是否有效
187+
188+
// 获取依赖关系
189+
const dependencies = formulaManager.getCrossSheetDependencies();
190+
```
191+
192+
#### 测试覆盖
193+
- **单元测试**: `__tests__/cross-sheet-formula-simple.test.ts`
194+
- **集成测试**: `__tests__/integration/cross-sheet-integration.test.ts`
195+
- **演示页面**: `examples/cross-sheet-demo.html`
196+
- **使用文档**: `docs/cross-sheet-formula-guide.md`
197+
198+
#### 性能指标
199+
- 100个跨Sheet公式计算 < 5秒
200+
- 20个公式批量重新计算 < 2秒
201+
- 缓存命中率 > 80%
202+
- 内存使用优化,支持大规模数据
203+
204+
205+
#### 使用限制
206+
- 跨Sheet公式目前主要用于读取操作,写入操作仍在原Sheet中进行
207+
- 复杂的跨Sheet引用可能需要异步处理以获得最佳性能
208+
- 循环依赖检测基于静态分析,运行时循环依赖需要额外的错误处理

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,15 @@ $ rush update
192192

193193
# ⭐️ Star History
194194

195-
[![Star History Chart](https://api.star-history.com/svg?repos=visactor/vtable&type=Date)](https://star-history.com/#visactor/vtable&Date)
195+
## Star History
196+
197+
<a href="https://gitdata.xuanhun520.com/#visactor/vtable&Date">
198+
<picture >
199+
200+
<img style="width: 800px; height: 533px;" alt="Star History Chart" src="https://gitdata.xuanhun520.com/api/starimg?repos=visactor/vtable&type=Date&theme=dark" />
201+
</picture>
202+
</a>
203+
196204

197205
# 🤝 Contribution
198206

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"changes": [
3+
{
4+
"comment": "fix: when pivot table set grid-tree subTotal value not show #4815\n\n",
5+
"type": "none",
6+
"packageName": "@visactor/vtable"
7+
}
8+
],
9+
"packageName": "@visactor/vtable",
10+
"email": "892739385@qq.com"
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"changes": [
3+
{
4+
"comment": "feat: vtable-sheet support cross sheet calculate formula\n\n",
5+
"type": "none",
6+
"packageName": "@visactor/vtable"
7+
}
8+
],
9+
"packageName": "@visactor/vtable",
10+
"email": "892739385@qq.com"
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"changes": [
3+
{
4+
"comment": "fix: delete key down should not complete edit cell\n\n",
5+
"type": "none",
6+
"packageName": "@visactor/vtable"
7+
}
8+
],
9+
"packageName": "@visactor/vtable",
10+
"email": "892739385@qq.com"
11+
}

docs/assets/guide/en/cell_type/cellType.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,3 +253,72 @@ The following shows an example of `cellType: ()=>{}`: (Please refer to [Example]
253253
keepAspectRatio:true,
254254
}
255255
```
256+
257+
## Extension: Custom Column Types (TypeScript)
258+
259+
In real-world applications, in addition to VTable’s built-in `cellType` values (such as `text`, `link`, `image`, `video`, `progressbar`, `sparkline`, and `chart`), it is often necessary to attach **business-specific configurations** to column definitions, for example:
260+
261+
- Permission or visibility control: `permissionKey`
262+
- Tracking and analytics metadata: `trackId` / `trackParams`
263+
- Unified rendering strategy flags: `highlightOnNegative` / `useTagStyle`
264+
- DSL fields used by higher-level wrapper components: `renderAs` / `variant`
265+
266+
These fields are usually **not consumed directly by VTable itself**. Instead, they are read and handled by business-layer abstractions, such as a unified `cellRender`, custom hooks, or column factory utilities.
267+
268+
To support this use case, VTable provides a **type-level extension mechanism** that allows developers to extend `ColumnDefine` via TypeScript _module augmentation_. This enables defining custom column types with full type inference, validation, and IDE autocomplete support.
269+
270+
### 1) Define a custom column type
271+
272+
```ts
273+
import type { HeaderDefine } from '@visactor/vtable';
274+
275+
// Custom column body definition (example: a customized button column)
276+
export interface IColoredButtonColumnBody {
277+
cellType: 'button';
278+
field: string;
279+
280+
/** Business-specific extension field: highlight when the value is negative */
281+
highlightOnNegative?: boolean;
282+
283+
text?: string;
284+
style?: any;
285+
}
286+
287+
// Full column definition (Header + Body)
288+
export type ColoredButtonColumnDefine = IColoredButtonColumnBody & HeaderDefine;
289+
```
290+
291+
### 2) Register the type via module augmentation
292+
293+
```ts
294+
declare module '@visactor/vtable/es/ts-types' {
295+
interface CustomColumnBodyDefineMap {
296+
coloredButton: IColoredButtonColumnBody;
297+
}
298+
299+
interface CustomColumnDefineMap {
300+
coloredButtonColumn: ColoredButtonColumnDefine;
301+
}
302+
}
303+
```
304+
305+
### 3) Use the custom column type in `columns`
306+
307+
```ts
308+
import type { ColumnsDefine } from '@visactor/vtable';
309+
310+
const columns: ColumnsDefine = [
311+
{
312+
field: 'value',
313+
title: 'Custom Button Column',
314+
cellType: 'button',
315+
text: 'check',
316+
highlightOnNegative: true // ✅ extended field from CustomColumnDefineMap
317+
}
318+
];
319+
```
320+
321+
> **Note:**
322+
> The example above demonstrates a **type-level extension** only.
323+
> Whether fields such as `highlightOnNegative` produce actual visual or behavioral effects depends on business-side rendering logic (e.g., custom `cellRender`, hooks, or column factories).
324+
> VTable itself does not interpret or handle these fields automatically.

docs/assets/guide/zh/cell_type/cellType.md

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,4 +254,70 @@ VTable 所支持的数据类型共有 7 种,分别为:
254254
width:'auto',
255255
keepAspectRatio:true,
256256
}
257-
```
257+
```
258+
## 扩展:自定义列类型(TypeScript)
259+
260+
在实际业务中,除了 VTable 内置的 `cellType`(text/link/image/video/progressbar/sparkline/chart 等),我们常常还需要在列定义里附加一些 **业务侧专用配置**,例如:
261+
262+
- 权限/可见性控制:`permissionKey`
263+
- 埋点信息:`trackId` / `trackParams`
264+
- 统一渲染策略开关:`highlightOnNegative` / `useTagStyle`
265+
- 上层封装组件的 DSL 字段:`renderAs` / `variant`
266+
267+
这些字段通常不会被 VTable 内部直接消费,而是由业务侧封装层(如统一的 `cellRender`、hook、列工厂函数等)读取并实现对应行为。
268+
269+
为此,VTable 提供了一个 **类型扩展入口**,允许开发者通过 TypeScript 的 module augmentation(模块扩展)为 `ColumnDefine` 增加自定义列类型定义,从而获得完整的类型提示与校验能力。
270+
271+
### 1)定义自定义列类型
272+
273+
```ts
274+
import type { HeaderDefine } from '@visactor/vtable';
275+
276+
// 自定义列 body 配置(示例:自定义按钮列)
277+
export interface IColoredButtonColumnBody {
278+
cellType: 'button';
279+
field: string;
280+
281+
/** 业务侧扩展字段:当值为负数时高亮 */
282+
highlightOnNegative?: boolean;
283+
284+
text?: string;
285+
style?: any;
286+
}
287+
288+
// 完整列定义(Header + Body)
289+
export type ColoredButtonColumnDefine = IColoredButtonColumnBody & HeaderDefine;
290+
```
291+
292+
### 2)通过模块扩展注册类型
293+
294+
```ts
295+
declare module '@visactor/vtable/es/ts-types' {
296+
interface CustomColumnBodyDefineMap {
297+
coloredButton: IColoredButtonColumnBody;
298+
}
299+
300+
interface CustomColumnDefineMap {
301+
coloredButtonColumn: ColoredButtonColumnDefine;
302+
}
303+
}
304+
```
305+
306+
### 3)在 columns 中使用
307+
308+
```ts
309+
import type { ColumnsDefine } from '@visactor/vtable';
310+
311+
const columns: ColumnsDefine = [
312+
{
313+
field: 'value',
314+
title: '自定义按钮列',
315+
cellType: 'button',
316+
text: 'check',
317+
highlightOnNegative: true // ✅ 来自 CustomColumnDefineMap 的扩展字段
318+
}
319+
];
320+
```
321+
322+
> 注意:以上示例展示的是 **类型系统层面的扩展能力**
323+
> `highlightOnNegative` 这类字段是否产生实际效果,需要由业务侧封装的渲染逻辑(例如自定义 `cellRender`、hook 或列工厂)去读取并执行。VTable 本身不会自动解析该字段。

packages/vtable-plugins/src/excel-edit-cell-keyboard.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,12 @@ export class ExcelEditCellKeyboardPlugin implements pluginsDefinition.IVTablePlu
7575
//判断是键盘触发编辑单元格的情况下,那么在编辑状态中切换方向需要选中下一个继续编辑
7676
if (this.table.editorManager.editingEditor && this.table.editorManager.beginTriggerEditCellMode === 'keydown') {
7777
const { col, row } = this.table.editorManager.editCell;
78-
this.table.editorManager.completeEdit();
78+
if (eventKey !== ExcelEditCellKeyboardResponse.BACKSPACE && eventKey !== ExcelEditCellKeyboardResponse.DELETE) {
79+
this.table.editorManager.completeEdit();
80+
} else {
81+
//如果输入了删除或退格键,应正常删除输入框内容
82+
return;
83+
}
7984
this.table.getElement().focus();
8085
if (!event.shiftKey && !event.ctrlKey && !event.metaKey) {
8186
//有这些配合键,则不进行选中下一个单元格的行为 执行vtable内部逻辑

packages/vtable-plugins/src/table-series-number.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,10 @@ export class TableSeriesNumber implements pluginsDefinition.IVTablePlugin {
489489

490490
syncRowHeightToComponent() {
491491
// console.log('syncRowHeightToComponent adjust', adjustStartRowIndex, adjustEndRowIndex);
492+
const rowRange = this.table.getBodyVisibleRowRange();
493+
if (!rowRange) {
494+
return;
495+
}
492496
const { rowStart, rowEnd } = this.table.getBodyVisibleRowRange();
493497
const adjustStartRowIndex = Math.max(rowStart - 2, this.table.frozenRowCount);
494498
const adjustEndRowIndex = Math.min(rowEnd + 2, this.table.rowCount - 1);

0 commit comments

Comments
 (0)