fischer-agentkit/docs/plans/2026-06-29-001-feat-bitable...

22 KiB
Raw Permalink Blame History

title type date origin
feat: Bitable UI Completeness — Stage 1 (File Layer + Default Fields + In-Table Field Ops + Select Editor) feat 2026-06-29 docs/brainstorms/2026-06-29-bitable-ui-completeness-requirements.md

Bitable UI Completeness — Stage 1

Summary

引入"多维表格文件"作为最上级容器,重构 文件 → 数据表 → 字段/记录 三层骨架补齐新建表默认字段、表内列头字段操作、select 下拉编辑器。这是 4 阶段完善计划的第一阶段,聚焦让 bitable 从"功能残缺"到"用户主动建表体验可用"。

Problem Frame

bitable 后端 v1 齐备但前端产品形态残缺(见 origin 文档 Problem Frame。三类核心缺口导致无法正常使用缺最上级文件容器、新建表无默认字段、表内不能直接管理字段。此外 select 编辑器仍是文本输入。Stage 1 解决这四件事,让用户能完成"建文件 → 建表 → 表内配字段 → 填数据"的基本闭环。


Requirements

后端文件层

R1. 引入 BitableFile 实体作为最上级容器。Table 通过 file_id 外键归属文件。文件自有元数据name/icon/description/owner_user_id支持 CRUD。文件级 ownership 检查复用现有 _check_table_ownership 模式(见 docs/solutions/architecture-patterns/bitable-companion-service-security-reliability-patterns.md 模式 4

R2. 新建数据表时自动创建 5 个默认字段标题textowner=user、状态select预设"未开始/进行中/已完成"3 选项owner=user、日期dateowner=user、创建人textowner=agent、创建时间datetimeowner=agent。默认字段遵循 Field Ownership 模型——agent-owned 字段由系统在记录创建时自动填充。

前端文件层与导航

R3. 三层导航层级:文件列表 → 文件详情(含多张表)→ 表内(字段/记录/视图)。文件列表是 /bitable 的新默认页,显示用户拥有的所有文件卡片。点文件卡片进入文件详情,左侧 sidebar 显示该文件的表列表,右侧显示选中表的 grid。

R4. 文件 CRUD UI文件列表页有"新建文件"按钮(弹窗输入名称/选图标/选描述);文件卡片支持重命名、删除(带确认);文件详情 topbar 显示文件名与返回按钮。

前端表内体验

R5. 表内字段操作走列头下拉菜单。点 grid 列头弹出菜单:重命名、修改字段类型、隐藏、删除。不再依赖右侧"字段管理"弹层作为唯一入口FieldManagePanel 保留作为批量管理入口)。删除字段需二次确认(会删除该列所有数据)。

R6. select/multiselect 字段编辑器使用下拉选项(带颜色标签),替换当前 VxeInput 文本输入。选项从字段 config.options 读取,编辑时显示为可搜索下拉,选中后写入 record value。


Key Technical Decisions

KTD1. BitableFile 作为独立实体Table 加 file_id 外键。 不采用"轻量分组"方案Table 加 group_name 字段)。理由:文件需要自己的 ownership/CRUD/元数据,轻量分组会在后续权限/共享能力上撞天花板。当前 schema V1 用 create_all 模式无现有数据需迁移引入文件层是干净的新增origin KD2

KTD2. Schema 升级用 _SCHEMA_VERSION 递增 + 启动时迁移,不引入 alembic。 现有 src/agentkit/bitable/db.py 已有 _SCHEMA_VERSION = 1 与预留的 _apply_v2_migration 注释位。文件层引入升级到 V2创建 bitable_files 表,给 bitable_tablesfile_id 列。启动时 init_db() 检测版本并执行迁移。保持与现有模式一致,不为单次迁移引入 alembic 全套。

