CodeMoss 看板模式 (Kanban Mode) 实现计划
模式切换入口 : 在 SidebarHeader 版本号旁添加 "对话模式 | 看板模式" 切换控件
看板模式全屏 : 切换到看板模式时隐藏侧边栏,主内容区全屏展示看板(切换入口保留)
项目管理 : 进入看板模式后先展示项目列表,支持创建/编辑/删除项目
看板视图 : 点击项目进入看板,5 个列:待办、进行中、测试、完成、取消
任务管理 : 看板中创建任务,数据完全独立于历史对话
任务创建弹窗 : 标题、描述、引擎选择、模型选择、分支选择、图片上传、"开始"开关、创建按钮
"开始"开关行为 : 开 = 创建任务(进行中) + 自动启动 AI 对话;关 = 仅创建任务(待办)
决策点
选择
原因
侧边栏行为
看板模式下隐藏侧边栏,全屏展示看板
用户明确要求,参考图二
切换入口
SidebarHeader 版本号旁保留切换按钮
即使侧边栏隐藏,也能通过顶部小入口切回
状态管理
遵循现有 custom hooks 模式,不引入新库
项目架构一致性
数据持久化
localStorage (第一阶段)
零 Rust 改动,快速实现
拖拽库
@hello-pangea/dnd
与参考项目一致,API 稳定
视图切换
纯状态驱动 (不引入路由库)
遵循现有模式
数据隔离
看板任务独立存储,不混入对话数据
需求明确要求
src/features/kanban/ # 新增 feature 模块
types.ts # 看板数据模型定义
constants.ts # 列配置、存储键、颜色
hooks/
useKanbanStore.ts # 核心数据 hook (CRUD + 持久化)
useKanbanNavigation.ts # 看板内部视图导航 (项目列表 ↔ 看板)
components/
KanbanView.tsx # 看板模式入口容器 (条件渲染项目列表 or 看板)
KanbanModeToggle.tsx # 模式切换控件 (对话 | 看板)
ProjectList.tsx # 项目列表页 (网格卡片 + 创建按钮)
ProjectCard.tsx # 项目卡片
ProjectFormModal.tsx # 项目创建/编辑弹窗
KanbanBoard.tsx # 看板视图 (DragDropContext + 5 列)
KanbanBoardHeader.tsx # 看板顶部 (返回按钮 + 项目名 + 模式切换)
KanbanColumn.tsx # 看板单列 (Droppable + 卡片列表)
KanbanCard.tsx # 任务卡片 (Draggable)
TaskCreateModal.tsx # 任务创建弹窗
utils/
kanbanStorage.ts # localStorage 读写工具
kanbanId.ts # nanoid 或 timestamp ID 生成
src/styles/kanban.css # 看板全部样式
文件
修改内容
改动量
src/App.tsx (2354行)
新增 appMode state + useKanbanStore hook + kanbanNode 组装 + 传递给 AppLayout
~25 行
src/types.ts
新增 AppMode = "chat" | "kanban"
1 行
src/features/app/components/SidebarHeader.tsx
添加 appMode + onAppModeChange props,渲染 KanbanModeToggle
~10 行
src/features/app/components/Sidebar.tsx
透传 appMode + onAppModeChange 到 SidebarHeader
~5 行
src/features/app/components/AppLayout.tsx
新增 showKanban + kanbanNode props,看板模式条件渲染
~15 行
src/features/layout/components/DesktopLayout.tsx
新增 showKanban + kanbanNode props,看板全屏渲染(隐藏 sidebar + resizer)
~15 行
src/features/layout/hooks/useLayoutNodes.tsx
透传 appMode + onAppModeChange 到 Sidebar
~5 行
package.json
新增 @hello-pangea/dnd 依赖
1 行
// src/features/kanban/types.ts
export type KanbanTaskStatus = "todo" | "inprogress" | "testing" | "done" | "cancelled" ;
export type KanbanColumnDef = {
id : KanbanTaskStatus ;
labelKey : string ; // i18n key
color : string ;
} ;
export type KanbanProject = {
id : string ;
name : string ;
createdAt : number ; // timestamp
updatedAt : number ;
} ;
export type KanbanTask = {
id : string ;
projectId : string ;
title : string ;
description : string ;
status : KanbanTaskStatus ;
engineType : string ; // "claude" | "codex" | "gemini" | "opencode"
modelId : string | null ;
branchName : string ;
images : string [ ] ; // 图片文件路径
autoStart : boolean ; // 创建时是否自动开始
sortOrder : number ; // 列内排序权重
threadId : string | null ; // 关联的对话 thread ID (autoStart=true 时填充)
createdAt : number ;
updatedAt : number ;
} ;
// 看板视图导航状态
export type KanbanViewState =
| { view : "projects" }
| { view : "board" ; projectId : string } ;
// localStorage 持久化结构
export type KanbanStoreData = {
projects : KanbanProject [ ] ;
tasks : KanbanTask [ ] ;
} ;
6.1 KanbanModeToggle (模式切换控件)
位置: SidebarHeader 版本号右侧
外观: 两个小图标按钮(MessageSquare / LayoutDashboard),当前激活项高亮
看板模式全屏时: 在 KanbanBoardHeader 左上角也显示此控件(用于切回对话模式)
KanbanView
├── viewState === "projects" → <ProjectList>
└── viewState === "board" → <KanbanBoard>
<div class="kanban-projects">
<div class="kanban-projects-header">
<h1>项目</h1>
<p>管理您的项目并跟踪其进度</p>
<button>+ 创建项目</button>
</div>
<div class="kanban-projects-grid"> <!-- 参考图二: 3 列网格 -->
{projects.map(p => <ProjectCard>)}
</div>
</div>
显示: 项目名称 + 创建日期 + "..." 菜单(编辑/删除)
点击进入看板视图
<div class="kanban-board">
<KanbanBoardHeader> <!-- 返回箭头 + 项目名 + 模式切换 -->
<DragDropContext onDragEnd={...}>
<div class="kanban-columns"> <!-- 水平滚动的 5 列 -->
{KANBAN_COLUMNS.map(col => <KanbanColumn>)}
</div>
</DragDropContext>
</div>
<div class="kanban-column">
<div class="kanban-column-header">
<span class="kanban-column-dot" style={color} />
<span>{columnName}</span>
<span class="kanban-column-count">{tasks.length}</span>
<button class="kanban-column-add">+</button>
</div>
<Droppable droppableId={columnId}>
{tasks.map((task, i) => <KanbanCard index={i}>)}
</Droppable>
</div>
显示: 任务标题 + 引擎/模型标签 + "..." 菜单(编辑/删除/移动)
Draggable 包裹,支持跨列拖拽
6.8 TaskCreateModal (任务创建弹窗)
<dialog class="kanban-task-modal">
<input placeholder="任务标题" />
<textarea placeholder="添加更多详情(可选)。输入 @ 搜索文件。" />
<div class="kanban-task-modal-selectors">
<EngineSelector /> <!-- 复用现有组件 -->
<ModelSelector /> <!-- 下拉选择模型 -->
<BranchSelector /> <!-- 下拉选择分支 -->
</div>
<div class="kanban-task-modal-footer">
<button class="image-upload">📎</button>
<div class="kanban-task-modal-actions">
<Toggle label="开始" /> <!-- 开 = 创建后自动启动对话 -->
<button>创建</button>
</div>
</div>
</dialog>
// 在 MainApp 函数中新增:
const [ appMode , setAppMode ] = useState < AppMode > ( "chat" ) ;
const {
projects, tasks,
kanbanViewState, setKanbanViewState,
createProject, updateProject, deleteProject,
createTask, updateTask, deleteTask,
reorderTask,
} = useKanbanStore ( ) ;
// 看板节点组装
const kanbanNode = appMode === "kanban" ? (
< KanbanView
viewState = { kanbanViewState }
onViewStateChange = { setKanbanViewState }
projects = { projects }
tasks = { tasks }
onCreateProject = { createProject }
onUpdateProject = { updateProject }
onDeleteProject = { deleteProject }
onCreateTask = { createTask }
onUpdateTask = { updateTask }
onDeleteTask = { deleteTask }
onReorderTask = { reorderTask }
onAppModeChange = { setAppMode }
// 引擎/模型/分支 props 复用现有数据
engines = { engineStatuses }
models = { effectiveModels }
branches = { branches }
// 启动对话需要的 callbacks
connectWorkspace = { connectWorkspace }
startThreadForWorkspace = { startThreadForWorkspace }
sendUserMessageToThread = { sendUserMessageToThread }
/ >
) : null ;
// 修改视图条件
const showHome = ! activeWorkspace && appMode === "chat" ;
const showKanban = appMode === "kanban" ;
7.2 布局集成 (DesktopLayout 修改)
看板模式时:
├── 隐藏 sidebar + sidebar-resizer
└── <section class="main"> 渲染 kanbanNode (全屏)
对话模式时:
└── 保持原有布局不变
7.3 useKanbanStore hook 核心逻辑
// 1. 初始化: 从 localStorage 加载数据
// 2. CRUD: 不可变更新 (spread + filter/map)
// 3. 持久化: useEffect 监听 store 变化,防抖写入 localStorage
// 4. 拖拽排序: reorderTask(taskId, newStatus, newSortOrder) 更新状态和排序
当用户点击"看板模式"时:
appMode 设为 "kanban"
DesktopLayout 检测到 showKanban=true,隐藏 sidebarNode + sidebar-resizer
<section class="main"> 占满全宽,只渲染 kanbanNode
看板头部 KanbanBoardHeader 左侧显示 KanbanModeToggle,可以切回对话模式
当用户点击"对话模式"时:
appMode 设为 "chat"
恢复正常的侧边栏 + 主内容区布局
侧边栏中的 KanbanModeToggle 再次可见
创建 KanbanTask,status = "todo", threadId = null
任务出现在"待办"列
创建 KanbanTask,status = "inprogress", autoStart = true
根据任务的 engineType 和 modelId,调用现有的对话启动流程:
connectWorkspace(workspaceId) 连接工作区
startThreadForWorkspace(workspaceId) 创建新 thread
sendUserMessageToThread(threadId, taskDescription) 发送任务描述
将返回的 threadId 保存到 KanbanTask.threadId
任务出现在"进行中"列
注: 第一阶段"开始"功能可以先实现基本流程,后续迭代优化对话关联体验。
步骤
任务
文件
1.1
安装 @hello-pangea/dnd
package.json
1.2
在 src/types.ts 新增 AppMode 类型
src/types.ts
1.3
创建看板类型定义
src/features/kanban/types.ts
1.4
创建看板常量 + ID 工具 + 存储工具
constants.ts, kanbanId.ts, kanbanStorage.ts
步骤
任务
文件
2.1
实现 useKanbanStore hook
hooks/useKanbanStore.ts
2.2
实现 useKanbanNavigation hook
hooks/useKanbanNavigation.ts
步骤
任务
文件
3.1
创建 KanbanModeToggle 组件
components/KanbanModeToggle.tsx
3.2
修改 SidebarHeader 添加切换控件
SidebarHeader.tsx
3.3
透传 appMode 通过 Sidebar → useLayoutNodes → App
Sidebar.tsx, useLayoutNodes.tsx
3.4
添加切换控件样式
kanban.css
步骤
任务
文件
4.1
修改 DesktopLayout 支持看板全屏模式
DesktopLayout.tsx
4.2
修改 AppLayout 透传看板 props
AppLayout.tsx
4.3
修改 App.tsx 添加 appMode 状态和 kanbanNode 组装
App.tsx
步骤
任务
文件
5.1
创建 KanbanView 入口容器
components/KanbanView.tsx
5.2
创建 ProjectList + ProjectCard
ProjectList.tsx, ProjectCard.tsx
5.3
创建 ProjectFormModal
ProjectFormModal.tsx
5.4
添加项目列表样式
kanban.css
步骤
任务
文件
6.1
创建 KanbanBoardHeader
KanbanBoardHeader.tsx
6.2
创建 KanbanColumn (Droppable)
KanbanColumn.tsx
6.3
创建 KanbanCard (Draggable)
KanbanCard.tsx
6.4
创建 KanbanBoard (DragDropContext)
KanbanBoard.tsx
6.5
添加看板视图样式
kanban.css
步骤
任务
文件
7.1
创建 TaskCreateModal
TaskCreateModal.tsx
7.2
添加弹窗样式
kanban.css
步骤
任务
文件
8.1
实现 autoStart 逻辑: 创建对话 + 发送消息
KanbanView.tsx or useKanbanStore.ts
8.2
任务与 thread 关联 (threadId 写回)
useKanbanStore.ts
阶段 9: 样式打磨 + i18n (预计 2 步)
步骤
任务
文件
9.1
完善所有看板组件的样式细节
kanban.css
9.2
添加中英文翻译
i18n/locales/en.ts, zh.ts
App.tsx 复杂度 : 文件已 2354 行,新增约 25 行可控。看板逻辑主要在 useKanbanStore hook 中。
props drilling 链 : useLayoutNodes 已接收 ~400 个属性,新增 appMode + onAppModeChange 约 2 个。
@hello-pangea/dnd + React 19 : 需验证兼容性。备选方案: @dnd-kit/core。
localStorage 5MB 限制 : 只存文件路径,不存图片数据,足够数千个任务。
"开始"功能 : 需要复用现有的 workspace → thread → sendMessage 流程,可能需要处理"当前没有 workspace"的场景。
对话视图内展示看板任务状态
任务详情页(点击卡片展开右侧面板)
看板过滤/搜索
任务评论/附件
多人协作
后端 Rust JSON 文件持久化 (后续从 localStorage 迁移)