docs(bitable-p0): add implementation plan for P0 UX polish + agent parity

ce-plan Deep plan (6 Implementation Units, 3 delivery phases):
- Phase 1: U1 R5 design token system + vxe-table dependency declaration
- Phase 2: U2-U5 R1-R4 frontend UX (inline field config, record drawer,
  view type switcher, grouping + conditional formatting)
- Phase 3: U6 R15a BitableTool 4 new actions + DELETE /views endpoint

11 KTDs covering: CSS token layer, vxe-table ghost dependency fix,
inline field configurator (hybrid vxe-table slot + custom component),
record detail drawer (single column 480/640px), view type dropdown
with disabled states, grouping + conditional format in View.config
with backend Pydantic validation, BitableTool action registration
(handlers dict + input_schema enum), X-Internal-Token ownership
semantics, 3-phase delivery with config schema freeze for parallel U6.

Phase 5.3 headless ce-doc-review (5 reviewers, 14 findings):
- Applied 2 safe_auto (U6 verification method, U5→U6 dependency)
- Applied 2 gated_auto (input_schema enum step, color_token→color_key)
- Applied 5 P1 manual fixes (backend config validation, X-Internal-Token
  ownership, grouping+CF combo state, LoadingState/ErrorState justification,
  R3/R4 backend assumption verification)
- 8 P2/P3 manual findings appended to Open Questions

Origin: docs/brainstorms/2026-07-03-bitable-comparative-evaluation-requirements.md
This commit is contained in:
chiguyong 2026-07-03 13:49:57 +08:00
parent f8927d1749
commit 96ccca3d87
1 changed files with 521 additions and 0 deletions

View File