KTD3. 默认字段在 service 层 create_table 内创建,不在数据库层用 trigger。 service 层 create_table 在创建 Table 后立即批量创建 5 个默认 Field。理由可测试、可复用、不依赖数据库特定语法。agent-owned 字段(创建人/创建时间)在 create_record 时由 service 自动填充当前 user_id 与 timestamp。

KTD4. 前端路由重构为嵌套结构。 /bitable → 文件列表;/bitable/:fileId → 文件详情(含表列表 sidebar/bitable/:fileId/:tableId → 表内。当前 BitableView.vue 拆为 BitableFileListView.vue + BitableFileDetailView.vue。表内视图复用现有 BitableGrid + ViewSwitcher 等组件。

KTD5. 列头下拉菜单用 vxe-table 的 header slot + Ant Design Vue Dropdown。 不自建列头组件。vxe-table 支持自定义 header slot在 slot 内渲染列名 + 下拉触发图标。菜单项调用现有 store 的 updateField/deleteField action需新增

KTD6. select 编辑器用 vxe-table 自定义编辑器 + Ant Design Vue Select。 注册一个 SelectCellEditor 自定义编辑器,内部用 a-select(带搜索、颜色标签)。选项从 field.config.options 读取。multiselect 用 mode="multiple"。替换 BitableGrid.vue 中 select/multiselect 的 editRender: { name: 'VxeInput' }


High-Level Technical Design

三层导航数据流

flowchart TB
    A[/bitable 文件列表] --> B[选文件卡片]
    B --> C[/bitable/:fileId 文件详情]
    C --> D[左侧 sidebar 选表]
    D --> E[/bitable/:fileId/:tableId 表内]
    E --> F[BitableGrid + ViewSwitcher]
    C --> G[新建表 - 自带默认字段]

后端文件层 schema 变更

flowchart LR
    F[bitable_files] --1:N--> T[bitable_tables]
    T --1:N--> FL[bitable_fields]
    T --1:N--> R[bitable_records]
    T --1:N--> V[bitable_views]

bitable_files: id, name, icon, description, owner_user_id, created_at, updated_at bitable_tables: 新增 file_id 外键列

默认字段创建时序

sequenceDiagram
    participant U as 用户
    participant API as REST API
    participant S as BitableService
    participant R as Repository
    U->>API: POST /files/{file_id}/tables {name}
    API->>S: create_table(file_id, name)
    S->>R: create Table record
    S->>S: _build_default_fields(table_id)
    S->>R: create_records_batch 5 fields
    S-->>API: Table + 5 Fields
    API-->>U: 201 Created

Implementation Units

U1. Backend: BitableFile entity + schema V2 migration

Goal: 引入 BitableFile Pydantic 模型 + ORM model + repository + service + REST endpoints升级 schema 到 V2。

Requirements: R1

Dependencies: 无(基础单元)

Files:

  • src/agentkit/bitable/models.py — 新增 BitableFile Pydantic 模型
  • src/agentkit/bitable/db.py — 新增 FileModel ORM_SCHEMA_VERSION = 2;实现 _apply_v2_migration(创建 files 表,给 tables 加 file_id 列);Tablefile_id 字段
  • src/agentkit/bitable/repository.py — 新增 FileRepositoryCRUD + list_by_owner
  • src/agentkit/bitable/service.py — 新增 BitableService 的文件方法create_file/list_files/get_file/update_file/delete_filecreate_table 改签名加 file_id 参数
  • src/agentkit/server/routes/bitable.py — 新增 /files 端点POST/GET/GET/:id/PUT/:id/DELETE/:id/files/{file_id}/tables POST 端点;文件级 ownership 检查 _check_file_ownership
  • tests/unit/bitable/test_file_crud.py — 新建测试文件

Approach:

  • BitableFile 模型字段id, name, icon (emoji 字符串), description, owner_user_id, created_at, updated_at
  • 文件 ownership 检查复用 _check_table_ownership 模式solutions doc 模式 4404 before 403internal token bypass
  • delete_file 级联删除该文件下所有 tables及其 fields/records/views—— 复用现有 delete_table 逻辑循环
  • schema V2 迁移用 ALTER TABLE bitable_tables ADD COLUMN file_id VARCHAR + CREATE TABLE bitable_files
  • 现有无 file_id 的 table 在迁移时创建一个"默认文件"并归属之(防御性,虽然 verifier 确认无现有数据)

Patterns to follow:

  • docs/solutions/architecture-patterns/bitable-companion-service-security-reliability-patterns.md 模式 1服务隔离、模式 4IDOR ownership 检查)
  • 现有 _check_table_ownership in src/agentkit/server/routes/bitable.py

