12 KiB
12 KiB
Wolai-clone 协同表格方案(v3.1)——Luckysheet 体验 × Supabase 数据底座
0. 背景与目标
- 当前 v3.0 架构已经完成 BlockNote + Yjs + Hocuspocus + Supabase Realtime 的基础协同能力,内置块类型仅支持「简单表格」,无法满足飞书/钉钉/金山文档级交互。
- 新版本需要让用户在文档任意位置插入「在线表格块」,可在文档内预览、可全屏编辑、可多人实时协作,并支持 Excel 级功能(公式、条件格式、批量粘贴等)。
- 同时,考虑到未来要把表格作为独立数据对象(多处引用、导出、AI/OCR 写入等),必须把表格数据与 BlockNote 主文档解耦,避免大表拖垮文档 CRDT。
1. 设计原则
- 用户心智优先:界面与交互最大程度贴近 Excel/WPS/飞书表格,复制粘贴零障碍。
- 数据解耦:BlockNote 块只保存
tableId与视图参数,真实表格数据落在 Supabase + 独立 Yjs SubDoc,确保性能、复用与权限扩展。 - 协同一致性:复用现有 Yjs/Hocuspocus/Supabase Realtime 通道,内嵌/全屏共享同一数据源,支持多人光标与冲突解决。
- 渐进增强:先满足核心编辑体验,再分阶段接入高级能力(导入导出、公式库、与 MinerU/AI 的互通)。
2. 技术选型与理由
| 维度 | 方案 | 理由 |
|---|---|---|
| 表格 UI/编辑器 | Luckysheet (@dream-num) | Excel 级 UI/工具栏/公式/条件格式,复制粘贴兼容 WPS/飞书/钉钉,支持 headless 嵌入。 |
| 数据渲染内核 | Luckysheet + 虚拟滚动 | 经过大规模验证,500×100 也能稳定运行。 |
| 实时协作 | Yjs SubDoc + luckysheet-yjs-binding | 官方 binding,直接复用现有 Hocuspocus Provider;每张表格一个 SubDoc,避免主文档体积膨胀。 |
| 数据持久化 | Supabase Postgres (document_tables, document_table_rows) + 定时快照 |
让表格成为独立实体,可复用/引用/授权,同时方便后台 API、导出和 AI 写入。 |
| 内联预览 | 自研 React 轻量预览组件 + 行列摘要 | 保持文档流畅,默认展示前 5 行,支持 hover 工具条。 |
| 全屏编辑 | <FullScreenTableEditor> + Luckysheet |
提供 Excel 式工具栏、状态栏、协作者指示、暗黑模式。 |
| 公式引擎 | Luckysheet 内置 + HyperFormula(后续增强) | 先满足 SUM/IF 等高频场景,再按需升级。 |
放弃:自研 Data Grid(周期长)、Handsontable(商业授权)、AG-Grid(过重)、Tiptap Table(功能不足)。
3. 架构概览
┌───────────────────────────┐
│ Next.js 前端 │
│ ┌───────────────────────┐ │
│ │ BlockNote (文档 Y.Doc) │ │
│ │ └─ TableBlock │ │
│ │ attrs: {tableId} │ │
│ └───────────────────────┘ │
│ │引用 │
│ ┌───────────────────────┐ │
│ │ LuckysheetProvider │ │
│ │ └─ Y.SubDoc(tableId)│ │
│ │ └─ Supabase Realtime│ │
│ └───────────────────────┘ │
└────────────┬──────────────┘
│REST/RPC
┌────────────▼──────────────┐
│ FastAPI 后端 + Supabase │
│ ├─ document_tables │
│ ├─ document_table_rows │
│ ├─ RLS / Realtime 触发器 │
│ └─ 导出/导入/AI 接口 │
└───────────────────────────┘
- BlockNote 主文档:仅存
tableId、标题、视图配置等轻量信息。 - 表格 Y.SubDoc:按需加载;Luckysheet 与之绑定,实现实时协作。
- Supabase 数据:提供持久化/查询/权限/导出能力;Yjs 定时把最新快照写入数据库,同时监听数据库变化以支持非 Web 客户端。
4. 数据模型
create table document_tables (
id uuid primary key default gen_random_uuid(),
workspace_id uuid not null references workspaces(id) on delete cascade,
document_id uuid not null references documents(id) on delete cascade,
title text not null default '未命名表格',
schema jsonb not null default '{}'::jsonb, -- 列定义/格式/宽度
view_preferences jsonb not null default '{}'::jsonb,
is_archived boolean not null default false,
snapshot jsonb,
last_synced_at timestamptz,
created_by uuid references profiles(id) on delete set null,
updated_by uuid references profiles(id) on delete set null,
created_at timestamptz not null default timezone('utc', now()),
updated_at timestamptz not null default timezone('utc', now())
);
create table document_table_rows (
id uuid primary key default gen_random_uuid(),
workspace_id uuid not null references workspaces(id) on delete cascade,
document_id uuid not null references documents(id) on delete cascade,
table_id uuid not null references document_tables(id) on delete cascade,
row_index integer not null, -- 稳定排序键
row_data jsonb not null default '{}'::jsonb, -- 单元格字典,按列 key 存储
row_hash text,
is_deleted boolean not null default false,
updated_by uuid references profiles(id) on delete set null,
created_at timestamptz not null default timezone('utc', now()),
updated_at timestamptz not null default timezone('utc', now())
);
- ✅(2025-02-22)
supabase_local已执行建表 + 索引 + 触发器 + RLS,迁移文件:supabase/migrations/20250222_add_document_tables.sql。 - RLS:沿用
workspace_members,document_tables/document_table_rows在写入前通过触发器校验 workspace/document 一致,所有读写均需加入同一 workspace。 - 每张表格的实时编辑依赖 Yjs SubDoc;后台任务(导出 CSV/Excel、AI 填表、MinerU OCR 转表)通过 REST API 操作数据库。
- BlockNote 块示例:
{
"id": "block_xxx",
"type": "table",
"props": {
"tableId": "d3d7-...",
"displayMode": "compact",
"previewRows": 5
}
}
5. 功能模块拆解
- 块插入与预览
- 斜杠命令
/table、工具栏按钮、AI 建议等入口。 - 默认创建 10×5 空表,预览显示前 5 行 + 列头,hover 显示快速操作(新建/全屏/复制链接)。
- 斜杠命令
- 全屏编辑器
- Excel 风格工具栏(行列操作、合并、筛选、条件格式、公式插入、单元格格式)。
- 协作者状态:顶部显示头像、单元格边框高亮。
- 暗黑模式、移动端强制全屏。
- 数据同步
- Luckysheet ↔ Y.SubDoc:官方 binding。
- SubDoc ↔ Supabase:节流(1-2s)后写入
document_tables/document_table_rows;大表行级 diff。 - 后端提供导出 CSV/Excel、批量导入 API。
- 高级能力
- 条件格式模版、冻结行列、查看历史版本。
- 允许多个文档引用同一
tableId(只读/编辑权限可控)。 - AI/ MinerU 写表:后端接口
/api/v1/tables/{id}/rows支持 append/merge。
6. 实施计划
| 阶段 | 时间 | 目标 | 关键任务 | 产出 / 验收 |
|---|---|---|---|---|
| P0 需求巩固 | 0.5d | 明确体验 & 数据需求 | - 联合设计/产品确认预览、高级功能优先级 - 定义列类型 MVP(文本/数字/货币/日期/选择/复选/公式/引用) - 确认与 MinerU/AI 的接口需求 |
更新 PRD + 交互稿 |
| P1 数据面准备 | 1d | 建 Supabase 表 & API | - 执行 SQL 建表 + RLS + 触发器(Supabase Realtime 通知) - FastAPI 增加 /tables CRUD、/tables/{id}/rows 批量读写- 单元测试 + API 文档 |
后端分支 + Swagger |
| P2 Yjs/Luckysheet 骨架 | 2d | 协同内核跑通 | - 引入 @dream-num/luckysheet、luckysheet-yjs-binding - 实现 <LuckysheetProvider>,封装 SubDoc 生命周期、连接状态提示- 支持单独打开表格编辑页(不依赖 BlockNote) |
可共享链接、协同无冲突 |
| P3 BlockNote 表格块 & 预览 | 2d | 文档内插入与缩略展示 | - 自定义 block schema + slash command - 预览组件(前5行、hover toolbar、loading/错误态) - 表格块和 Supabase 数据绑定(创建时写表、删除时软删) |
文档里可插入表格并跳转全屏 |
| P4 全屏编辑器 & 工具栏 | 3d | 飞书式编辑体验 | - <FullScreenTableEditor>:工具栏、状态栏、协作者列表- 支持插入/删除/合并/冻结/条件格式/基础公式 - 完善暗黑/移动端 UI |
500×50 表格流畅、多端一致 |
| P5 持久化 & 性能 | 2d | 数据安全 & 优化 | - SubDoc → Supabase 节流、row-level diff - 历史快照(定时写入 table_versions) - 预览模式虚拟滚动、全屏懒加载资源 |
刷新不丢数据、大表不卡顿 |
| P6 高级扩展 | 2d+ | 导入导出 & AI | - CSV/Excel 导入导出 - MinerU OCR 输出自动转表 + 写入 - 表格引用共享、权限控制 UI |
E2E 测试 + 文档 |
若时间紧,可先完成 P0~P4 形成可用 MVP,之后再迭代 P5/P6。
进展速记(2025-02-22)
- ✅ P1「执行 SQL 建表 + RLS + 触发器」已完成(详见上文数据模型 & 迁移文件),剩余
/tables//tables/{id}/rowsAPI + 单元测试待开发。 - ✅ P2「Luckysheet Provider + Yjs SubDoc 骨架」:Next.js 侧封装
LuckysheetCanvas,复用 Hocuspocus 通道,表格编辑自动广播到 Y.Doc 与 Supabase snapshot。 - ✅ P3「BlockNote 表格块 & 预览」:自定义
tableBlock+ slash/table,支持在线创建、缩略展示、重命名、全屏入口。 - ✅ P4「全屏编辑器」:落地
<TableEditorOverlay>,集成 Luckysheet 工具栏、保存状态、协同提示,500×50 表格实测流畅。
7. 依赖与工具
pnpm add @dream-num/luckysheet luckysheet-yjs-binding @hocuspocus/provider yjs y-protocols zustand lucide-react
# 后端
pip install fastapi supabase-py psycopg[binary] uvicorn[standard]
- 设计稿:Figma(飞书表格参考)。
- 协同测试:Cypress + Playwright(多客户端场景)。
8. 验收清单
/table插入后出现缩略预览,支持命名/重命名。- 多端同时编辑同一表,光标位置、单元格内容同步延迟 < 800ms。
- 刷新或重连后表格数据一致,Supabase 中有对应记录。
- 全屏编辑支持:插入/删除行列、调整列宽、冻结、合并、条件格式、公式 (SUM/AVERAGE/IF)。
- 支持从 Excel/WPS/飞书/钉钉直接粘贴,保留行列和基础格式。
- CSV/Excel 导出可用,至少支持 UTF-8。
- 移动端默认全屏,横屏提示可编辑。
9. 后续路线(与整体架构衔接)
- 多视图:基于同一
tableId派生看板、画廊,复用 Supabase 数据。 - AI Assist:支持「生成表格」「自动补数据」「智能公式建议」,后端复用 LightRAG + GPT-4o。
- OCR 写表:MinerU 解析复杂表格后直接写入
document_table_rows,用户可在 Luckysheet 中二次确认。 - 权限与共享: 表格可独立分享/只读/协作,并在后台记录操作日志。
此方案兼顾用户熟悉的 Excel 体验与 Supabase 数据化能力,为后续多视图、AI、OCR 等模块铺平道路。接下来可按 P0~P4 推进 MVP,实现飞书级表格块体验。*** End Patch