Files
mnote/design/表格方案.md
T
2025-11-23 10:55:04 +08:00

12 KiB
Raw Blame History

Wolai-clone 协同表格方案(v3.1)——Luckysheet 体验 × Supabase 数据底座

0. 背景与目标

  • 当前 v3.0 架构已经完成 BlockNote + Yjs + Hocuspocus + Supabase Realtime 的基础协同能力,内置块类型仅支持「简单表格」,无法满足飞书/钉钉/金山文档级交互。
  • 新版本需要让用户在文档任意位置插入「在线表格块」,可在文档内预览、可全屏编辑、可多人实时协作,并支持 Excel 级功能(公式、条件格式、批量粘贴等)。
  • 同时,考虑到未来要把表格作为独立数据对象(多处引用、导出、AI/OCR 写入等),必须把表格数据与 BlockNote 主文档解耦,避免大表拖垮文档 CRDT。

1. 设计原则

  1. 用户心智优先:界面与交互最大程度贴近 Excel/WPS/飞书表格,复制粘贴零障碍。
  2. 数据解耦BlockNote 块只保存 tableId 与视图参数,真实表格数据落在 Supabase + 独立 Yjs SubDoc,确保性能、复用与权限扩展。
  3. 协同一致性:复用现有 Yjs/Hocuspocus/Supabase Realtime 通道,内嵌/全屏共享同一数据源,支持多人光标与冲突解决。
  4. 渐进增强:先满足核心编辑体验,再分阶段接入高级能力(导入导出、公式库、与 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-22supabase_local 已执行建表 + 索引 + 触发器 + RLS,迁移文件:supabase/migrations/20250222_add_document_tables.sql
  • RLS:沿用 workspace_membersdocument_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. 功能模块拆解

  1. 块插入与预览
    • 斜杠命令 /table、工具栏按钮、AI 建议等入口。
    • 默认创建 10×5 空表,预览显示前 5 行 + 列头,hover 显示快速操作(新建/全屏/复制链接)。
  2. 全屏编辑器
    • Excel 风格工具栏(行列操作、合并、筛选、条件格式、公式插入、单元格格式)。
    • 协作者状态:顶部显示头像、单元格边框高亮。
    • 暗黑模式、移动端强制全屏。
  3. 数据同步
    • Luckysheet ↔ Y.SubDoc:官方 binding。
    • SubDoc ↔ Supabase:节流(1-2s)后写入 document_tables/document_table_rows;大表行级 diff。
    • 后端提供导出 CSV/Excel、批量导入 API。
  4. 高级能力
    • 条件格式模版、冻结行列、查看历史版本。
    • 允许多个文档引用同一 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}/rows API + 单元测试待开发。
  • 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. 后续路线(与整体架构衔接)

  1. 多视图:基于同一 tableId 派生看板、画廊,复用 Supabase 数据。
  2. AI Assist:支持「生成表格」「自动补数据」「智能公式建议」,后端复用 LightRAG + GPT-4o。
  3. OCR 写表:MinerU 解析复杂表格后直接写入 document_table_rows,用户可在 Luckysheet 中二次确认。
  4. 权限与共享: 表格可独立分享/只读/协作,并在后台记录操作日志。

此方案兼顾用户熟悉的 Excel 体验与 Supabase 数据化能力,为后续多视图、AI、OCR 等模块铺平道路。接下来可按 P0~P4 推进 MVP,实现飞书级表格块体验。*** End Patch