Test scenarios:

  • Happy path: 创建文件 → 获取 → 列表 → 更新 → 删除
  • Edge case: 删除文件时级联删除其下所有表(验证 tables/fields/records 都被清理)
  • Error path: 非文件 owner 访问返回 404不泄露存在性
  • Error path: internal token bypass ownership 检查
  • Integration: 创建文件 → 在文件下创建 table → table.file_id 正确关联
  • Covers AE1. 新建文件"销售管线"(文件创建部分)

Verification: pytest tests/unit/bitable/test_file_crud.py -v 全绿;ruff check src/agentkit/bitable/ 无 lint 错误。


U2. Backend: Default fields on table creation

Goal: create_table 自动创建 5 个默认字段agent-owned 字段在 create_record 时自动填充。

Requirements: R2

Dependencies: U1create_table 签名变更)

Files:

  • src/agentkit/bitable/service.pycreate_table 内调用 _create_default_fields(table_id, owner_user_id)create_record 内自动填充 agent-owned 字段(创建人 = owner_user_id创建时间 = now
  • src/agentkit/bitable/models.py — 新增 DEFAULT_FIELD_TEMPLATES 常量5 个默认字段定义)
  • tests/unit/bitable/test_default_fields.py — 新建测试文件

Approach:

  • DEFAULT_FIELD_TEMPLATES5 个字段定义,含 name/type/owner/config
  • 状态 select 字段 config: {"options": [{"label":"未开始","value":"not_started","color":"default"},{"label":"进行中","value":"in_progress","color":"processing"},{"label":"已完成","value":"done","color":"success"}]}
  • _create_default_fieldsrepository.create_records_batch 一次创建 5 个 Field
  • create_record 检查 table 的 agent-owned 字段,若 values 未提供则自动填充

Patterns to follow:

  • 现有 create_table in src/agentkit/bitable/service.py
  • CONCEPTS.md Field Ownership 定义

Test scenarios:

  • Happy path: 创建 table → 验证返回 5 个默认字段(名称/类型/owner 正确)
  • Happy path: 状态字段 config.options 有 3 个预设选项
  • Happy path: 创建 record → 创建人字段自动填充 owner_user_id
  • Happy path: 创建 record → 创建时间字段自动填充当前 timestamp
  • Edge case: 用户传 record values 时覆盖创建人字段 → agent-owned 字段不被用户覆盖
  • Covers AE1. 新建表"客户"(默认字段部分)

Verification: pytest tests/unit/bitable/test_default_fields.py -v 全绿。


U3. Frontend: File layer store + API client + navigation restructure

Goal: 前端文件层 API client + store + 三层导航视图重构。

Requirements: R3, R4

Dependencies: U1后端文件 API