@ -0,0 +1,521 @@
---
title: "feat: Bitable P0 UX Polish + Agent Parity"
type: feat
date: 2026-07-03
origin: docs/brainstorms/2026-07-03-bitable-comparative-evaluation-requirements.md
---
# Bitable P0 UX Polish + Agent Parity
## Summary
引入统一设计 token 系统、补齐 grid 视图 UX 缺口(内联字段配置、记录详情抽屉、视图类型切换、分组与条件格式)、闭合 agent 对等缺口BitableTool 4 新动作 + DELETE /views 端点)。这是 bitable 从"功能残缺"到"grid 体验达飞书/Twenty 水准 + agent 对等"的 P0 交付,分 3 阶段R5 token 基座 → R1-R4 前端 UX → R15a 后端+agent 对等。
## Problem Frame
bitable 后端 v1 齐备28 端点 + 公式引擎 + 三类采集但前端产品形态残缺——grid 体验未达竞品水准(列头编辑跳抽屉、无记录详情、无分组/条件格式、视觉无统一设计语言),且 BitableTool 仅 6 动作 vs 28 REST 端点存在系统性 agent 孤儿风险。P0 聚焦"已存在功能的 UX 打磨 + agent 对等最高优先级子项"P1/P2 功能广度延后。
origin 文档(`docs/brainstorms/2026-07-03-bitable-comparative-evaluation-requirements.md`已完成三向对比评估agentkit vs Twenty vs 飞书)、差距分析、优先级建议,本 plan 承接其 P0 范围R1/R2/R3/R4/R5/R15a
---
## Scope
### In Scope (P0)
- R5: 统一设计 token 系统CSS 变量层:颜色/间距/圆角/字号)+ 字段类型图标 + 彩色 chip 升级
- R1: 列内联字段配置(列头菜单直接编辑,不跳右侧抽屉)
- R2: 记录详情侧边抽屉(行点击展开,全字段类型可视化展示与编辑)
- R3: 视图类型切换与创建ViewSwitcher 暴露 5 种类型,禁用态标注"规划中"
- R4: grid 视图内分组与条件格式(多字段分组 + 规则自动着色)
- R15a: BitableTool 动作补全6→10 动作)+ DELETE /views 后端端点
### Out of Scope (Deferred to P1/P2)
- R6/R7: 看板/画廊视图实现P1
- R8: 字段类型扩展 17 项 + schema V3 迁移P1
- R9/R10: 公式库扩展 + 跨表关联增强P1
- R11: 甘特/表单视图P2
- R12/R13/R14: 自动化/仪表盘/细粒度权限P2
- R15b/R15c: NL→表 agent 技能 / 定时采集 UIB 线,独立推进)
- 并发编辑 UX、实时协作P1+
- 大规模优化(列式存储/分区v3
### Pre-conditions / Assumptions
- 后端 v1 齐备且稳定28 端点 + 公式引擎 + 三类采集已就位)
- `ViewType` 枚举已有 5 种类型grid/kanban/gantt/gallery/form—— 后端无需改枚举
- `CreateViewRequest` 已接受 `view_type` 字段 —— R3 纯前端
- `UpdateViewRequest.config: dict` 可直接存 `group_by`/`conditional_formatting` —— R4 后端无需改模型
- vxe-table 4 作为 grid 实现基础(需先消除幽灵依赖)
- PostgreSQL 性能足以支撑 v1/v2 规模(<10 万行大规模延后 v3
- P0 视觉风格对齐基于现有 Ant Design Vue + vxe-table 主题定制,不引入新 UI 库
---
## Key Technical Decisions
**KTD1. 设计 token 用 CSS 自定义属性层,不引入 Tailwind/Sass。** 在 `src/agentkit/server/frontend/src/styles/bitable-tokens.css` 定义 `:root` 下的 CSS 变量(`--bitable-color-*`/`--bitable-spacing-*`/`--bitable-radius-*`/`--bitable-font-*`),通过 Ant Design Vue 的 ConfigProvider token 覆盖与 vxe-table 的 CSS 变量对接。理由:零依赖、运行时可覆盖、与现有 Ant Design Vue 4 token 系统兼容。颜色调色板 8 色预设,全部满足 WCAG AA 对比度≥4.5:1
**KTD2. vxe-table 幽灵依赖在 U1 显式声明。** `src/agentkit/server/frontend/package.json` 添加 `vxe-table``vxe-pc-ui` 版本声明(与主仓 node_modules 实际版本对齐),消除 hoisting 风险。这是 R1/R3/R4 实施的前置条件。
**KTD3. R1 内联字段配置用 vxe-table header slot + 自定义 InlineFieldConfigurator 组件(混合方案)。** 不用 vxe-table 内置编辑(功能受限),不自建完整列头组件(重复造轮子)。在 vxe-table 的 header slot 内渲染列名 + 下拉触发图标,下拉面板内嵌 `InlineFieldConfigurator.vue`(复用 `FieldConfigForm.vue` 的类型切换/选项管理逻辑,但不抽屉化)。`FieldManagePanel.vue` 保留作为批量管理入口。
**KTD4. R2 记录详情抽屉单列纵向,宽度 480px与 FieldManagePanel 一致),>10 字段时扩展至 640px。** 不用双列紧凑窄屏退化复杂、字段类型多时视觉混乱。sticky header 显示记录标题body 按字段顺序纵向排列每字段一行label + value。attachment/image 显示缩略图formula 显示只读计算结果lookup 显示关联值。宽度断点通过 design token 控制(`--bitable-drawer-width`/`--bitable-drawer-width-wide`)。
**KTD5. R3 视图类型选择用 Ant Design Vue Dropdown + disabled items。** `ViewSwitcher.vue` 的"新建视图"按钮改为 Dropdown5 种类型列出未实现的kanban/gallery/gantt/form`disabled` + tooltip "规划中"。点击 grid 调用 `handleCreateView``view_type: 'grid'`(不再硬编码)。后端 `CreateViewRequest` 已支持 `view_type`,无需后端改动。
**KTD6. R4 分组与条件格式存入 View.config后端用 Pydantic 校验 config 子结构。** `group_by: [{field_id, direction}]`(最多 3 字段)+ `conditional_formatting: [{field_id, operator, value, color_key}]`7 运算符)。前端 `ViewConfigPanel.vue` 新增分组与条件格式编辑器,提交时 PUT 进 `config` dict。后端 `UpdateViewRequest.config` 已是 `dict[str, Any]`,但**新增 Pydantic 校验模型**`GroupByItem`/`ConditionalFormatRule`)在 service 层 validate config 子结构——operator 枚举校验、color_key 限定 8 色白名单、group_by 长度 ≤3。理由agent 通过 BitableTool 的 `update_view` 动作可直接写 config前端校验对 agent 路径无效,必须服务端 enforce闭合 ce-doc-review 安全 finding。颜色存语义 key`'red'|'orange'|'yellow'|'green'|'blue'|'purple'|'gray'|'neutral'`),前端 `groupingRulesUtils.ts` 提供 `colorKeyToCssVar()` 映射到 `--bitable-cf-*`,避免前端 CSS 实现细节持久化到数据库。
**KTD7. R4 条件格式规则构建器用列表式rule list非向导式、非 DSL。** 每条规则一行:字段选择 + 运算符选择 + 值输入 + 颜色选择8 色 token 预设)+ 启用/禁用开关。规则按顺序优先(首条匹配 wins。预览实时着色当前 grid 数据样本。
**KTD8. R4 分组交互:默认展开、首字段优先排序、分组头显示聚合行。** 分组头显示分组字段值 + 计数(+ 求和/平均值如果字段为 number。多字段分组时层级嵌套可折叠/展开。拖拽分组字段调整层级顺序可选P0 不强制)。
**KTD9. R15a 后端新增 DELETE /views/{view_id} 端点,复用现有 ownership 检查模式。** 路由 `@router.delete("/views/{view_id}", status_code=204)`,调用 `service.delete_view(view_id)`,前置 `_check_table_ownership`(通过 view → table 关联查 owner。404-before-403 与现有 27 端点一致(见 `docs/solutions/architecture-patterns/bitable-companion-service-security-reliability-patterns.md` 模式 4。**X-Internal-Token 路径 ownership 语义**:内部令牌绑定系统 agent 身份(`user_id="__bitable_internal__"`所有写操作记审计日志。agent 通过 BitableTool 调用 `_delete_view`X-Internal-Token 透传但 ownership 检查仍执行——内部令牌仅 bypass ownership与现有 28 端点一致不等于全权。Test scenario 验证X-Internal-Token 调用 `_delete_view` 操作非自己资源时返回 404。
**KTD10. R15a BitableTool 4 新动作与现有 6 动作同模式。** `bitable_tool.py` 新增 `_create_view`/`_update_view`/`_update_field`/`_delete_view` 4 个 async def复用现有 `_call_api` 内部方法JWT 或 X-Internal-Token 认证)。**动作注册需同步更新两处**(1) `execute()``handlers` dict 添加 4 个映射;(2) `input_schema.properties.action.enum` 添加 4 个字符串(`create_view`/`update_view`/`update_field`/`delete_view`)。若只改 handlers 不改 enumagent 的 LLM 看不到新动作可选值4 个新动作实际不可调用。`update_field` 覆盖 R1 的 PATCH /fields/{id}`create_view`/`update_view` 覆盖 R3/R4 的视图操作,`delete_view` 覆盖新增的 DELETE 端点。
**KTD11. 交付分 3 阶段,每阶段可独立验证。** Phase 1 (U1) token 基座 → Phase 2 (U2-U5) 前端 UX → Phase 3 (U6) 后端+agent。Phase 2 的 4 个 U-ID 可并行(共享 U1 token 但互不依赖Phase 3 依赖 Phase 2 的 U4 + U5create_view/update_view 的 view_type + group_by/conditional_formatting config 结构需与前端一致)。**Phase 2 开始时即冻结 config schema 契约文档**U6 可与 U4/U5 并行实现,仅集成测试在 Phase 2 完成后。
---
## Implementation Units
### Phase 1 — Foundation
#### U1: R5 Design Token System + vxe-table Dependency Declaration
**Goal:** 建立统一设计 token 系统CSS 变量层),重写 bitable 组件颜色/间距/圆角/字号,补齐字段类型图标与彩色 chip 升级,显式声明 vxe-table 依赖。这是 Phase 2 所有 UI 工作的前置基座。
**Files:**
- `src/agentkit/server/frontend/package.json` — 添加 `vxe-table` + `vxe-pc-ui` 依赖声明
- `src/agentkit/server/frontend/src/styles/bitable-tokens.css` (new) — CSS 自定义属性定义
- `src/agentkit/server/frontend/src/main.ts` — import bitable-tokens.css
- `src/agentkit/server/frontend/src/components/bitable/BitableGrid.vue` — 替换硬编码颜色为 token 引用
- `src/agentkit/server/frontend/src/components/bitable/ColumnHeaderMenu.vue` — token 化
- `src/agentkit/server/frontend/src/components/bitable/SelectDisplay.vue` — chip 升级8 色 token 调色板 + 对比度修复)
- `src/agentkit/server/frontend/src/components/bitable/SelectCellEditor.vue` — token 化
- `src/agentkit/server/frontend/src/components/bitable/AttachmentCell.vue` — token 化
- `src/agentkit/server/frontend/src/components/bitable/ImageCell.vue` — token 化
- `src/agentkit/server/frontend/src/components/bitable/FileCard.vue` — token 化
- `src/agentkit/server/frontend/src/views/BitableFileListView.vue` — token 化
- `src/agentkit/server/frontend/src/views/BitableFileDetailView.vue` — token 化
- `src/agentkit/server/frontend/src/components/bitable/FieldTypeIcon.vue` (new) — 9 种字段类型图标Ant Design Outlined
- `src/agentkit/server/frontend/src/composables/useResponsiveBreakpoint.ts` (new) — 768/1024/1440 断点 composable
- `src/agentkit/server/frontend/src/components/bitable/LoadingState.vue` (new) — 统一加载态(骨架屏)
- `src/agentkit/server/frontend/src/components/bitable/ErrorState.vue` (new) — 统一错误态(行内提示)
**Approach:**
1. 在 `bitable-tokens.css` 定义 4 类 token
- 颜色:`--bitable-color-primary`/`--bitable-color-bg`/`--bitable-color-text`/`--bitable-color-border`/`--bitable-cf-{red,orange,yellow,green,blue,purple,gray,neutral}`(条件格式 8 色预设,全部 WCAG AA ≥4.5:1
- 间距:`--bitable-spacing-{xs,sm,md,lg,xl}`4/8/12/16/24px
- 圆角:`--bitable-radius-{sm,md,lg}`4/6/8px
- 字号:`--bitable-font-{xs,sm,md,lg}`12/13/14/16px
- 抽屉宽度:`--bitable-drawer-width: 480px`/`--bitable-drawer-width-wide: 640px`
2. 逐组件 grep 硬编码 hex 颜色(`#[0-9a-fA-F]{3,6}`),替换为 token var()
3. `FieldTypeIcon.vue` 映射 9 种类型到 Ant Design Outlined 图标text→FileTextOutlined, number→NumberOutlined, date→CalendarOutlined, select→TagOutlined, multiselect→TagsOutlined, attachment→PaperClipOutlined, image→PictureOutlined, formula→FunctionOutlined, lookup→LinkOutlined
4. `SelectDisplay.vue` chip 配色从 8 色 token 调色板取色,每色确保 ≥4.5:1 对比度
5. `useResponsiveBreakpoint.ts` 暴露 `isMobile`/`isTablet`/`isDesktop` 响应式断点768/1024/1440
6. `LoadingState.vue` + `ErrorState.vue` 作为 bitable 内部统一加载/错误态组件(**P0 提升理由**U3 RecordDetailDrawer 异步加载需骨架屏避免白屏、U2/U4 提交需 loading 态防重复点击。U2-U5 Test scenarios 强制引用这两个组件证明确实被消费)
7. `useResponsiveBreakpoint.ts` 在 U3抽屉 `isMobile` 时全屏覆盖)+ U5ViewConfigPanel `isMobile` 时改底部抽屉)显式消费
8. **R3/R4 后端假设验证**Phase 1 退出条件grep + pytest round-trip 验证 `CreateViewRequest` 接受 `view_type``UpdateViewRequest` 接受任意 config dict。若验证失败Phase 2 需补后端工作项
**Test scenarios:**
1. Given bitable-tokens.css, When grep `#[0-9a-fA-F]{3,6}` in bitable components, Then 零硬编码 hex全部用 var()
2. Given FieldTypeIcon, When 渲染 9 种字段类型, Then 各有对应 Ant Design Outlined 图标
3. Given SelectDisplay chip, When axe-core 扫描, Then 所有关键文本对比度 ≥4.5:1WCAG AA
4. Given package.json, When `npm ls vxe-table vxe-pc-ui`, Then 两者均为显式声明依赖(非 hoisting
5. Given useResponsiveBreakpoint, When viewport < 768px, Then `isMobile === true`
6. Given LoadingState, When 异步加载, Then 显示骨架屏(非 spinner
7. Given ErrorState, When 异步失败, Then 显示行内错误提示 + 重试按钮
**Verification:**
- `npm run typecheck` 通过
- `npm run build:frontend` 通过
- axe-core 扫描 bitable 页面对比度全绿
- grep 硬编码 hex 零匹配
---
### Phase 2 — Frontend UX (depends on U1)
#### U2: R1 Inline Field Configuration
**Goal:** 列头菜单直接编辑字段(重命名/改类型/选项管理),不跳右侧 FieldManagePanel 抽屉。FieldManagePanel 保留作为批量管理入口。
**Files:**
- `src/agentkit/server/frontend/src/components/bitable/InlineFieldConfigurator.vue` (new) — 内联字段配置面板(复用 FieldConfigForm 逻辑)
- `src/agentkit/server/frontend/src/components/bitable/ColumnHeaderMenu.vue` — 菜单重构:编辑 → 内联展开(非跳抽屉)
- `src/agentkit/server/frontend/src/components/bitable/BitableGrid.vue` — header slot 集成 InlineFieldConfigurator
- `src/agentkit/server/frontend/src/components/bitable/FieldManagePanel.vue` — 保留,添加"批量管理"定位提示
- `src/agentkit/server/frontend/src/stores/bitable.ts` — 复用现有 `updateField` action
- `src/agentkit/server/frontend/e2e/bitable-field-ops.spec.ts` — extend: 内联编辑场景
- `src/agentkit/server/frontend/src/helpers/fieldRenderUtils.ts` (new) — 纯函数:字段类型校验、类型转换兼容性检查
**Approach:**
1. `InlineFieldConfigurator.vue``FieldConfigForm.vue` 抽取核心逻辑(类型切换、选项管理、校验),以 inline panel 形式渲染(非抽屉)
2. `ColumnHeaderMenu.vue` 的"编辑"项改为 toggle InlineFieldConfigurator 在列头下方展开
3. 类型变更提交前调用 `fieldRenderUtils.checkTypeCompatibility(oldType, newType, existingValues)` —— 若现有值不可转换则显示警告 + 阻止提交
4. 重命名/选项管理直接调用 store `updateField(fieldId, patch)` → PATCH /fields/{id}
5. 键盘可达Tab 到列头菜单 → Enter 展开 → Tab 字段间切换 → Esc 关闭
**Test scenarios:**
1. Given select 字段有 3 选项, When 点击列头菜单"编辑", Then InlineFieldConfigurator 内联展开(不跳右侧抽屉)
2. Given 字段名变更提交, When PATCH /fields/{id}, Then 返回 200 + grid 在 1 帧内重渲染新标签
3. Given 字段类型 text → number, When 现有记录值不可转换, Then 显示警告 + 阻止提交
4. Given select 选项管理, When 新增/删除/重命名选项, Then 内联完成 + 提交后 chip 更新
5. Given 键盘导航, When Tab 到列头菜单 → Enter, Then 展开 InlineFieldConfigurator + 焦点在首字段
6. Given FieldManagePanel, When 从列头菜单"批量管理"打开, Then 仍可用(保留入口)
**Verification:**
- `npm run typecheck` 通过
- e2e `bitable-field-ops.spec.ts` 内联编辑场景通过
- axe-core 键盘导航可达性通过
---
#### U3: R2 Record Detail Drawer
**Goal:** grid 行点击展开右侧详情抽屉显示所有字段类型的可视化展示与编辑。单列纵向480px>10 字段扩展 640px
**Files:**
- `src/agentkit/server/frontend/src/components/bitable/RecordDetailDrawer.vue` (new) — 记录详情抽屉
- `src/agentkit/server/frontend/src/components/bitable/BitableGrid.vue` — 行点击事件 → 打开抽屉
- `src/agentkit/server/frontend/src/stores/bitable.ts``currentRecord` state + `openRecordDetail`/`closeRecordDetail` actions
- `src/agentkit/server/frontend/src/api/bitable.ts` — 复用现有 `queryRecords`(按 record_id 查询)
- `src/agentkit/server/frontend/e2e/bitable-record-drawer.spec.ts` (new) — 抽屉 e2e
- `src/agentkit/server/frontend/src/helpers/recordDrawerUtils.ts` (new) — 纯函数字段值渲染格式化、attachment/image 缩略图 URL 生成
**Approach:**
1. `RecordDetailDrawer.vue` 用 Ant Design Vue `a-drawer``width` 绑定 design token`--bitable-drawer-width` / `--bitable-drawer-width-wide`
2. sticky header 显示记录标题字段值(首个 text 类型字段)
3. body 按字段顺序纵向排列,每字段一行:
- label字段名 + FieldTypeIcon
- value根据类型渲染text/number/date 直接显示select/multiselect 用 SelectDisplay chipattachment 显示文件名列表image 显示缩略图网格formula 显示只读计算结果lookup 显示关联表字段值)
4. user-owned 字段可编辑inline edit → upsertagent-owned 字段只读
5. 编辑提交调用 store `upsertRecord` → upsert 保留 agent 列(见 origin R2 验收标准)
6. Esc 关闭抽屉
**Test scenarios:**
1. Given grid 行, When 用户点击行, Then 右侧抽屉展开显示所有字段(含 attachment/formula/lookup
2. Given 抽屉打开且字段为 attachment/image, When 渲染, Then 显示缩略图/预览(非原始 URL
3. Given 抽屉打开且字段为 formula, When 渲染, Then 显示计算结果(只读,不可编辑)
4. Given 抽屉中编辑 user-owned 字段并提交, When 后端 upsert, Then agent 列不被覆盖
5. Given 字段数 ≤ 10, When 抽屉渲染, Then 宽度 480px
6. Given 字段数 > 10, When 抽屉渲染, Then 宽度 640px
7. Given 抽屉打开, When 按 Esc, Then 抽屉关闭
**Verification:**
- `npm run typecheck` 通过
- e2e `bitable-record-drawer.spec.ts` 通过
- upsert 保留 agent 列(现有 test_service.py 覆盖)
---
#### U4: R3 View Type Switcher
**Goal:** ViewSwitcher 支持选 grid/kanban/gallery/gantt/form新建视图选类型不再硬编码 grid。未实现的以禁用态展示 + 标注"规划中"。
**Files:**
- `src/agentkit/server/frontend/src/components/bitable/ViewSwitcher.vue` — "新建视图"改为 Dropdown + 5 类型选择
- `src/agentkit/server/frontend/src/views/BitableFileDetailView.vue``handleCreateView` 接受 `view_type` 参数(不再硬编码 'grid'
- `src/agentkit/server/frontend/src/stores/bitable.ts``createView` action 传 `view_type`
- `src/agentkit/server/frontend/src/api/bitable.ts``createView` API 调用传 `view_type`
- `src/agentkit/server/frontend/e2e/bitable-view.spec.ts` — extend: 类型选择场景
- `src/agentkit/server/frontend/src/helpers/viewSwitcherUtils.ts` (new) — 纯函数视图类型元数据label/icon/disabled/tooltip
**Approach:**
1. `viewSwitcherUtils.ts` 定义 5 种类型元数据:
- grid: { label: '表格', icon: TableOutlined, disabled: false }
- kanban: { label: '看板', icon: AppstoreOutlined, disabled: true, tooltip: '规划中' }
- gallery: { label: '画廊', icon: PictureOutlined, disabled: true, tooltip: '规划中' }
- gantt: { label: '甘特', icon: BarChartOutlined, disabled: true, tooltip: '规划中' }
- form: { label: '表单', icon: FormOutlined, disabled: true, tooltip: '规划中' }
2. `ViewSwitcher.vue` 的"新建视图"按钮改为 `a-dropdown`,列出 5 类型disabled 项设 `disabled` + tooltip
3. `handleCreateView``BitableFileDetailView.vue` 接受 `viewType: ViewType` 参数,调用 store `createView({ table_id, name, view_type })`
4. store `createView` 调用 API `createView``view_type` 字段
5. 后端 `CreateViewRequest` 已支持 `view_type`line 181无需后端改动
**Test scenarios:**
1. Given ViewSwitcher, When 用户点击"新建视图", Then 显示 5 种类型选择grid/kanban/gallery/gantt/form
2. Given kanban/gallery/gantt/form 未实现, When 渲染, Then 以禁用态展示 + 标注"规划中" tooltip
3. Given 新建视图选 grid, When 创建, Then 调用 POST /views 传 `view_type=grid`(不再硬编码)
4. Given 禁用态类型, When 点击, Then 不触发创建 + 显示"规划中" tooltip
5. Given 后端 CreateViewRequest, When 接收 `view_type` 字段, Then 正确存储(现有后端已支持)
**Verification:**
- `npm run typecheck` 通过
- e2e `bitable-view.spec.ts` 类型选择场景通过
- POST /views 请求体含 `view_type` 字段
---
#### U5: R4 Grouping + Conditional Formatting
**Goal:** grid 视图内多字段分组(最多 3 字段)+ 条件格式规则自动着色7 运算符)。分组与条件格式存入 View.config。
**Files:**
- `src/agentkit/server/frontend/src/components/bitable/ViewConfigPanel.vue` — 新增分组 + 条件格式编辑器 tab
- `src/agentkit/server/frontend/src/components/bitable/GroupingEditor.vue` (new) — 分组编辑器(字段选择 + 排序 + 聚合)
- `src/agentkit/server/frontend/src/components/bitable/ConditionalFormatEditor.vue` (new) — 条件格式规则列表编辑器
- `src/agentkit/server/frontend/src/components/bitable/BitableGrid.vue` — 分组渲染 + 条件格式着色逻辑
- `src/agentkit/server/frontend/src/stores/bitable.ts``updateViewConfig` actionPATCH /views config
- `src/agentkit/server/frontend/src/api/bitable.ts` — 复用现有 `updateView`
- `src/agentkit/server/frontend/e2e/bitable-grouping.spec.ts` (new) — 分组 + 条件格式 e2e
- `src/agentkit/server/frontend/src/helpers/groupingRulesUtils.ts` (new) — 纯函数:分组层级计算、聚合值计算、条件格式规则匹配
- `tests/unit/bitable/test_grouping.py` (new) — 后端 config 存储测试
- `tests/unit/bitable/test_conditional_formatting.py` (new) — 后端 config 存储测试
**Approach:**
1. View.config schema前端约定 + 后端 Pydantic 校验,见 KTD6
```typescript
{
group_by: [{ field_id: string, direction: 'asc' | 'desc' }], // 最多 3 项
conditional_formatting: [{
field_id: string,
operator: 'equals' | 'not-equals' | 'contains' | 'is-empty' | 'greater-than' | 'less-than' | 'between',
value: string,
color_key: 'red' | 'orange' | 'yellow' | 'green' | 'blue' | 'purple' | 'gray' | 'neutral'
}]
}
```
2. `GroupingEditor.vue`:字段多选(最多 3+ 方向切换 + 拖拽排序层级
3. `ConditionalFormatEditor.vue`:列表式规则编辑器,每行 = 字段 + 运算符 + 值 + 颜色8 色 key 预设)+ 启用开关
4. `BitableGrid.vue` 分组渲染:按 group_by 字段层级嵌套,分组头显示字段值 + 计数 + number 字段聚合SUM/AVG默认展开可折叠
5. `BitableGrid.vue` 条件格式着色:遍历 conditional_formatting 规则,首条匹配 wins单元格背景色用 `var(colorKeyToCssVar(color_key))`。**组合态约定**:分组 + 条件格式同时启用时,条件格式仅作用于数据单元格,分组头不着色(避免视觉冲突)
6. 提交时调用 store `updateViewConfig(viewId, { group_by, conditional_formatting })` → PATCH /views config
7. 后端 service 层用 Pydantic 校验 config 子结构(`GroupByItem`/`ConditionalFormatRule`),拒绝非法 operator/color_key/超长 group_by422
**Test scenarios:**
1. Given grid 视图, When 用户开启分组, Then 支持最多 3 字段分组(对标飞书/Twenty
2. Given 条件格式规则 operator=equals, When 单元格值匹配, Then 自动着色
3. Given 两条规则匹配同一单元格, When 冲突, Then 首条规则优先(按用户排序)
4. Given 着色, When 颜色来源审计, Then 全部来自 design token 调色板8 色预设,无硬编码 hex
5. Given 分组头, When 渲染, Then 显示分组字段值 + 计数 + number 字段聚合SUM/AVG
6. Given 多字段分组, When 渲染, Then 层级嵌套 + 可折叠/展开
7. Given PATCH /views config, When 后端存储, Then config dict 含 group_by + conditional_formatting
8. Given 7 运算符, When 测试 each, Then equals/not-equals/contains/is-empty/greater-than/less-than/between 全部正确匹配
**Verification:**
- `npm run typecheck` 通过
- e2e `bitable-grouping.spec.ts` 通过
- pytest `test_grouping.py` + `test_conditional_formatting.py` 通过
- grep 着色 hex 零匹配(全部用 token
---
### Phase 3 — Agent Parity (depends on U4)
#### U6: R15a BitableTool 4 New Actions + DELETE /views Endpoint
**Goal:** BitableTool 从 6 动作扩展到 10 动作(新增 create_view/update_view/update_field/delete_view后端新增 DELETE /views/{view_id} 端点,消除 agent 孤儿风险。
**Files:**
- `src/agentkit/server/routes/bitable.py` — 新增 `DELETE /views/{view_id}` 端点line ~660 后)
- `src/agentkit/bitable/service.py` — 新增 `delete_view(view_id)` 方法
- `src/agentkit/bitable/repository.py` — 新增 `delete_view(view_id)` 方法
- `src/agentkit/tools/bitable_tool.py` — 新增 4 个 async def: `_create_view`/`_update_view`/`_update_field`/`_delete_view`line ~466 后)
- `src/agentkit/server/frontend/src/api/bitable.ts` — 新增 `deleteView(viewId)` 方法
- `src/agentkit/server/frontend/src/components/bitable/ViewSwitcher.vue` — 视图删除入口(调用 deleteView
- `tests/unit/bitable/test_bitable_tool.py` — extend: 4 新动作测试
- `tests/unit/bitable/test_routes.py` — extend: DELETE /views 测试
- `src/agentkit/server/frontend/e2e/bitable-agent-parity.spec.ts` (new) — agent 对等 e2e
**Approach:**
1. 后端 `DELETE /views/{view_id}`:
- 路由:`@router.delete("/views/{view_id}", status_code=204)`
- 前置:通过 view_id 查 view → table_id → `_check_table_ownership`404-before-403
- 调用 `service.delete_view(view_id)``repository.delete_view(view_id)`
- 返回 204 No Content
2. BitableTool 4 新动作(复用现有 `_call_api` 内部方法):
- `_create_view(table_id, name, view_type, config)` → POST /tables/{table_id}/views
- `_update_view(view_id, name, config)` → PATCH /views/{view_id}
- `_update_field(field_id, name, type, config)` → PATCH /fields/{field_id}
- `_delete_view(view_id)` → DELETE /views/{view_id}
3. 动作注册:在 BitableTool 的 `_ACTIONS` 字典(或等价注册机制)添加 4 项,总数 6→10
4. 前端 `api/bitable.ts` 新增 `deleteView(viewId)` 调用 DELETE /views/{view_id}
5. `ViewSwitcher.vue` 视图 tab 添加删除按钮dropdown 菜单或右键),调用 `deleteView` + 二次确认
**Test scenarios:**
1. Given BitableTool, When 调用 `create_view`/`update_view`/`update_field`/`delete_view`, Then 4 个新动作全部可用6→10 动作)
2. Given 视图列表, When 用户点击删除, Then 调用 DELETE /views/{id} + 二次确认
3. Given DELETE /views/{view_id}, When 视图不存在, Then 返回 404
4. Given DELETE /views/{view_id}, When 无所有权, Then 返回 404非 403existence disclosure 防护)
5. Given R3/R4 配置变更, When agent 调用 `create_view`/`update_view` 传 `type`/`group_by`/`conditional_formatting`, Then 配置成功写入(与 REST PATCH /views 等价)
6. Given 字段配置, When agent 调用 `update_field`, Then 与 PATCH /fields/{id} 等价
7. Given BitableTool 动作清单, When 审计, Then 10 个动作覆盖 28 端点中的核心 CRUDcreate_table/import_excel/import_database/collect_api/upsert_records/query_records/create_view/update_view/update_field/delete_view
8. Given 内部 token 认证, When agent 调用 BitableTool, Then X-Internal-Token 透传成功
**Verification:**
- `ruff check src/ && ruff format src/` 通过
- pytest `test_bitable_tool.py` + `test_routes.py` 通过
- e2e `bitable-agent-parity.spec.ts` 通过
- BitableTool 动作数 10验证 `execute()` 内 handlers dict keys + `input_schema.properties.action.enum` 均含 10 项)
---
## Risks & Dependencies
### Risks
| Risk | Likelihood | Impact | Mitigation |
|------|-----------|--------|------------|
| vxe-table 4 主题定制深度不足token 覆盖不到所有组件样式 | 中 | 中 | U1 先做 token 映射 PoC验证 vxe-table CSS 变量可覆盖;不行则用 wrapper 组件 + scoped CSS |
| 条件格式 7 运算符在 vxe-table 行渲染中性能差(大数据量) | 低 | 中 | P0 假设 <10k 首版不做虚拟滚动优化 >10k 行降级为禁用条件格式提示 |
| R4 分组渲染与 vxe-table 内置分组冲突 | 中 | 高 | 不用 vxe-table 内置分组,自建分组 wrapper 层(数据分桶 + 折叠 UIgrid 只渲染当前分组数据 |
| BitableTool 4 新动作的 X-Internal-Token 透传在 agent 编排场景失效 | 低 | 高 | U6 测试契约覆盖 agent 编排场景redis 标记);复用现有 6 动作的认证模式 |
| design token 与 Ant Design Vue 4 ConfigProvider token 冲突 | 低 | 低 | bitable-tokens.css 用 `--bitable-*` 前缀,不覆盖 Ant Design 全局 token |
### Dependencies
- **U1 → U2/U3/U4/U5**: Phase 2 所有 UI 工作依赖 U1 token 系统 + vxe-table 依赖声明
- **U4 → U6**: U6 的 `create_view`/`update_view` 动作需与 U4 的 view_type 一致
- **U5 → U6**: U6 的 `update_view` 动作需与 U5 的 group_by/conditional_formatting config 结构一致Phase 2 开始时冻结 config schema 契约U6 可并行实现)
- **外部依赖**: vxe-table 4 + vxe-pc-ui版本与主仓 node_modules 对齐、Ant Design Vue 4 Outlined 图标
- **既有约束**: AGENTS.md 规则no-emoji、Pydantic v2、no-any、pytest asyncio_mode=auto、ruff check/formatpy311行宽 100
---
## System-Wide Impact
### 后端改动
- **新增端点**: `DELETE /api/v1/bitable/views/{view_id}`U6—— 第 29 个端点
- **service/repository**: 新增 `delete_view` 方法U6
- **无 schema 迁移**: View.config 已是 `dict[str, Any]`group_by/conditional_formatting 作为 config key 存储,无需 V2→V3 迁移
- **无 FieldType 扩展**: P0 不引入新字段类型R8 延后 P1
### 前端改动
- **新组件**: `FieldTypeIcon`/`InlineFieldConfigurator`/`RecordDetailDrawer`/`GroupingEditor`/`ConditionalFormatEditor`/`LoadingState`/`ErrorState`7 个)
- **新 composable**: `useResponsiveBreakpoint`
- **新 helpers**: `fieldRenderUtils`/`recordDrawerUtils`/`viewSwitcherUtils`/`groupingRulesUtils`4 个纯函数模块)
- **新样式**: `bitable-tokens.css`design token 层)
- **改动组件**: `BitableGrid`/`ColumnHeaderMenu`/`ViewSwitcher`/`ViewConfigPanel`/`SelectDisplay`/`FieldManagePanel` + 2 个 viewtoken 化 + 功能集成)
- **package.json**: 显式声明 vxe-table + vxe-pc-ui
### Agent 对等影响
- BitableTool 动作数 6→10覆盖视图 CRUD + 字段更新
- agent 可通过 BitableTool 完成与人类等价的视图/字段操作(闭合 R15a 缺口)
- 为 R15bNL→表 agent 编排铺路agent 可编排 create_table + create_field + create_view
### 测试影响
- 新增后端测试: `test_grouping.py`/`test_conditional_formatting.py` + extend `test_bitable_tool.py`/`test_routes.py`
- 新增前端 e2e: `bitable-record-drawer.spec.ts`/`bitable-grouping.spec.ts`/`bitable-agent-parity.spec.ts`
- 新增前端 helpers: 4 个纯函数模块vitest 测试)
---
## Test Strategy Summary
| U-ID | 后端单元测试 | 前端单元测试 | e2e 测试 | 集成标记 |
|------|------------|------------|---------|---------|
| U1 (R5) | - | `helpers/designTokenAudit.ts`grep token 使用) | `bitable-view.spec.ts`visual regression | - |
| U2 (R1) | `test_routes.py`PATCH /fields/{id} | `helpers/fieldRenderUtils.ts` | `bitable-field-ops.spec.ts`extend | - |
| U3 (R2) | `test_service.py`upsert 保留 user 列) | `helpers/recordDrawerUtils.ts` | `bitable-record-drawer.spec.ts`new | - |
| U4 (R3) | `test_routes.py`POST /views type 参数) | `helpers/viewSwitcherUtils.ts` | `bitable-view.spec.ts`extend | - |
| U5 (R4) | `test_grouping.py` + `test_conditional_formatting.py`new | `helpers/groupingRulesUtils.ts` | `bitable-grouping.spec.ts`new | - |
| U6 (R15a) | `test_bitable_tool.py`4 new actions+ `test_routes.py`DELETE /views | - | `bitable-agent-parity.spec.ts`new | redisnotify_callback |
**测试约定**: 后端 pytestasyncio_mode=auto标记 integration/redis/postgres前端 vitest纯函数抽 helpers/,不用 @vue/test-utilse2e Playwright。
**Agent 对等测试契约**: U6 交付时附 BitableTool 4 新动作的契约测试,验证 agent 能完成与人类等价的视图/字段操作。
**横切测试(适用所有 U-ID**:
- WCAG AA 可访问性axe-core 扫描键盘导航 + 对比度 + ARIA role
- 空状态:无字段/无记录/无视图的空状态文案
- design token 审计grep 硬编码 hex 零匹配
---
## Execution Posture
**Posture signal**: 标准 TDD后端 pytest first前端 helpers vitest first。后端 `DELETE /views` 端点用 TDD先写 test_routes.py 失败用例,再实现)。前端组件不强求 TDDVue 组件 TDD 投入产出比低),但纯函数 helpers 用 TDD。
**Sequencing**:
1. Phase 1 (U1) —— token 基座,可独立验证
2. Phase 2 (U2/U3/U4/U5) —— 4 个 U-ID 可并行(共享 U1 token 但互不依赖)
3. Phase 3 (U6) —— 依赖 U4 的 view_type + U5 的 config 结构
**Branch**: `feat/bitable-enhancement`(当前分支)
---
## Open Questions (Deferred to Execution)
以下来自 origin 文档 Outstanding Questions + ce-doc-review manual findingsP0 范围内可在实现时决策P1/P2 延后:
### P0 范围内(实现时决策)
- **vxe-table 容量上限**: P0 假设 <10k 若实测 >10k 行性能差则降级(禁用条件格式提示或虚拟滚动延后 P1
- **条件格式规则构建器细节**: 列表式KTD7预览实时着色当前 grid 数据样本
- **分组交互细节**: 默认展开、首字段优先排序、分组头显示聚合行KTD8
- **R2 抽屉宽度**: 480px≤10 字段)/ 640px>10 字段KTD4
- **禁用态视图路线图**: tooltip "规划中"hardcode不读 configP0 不做投票机制)
- **响应式断点**: 768/1024/1440U1 useResponsiveBreakpoint
- **加载/错误状态**: 骨架屏LoadingState+ 行内提示ErrorStateU1 统一组件
### 延后 P1/P2不在本 plan 范围)
- **user 字段用户模型** (P1, R8): user_id 解析、跨表用户名查询
- **C 先行优先级策略实证依据** (P1, product): 用户访谈/A-B 数据
- **并发编辑 UX** (P1): agent + 用户双写入冲突解决、optimistic locking
- **schema V3 双向关联回滚策略** (P3, R8): drop column vs 保留为 text
- **R13 仪表盘图表库 buy-vs-build** (P2): ECharts/Chart.js/AntV G2 选型
- **R6 看板组件选型** (P1): 自建 vs 现成库
- **R9 公式库第三方 parser** (P1): 是否引入
### From 2026-07-03 ce-plan Phase 5.3 headless ce-doc-review
ce-doc-review5 reviewersheadless pass 的 manual findings需实现时决策
- **条件格式 WCAG 1.4.1 色盲可感知性** — U5 KTD7 (P1, design-lens, confidence 80)
条件格式仅靠颜色区分8 色预设中红/绿/橙/黄对色盲用户不可区分。WCAG 1.4.1 要求颜色不能作为唯一区分手段。需实现时决策:(1) 规则增加可选 `decoration` 字段(下划线/加粗/斜体/图标);(2) 单元格着色同时附加左侧色条 + 图标。最小方案:规则编辑器默认勾选"同时加粗文本"。
- **RecordDetailDrawer 加载/错误/404 状态** — U3 (P1, design-lens, confidence 78)
抽屉异步按 record_id 查询,需规定网络失败/记录被并发删除/权限丢失时的状态。U1 建了 LoadingState/ErrorStateU3 需强制引用:(1) 打开中显示骨架屏;(2) 查询 404 显示"记录不存在或已被删除" + 关闭按钮;(3) 查询 5xx 显示 ErrorState + 重试按钮。
- **新编辑器组件空状态** — U3/U5 (P2, design-lens, confidence 72)
RecordDetailDrawer 打开但记录 0 字段、GroupingEditor 可选字段 <1ConditionalFormatEditor 0 条规则时的引导文案需定义实现时补各组件空状态文案
- **保存中按钮状态** — U2/U4 (P2, design-lens, confidence 70)
PATCH /fields、POST /views 提交期间按钮需 disabled + loading 图标,防重复点击。实现时在 U2 InlineFieldConfigurator + U4 ViewSwitcher 补 loading 态。
- **delete_view 硬删/软删 + 最后视图保护** — U6 (P2, security-lens, confidence 68)
硬删不可逆agent 误调 `_delete_view` 即数据丢失。需决策:(1) soft deletedeleted_at 标记)+ 可恢复;(2) hard delete 但禁止删除表的最后一个视图(返回 409 Conflict。实现时在 U6 Test scenarios 补对应用例。
- **分组 wrapper 与 vxe-table 交互限制** — U5 Risks (P3, feasibility, confidence 70)
自建分组 wrapper 层会丢失跨分组多选、滚动位置、vxe-table 内置筛选与分组交互。P0 已知限制:不支持跨分组多选、折叠分组时虚拟滚动位置重置。后续 P1 优化。
- **U2 lookup 类型缺口** — U2 (P3, coherence, confidence 60)
U2 复用 FieldConfigForm 的 8 类型lookup 字段内联编辑延后 R8P1。已知限制不阻塞 P0。
- **vxe-pc-ui 依赖必要性** — U1 KTD2 (P2, feasibility, confidence 80)
KTD2 声明 vxe-pc-ui 但代码库仅 import vxe-table。需 U1 实施时验证 vxe-pc-ui 是否为 vxe-table v4 的 peer dependency。若非 peer dep 则移除,避免多余依赖。
---
## Origin Traceability
本 plan 承接 origin 文档(`docs/brainstorms/2026-07-03-bitable-comparative-evaluation-requirements.md`)的 P0 范围:
| R-ID | origin 章节 | 本 plan U-ID | 交付阶段 |
|------|-----------|------------|---------|
| R5 | Priority Recommendations P0 | U1 | Phase 1 |
| R1 | Priority Recommendations P0 | U2 | Phase 2 |
| R2 | Priority Recommendations P0 | U3 | Phase 2 |
| R3 | Priority Recommendations P0 | U4 | Phase 2 |
| R4 | Priority Recommendations P0 | U5 | Phase 2 |
| R15a | Priority Recommendations P0 (agent 对等最高优先级子项) | U6 | Phase 3 |
origin 文档的 Acceptance Criteria (P0) + 横切验收标准WCAG AA + 空状态)已映射到各 U-ID 的 Test scenarios。Agent 对等评估方法的 4 个新动作create_view/update_view/update_field/delete_view全部在 U6 实现。