fischer-agentkit/docs/brainstorms/2026-07-02-private-board-re...

79 lines
9.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
date: 2026-07-02
topic: private-board-restrictions-and-scheme-b-bubbles
---
## Summary
收尾私董会(@board模块的 UI 细节与单会话状态约束。三处改动:(1) 限制一个对话只能存在一个私董会,新建私董会必须从新会话发起;(2) 将 `BoardBannerCard`(私董会开始卡片)从带边框 / 紫条 / 进度条 / 专家 chip 的重样式简化为单行标题 + 副标题;(3) 给所有 `AssistantText` 渲染添加方案 B 风格的浅灰圆角矩形气泡,与方案 B 截图保持一致。
## Problem Frame
私董会功能自 2026-06 上线以来已能正确触发多轮讨论,但 UI 上仍残留三处粗糙点:
1. **单会话多私董会无约束**。`ChatInput.vue:75` 的"私董会"按钮 `@click` 直接 `showBoardModal = true`,对当前会话是否已经存在私董会无任何判断。后端在 `board_started` 事件中没有按会话做去重,连续两次 `SendMessage("@board:...")` 会在同一会话里创建第二个私董会,叠加在第一个未结束的私董会之上,`boardState.experts` 被覆盖、轮次错乱、`StickyModeHeader` 头像数与实际不符。
2. **`BoardBannerCard` 样式过重**。`BoardBannerCard.vue:55-137` 使用了 `background / border / border-radius / box-shadow` 四件套 + 4px 紫条 + 进度条 + 专家 chip pill与方案 B 整体"克制、不重样式"的取向冲突。方案 B 截图(参考 `docs/.../2026-06-18-chat-area-vi-redesign-requirements.md` 中的方案 B 示意)的"开始"标题区域是单行文本,不带装饰。
3. **方案 B 气泡未落地**。方案 B 截图中的"专家发言"区域是**有**浅灰圆角矩形气泡包裹内容(不是无气泡),与 ChatGPT / Notion AI 风格一致。当前 `AssistantText.vue:1-30` 的内容区 `.assistant-text` 没有背景 / 边框 / 圆角,气泡效果完全缺失。
## Key Decisions
- **私董会限制的"已存在"判断以 `boardState.status` 为准**`status === 'discussing' | 'concluding'` 时禁止在当前会话再次发起;`status === 'completed' | 'dissolved' | null` 时允许(已完成 / 已解散的旧私董会不阻塞新私董会)。判断点放在 `ChatInput.vue` "私董会"按钮 `@click` 处(最自然的 UX 拦截点),不放在 `BoardMeetingModal` 内部(避免用户填表后才发现不能发起)。
- **私董会限制的反馈方式是 a-modal 弹窗 + 快捷新建按钮**。点击"私董会"按钮时若检测到已有私董会,弹出 `a-modal`,标题"当前会话已存在私董会",副文"请新建会话来创建新的私董会",按钮"我知道了" + "新建会话"。"新建会话"按钮直接调用 `chatStore.createConversation()``chatStore.selectConversation(newId)`,让用户立即在新会话里继续操作。
- **BoardBannerCard 简化为单行标题 + 副标题**。完全去掉 `BankOutlined` 图标、专家 chip 列表、4px 紫条、进度条、卡片背景 / 边框 / 圆角 / 阴影。最终输出形如:
```
私董会 — 利用 agent 实现私董会的功能,应该用什么功能来打动客户
轮次:第 1 / 5 轮
```
标题字号 = `var(--font-base)` 加粗 + 主题文本;副标题字号 = `var(--font-xs)` + `var(--text-tertiary)`。`StickyModeHeader` 顶部的紫色"私董会"徽章 + 主题 + 专家头像组保持不变,承担需要"重样式"的展示职责。
- **方案 B 浅灰气泡应用到所有 assistant 消息**。具体范围:`role === 'assistant'` 的所有 `MessageShell` 内的内容(普通 chat、@team 阶段、@board 发言、Debate、Plan exec、Tool result 等)都加同款浅灰圆角矩形气泡;`role === 'user'` 的用户消息气泡保留现有 `UserBubble.vue` 的右对齐独立样式,不加 AssistantText 风格的浅灰块。气泡使用 token 颜色(`var(--bg-secondary)` 或 `var(--bg-elevated)` 系)+ 圆角 `var(--radius-md)` + 内边距 `var(--space-3) var(--space-4)`,确保与方案 B 截图视觉一致;颜色与边框用 CSS 变量绑定,**禁止硬编码** `#f3f4f6` / `#fbfbfa` / `#ededec` 等值。
- **气泡内的代码块、表格、行内代码样式保持不变**。`AssistantText.vue:257-401` 的 `pre / hljs / code / table` 样式已经在 dark-on-light 配色上做了适配(`--code-bg` / `--code-fg` / `--code-keyword` 等 token气泡背景换浅灰后这些 token 自动适配,不需要单独再改。
- **不触碰 StickyModeHeader 顶部条**。顶部条的紫色边框、徽章、4 个专家头像等不属于本次改动范围。
## Requirements
### 单会话私董会限制
- R1. `ChatInput.vue` 的"私董会"按钮 `@click` 处理函数在打开 `BoardMeetingModal` 前,先检查 `chatStore.boardState.value`:若非 null 且 `status === 'discussing' | 'concluding'`,触发 a-modal 弹窗,**不**打开 `BoardMeetingModal`
- R2. a-modal 弹窗内容:标题"当前会话已存在私董会",副文案"请新建会话来创建新的私董会",按钮"我知道了"(关闭弹窗)+ "新建会话"(主操作)。"新建会话"按钮点击后:(a) 关闭弹窗;(b) 调用 `chatStore.createConversation()`(c) `await chatStore.selectConversation(newId)`(d) 不自动打开 `BoardMeetingModal`,由用户在新会话中再次点击"私董会"按钮继续。
- R3. 若 `boardState.value === null``status === 'completed' | 'dissolved'`,保持当前行为:`showBoardModal = true` 直接打开 `BoardMeetingModal`,不弹提示。
- R4. 判定不依赖后端 / `is_board` 标记 / `conv.is_board`——以前端 `chatStore.boardState.value` 实时状态为权威源,避免 reload 后误判。
### 私董会开始卡片简化
- R5. `BoardBannerCard.vue` 重构为单行标题 + 副标题:保留 `topic / maxRounds / currentRound` props向后兼容调用方不再使用 `experts` props删除 prop
- R6. 模板输出仅两行:第一行 `私董会 — {topic}`(无 BankOutlined、无边框、无背景、无圆角、无 4px 紫条);第二行 `轮次:第 {currentRound} / {maxRounds} 轮`(小灰字)。
- R7. `<style scoped>` 中删除 `.board-banner-card` / `.board-banner-card__bar` / `.board-banner-card__chip` 等所有重样式相关类;保留 `.board-banner-card__title` / `.board-banner-card__meta` 两条最小样式。
- R8. `useMessageRenderer.ts``board_started` 的渲染路径不变(仍然渲染 `BoardBannerCard` 组件),确保 streaming 期间与 reload 后的视觉一致。
### AssistantText 浅灰气泡
- R9. `MessageShell.vue``.message-shell__content` 增加浅灰气泡样式:仅当 `role === 'assistant'` 时生效(`user` 角色不触发);`background: var(--bg-secondary)` + `border-radius: var(--radius-md)` + `padding: var(--space-3) var(--space-4)` + `border: 1px solid var(--border-color)` + `color: var(--text-primary)`
- R10. 气泡样式**不**使用 `!important`,不覆盖组件内已有的代码块 / 表格 / 路由 tag 样式(这些样式已经在 R-9 之外独立维护)。
- R11. 浅灰气泡不影响 `BoardRoundCard``AssistantText` 的渲染(已统一走 `MessageShell` 槽位)。
- R12. 私董会专家发言(`board_speech` / `board_summary`)、普通 chat assistant 消息、@team 阶段消息、Debate 消息都通过 `MessageShell` + `AssistantText` 渲染,因此统一获得 R-9 浅灰气泡,无需逐个组件加样式。
- R13. 气泡宽度继承 `.message-shell__content` 的现有 `width: 100%; max-width: 100%`——气泡跟随消息列宽自适应,不强制固定最大宽度。
## Scope Boundaries
### Deferred for later
- **后端按会话去重 `board_started`**:本次只做前端拦截,**不**改后端逻辑。后端允许同一会话收到多次 `board_started` 是当前事实,本次不做接口变更;前端的"未在新会话发起"拦截在功能上等价于"阻止重复发起"。如果未来需要在多端 / 多浏览器同步场景下做强一致,再考虑后端校验。
- **StickyModeHeader 顶部条的视觉细化**(徽章大小、专家头像间距、紫色边框粗细)不在本次范围。
- **BoardConclusionCard / DebateBannerCard / TeamPlanCard 等其他 board 模式组件的样式统一**:本次只改 `BoardBannerCard`,其他卡片样式留待后续迭代。
### Outside this product's identity
- 不调整方案 B 调色板(`expertIdentity.ts` 的 12 色 PALETTE和专家头像首字符规则。
- 不调整私董会后端流程(`BoardOrchestrator` / `chatStream` 事件顺序)。
- 不调整 AssistantText 的 markdown 渲染逻辑、代码高亮、表格样式。
## Dependencies / Assumptions
- 假设:`chatStore.createConversation()` 存在并返回新会话 id`chatStore.ts:310` 已确认)。
- 假设:`chatStore.selectConversation(id)` 可异步调用(`chatStore.ts:218` 已确认)。
- 假设:`BoardState.status` 类型为 `"discussing" | "concluding" | "completed" | "dissolved"``chatStream.ts:65` 已确认),"已存在私董会"判断取 `discussing | concluding`
- 假设:`--bg-secondary` / `--radius-md` / `--space-3` / `--space-4` / `--border-color` / `--text-primary` 已在 `tokens.css` 中定义并被前端使用(`styles/tokens.css` 已确认存在)。
- 不确定性:私董会可能存在的中间状态(`forming` / `executing` / `synthesizing` 等)目前不在 `BoardState.status` 联合中;如果未来增加新 status本次"已存在"判断需扩展。