Files:

  • src/agentkit/server/frontend/src/api/bitable.ts — 新增 IBitableFile 类型 + file CRUD API 函数
  • src/agentkit/server/frontend/src/stores/bitable.ts — 新增 files state + loadFiles/createFile/updateFile/deleteFile actionsloadTables 改为按 fileId 过滤
  • src/agentkit/server/frontend/src/views/BitableFileListView.vue — 新建:文件列表页(卡片网格 + 新建按钮)
  • src/agentkit/server/frontend/src/views/BitableFileDetailView.vue — 新建文件详情页topbar + 左侧表列表 sidebar + 右侧表内 grid
  • src/agentkit/server/frontend/src/views/BitableView.vue — 删除或改为 redirect 到 /bitable
  • src/agentkit/server/frontend/src/router/index.ts — 重构 /bitable 路由为嵌套:/bitable(文件列表)、/bitable/:fileId(文件详情)、/bitable/:fileId/:tableId(表内,可选拆为子路由或 query
  • src/agentkit/server/frontend/src/components/bitable/FileCard.vue — 新建:文件卡片组件(图标+名称+表数量+描述)
  • src/agentkit/server/frontend/src/components/bitable/FileCreateModal.vue — 新建:创建文件弹窗
  • src/agentkit/server/frontend/src/components/bitable/TableViewList.vue — 修改props 加 fileIdemit create 时带 fileId

Approach:

  • BitableFileListView 布局:顶部"新建文件"按钮 + 卡片网格(每卡片显示 icon/name/表数量/描述/操作菜单)
  • BitableFileDetailView 布局:复用现有 BitableView.vue 的 topbar + sidebar + main 结构,但 topbar 显示文件名 + 返回按钮sidebar 显示该文件的表列表
  • 路由用嵌套 children/bitable → FileListView/bitable/:fileId → FileDetailView内部根据是否选中 table 渲染 grid 或 placeholder
  • 文件删除用 a-popconfirm 二次确认

Patterns to follow:

  • 现有 BitableView.vue 的 topbar + sidebar + main 布局
  • 现有 TableCreateModal.vue 的弹窗模式
  • Ant Design Vue Card / Modal / Popconfirm 组件

Test scenarios:

  • Happy path: 访问 /bitable → 显示文件列表(空态有引导)
  • Happy path: 点"新建文件" → 弹窗 → 输入名称 → 创建 → 列表刷新显示新卡片
  • Happy path: 点文件卡片 → 跳转 /bitable/:fileId → 显示文件详情sidebar 表列表)
  • Happy path: 在文件详情点"新建表" → 表创建后 sidebar 显示
  • Edge case: 删除文件 → popconfirm 确认 → 列表移除
  • Error path: 访问不存在的 fileId → 显示 404 或回退到列表
  • Covers AE1. 新建文件"销售管线"(前端流程)

Verification: npm run typecheck 通过;npm run dev 手动验证三层导航e2e 测试在 U6 覆盖。


U4. Frontend: In-table field operations (column header dropdown)

Goal: grid 列头下拉菜单支持重命名/改类型/隐藏/删除字段。

Requirements: R5

Dependencies: U3store 重构)

Files:

  • src/agentkit/server/frontend/src/components/bitable/BitableGrid.vue — 修改:列 header slot 渲染列名 + 下拉触发图标;移除 select/multiselect 的 VxeInput editRender在 U5 完成)
  • src/agentkit/server/frontend/src/components/bitable/ColumnHeaderMenu.vue — 新建:列头菜单组件(重命名/改类型/隐藏/删除)
  • src/agentkit/server/frontend/src/components/bitable/FieldConfigForm.vue — 修改:支持重命名与改类型(可能复用现有表单)
  • src/agentkit/server/frontend/src/stores/bitable.ts — 新增 updateField(fieldId, patch) + deleteField(fieldId) + hideField(fieldId, viewId) actions

