diff --git a/docs/ux/bitable-grid-guidelines.md b/docs/ux/bitable-grid-guidelines.md
new file mode 100644
index 0000000..857a583
--- /dev/null
+++ b/docs/ux/bitable-grid-guidelines.md
@@ -0,0 +1,196 @@
+# Bitable 多维表格 UI/UX 规范
+
+> 适用范围:所有基于 vxe-table 的 bitable 视图(`BitableGrid.vue` 及其变体)。
+> 目标:对齐 Twenty / Notion / Airtable 风格,消除「不像表格」「没有分隔线」「标题与数据对不齐」等基础 UI/UX 问题。
+
+## 1. 布局原则
+
+### 1.1 表格高度必须随内容(`height: auto`)
+
+- **禁止**强制 `height: 100%` 或 `flex: 1` 撑满父容器。
+- 少量数据时,表格底部应紧贴最后一行,而不是拉伸出巨大空白。
+- 滚动条应出现在表格内容**真正超出视口**时,而不是因为容器被强制撑高。
+
+```css
+/* Good */
+.bitable-grid-scope { height: auto; }
+
+/* Bad — causes the gap between header and data rows */
+.bitable-grid-scope { height: 100%; }
+```
+
+### 1.2 父容器不得挤压表格
+
+表格父容器应使用 `flex: 0 0 auto` 或 `height: auto`,避免剩余空间被表格占据。
+
+```css
+/* Good */
+.bitable-file-detail-view__grid-container { flex: 0 0 auto; overflow: visible; }
+
+/* Bad — stretches the grid body */
+.bitable-file-detail-view__grid-container { flex: 1; overflow: hidden; }
+```
+
+## 2. 边框与分隔
+
+### 2.1 必须提供列分隔线
+
+所有数据单元格和列头单元格必须有右侧竖线(`border-right`)。
+
+```css
+.vxe-body--column,
+.vxe-header--column { border-right: 1px solid var(--bitable-color-border); }
+```
+
+- 最右侧一列不显示右边界(`last-child { border-right: 0 }`),避免边界悬空。
+- 行分隔线使用更浅的 `--bitable-color-border`(1px)。
+- 列头下边界使用更深的 `--bitable-color-border-hover`(2px),与行分隔形成层次。
+
+### 2.2 禁止无意义的双重/三重分隔线
+
+- 标题区、视图切换区、列头区只能有**一条**主分隔线。
+- 如果父容器已经画了分隔线,子容器不要再重复画。
+
+## 3. 对齐与间距
+
+### 3.1 标题与数据单元格必须对齐
+
+- 列头单元格 `padding` 与数据单元格 `padding` 必须一致。
+- 所有单元格使用相同的垂直对齐方式(默认居中或居顶,但不能混用)。
+
+```css
+.vxe-header--column,
+.vxe-body--column { padding: var(--bitable-spacing-sm) var(--bitable-spacing-md); }
+```
+
+### 3.2 字号规范
+
+| 元素 | Token | 说明 |
+|------|-------|------|
+| 列头文字 | `--bitable-font-sm` (13px) | 略小于正文,表达层级 |
+| 数据单元格 | `--bitable-font-md` (14px) | 与 antd Table 正文一致 |
+| 空状态/提示 | `--bitable-font-sm` (13px) | 占位提示 |
+
+### 3.3 行高(Twenty 风格)
+
+| 元素 | 高度 | 说明 |
+|------|------|------|
+| 数据行 | 44px | 比传统表格更舒展,便于放置 chip/头像 |
+| 列头行 | 40px | 略低于数据行,表达层级 |
+| 行选择列 | 44px | 与数据行对齐 |
+
+- 禁止 36px 以下行高,避免 chip/多选标签被截断。
+- 列头与数据行高度不同是刻意设计,但差距必须 ≤ 4px。
+
+## 4. 视觉层次
+
+### 4.1 列头必须可识别(Twenty 风格)
+
+- 背景色使用 `--bitable-color-bg-secondary`。
+- 列头下边界 **1px** `var(--bitable-color-border-hover)`,比行分隔略重即可,禁止 2px 粗线。
+- 列头文字 `font-weight: 500`,颜色 `--bitable-color-text-secondary`,表达 muted 层级。
+- 列头必须显示字段类型图标(如文本用 FileText、日期用 Calendar、多选用 Tags),图标颜色 `--bitable-color-text-tertiary`。
+- **禁止**把字段类型图标做成「编辑」样式,避免用户误以为点击图标就是编辑。
+
+### 4.2 标题区、视图区、表格区的层次(Twenty 风格)
+
+从上到下:
+
+1. **顶部文件标题栏** — 文件名称 + 返回按钮(最轻)
+2. **对象/视图工具栏** — 左侧「对象图标 + 当前视图下拉 · 记录数徽章」,右侧「+ 新建记录 / 筛选 / 排序 / 选项」
+3. **列头** — 1px 下边界 + 背景色区分
+4. **数据行** — 1px 行分隔 + 1px 列分隔 + hover 高亮
+5. **占位行** — 虚线底边 + hover 高亮
+
+「选项」下拉收纳低频操作(字段管理、刷新、视图配置、删除视图);「新建视图」统一放在当前视图下拉菜单底部。
+
+## 5. 新增记录交互
+
+### 5.1 新增记录入口(Twenty 风格)
+
+- **主要入口**:工具栏右侧放置显眼的「+ 新建记录」主按钮(Twenty 的 `+ New`)。
+- **次要入口**:始终在数据列表末尾渲染一行**占位行**(pseudo-row),点击任意单元格也触发新增。
+- 占位行样式:
+ - 虚线底边(`border-bottom: 1px dashed`)
+ - pointer 光标
+ - hover 时背景变为 `--bitable-color-bg-tertiary`
+
+### 5.2 代码实现要点
+
+- 占位行的 `_rowId` 使用固定哨兵值(如 `__placeholder__`),`_recordId` 为空字符串。
+- 在 `cell-click` 事件中优先检测占位行,再处理普通行的其他交互。
+- 只要表格非分组模式,就追加占位行,保证空表也有可点击目标。
+
+## 6. 暗色/浅色主题
+
+- 所有颜色必须使用 `--bitable-*` token,禁止硬编码 hex。
+- 边框颜色在暗色模式下应自动跟随全局 `--border-color`。
+- 避免使用 `box-shadow` 创造分隔(在暗色主题下容易发灰、不自然)。
+
+### 6.1 必须覆盖 vxe-table 默认 CSS 变量
+
+vxe-table 的默认变量是亮色主题值(`#fff`、`#e8eaec` 等)。即使全局 `data-theme="dark"` 已设置,vxe-table 仍需要显式重映射变量,否则会出现白底、淡边框等「刷新后无变化」的现象。
+
+```css
+.bitable-grid-scope :deep(.vxe-table) {
+ --vxe-ui-layout-background-color: var(--bitable-color-bg);
+ --vxe-ui-table-header-background-color: var(--bitable-color-bg-secondary);
+ --vxe-ui-table-border-color: var(--bitable-color-border);
+ --vxe-ui-font-color: var(--bitable-color-text);
+ --vxe-ui-table-row-hover-background-color: var(--bitable-color-bg-tertiary);
+ --vxe-ui-table-row-striped-background-color: var(--bitable-color-bg-secondary);
+}
+```
+
+- 在表格根节点 `.vxe-table` 上重映射,作用域最小。
+- 同时保持 `data-vxe-ui-theme` 与 `data-theme` 同步(全局兜底)。
+- 任何新增 vxe-table 实例都必须执行此重映射,禁止依赖 vxe-table 默认主题。
+
+## 7. 单元格渲染
+
+### 7.1 select / multiselect 必须渲染为 pill chip
+
+```css
+.select-display__chip {
+ border-radius: 999px;
+ padding: 2px 10px;
+ border: 1px solid;
+}
+```
+
+- 禁止使用直角或 4px 小圆角 chip,避免像 antd Tag 而非 CRM 风格。
+- 多选标签之间保留小间距,允许换行,但单元格内最多两行。
+
+### 7.2 date 字段必须格式化显示
+
+- 后端存储 ISO-8601,前端显示 `YYYY-MM-DD`(中文 locale)。
+- 禁止在单元格中直接显示原始时间戳或带 T/Z 的字符串。
+
+### 7.3 行选择与行打开方式
+
+- 必须提供 `type: 'checkbox'` 列作为首列。
+- 行选择不影响单元格编辑或打开详情抽屉;点击复选框只切换选中态。
+- **不再使用单独的行号列(#)**;Twenty 风格下首列即复选框,第一数据列是主字段列。
+- 点击**主字段列单元格**打开记录详情抽屉;其他可编辑列保持单击进入单元格编辑。
+
+## 8. 检查清单(Code Review 用)
+
+提交/ review bitable grid 相关改动时,逐项确认:
+
+- [ ] 表格高度是否随内容,无强制撑高
+- [ ] 父容器是否未使用 `flex: 1` 拉伸表格
+- [ ] 列头与数据单元格是否有竖向分隔线
+- [ ] 列头下边界是否为 1px 且比行分隔略重
+- [ ] 列头 padding 是否与数据单元格一致
+- [ ] 列头是否显示字段类型图标
+- [ ] 数据行高是否为 44px、列头行高是否为 40px
+- [ ] 是否有行选择复选框列(无 # 行号列)
+- [ ] 主字段列点击是否打开记录详情抽屉
+- [ ] 最后一列是否无右侧悬浮边界线
+- [ ] 字号是否使用 `--bitable-font-sm` / `--bitable-font-md`
+- [ ] select 字段是否渲染为 pill chip
+- [ ] date 字段是否格式化显示
+- [ ] 新增记录是否通过末尾占位行实现
+- [ ] 颜色是否全部使用 `--bitable-*` token
+- [ ] 是否覆盖 vxe-table 默认 CSS 变量以适配暗色主题
+- [ ] 是否未引入无意义的双重/三重水平线
diff --git a/src/agentkit/server/frontend/components.d.ts b/src/agentkit/server/frontend/components.d.ts
index 5db51bb..14c0ccd 100644
--- a/src/agentkit/server/frontend/components.d.ts
+++ b/src/agentkit/server/frontend/components.d.ts
@@ -94,6 +94,7 @@ declare module 'vue' {
ConditionNode: typeof import('./src/components/workflow/ConditionNode.vue')['default']
ContextPill: typeof import('./src/components/chat/ContextPill.vue')['default']
DashboardOverview: typeof import('./src/components/evolution/DashboardOverview.vue')['default']
+ DateDisplay: typeof import('./src/components/bitable/DateDisplay.vue')['default']
DebateArgumentCard: typeof import('./src/components/chat/messages/DebateArgumentCard.vue')['default']
DebateBannerCard: typeof import('./src/components/chat/messages/DebateBannerCard.vue')['default']
DebateConclusionCard: typeof import('./src/components/chat/messages/DebateConclusionCard.vue')['default']
diff --git a/src/agentkit/server/frontend/src/components/bitable/DateDisplay.vue b/src/agentkit/server/frontend/src/components/bitable/DateDisplay.vue
new file mode 100644
index 0000000..88ec62c
--- /dev/null
+++ b/src/agentkit/server/frontend/src/components/bitable/DateDisplay.vue
@@ -0,0 +1,29 @@
+
+ {{ formatted }}
+
+
+
+
+
diff --git a/src/agentkit/server/frontend/src/components/bitable/ViewConfigPanel.vue b/src/agentkit/server/frontend/src/components/bitable/ViewConfigPanel.vue
index 01d5dd2..625adbe 100644
--- a/src/agentkit/server/frontend/src/components/bitable/ViewConfigPanel.vue
+++ b/src/agentkit/server/frontend/src/components/bitable/ViewConfigPanel.vue
@@ -111,6 +111,7 @@ const props = defineProps<{
open: boolean
fields: IBitableField[]
view: IBitableView | null
+ initialTab?: 'filter' | 'sort' | 'hidden' | 'grouping' | 'conditional-format'
}>()
const emit = defineEmits<{
@@ -127,7 +128,17 @@ const { isMobile } = useResponsiveBreakpoint()
const drawerPlacement = computed(() => (isMobile.value ? 'bottom' : 'right'))
const drawerWidth = computed(() => (isMobile.value ? '100%' : 520))
-const activeTab = ref('filter')
+const activeTab = ref(props.initialTab ?? 'filter')
+
+watch(
+ () => props.open,
+ (isOpen) => {
+ if (isOpen && props.initialTab) {
+ activeTab.value = props.initialTab
+ }
+ },
+)
+
const filterRef = ref | null>(null)
// Current config from view
diff --git a/src/agentkit/server/frontend/src/components/bitable/ViewSwitcher.vue b/src/agentkit/server/frontend/src/components/bitable/ViewSwitcher.vue
index c9bb941..e08e517 100644
--- a/src/agentkit/server/frontend/src/components/bitable/ViewSwitcher.vue
+++ b/src/agentkit/server/frontend/src/components/bitable/ViewSwitcher.vue
@@ -1,94 +1,53 @@
-
-
-
-
-
- 新建视图
+
+ {{ currentView?.name ?? '全部数据' }}
+
-
+
-
-
- {{ meta.label }}
+
+
+
+ {{ v.name }}
+
+
+ 新建视图
+
-
-
- 配置
-
-
-
-
-
- 删除
-
-
diff --git a/src/agentkit/server/frontend/src/stores/bitable.ts b/src/agentkit/server/frontend/src/stores/bitable.ts
index df9331e..618a0c5 100644
--- a/src/agentkit/server/frontend/src/stores/bitable.ts
+++ b/src/agentkit/server/frontend/src/stores/bitable.ts
@@ -285,6 +285,26 @@ export const useBitableStore = defineStore('bitable', () => {
}
}
+ /** Create a new empty record in the current table */
+ async function createRecord(): Promise {
+ if (!currentTable.value) return null
+ try {
+ const resp = await bitableApi.createRecords(currentTable.value.id, [{}])
+ const record = resp.records[0]
+ if (record) {
+ records.value.unshift(record)
+ return record.id
+ }
+ return null
+ } catch (err) {
+ notification.error({
+ message: '创建记录失败',
+ description: err instanceof Error ? err.message : String(err),
+ })
+ return null
+ }
+ }
+
/** Add a new field */
async function addField(
name: string,
@@ -738,6 +758,7 @@ export const useBitableStore = defineStore('bitable', () => {
selectTable,
loadMoreRecords,
updateCell,
+ createRecord,
addField,
createTable,
updateField,
diff --git a/src/agentkit/server/frontend/src/views/BitableFileDetailView.vue b/src/agentkit/server/frontend/src/views/BitableFileDetailView.vue
index acac10b..34086b9 100644
--- a/src/agentkit/server/frontend/src/views/BitableFileDetailView.vue
+++ b/src/agentkit/server/frontend/src/views/BitableFileDetailView.vue
@@ -50,26 +50,72 @@
-