Approach:

  • vxe-table column 配置加 header-class-name + 使用 header slot 自定义渲染
  • header slot 内:列名文本 + 一个 ... 图标触发 a-dropdown
  • 菜单项:
    • 重命名 → 弹 a-modal 输入新名称 → 调 store.updateField
    • 修改类型 → 弹 a-modal 选新类型 → 调 store.updateField(注意:改类型可能清空 config
    • 隐藏 → 调 store.hideField(写入当前 view 的 hidden_fields
    • 删除 → a-popconfirm 确认 → 调 store.deleteField
  • 删除字段会级联删除该字段的所有 record values后端已支持

Patterns to follow:

  • vxe-table header slot 文档
  • Ant Design Vue Dropdown / Modal / Popconfirm

Test scenarios:

  • Happy path: 点列头 → 菜单弹出 4 项
  • Happy path: 重命名 → 输入新名称 → 表头实时更新
  • Happy path: 隐藏字段 → 该列从 grid 消失(仍存在于字段管理面板)
  • Happy path: 删除字段 → popconfirm 确认 → 该列与数据消失
  • Edge case: 删除主键字段 → 提示不允许或确认后清除 primary_key_field_id
  • Covers AE1. 用户点"标题"列头下拉 → 选"重命名"改为"公司名"

Verification: npm run typecheck 通过;手动验证列头菜单 4 个操作。


U5. Frontend: select/multiselect dropdown editor

Goal: select/multiselect 字段编辑器从文本输入改为下拉选项(带颜色标签)。

Requirements: R6

Dependencies: U4BitableGrid 已修改)

Files:

  • src/agentkit/server/frontend/src/components/bitable/SelectCellEditor.vue — 新建:自定义编辑器组件(用 a-select
  • src/agentkit/server/frontend/src/components/bitable/BitableGrid.vue — 修改select/multiselect 列的 editRender 指向自定义编辑器;移除 ponytail: select editor uses text input 注释
  • src/agentkit/server/frontend/src/stores/bitable.ts — 可能需要 getFieldOptions(fieldId) getter

Approach:

  • 注册 vxe-table 自定义编辑器 SelectCellEditor
    • props: field(含 config.options
    • 渲染 a-selectshow-searchlabel-in-value、选项带颜色 tag
    • multiselect 用 mode="multiple"
  • BitableGrid.vue column 配置select/multiselect 的 editRender: { name: 'SelectCellEditor', options: field.config.options }
  • 选项颜色用 a-tag :color="option.color" 渲染

Patterns to follow:

  • vxe-table 自定义编辑器文档
  • Ant Design Vue Select + Tag

Test scenarios:

  • Happy path: 双击 select 单元格 → 下拉弹出 3 个选项(带颜色)
  • Happy path: 选一个选项 → 单元格值更新为 option.value
  • Happy path: multiselect 字段 → 可多选
  • Happy path: 搜索功能 → 输入文字过滤选项
  • Edge case: 字段无 options config → 下拉为空 + 提示
  • Covers R6

Verification: npm run typecheck 通过;手动验证 select 编辑器交互。


U6. E2E test coverage expansion

Goal: 扩展 e2e 测试覆盖 Stage 1 关键流程。

Requirements: Success CriteriaE2E 覆盖)

Dependencies: U3, U4, U5前端功能完成

Files:

  • src/agentkit/server/frontend/e2e/bitable-view.spec.ts — 修改:保留 B1/B2扩展覆盖文件导航
  • src/agentkit/server/frontend/e2e/bitable-file-flow.spec.ts — 新建:文件 CRUD + 三层导航流程
  • src/agentkit/server/frontend/e2e/bitable-field-ops.spec.ts — 新建:列头字段操作 + select 编辑器

Approach:

  • bitable-file-flow.spec.ts
    • 访问 /bitable → 验证文件列表渲染
    • 新建文件 → 验证卡片出现
    • 进入文件 → 验证 sidebar 表列表
    • 新建表 → 验证默认字段显示
    • 切换表 → 验证 grid 切换
  • bitable-field-ops.spec.ts
    • 点列头 → 验证菜单弹出
    • 重命名 → 验证表头更新
    • 隐藏 → 验证列消失
    • select 编辑器 → 验证下拉交互

Patterns to follow:

  • 现有 bitable-view.spec.ts 的 B1/B2 模式
  • Playwright 测试模式

Test scenarios:

  • Happy path: 文件列表 → 新建文件 → 进入 → 新建表(含默认字段)→ 切换表(完整流程)
  • Happy path: 列头重命名 + 隐藏 + select 编辑器交互
  • Smoke: /bitable 不白屏、核心元素可见(保留 B1/B2

Verification: npx playwright test e2e/bitable-*.spec.ts 全绿。


Scope Boundaries

本次范围内Stage 1

R1-R6 全部 + U1-U6 全部。这是 origin 文档 4 阶段中的阶段一。

Deferred to Follow-Up Work

以下 R 在 origin 文档中定义,本次不实现,留给后续 lfg 调用:

  • Stage 2R7-R10:三类采集入口前端 UIExcel/DB/API、Agent 写入反馈 UI
  • Stage 3R11-R13:看板视图、画廊视图、公式编辑器增强
  • Stage 4R14-R17:权限模型、自动化触发器、表单视图、甘特视图

Outside this product's identity

(从 origin 文档继承通用电子表格、ETL/数据管道平台、BI 仪表盘、知识库 RAG 替代。


System-Wide Impact

  • 数据模型变更:新增 bitable_files 表,bitable_tablesfile_id 列。schema V1 → V2 启动时迁移。
  • API 边界:新增 /api/v1/bitable/files 端点组。现有 /tables 端点改为 /files/{file_id}/tables(保留旧端点兼容性,标记 deprecated
  • 前端路由/bitable 从单视图重构为嵌套路由。现有书签需重定向。
  • 领域词汇CONCEPTS.md 需补"多维表格文件/BitableFile"条目。

Risks & Dependencies

  • 风险schema V2 迁移若失败可能导致启动卡住。缓解:迁移用 try/except 包裹,失败时 log 并继续(向后兼容 V1 表为"默认文件"归属)。
  • 风险vxe-table header slot 与自定义编辑器的集成可能在版本差异下行为不一致。缓解U4/U5 实现时先写最小验证 demo。
  • 依赖U2 依赖 U1create_table 签名变更。U3 依赖 U1前端调用后端文件 API。U4/U5 依赖 U3store 重构。U6 依赖 U3/U4/U5。
  • 依赖:现有 docs/solutions/architecture-patterns/bitable-companion-service-security-reliability-patterns.md 的 10 个模式必须遵守(特别是 IDOR ownership 检查、batch 操作、async I/O

Open Questions

Resolve During Implementation

  • 文件图标用 emoji 字符串还是预设图标集?默认用 emoji 字符串(前端用 a-input 输入),实现时确认。
  • 现有 /tables 端点是否保留?保留并标记 deprecated新端点 /files/{file_id}/tables 为推荐路径。
  • BitableView.vue 删除还是保留为 redirect改为 redirect 到 /bitable

Deferred to Implementation

  • vxe-table header slot 的具体 API 形态(版本相关,实现时查文档确认)。
  • select 编辑器在 multiselect 下的值序列化格式(数组 vs 逗号分隔字符串,复用现有后端约定)。

Sources & Research

  • Origin requirements: docs/brainstorms/2026-06-29-bitable-ui-completeness-requirements.md
  • 安全/可靠性模式: docs/solutions/architecture-patterns/bitable-companion-service-security-reliability-patterns.md10 个模式,本次实现必须遵守)
  • 现有后端实现: src/agentkit/bitable/{models,db,repository,service}.py + src/agentkit/server/routes/bitable.py
  • 现有前端实现: src/agentkit/server/frontend/src/views/BitableView.vue + src/agentkit/server/frontend/src/components/bitable/*.vue + src/agentkit/server/frontend/src/stores/bitable.ts
  • 领域词汇: CONCEPTS.md Bitable/Field Ownership/Recalc 定义
  • 飞书多维表格范式: 文件→表→字段/记录三层;列头下拉管理字段;新建表默认字段
  • twentyhq/twenty 布局参考: https://github.com/twentyhq/twenty
  • vxe-table 4 文档: header slot 与自定义编辑器
  • Ant Design Vue 4: Card/Modal/Dropdown/Select/Popconfirm/Tag 组件