feat: add queue management and terminal dashboard documentation in Chinese

- Introduced comprehensive documentation for the queue management feature, detailing its pain points, core functionalities, and component structure.
- Added terminal dashboard documentation, highlighting its layout, core features, and usage examples.
- Created an index page in Chinese for Claude Code Workflow, summarizing its purpose and core features, along with quick links to installation and guides.
This commit is contained in:
catlog22
2026-03-01 10:52:46 +08:00
parent a753327acc
commit 2fb93d20e0
34 changed files with 6908 additions and 257 deletions

View File

@@ -0,0 +1,600 @@
# 组件库
## 一句话概述
**基于 Radix UI 原语和 Tailwind CSS 构建的可复用 UI 组件综合集合,遵循 shadcn/ui 模式,提供一致、可访问和可定制的界面。**
---
## 概述
**位置**: `ccw/frontend/src/components/ui/`
**用途**: 为构建 CCW 前端应用程序提供一致的 UI 组件集合。
**技术栈**:
- **Radix UI**: 无样式、可访问的组件原语
- **Tailwind CSS**: 带自定义主题的实用优先样式
- **class-variance-authority (CVA)**: 类型安全的变体 props 管理
- **Lucide React**: 一致的图标系统
---
## 实时演示:组件库展示
:::demo ComponentGallery
# component-gallery.tsx
/**
* 组件库展示演示
* 所有 UI 组件的交互式展示
*/
export function ComponentGallery() {
const [selectedCategory, setSelectedCategory] = React.useState('all')
const [buttonVariant, setButtonVariant] = React.useState('default')
const [switchState, setSwitchState] = React.useState(false)
const [checkboxState, setCheckboxState] = React.useState(false)
const [selectedTab, setSelectedTab] = React.useState('variants')
const categories = [
{ id: 'all', label: '全部组件' },
{ id: 'buttons', label: '按钮' },
{ id: 'forms', label: '表单' },
{ id: 'feedback', label: '反馈' },
{ id: 'navigation', label: '导航' },
{ id: 'overlays', label: '叠加层' },
]
const components = {
buttons: [
{ name: 'Button', variants: ['default', 'destructive', 'outline', 'secondary', 'ghost', 'link', 'gradient'] },
],
forms: [
{ name: 'Input', type: 'text' },
{ name: 'Textarea', type: 'textarea' },
{ name: 'Select', type: 'select' },
{ name: 'Checkbox', type: 'checkbox' },
{ name: 'Switch', type: 'switch' },
],
feedback: [
{ name: 'Badge', variants: ['default', 'secondary', 'success', 'warning', 'destructive'] },
{ name: 'Progress', type: 'progress' },
{ name: 'Alert', type: 'alert' },
],
navigation: [
{ name: 'Tabs', type: 'tabs' },
{ name: 'Breadcrumb', type: 'breadcrumb' },
],
overlays: [
{ name: 'Dialog', type: 'dialog' },
{ name: 'Drawer', type: 'drawer' },
{ name: 'Dropdown', type: 'dropdown' },
],
}
const buttonVariants = ['default', 'destructive', 'outline', 'secondary', 'ghost', 'link']
return (
<div className="p-6 bg-background space-y-8">
{/* 标题 */}
<div>
<h1 className="text-2xl font-bold">UI 组件库</h1>
<p className="text-muted-foreground">所有可用 UI 组件的交互式展示</p>
</div>
{/* 分类过滤 */}
<div className="flex flex-wrap gap-2">
{categories.map((cat) => (
<button
key={cat.id}
onClick={() => setSelectedCategory(cat.id)}
className={`px-4 py-2 rounded-md text-sm transition-colors ${
selectedCategory === cat.id
? 'bg-primary text-primary-foreground'
: 'border hover:bg-accent'
}`}
>
{cat.label}
</button>
))}
</div>
{/* 按钮部分 */}
{(selectedCategory === 'all' || selectedCategory === 'buttons') && (
<section className="space-y-4">
<h2 className="text-lg font-semibold">按钮</h2>
<div className="space-y-6">
{/* 变体选择器 */}
<div className="space-y-3">
<label className="text-sm font-medium">变体</label>
<div className="flex flex-wrap gap-2">
{buttonVariants.map((variant) => (
<button
key={variant}
onClick={() => setButtonVariant(variant)}
className={`px-4 py-2 rounded-md text-sm capitalize transition-colors ${
buttonVariant === variant
? 'bg-primary text-primary-foreground ring-2 ring-ring'
: 'border hover:bg-accent'
}`}
>
{variant}
</button>
))}
</div>
</div>
{/* 按钮尺寸 */}
<div className="space-y-3">
<label className="text-sm font-medium">尺寸</label>
<div className="flex items-center gap-3 flex-wrap">
<button className={`h-8 rounded-md px-3 text-sm ${buttonVariant === 'default' ? 'bg-primary text-primary-foreground' : 'border'}`}>
</button>
<button className={`h-10 px-4 py-2 rounded-md text-sm ${buttonVariant === 'default' ? 'bg-primary text-primary-foreground' : 'border'}`}>
默认
</button>
<button className={`h-11 rounded-md px-8 text-sm ${buttonVariant === 'default' ? 'bg-primary text-primary-foreground' : 'border'}`}>
</button>
<button className={`h-10 w-10 rounded-md flex items-center justify-center ${buttonVariant === 'default' ? 'bg-primary text-primary-foreground' : 'border'}`}>
</button>
</div>
</div>
{/* 所有按钮变体 */}
<div className="space-y-3">
<label className="text-sm font-medium">所有变体</label>
<div className="flex flex-wrap gap-3 p-4 border rounded-lg bg-muted/20">
<button className="px-4 py-2 rounded-md text-sm bg-primary text-primary-foreground hover:opacity-90">默认</button>
<button className="px-4 py-2 rounded-md text-sm bg-destructive text-destructive-foreground hover:opacity-90">危险</button>
<button className="px-4 py-2 rounded-md text-sm border bg-background hover:bg-accent">轮廓</button>
<button className="px-4 py-2 rounded-md text-sm bg-secondary text-secondary-foreground hover:opacity-80">次要</button>
<button className="px-4 py-2 rounded-md text-sm hover:bg-accent">幽灵</button>
<button className="px-4 py-2 rounded-md text-sm text-primary underline-offset-4 hover:underline">链接</button>
<button className="px-4 py-2 rounded-md text-sm bg-gradient-to-r from-blue-500 to-purple-500 text-white hover:opacity-90">渐变</button>
</div>
</div>
</div>
</section>
)}
{/* 表单部分 */}
{(selectedCategory === 'all' || selectedCategory === 'forms') && (
<section className="space-y-4">
<h2 className="text-lg font-semibold">表单组件</h2>
<div className="grid md:grid-cols-2 gap-6">
{/* 输入框 */}
<div className="space-y-3">
<label className="text-sm font-medium">输入框</label>
<input
type="text"
placeholder="输入文本..."
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
/>
<input
type="text"
placeholder="错误状态"
className="flex h-10 w-full rounded-md border border-destructive bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-destructive"
/>
</div>
{/* 文本区域 */}
<div className="space-y-3">
<label className="text-sm font-medium">文本区域</label>
<textarea
placeholder="输入多行文本..."
className="flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
/>
</div>
{/* 复选框 */}
<div className="space-y-3">
<label className="text-sm font-medium">复选框</label>
<div className="space-y-2">
<label className="flex items-center gap-2 text-sm cursor-pointer">
<input type="checkbox" className="h-4 w-4 rounded border border-primary" checked={checkboxState} onChange={(e) => setCheckboxState(e.target.checked)} />
<span>接受条款和条件</span>
</label>
<label className="flex items-center gap-2 text-sm cursor-pointer opacity-50">
<input type="checkbox" className="h-4 w-4 rounded border border-primary" />
<span>订阅新闻通讯</span>
</label>
</div>
</div>
{/* 开关 */}
<div className="space-y-3">
<label className="text-sm font-medium">开关</label>
<div className="space-y-3">
<label className="flex items-center gap-3 cursor-pointer">
<div className="relative">
<input type="checkbox" className="sr-only peer" checked={switchState} onChange={(e) => setSwitchState(e.target.checked)} />
<div className="w-9 h-5 bg-input rounded-full peer peer-focus:ring-2 peer-focus:ring-ring peer-checked:bg-primary after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-background after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:after:translate-x-full" />
</div>
<span className="text-sm">启用通知 {switchState ? '(开)' : '(关)'}</span>
</label>
</div>
</div>
{/* 下拉选择 */}
<div className="space-y-3">
<label className="text-sm font-medium">下拉选择</label>
<select className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring">
<option value="">选择一个选项</option>
<option value="1">选项 1</option>
<option value="2">选项 2</option>
<option value="3">选项 3</option>
</select>
</div>
{/* 表单操作 */}
<div className="space-y-3">
<label className="text-sm font-medium">表单操作</label>
<div className="flex gap-2">
<button className="px-4 py-2 rounded-md text-sm bg-primary text-primary-foreground hover:opacity-90">提交</button>
<button className="px-4 py-2 rounded-md text-sm border hover:bg-accent">取消</button>
</div>
</div>
</div>
</section>
)}
{/* 反馈部分 */}
{(selectedCategory === 'all' || selectedCategory === 'feedback') && (
<section className="space-y-4">
<h2 className="text-lg font-semibold">反馈组件</h2>
{/* 徽章 */}
<div className="space-y-3">
<label className="text-sm font-medium">徽章</label>
<div className="flex flex-wrap gap-2">
<span className="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold bg-primary text-primary-foreground">默认</span>
<span className="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold bg-secondary text-secondary-foreground">次要</span>
<span className="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold bg-destructive text-destructive-foreground">危险</span>
<span className="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold bg-success text-white">成功</span>
<span className="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold bg-warning text-white">警告</span>
<span className="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold bg-info text-white">信息</span>
<span className="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold text-foreground">轮廓</span>
</div>
</div>
{/* 进度条 */}
<div className="space-y-3">
<label className="text-sm font-medium">进度条</label>
<div className="space-y-3 max-w-md">
<div>
<div className="flex justify-between text-xs mb-1">
<span>处理中...</span>
<span>65%</span>
</div>
<div className="h-2 bg-muted rounded-full overflow-hidden">
<div className="h-full bg-primary rounded-full transition-all" style={{ width: '65%' }}/>
</div>
</div>
<div>
<div className="flex justify-between text-xs mb-1">
<span>上传中...</span>
<span>30%</span>
</div>
<div className="h-2 bg-muted rounded-full overflow-hidden">
<div className="h-full bg-blue-500 rounded-full transition-all" style={{ width: '30%' }}/>
</div>
</div>
</div>
</div>
{/* 警告 */}
<div className="space-y-3">
<label className="text-sm font-medium">警告提示</label>
<div className="space-y-3">
<div className="flex items-start gap-3 p-4 border rounded-lg bg-destructive/10 border-destructive/20 text-destructive">
<span className="text-lg">⚠</span>
<div className="flex-1">
<div className="font-medium text-sm">发生错误</div>
<div className="text-xs mt-1 opacity-80">出现了一些问题,请重试。</div>
</div>
</div>
<div className="flex items-start gap-3 p-4 border rounded-lg bg-success/10 border-success/20 text-success">
<span className="text-lg">✓</span>
<div className="flex-1">
<div className="font-medium text-sm">成功!</div>
<div className="text-xs mt-1 opacity-80">您的更改已保存。</div>
</div>
</div>
</div>
</div>
</section>
)}
{/* 导航部分 */}
{(selectedCategory === 'all' || selectedCategory === 'navigation') && (
<section className="space-y-4">
<h2 className="text-lg font-semibold">导航组件</h2>
{/* 标签页 */}
<div className="space-y-3">
<label className="text-sm font-medium">标签页</label>
<div className="border-b">
<div className="flex gap-4">
{['概览', '文档', 'API 参考', '示例'].map((tab) => (
<button
key={tab}
onClick={() => setSelectedTab(tab.toLowerCase().replace(' ', '-'))}
className={`pb-3 px-1 text-sm border-b-2 transition-colors ${
selectedTab === tab.toLowerCase().replace(' ', '-')
? 'border-primary text-primary'
: 'border-transparent text-muted-foreground hover:text-foreground'
}`}
>
{tab}
</button>
))}
</div>
</div>
</div>
{/* 面包屑 */}
<div className="space-y-3">
<label className="text-sm font-medium">面包屑</label>
<nav className="flex items-center gap-2 text-sm text-muted-foreground">
<a href="#" className="hover:text-foreground">首页</a>
<span>/</span>
<a href="#" className="hover:text-foreground">组件</a>
<span>/</span>
<span className="text-foreground">库</span>
</nav>
</div>
</section>
)}
{/* 叠加层部分 */}
{(selectedCategory === 'all' || selectedCategory === 'overlays') && (
<section className="space-y-4">
<h2 className="text-lg font-semibold">叠加层组件</h2>
<div className="grid md:grid-cols-3 gap-4 text-sm">
<div className="p-4 border rounded-lg">
<h3 className="font-medium mb-2">对话框</h3>
<p className="text-muted-foreground text-xs">用于焦点用户交互的模态对话框。</p>
<button className="mt-3 px-3 py-1.5 text-xs bg-primary text-primary-foreground rounded">打开对话框</button>
</div>
<div className="p-4 border rounded-lg">
<h3 className="font-medium mb-2">抽屉</h3>
<p className="text-muted-foreground text-xs">从屏幕边缘滑入的侧边面板。</p>
<button className="mt-3 px-3 py-1.5 text-xs border rounded hover:bg-accent">打开抽屉</button>
</div>
<div className="p-4 border rounded-lg">
<h3 className="font-medium mb-2">下拉菜单</h3>
<p className="text-muted-foreground text-xs">上下文菜单和操作列表。</p>
<button className="mt-3 px-3 py-1.5 text-xs border rounded hover:bg-accent">▼ 打开菜单</button>
</div>
</div>
</section>
)}
</div>
)
}
:::
---
## 可用组件
### 表单组件
| 组件 | 描述 | Props |
|------|------|------|
| [Button](/components/ui/button) | 可点击的操作按钮,带变体和尺寸 | `variant`, `size`, `asChild` |
| [Input](/components/ui/input) | 文本输入字段 | `error` |
| [Textarea](/components/ui/textarea) | 多行文本输入 | `error` |
| [Select](/components/ui/select) | 下拉选择Radix | Select 组件 |
| [Checkbox](/components/ui/checkbox) | 布尔复选框Radix | `checked`, `onCheckedChange` |
| [Switch](/components/ui/switch) | 切换开关 | `checked`, `onCheckedChange` |
### 布局组件
| 组件 | 描述 | Props |
|------|------|------|
| [Card](/components/ui/card) | 带标题/脚注的内容容器 | 嵌套组件 |
| [Separator](/components/ui/separator) | 视觉分隔符 | `orientation` |
| [ScrollArea](/components/ui/scroll-area) | 自定义滚动条容器 | - |
### 反馈组件
| 组件 | 描述 | Props |
|------|------|------|
| [Badge](/components/ui/badge) | 状态指示器标签 | `variant` |
| [Progress](/components/ui/progress) | 进度条 | `value` |
| [Alert](/components/ui/alert) | 通知消息 | `variant` |
| [Toast](/components/ui/toast) | 临时通知Radix | Toast 组件 |
### 导航组件
| 组件 | 描述 | Props |
|------|------|------|
| [Tabs](/components/ui/tabs) | 标签页导航Radix | Tabs 组件 |
| [TabsNavigation](/components/ui/tabs-navigation) | 自定义标签栏 | `tabs`, `value`, `onValueChange` |
| [Breadcrumb](/components/ui/breadcrumb) | 导航面包屑 | Breadcrumb 组件 |
### 叠加层组件
| 组件 | 描述 | Props |
|------|------|------|
| [Dialog](/components/ui/dialog) | 模态对话框Radix | `open`, `onOpenChange` |
| [Drawer](/components/ui/drawer) | 侧边面板Radix | `open`, `onOpenChange` |
| [Dropdown Menu](/components/ui/dropdown) | 上下文菜单Radix | Dropdown 组件 |
| [Popover](/components/ui/popover) | 浮动内容Radix | `open`, `onOpenChange` |
| [Tooltip](/components/ui/tooltip) | 悬停工具提示Radix | `content` |
| [AlertDialog](/components/ui/alert-dialog) | 确认对话框Radix | Dialog 组件 |
### 展开组件
| 组件 | 描述 | Props |
|------|------|------|
| [Collapsible](/components/ui/collapsible) | 展开/折叠内容Radix | `open`, `onOpenChange` |
| [Accordion](/components/ui/accordion) | 可折叠部分Radix | Accordion 组件 |
---
## 按钮变体
Button 组件通过 CVAclass-variance-authority支持 8 种变体:
| 变体 | 用途 | 预览 |
|---------|----------|--------|
| `default` | 主要操作 | <span className="inline-block px-3 py-1 rounded bg-primary text-primary-foreground text-xs">默认</span> |
| `destructive` | 危险操作 | <span className="inline-block px-3 py-1 rounded bg-destructive text-destructive-foreground text-xs">危险</span> |
| `outline` | 次要操作 | <span className="inline-block px-3 py-1 rounded border text-xs">轮廓</span> |
| `secondary` | 较少强调 | <span className="inline-block px-3 py-1 rounded bg-secondary text-secondary-foreground text-xs">次要</span> |
| `ghost` | 微妙操作 | <span className="inline-block px-3 py-1 rounded text-xs">幽灵</span> |
| `link` | 文本链接 | <span className="inline-block px-3 py-1 underline text-primary text-xs">链接</span> |
| `gradient` | 特色操作 | <span className="inline-block px-3 py-1 rounded bg-gradient-to-r from-blue-500 to-purple-500 text-white text-xs">渐变</span> |
| `gradientPrimary` | 主要渐变 | <span className="inline-block px-3 py-1 rounded bg-gradient-to-r from-purple-500 to-pink-500 text-white text-xs">主要</span> |
### 按钮尺寸
| 尺寸 | 高度 | 内边距 |
|------|--------|---------|
| `sm` | 36px | 水平 12px |
| `default` | 40px | 水平 16px |
| `lg` | 44px | 水平 32px |
| `icon` | 40px | 正方形(仅图标) |
---
## 徽章变体
Badge 组件支持 9 种变体,用于不同的状态类型:
| 变体 | 用途 | 颜色 |
|---------|----------|-------|
| `default` | 一般信息 | 主要主题 |
| `secondary` | 较少强调 | 次要主题 |
| `destructive` | 错误/危险 | 危险主题 |
| `outline` | 微妙 | 仅文本颜色 |
| `success` | 成功状态 | 绿色 |
| `warning` | 警告状态 | 琥珀色 |
| `info` | 信息 | 蓝色 |
| `review` | 审查状态 | 紫色 |
| `gradient` | 特色 | 品牌渐变 |
---
## 使用示例
### Button
```tsx
import { Button } from '@/components/ui/Button'
<Button variant="default" onClick={handleClick}>
</Button>
<Button variant="destructive" size="sm">
</Button>
<Button variant="ghost" size="icon">
<SettingsIcon />
</Button>
```
### Input with Error State
```tsx
import { Input } from '@/components/ui/Input'
<Input
type="text"
error={hasError}
placeholder="输入您的名称"
value={name}
onChange={(e) => setName(e.target.value)}
/>
```
### Checkbox
```tsx
import { Checkbox } from '@/components/ui/Checkbox'
<Checkbox
checked={accepted}
onCheckedChange={setAccepted}
/>
<label></label>
```
### Switch
```tsx
import { Switch } from '@/components/ui/Switch'
<Switch
checked={enabled}
onCheckedChange={setEnabled}
/>
<span></span>
```
### Card
```tsx
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from '@/components/ui/Card'
<Card>
<CardHeader>
<CardTitle></CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent>
<p></p>
</CardContent>
<CardFooter>
<Button></Button>
</CardFooter>
</Card>
```
### Badge
```tsx
import { Badge, badgeVariants } from '@/components/ui/Badge'
<Badge variant="success"></Badge>
<Badge variant="warning"></Badge>
<Badge variant="destructive"></Badge>
```
---
## 可访问性
所有组件遵循 Radix UI 的可访问性标准:
- **键盘导航**:所有交互组件完全可键盘访问
- **ARIA 属性**:正确的角色、状态和属性
- **屏幕阅读器支持**:语义化 HTML 和 ARIA 标签
- **焦点管理**:可见的焦点指示器和逻辑 Tab 顺序
- **颜色对比度**:符合 WCAG AA 标准的颜色组合
### 键盘快捷键
| 组件 | 按键 |
|-----------|-------|
| Button | <kbd>Enter</kbd>, <kbd>Space</kbd> |
| Checkbox/Switch | <kbd>Space</kbd> 切换 |
| Select | <kbd>Arrow</kbd> 键,<kbd>Enter</kbd> 选择,<kbd>Esc</kbd> 关闭 |
| Dialog | <kbd>Esc</kbd> 关闭 |
| Tabs | <kbd>Arrow</kbd> 键导航 |
| Dropdown | <kbd>Arrow</kbd> 键,<kbd>Enter</kbd> 选择 |
---
## 相关链接
- [Radix UI Primitives](https://www.radix-ui.com/) - 无头 UI 组件库
- [Tailwind CSS](https://tailwindcss.com/) - 实用优先 CSS 框架
- [shadcn/ui](https://ui.shadcn.com/) - 组件模式参考
- [CVA Documentation](https://cva.style/) - Class Variance Authority

View File

@@ -0,0 +1,119 @@
---
title: Badge 徽章
description: 用于视觉分类的小型状态或标签组件
sidebar: auto
---
# Badge 徽章
## 概述
Badge 徽章组件用于以紧凑形式显示状态、类别或标签。它通常用于标签、状态指示器和计数。
## 语法演示
:::demo badge-variants
展示所有可用的徽章变体,包括默认、次要、破坏性、轮廓、成功、警告、信息、审查和渐变样式
:::
## 属性
<PropsTable :props="[
{ name: 'variant', type: '\'default\' | \'secondary\' | \'destructive\' | \'outline\' | \'success\' | \'warning\' | \'info\' | \'review\' | \'gradient\'', required: false, default: '\'default\'', description: '视觉样式变体' },
{ name: 'className', type: 'string', required: false, default: '-', description: '自定义 CSS 类名' },
{ name: 'children', type: 'ReactNode', required: true, default: '-', description: '徽章内容' }
]" />
## 变体说明
### Default默认
主题色背景的主要徽章。用于主要标签和类别。
### Secondary次要
次要信息的灰色徽章。
### Destructive破坏性
红色徽章,用于错误、危险状态或负面状态指示。
### Outline轮廓
只有文本和边框、无背景的徽章。用于微妙的标签。
### Success成功
绿色徽章,用于成功状态、完成的操作或正面状态指示。
### Warning警告
黄色/琥珀色徽章,用于警告、待处理状态或注意事项。
### Info信息
蓝色徽章,用于信息内容或中性状态。
### Review审查
紫色徽章,用于审查状态、待审查或反馈指示器。
### Gradient渐变
带品牌渐变背景的徽章,用于特色或突出显示的项目。
## 使用示例
### 基础徽章
```vue
<Badge>默认</Badge>
```
### 状态指示器
```vue
<Badge variant="success">活跃</Badge>
<Badge variant="warning">待处理</Badge>
<Badge variant="destructive">失败</Badge>
<Badge variant="info">草稿</Badge>
```
### 计数徽章
```vue
<div class="relative">
<Bell />
<Badge variant="destructive" class="absolute -top-2 -right-2 h-5 w-5 rounded-full p-0 flex items-center justify-center text-xs">
3
</Badge>
</div>
```
### 分类标签
```vue
<div class="flex gap-2">
<Badge variant="outline">React</Badge>
<Badge variant="outline">TypeScript</Badge>
<Badge variant="outline">Tailwind</Badge>
</div>
```
### 审查状态
```vue
<Badge variant="review">审查中</Badge>
```
### 渐变徽章
```vue
<Badge variant="gradient">特色</Badge>
```
## 相关组件
- [Card 卡片](/zh-CN/components/ui/card)
- [Button 按钮](/zh-CN/components/ui/button)
- [Avatar 头像](/zh-CN/components/ui/avatar)

View File

@@ -0,0 +1,80 @@
---
title: Button 按钮
description: 按钮组件用于触发操作或提交表单
sidebar: auto
---
# Button 按钮
## 概述
按钮是最常用的交互元素之一,用于触发操作、提交表单或导航到其他页面。
## 语法演示
:::demo button-variants
展示所有视觉变体的按钮组件
:::
## 属性
<PropsTable :props="[
{ name: 'variant', type: '\'default\' | \'destructive\' | \'outline\' | \'secondary\' | \'ghost\' | \'link\' | \'gradient\' | \'gradientPrimary\'', required: false, default: '\'default\'', description: '按钮的视觉变体' },
{ name: 'size', type: '\'default\' | \'sm\' | \'lg\' | \'icon\'', required: false, default: '\'default\'', description: '按钮的大小' },
{ name: 'asChild', type: 'boolean', required: false, default: 'false', description: '是否将 props 与子元素合并(用于 Radix UI 组合)' },
{ name: 'disabled', type: 'boolean', required: false, default: 'false', description: '是否禁用按钮' },
{ name: 'onClick', type: '() => void', required: false, default: '-', description: '点击事件回调函数' },
{ name: 'className', type: 'string', required: false, default: '-', description: '自定义 CSS 类名' },
{ name: 'children', type: 'ReactNode', required: true, default: '-', description: '按钮内容' }
]" />
## 变体说明
### Default默认
默认按钮用于主要的操作场景。
### Destructive破坏性
破坏性按钮用于删除、移除等不可逆的操作。
### Outline轮廓
轮廓按钮用于次要操作,视觉上更轻量。
### Secondary次要
次要按钮用于辅助操作。
### Ghost幽灵
幽灵按钮没有边框,视觉上最轻量。
### Link链接
链接按钮看起来像链接,但具有按钮的交互行为。
### Gradient渐变
渐变按钮使用品牌渐变色,悬停时带有发光效果。
### Gradient Primary主色渐变
主色渐变按钮使用主题主色渐变,悬停时带有增强的发光效果。
## 使用场景
| 场景 | 推荐变体 |
|------|----------|
| 主要操作(提交、保存) | default, gradientPrimary |
| 危险操作(删除、移除) | destructive |
| 次要操作 | outline, secondary |
| 取消操作 | ghost, outline |
| 导航链接 | link |
| 促销/特色 CTA | gradient |
## 相关组件
- [Input 输入框](/zh-CN/components/ui/input)
- [Select 选择器](/zh-CN/components/ui/select)
- [Dialog 对话框](/zh-CN/components/ui/dialog)

View File

@@ -0,0 +1,107 @@
---
title: Card 卡片
description: 用于分组相关内容的容器组件
sidebar: auto
---
# Card 卡片
## 概述
卡片组件是一个通用的容器,用于分组相关的内容和操作。它由多个子组件组成,协同工作以创建连贯的卡片布局。
## 语法演示
:::demo card-variants
展示不同的卡片布局,包括页眉、内容、页脚和渐变边框变体
:::
## 组件
卡片组件包含以下子组件:
| 组件 | 用途 |
|------|------|
| `Card` | 带有边框和背景的主容器 |
| `CardHeader` | 带有内边距的页眉部分 |
| `CardTitle` | 标题元素 |
| `CardDescription` | 带有次要颜色的描述文本 |
| `CardContent` | 带有顶部内边距的内容区域 |
| `CardFooter` | 用于操作的页脚部分 |
| `CardGradientBorder` | 带有渐变边框的卡片 |
## 属性
所有 Card 组件接受标准 HTML div 属性:
| 组件 | 属性 |
|------|------|
| `Card` | `className?: string` |
| `CardHeader` | `className?: string` |
| `CardTitle` | `className?: string`, `children?: ReactNode` |
| `CardDescription` | `className?: string`, `children?: ReactNode` |
| `CardContent` | `className?: string` |
| `CardFooter` | `className?: string` |
| `CardGradientBorder` | `className?: string` |
## 使用示例
### 基础卡片
```vue
<Card>
<CardContent>
<p>这是一个带有内容的基础卡片</p>
</CardContent>
</Card>
```
### 带页眉的卡片
```vue
<Card>
<CardHeader>
<CardTitle>卡片标题</CardTitle>
<CardDescription>卡片描述放在这里</CardDescription>
</CardHeader>
<CardContent>
<p>卡片内容放在这里</p>
</CardContent>
</Card>
```
### 带页脚的完整卡片
```vue
<Card>
<CardHeader>
<CardTitle>项目设置</CardTitle>
<CardDescription>管理您的项目配置</CardDescription>
</CardHeader>
<CardContent>
<p>配置您的项目设置和偏好</p>
</CardContent>
<CardFooter>
<Button>保存更改</Button>
</CardFooter>
</Card>
```
### 带渐变边框的卡片
```vue
<CardGradientBorder>
<CardHeader>
<CardTitle>特色卡片</CardTitle>
</CardHeader>
<CardContent>
<p>此卡片具有渐变边框效果</p>
</CardContent>
</CardGradientBorder>
```
## 相关组件
- [Button 按钮](/zh-CN/components/ui/button)
- [Badge 徽章](/zh-CN/components/ui/badge)
- [Separator 分隔线](/zh-CN/components/ui/separator)

View File

@@ -0,0 +1,120 @@
---
title: Checkbox 复选框
description: 用于二元选择的复选框组件
sidebar: auto
---
# Checkbox 复选框
## 概述
Checkbox 复选框组件允许用户从一组选项中选择一个或多个选项。基于 Radix UI Checkbox Primitive 构建,提供完整的无障碍支持,包括键盘导航。
## 语法演示
:::demo checkbox-variants
展示不同的复选框状态,包括选中、未选中、半选和禁用状态
:::
## 属性
<PropsTable :props="[
{ name: 'checked', type: 'boolean | \'indeterminate\'', required: false, default: 'false', description: '是否选中复选框' },
{ name: 'defaultChecked', type: 'boolean', required: false, default: 'false', description: '初始选中状态(非受控)' },
{ name: 'onCheckedChange', type: '(checked: boolean) => void', required: false, default: '-', description: '选中状态变化时的回调函数' },
{ name: 'disabled', type: 'boolean', required: false, default: 'false', description: '是否禁用复选框' },
{ name: 'required', type: 'boolean', required: false, default: 'false', description: '是否为必填项' },
{ name: 'name', type: 'string', required: false, default: '-', description: '表单输入名称' },
{ name: 'value', type: 'string', required: false, default: '-', description: '表单输入值' },
{ name: 'className', type: 'string', required: false, default: '-', description: '自定义 CSS 类名' }
]" />
## 状态说明
### Unchecked未选中
复选框未被选择时的默认状态。
### Checked已选中
复选框被选择时显示勾选图标。
### Indeterminate半选
混合状态(部分选择),通常用于父级复选框,当部分但不是全部子项被选中时使用。
### Disabled禁用
禁用的复选框不可交互,并以降低的透明度显示。
## 使用示例
### 基础复选框
```vue
<Checkbox />
```
### 带标签的复选框
```vue
<div class="flex items-center space-x-2">
<Checkbox id="terms" />
<label for="terms">我同意条款和条件</label>
</div>
```
### 受控复选框
```vue
<script setup>
import { ref } from 'vue'
const checked = ref(false)
</script>
<template>
<div class="flex items-center space-x-2">
<Checkbox v-model:checked="checked" />
<span>{{ checked ? '已选中' : '未选中' }}</span>
</div>
</template>
```
### 半选状态
```vue
<script setup>
import { ref } from 'vue'
const state = ref('indeterminate')
</script>
<template>
<Checkbox :checked="state" />
</template>
```
### 表单集成
```vue
<form @submit="handleSubmit">
<div class="space-y-2">
<div class="flex items-center space-x-2">
<Checkbox id="newsletter" name="newsletter" value="yes" />
<label for="newsletter">订阅新闻通讯</label>
</div>
<div class="flex items-center space-x-2">
<Checkbox id="updates" name="updates" value="yes" />
<label for="updates">接收产品更新</label>
</div>
</div>
<Button type="submit" class="mt-4">提交</Button>
</form>
```
## 相关组件
- [Input 输入框](/zh-CN/components/ui/input)
- [Select 选择器](/zh-CN/components/ui/select)
- [Radio Group 单选框组](/zh-CN/components/ui/radio-group)

View File

@@ -0,0 +1,118 @@
---
title: Input 输入框
description: 用于表单和用户输入的文本输入组件
sidebar: auto
---
# Input 输入框
## 概述
输入框组件提供了一个样式化的文本输入字段,扩展了原生 HTML input 元素,具有一致的样式和错误状态支持。
## 语法演示
:::demo input-variants
展示所有输入框状态,包括默认、错误和禁用
:::
## 属性
<PropsTable :props="[
{ name: 'type', type: 'string', required: false, default: '\'text\'', description: 'HTML input 类型text、password、email、number 等)' },
{ name: 'error', type: 'boolean', required: false, default: 'false', description: '输入框是否处于错误状态(显示破坏性边框)' },
{ name: 'disabled', type: 'boolean', required: false, default: 'false', description: '是否禁用输入框' },
{ name: 'placeholder', type: 'string', required: false, default: '-', description: '输入框为空时显示的占位符文本' },
{ name: 'value', type: 'string | number', required: false, default: '-', description: '受控输入框的值' },
{ name: 'defaultValue', type: 'string | number', required: false, default: '-', description: '非受控输入框的默认值' },
{ name: 'onChange', type: '(event: ChangeEvent) => void', required: false, default: '-', description: '变更事件回调函数' },
{ name: 'className', type: 'string', required: false, default: '-', description: '自定义 CSS 类名' }
]" />
## 状态
### Default默认
带有边框和焦点环的标准输入框。
### Error错误
错误状态,显示破坏性边框颜色。将 `error` 属性设置为 `true`
### Disabled禁用
禁用状态,透明度降低。将 `disabled` 属性设置为 `true`
### Focus聚焦
聚焦状态,带有环形轮廓。
## 使用示例
### 基础输入框
```tsx
import { Input } from '@/components/ui/Input'
function Example() {
return <input type="text" placeholder="输入文本..." />
}
```
### 受控输入框
```tsx
import { Input } from '@/components/ui/Input'
function Example() {
const [value, setValue] = useState('')
return (
<Input
type="text"
value={value}
onChange={(e) => setValue(e.target.value)}
placeholder="输入文本..."
/>
)
}
```
### 错误状态输入框
```tsx
import { Input } from '@/components/ui/Input'
function Example() {
return (
<Input
type="text"
error
placeholder="无效输入..."
/>
)
}
```
### 密码输入框
```tsx
import { Input } from '@/components/ui/Input'
function Example() {
return <Input type="password" placeholder="输入密码..." />
}
```
## 无障碍访问
- **键盘导航**:完全支持原生键盘操作
- **ARIA 属性**:支持所有标准输入框 ARIA 属性
- **焦点可见**:为键盘导航提供清晰的焦点指示器
- **错误状态**:错误状态的视觉指示(与 `aria-invalid``aria-describedby` 配合使用)
## 相关组件
- [Button 按钮](/zh-CN/components/ui/button)
- [Select 选择器](/zh-CN/components/ui/select)
- [Checkbox 复选框](/zh-CN/components/ui/checkbox)

View File

@@ -0,0 +1,127 @@
---
title: Select 选择器
description: 用于从选项列表中选择值的下拉选择组件
sidebar: auto
---
# Select 选择器
## 概述
Select 选择器组件允许用户从选项列表中选择单个值。基于 Radix UI Select Primitive 构建,提供开箱即用的无障碍支持和键盘导航。
## 语法演示
:::demo select-variants
展示不同的选择器配置,包括基础用法、带标签和带分隔线的示例
:::
## 子组件
Select 选择器组件包含以下子组件:
| 组件 | 用途 |
|------|------|
| `Select` | 管理状态的根组件 |
| `SelectTrigger` | 打开下拉菜单的按钮 |
| `SelectValue` | 显示选中的值 |
| `SelectContent` | 下拉菜单内容容器 |
| `SelectItem` | 单个可选项 |
| `SelectLabel` | 用于分组的不可交互标签 |
| `SelectGroup` | 将项目分组 |
| `SelectSeparator` | 项目之间的视觉分隔线 |
| `SelectScrollUpButton` | 长列表的向上滚动按钮 |
| `SelectScrollDownButton` | 长列表的向下滚动按钮 |
## 属性
### Select 根组件
| 属性 | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| `value` | `string` | - | 当前选中的值(受控) |
| `defaultValue` | `string` | - | 默认选中的值 |
| `onValueChange` | `(value: string) => void` | - | 值变化时的回调函数 |
| `disabled` | `boolean` | `false` | 是否禁用选择器 |
| `required` | `boolean` | `false` | 是否必填 |
| `name` | `string` | - | 表单输入名称 |
### SelectTrigger
| 属性 | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| `className` | `string` | - | 自定义 CSS 类名 |
### SelectItem
| 属性 | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| `value` | `string` | - | 选项值 |
| `disabled` | `boolean` | `false` | 是否禁用该选项 |
| `className` | `string` | - | 自定义 CSS 类名 |
## 使用示例
### 基础选择器
```vue
<Select>
<SelectTrigger>
<SelectValue placeholder="请选择一个选项" />
</SelectTrigger>
<SelectContent>
<SelectItem value="option1">选项 1</SelectItem>
<SelectItem value="option2">选项 2</SelectItem>
<SelectItem value="option3">选项 3</SelectItem>
</SelectContent>
</Select>
```
### 带标签和分组
```vue
<Select>
<SelectTrigger>
<SelectValue placeholder="选择水果" />
</SelectTrigger>
<SelectContent>
<SelectLabel>水果</SelectLabel>
<SelectItem value="apple">苹果</SelectItem>
<SelectItem value="banana">香蕉</SelectItem>
<SelectItem value="orange">橙子</SelectItem>
<SelectSeparator />
<SelectLabel>蔬菜</SelectLabel>
<SelectItem value="carrot">胡萝卜</SelectItem>
<SelectItem value="broccoli">西兰花</SelectItem>
</SelectContent>
</Select>
```
### 受控选择器
```vue
<script setup>
import { ref } from 'vue'
const selectedValue = ref('')
</script>
<template>
<Select v-model="selectedValue">
<SelectTrigger>
<SelectValue placeholder="请选择..." />
</SelectTrigger>
<SelectContent>
<SelectItem value="a">选项 A</SelectItem>
<SelectItem value="b">选项 B</SelectItem>
<SelectItem value="c">选项 C</SelectItem>
</SelectContent>
</Select>
</template>
```
## 相关组件
- [Input 输入框](/zh-CN/components/ui/input)
- [Checkbox 复选框](/zh-CN/components/ui/checkbox)
- [Button 按钮](/zh-CN/components/ui/button)

View File

@@ -0,0 +1,607 @@
# 仪表板
## 一句话概述
**仪表板通过直观的基于小部件的界面,提供项目工作流状态、统计信息和最近活动的概览。**
---
## 解决的痛点
| 痛点 | 当前状态 | 仪表板解决方案 |
|------|----------|----------------|
| **项目可见性不足** | 无法查看整体项目健康状况 | 带有技术栈和开发索引的项目信息横幅 |
| **指标分散** | 统计信息分布在多个位置 | 集中式统计数据,带有迷你趋势图 |
| **工作流状态未知** | 难以跟踪会话进度 | 带有状态细分的饼图 |
| **最近工作丢失** | 无法快速访问活动会话 | 带有任务详情的会话轮播 |
| **索引状态不明确** | 不知道代码是否已索引 | 实时索引状态指示器 |
---
## 概述
**位置**: `ccw/frontend/src/pages/HomePage.tsx`
**用途**: 仪表板主页,提供项目概览、统计信息、工作流状态和最近活动监控。
**访问**: 导航 → 仪表板(默认首页,路径为 `/`
**布局**:
```
+--------------------------------------------------------------------------+
| 仪表板头部(标题 + 刷新) |
+--------------------------------------------------------------------------+
| WorkflowTaskWidget组合卡片 |
| +--------------------------------------------------------------------+ |
| | 项目信息横幅(可展开) | |
| | - 项目名称、描述、技术栈徽章 | |
| | - 快速统计功能、bug修复、增强 | |
| | - 索引状态指示器 | |
| +----------------------------------+---------------------------------+ |
| | 统计部分 | 工作流状态 | 任务详情(轮播) | |
| | - 6 个迷你卡片 | - 饼图 | - 会话导航 | |
| | - 迷你趋势图 | - 图例 | - 任务列表2 列) | |
| +----------------+-----------------+-------------------------------+ |
+--------------------------------------------------------------------------+
| RecentSessionsWidget |
| +--------------------------------------------------------------------+ |
| | 标签页:所有任务 | 工作流 | 轻量任务 | |
| | +---------------+---------------+-------------------------------+ | |
| | | 带有状态、进度、标签、时间的任务卡片 | | |
| | +---------------------------------------------------------------+ | |
+--------------------------------------------------------------------------+
```
---
## 实时演示
:::demo DashboardOverview
# dashboard-overview.tsx
/**
* 仪表板概览演示
* 显示带有小部件的主仪表板布局
*/
export function DashboardOverview() {
return (
<div className="space-y-6 p-6 bg-background min-h-[600px]">
{/* 头部 */}
<div className="flex items-center justify-between">
<div>
<h1 className="text-2xl font-bold">仪表板</h1>
<p className="text-sm text-muted-foreground">
项目概览和活动监控
</p>
</div>
<button className="px-3 py-1.5 text-sm border rounded-md hover:bg-accent">
刷新
</button>
</div>
{/* 工作流统计小部件 */}
<div className="border rounded-lg overflow-hidden">
<div className="p-4 border-b bg-muted/30">
<h2 className="font-semibold">项目概览与统计</h2>
</div>
<div className="p-4">
<div className="grid grid-cols-3 gap-4">
<div className="space-y-3">
<div className="text-xs font-medium text-muted-foreground">统计数据</div>
<div className="grid grid-cols-2 gap-2">
{[
{ label: '活动会话', value: '12', color: 'text-blue-500' },
{ label: '总任务', value: '48', color: 'text-green-500' },
{ label: '已完成', value: '35', color: 'text-emerald-500' },
{ label: '待处理', value: '8', color: 'text-amber-500' },
].map((stat, i) => (
<div key={i} className="p-2 bg-muted/50 rounded">
<div className={`text-lg font-bold ${stat.color}`}>{stat.value}</div>
<div className="text-xs text-muted-foreground truncate">{stat.label}</div>
</div>
))}
</div>
</div>
<div className="space-y-3">
<div className="text-xs font-medium text-muted-foreground">工作流状态</div>
<div className="flex items-center justify-center h-24">
<div className="relative w-20 h-20">
<svg className="w-full h-full -rotate-90" viewBox="0 0 36 36">
<circle cx="18" cy="18" r="15" fill="none" stroke="currentColor" strokeWidth="3" className="text-muted opacity-20"/>
<circle cx="18" cy="18" r="15" fill="none" stroke="currentColor" strokeWidth="3" className="text-blue-500" strokeDasharray="70 100"/>
</svg>
<div className="absolute inset-0 flex items-center justify-center text-xs font-bold">70%</div>
</div>
</div>
<div className="text-xs text-center space-y-1">
<div className="flex items-center justify-center gap-1">
<div className="w-2 h-2 rounded-full bg-blue-500"/>
<span>已完成70%</span>
</div>
</div>
</div>
<div className="space-y-3">
<div className="text-xs font-medium text-muted-foreground">最近会话</div>
<div className="p-3 bg-accent/20 rounded border">
<div className="flex items-center justify-between mb-2">
<span className="text-sm font-medium">功能:身份验证流程</span>
<span className="text-xs px-2 py-0.5 rounded-full bg-green-500/20 text-green-600">运行中</span>
</div>
<div className="space-y-1.5">
<div className="flex items-center gap-2 text-xs">
<div className="w-3 h-3 rounded bg-green-500"/>
<span>实现登录表单</span>
</div>
<div className="flex items-center gap-2 text-xs">
<div className="w-3 h-3 rounded bg-amber-500"/>
<span>添加 OAuth 提供商</span>
</div>
<div className="flex items-center gap-2 text-xs">
<div className="w-3 h-3 rounded bg-muted"/>
<span className="text-muted-foreground">测试流程</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{/* 最近会话小部件 */}
<div className="border rounded-lg overflow-hidden">
<div className="border-b bg-muted/30">
<div className="flex gap-1 p-2">
{['所有任务', '工作流', '轻量任务'].map((tab, i) => (
<button
key={tab}
className={`px-3 py-1.5 text-xs rounded-md transition-colors ${
i === 0 ? 'bg-background text-foreground' : 'text-muted-foreground hover:bg-foreground/5'
}`}
>
{tab}
</button>
))}
</div>
</div>
<div className="p-4">
<div className="grid grid-cols-3 gap-3">
{[
{ name: '重构 UI 组件', status: '进行中', progress: 65 },
{ name: '修复登录 Bug', status: '待处理', progress: 0 },
{ name: '添加深色模式', status: '已完成', progress: 100 },
].map((task, i) => (
<div key={i} className="p-3 bg-muted/30 rounded border cursor-pointer hover:border-primary/30">
<div className="flex items-center justify-between mb-2">
<span className="text-xs font-medium line-clamp-1">{task.name}</span>
<span className={`text-xs px-1.5 py-0.5 rounded ${
task.status === '已完成' ? 'bg-green-500/20 text-green-600' :
task.status === '进行中' ? 'bg-blue-500/20 text-blue-600' :
'bg-gray-500/20 text-gray-600'
}`}>{task.status}</span>
</div>
{task.progress > 0 && task.progress < 100 && (
<div className="w-full h-1.5 bg-muted rounded-full overflow-hidden">
<div className="h-full bg-blue-500 rounded-full" style={{ width: `${task.progress}%` }}/>
</div>
)}
</div>
))}
</div>
</div>
</div>
</div>
)
}
:::
---
## 核心功能
| 功能 | 描述 |
|------|------|
| **项目信息横幅** | 可展开的横幅,显示项目名称、描述、技术栈(语言、框架、架构)、开发索引(功能/bug修复/增强)和实时索引状态 |
| **统计部分** | 6 个迷你统计卡片(活动会话、总任务、已完成任务、待处理任务、失败任务、今日活动),带有 7 天迷你趋势图 |
| **工作流状态饼图** | 环形图显示会话状态细分(已完成、进行中、计划中、已暂停、已归档),附带百分比 |
| **会话轮播** | 自动轮播5秒间隔的会话卡片带有任务列表、进度条和手动导航箭头 |
| **最近会话小部件** | 所有任务类型的标签页视图,带有筛选、状态徽章和进度指示器 |
| **实时更新** | 统计数据每 60 秒自动刷新,索引状态每 30 秒刷新 |
---
## 组件层次结构
```
HomePage
├── DashboardHeader
│ ├── 标题
│ └── 刷新操作按钮
├── WorkflowTaskWidget
│ ├── ProjectInfoBanner可展开
│ │ ├── 项目名称和描述
│ │ ├── 技术栈徽章
│ │ ├── 快速统计卡片
│ │ ├── 索引状态指示器
│ │ ├── 架构部分
│ │ ├── 关键组件
│ │ └── 设计模式
│ ├── 统计部分
│ │ └── MiniStatCard6 个卡片,带迷你趋势图)
│ ├── WorkflowStatusChart
│ │ └── 饼图与图例
│ └── SessionCarousel
│ ├── 导航箭头
│ └── 会话卡片(任务列表)
└── RecentSessionsWidget
├── 标签导航(全部 | 工作流 | 轻量任务)
├── 任务网格
│ └── TaskItemCard
└── 加载/空状态
```
---
## Props API
### HomePage 组件
| Prop | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| - | - | - | 此页面组件不接受任何 props数据通过 hooks 获取) |
### WorkflowTaskWidget
| Prop | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| `className` | `string` | `undefined` | 用于样式的额外 CSS 类 |
### RecentSessionsWidget
| Prop | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| `className` | `string` | `undefined` | 用于样式的额外 CSS 类 |
| `maxItems` | `number` | `6` | 要显示的最大项目数量 |
---
## 使用示例
### 基础仪表板
```tsx
import { HomePage } from '@/pages/HomePage'
// 仪表板在根路由 (/) 自动渲染
// 不需要 props - 数据通过 hooks 获取
```
### 嵌入 WorkflowTaskWidget
```tsx
import { WorkflowTaskWidget } from '@/components/dashboard/widgets/WorkflowTaskWidget'
function CustomDashboard() {
return (
<div className="p-6">
<WorkflowTaskWidget />
</div>
)
}
```
### 自定义最近会话小部件
```tsx
import { RecentSessionsWidget } from '@/components/dashboard/widgets/RecentSessionsWidget'
function ActivityFeed() {
return (
<div className="p-6">
<RecentSessionsWidget maxItems={10} />
</div>
)
}
```
---
## 状态管理
### 本地状态
| 状态 | 类型 | 描述 |
|------|------|------|
| `hasError` | `boolean` | 关键错误的错误跟踪 |
| `projectExpanded` | `boolean` | 项目信息横幅展开状态 |
| `currentSessionIndex` | `number` | 轮播中活动会话的索引 |
| `activeTab` | `'all' \| 'workflow' \| 'lite'` | 最近会话小部件筛选标签页 |
### Store 选择器Zustand
| Store | 选择器 | 用途 |
|-------|--------|------|
| `appStore` | `selectIsImmersiveMode` | 检查沉浸模式是否激活 |
### 自定义 Hooks数据获取
| Hook | 描述 | 重新获取间隔 |
|------|-------------|--------------|
| `useWorkflowStatusCounts` | 会话状态分布数据 | - |
| `useDashboardStats` | 带迷你趋势图的统计数据 | 60 秒 |
| `useProjectOverview` | 项目信息和技术栈 | - |
| `useIndexStatus` | 实时索引状态 | 30 秒 |
| `useSessions` | 活动会话数据 | - |
| `useLiteTasks` | 最近小部件的轻量任务数据 | - |
---
## 交互演示
### 统计卡片演示
:::demo MiniStatCards
# mini-stat-cards.tsx
/**
* 迷你统计卡片演示
* 带有迷你趋势图的独立统计卡片
*/
export function MiniStatCards() {
const stats = [
{ label: '活动会话', value: 12, trend: [8, 10, 9, 11, 10, 12, 12], color: 'blue' },
{ label: '总任务', value: 48, trend: [40, 42, 45, 44, 46, 47, 48], color: 'green' },
{ label: '已完成', value: 35, trend: [25, 28, 30, 32, 33, 34, 35], color: 'emerald' },
{ label: '待处理', value: 8, trend: [12, 10, 11, 9, 8, 7, 8], color: 'amber' },
{ label: '失败', value: 5, trend: [3, 4, 3, 5, 4, 5, 5], color: 'red' },
{ label: '今日活动', value: 23, trend: [5, 10, 15, 18, 20, 22, 23], color: 'purple' },
]
const colorMap = {
blue: 'text-blue-500 bg-blue-500/10',
green: 'text-green-500 bg-green-500/10',
emerald: 'text-emerald-500 bg-emerald-500/10',
amber: 'text-amber-500 bg-amber-500/10',
red: 'text-red-500 bg-red-500/10',
purple: 'text-purple-500 bg-purple-500/10',
}
return (
<div className="p-6 bg-background">
<h3 className="text-sm font-semibold mb-4">带迷你趋势图的统计</h3>
<div className="grid grid-cols-2 md:grid-cols-3 gap-4">
{stats.map((stat, i) => (
<div key={i} className="p-4 border rounded-lg bg-card">
<div className="flex items-center justify-between mb-2">
<span className="text-xs text-muted-foreground">{stat.label}</span>
<div className={`w-2 h-2 rounded-full ${colorMap[stat.color].split(' ')[1]}`}/>
</div>
<div className={`text-2xl font-bold ${colorMap[stat.color].split(' ')[0]}`}>{stat.value}</div>
<div className="mt-2 h-8 flex items-end gap-0.5">
{stat.trend.map((v, j) => (
<div
key={j}
className="flex-1 rounded-t"
style={{
height: `${(v / Math.max(...stat.trend)) * 100}%`,
backgroundColor: v === stat.value ? 'currentColor' : 'rgba(59, 130, 246, 0.3)',
}}
/>
))}
</div>
</div>
))}
</div>
</div>
)
}
:::
### 项目信息横幅演示
:::demo ProjectInfoBanner
# project-info-banner.tsx
/**
* 项目信息横幅演示
* 带有技术栈的可展开项目信息
*/
export function ProjectInfoBanner() {
const [expanded, setExpanded] = React.useState(false)
return (
<div className="p-6 bg-background">
<h3 className="text-sm font-semibold mb-4">项目信息横幅</h3>
<div className="border rounded-lg overflow-hidden">
{/* 横幅头部 */}
<div className="p-4 bg-muted/30 flex items-center justify-between">
<div>
<h4 className="font-semibold">我的项目</h4>
<p className="text-sm text-muted-foreground">使用 React 构建的现代化 Web 应用</p>
</div>
<button
onClick={() => setExpanded(!expanded)}
className="p-2 rounded-md hover:bg-accent"
>
<svg className={`w-5 h-5 transition-transform ${expanded ? 'rotate-180' : ''}`} fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</button>
</div>
{/* 技术栈徽章 */}
<div className="px-4 pb-3 flex flex-wrap gap-2">
{['TypeScript', 'React', 'Vite', 'Tailwind CSS', 'Zustand'].map((tech) => (
<span key={tech} className="px-2 py-1 text-xs rounded-full bg-primary/10 text-primary">
{tech}
</span>
))}
</div>
{/* 展开内容 */}
{expanded && (
<div className="p-4 border-t bg-muted/20 space-y-4">
<div>
<h5 className="text-xs font-semibold mb-2">架构</h5>
<div className="text-sm text-muted-foreground space-y-1">
<div>• 基于组件的 UI 架构</div>
<div>• 集中式状态管理</div>
<div>• RESTful API 集成</div>
</div>
</div>
<div>
<h5 className="text-xs font-semibold mb-2">关键组件</h5>
<div className="grid grid-cols-2 gap-2 text-sm">
{['会话管理器', '仪表板', '任务调度器', '分析'].map((comp) => (
<div key={comp} className="flex items-center gap-2">
<div className="w-1.5 h-1.5 rounded-full bg-primary"/>
{comp}
</div>
))}
</div>
</div>
</div>
)}
</div>
</div>
)
}
:::
### 会话轮播演示
:::demo SessionCarousel
# session-carousel.tsx
/**
* 会话轮播演示
* 带有导航的自动轮播会话卡片
*/
export function SessionCarousel() {
const [currentIndex, setCurrentIndex] = React.useState(0)
const sessions = [
{
name: '功能:用户身份验证',
status: 'running',
tasks: [
{ name: '实现登录表单', status: 'completed' },
{ name: '添加 OAuth 提供商', status: 'in-progress' },
{ name: '创建会话管理', status: 'pending' },
],
},
{
name: 'Bug 修复:内存泄漏',
status: 'running',
tasks: [
{ name: '识别泄漏源', status: 'completed' },
{ name: '修复清理处理器', status: 'in-progress' },
{ name: '添加单元测试', status: 'pending' },
],
},
{
name: '重构API 层',
status: 'planning',
tasks: [
{ name: '设计新接口', status: 'pending' },
{ name: '迁移现有端点', status: 'pending' },
{ name: '更新文档', status: 'pending' },
],
},
]
const statusColors = {
completed: 'bg-green-500',
'in-progress': 'bg-amber-500',
pending: 'bg-muted',
}
React.useEffect(() => {
const timer = setInterval(() => {
setCurrentIndex((i) => (i + 1) % sessions.length)
}, 5000)
return () => clearInterval(timer)
}, [sessions.length])
return (
<div className="p-6 bg-background">
<h3 className="text-sm font-semibold mb-4">会话轮播(每 5 秒自动轮播)</h3>
<div className="border rounded-lg p-4 bg-card">
<div className="flex items-center justify-between mb-3">
<span className="text-sm font-medium">会话 {currentIndex + 1} / {sessions.length}</span>
<div className="flex gap-1">
{sessions.map((_, i) => (
<button
key={i}
onClick={() => setCurrentIndex(i)}
className={`w-2 h-2 rounded-full transition-colors ${
i === currentIndex ? 'bg-primary' : 'bg-muted-foreground/30'
}`}
/>
))}
</div>
</div>
<div className="p-4 bg-accent/20 rounded border">
<div className="flex items-center justify-between mb-3">
<span className="font-medium">{sessions[currentIndex].name}</span>
<span className={`text-xs px-2 py-1 rounded-full ${
sessions[currentIndex].status === 'running' ? 'bg-green-500/20 text-green-600' : 'bg-blue-500/20 text-blue-600'
}`}>
{sessions[currentIndex].status === 'running' ? '运行中' : sessions[currentIndex].status === 'planning' ? '计划中' : sessions[currentIndex].status}
</span>
</div>
<div className="space-y-2">
{sessions[currentIndex].tasks.map((task, i) => (
<div key={i} className="flex items-center gap-2 text-sm">
<div className={`w-3 h-3 rounded ${statusColors[task.status]}`}/>
<span className={task.status === 'pending' ? 'text-muted-foreground' : ''}>{task.name}</span>
</div>
))}
</div>
</div>
<div className="flex justify-between mt-3">
<button
onClick={() => setCurrentIndex((i) => (i - 1 + sessions.length) % sessions.length)}
className="px-3 py-1.5 text-sm border rounded-md hover:bg-accent"
>
← 上一页
</button>
<button
onClick={() => setCurrentIndex((i) => (i + 1) % sessions.length)}
className="px-3 py-1.5 text-sm border rounded-md hover:bg-accent"
>
下一页 →
</button>
</div>
</div>
</div>
)
}
:::
---
## 可访问性
- **键盘导航**
- <kbd>Tab</kbd> - 在交互元素之间导航
- <kbd>Enter</kbd>/<kbd>Space</kbd> - 激活按钮和卡片
- <kbd>方向键</kbd> - 导航轮播会话
- **ARIA 属性**
- 导航按钮上的 `aria-label`
- 可展开部分的 `aria-expanded`
- 实时更新的 `aria-live` 区域
- **屏幕阅读器支持**
- 所有图表都有文字描述
- 状态指示器包含文字标签
- 导航被正确宣布
---
## 相关链接
- [会话](/features/sessions) - 查看和管理所有会话
- [终端仪表板](/features/terminal) - 终端优先监控界面
- [队列](/features/queue) - 问题执行队列管理
- [内存](/features/memory) - 持久化内存管理
- [设置](/features/settings) - 全局应用设置

View File

@@ -0,0 +1,283 @@
# 队列管理
## 一句话概述
**队列管理页面提供对问题执行队列的集中控制,配备调度器控件、状态监控和会话池管理。**
---
## 解决的痛点
| 痛点 | 当前状态 | 队列解决方案 |
|------|----------|--------------|
| **执行无序** | 没有统一的任务队列 | 带分组项目的集中化队列 |
| **调度器状态未知** | 不知道调度器是否在运行 | 实时状态指示器(空闲/运行/暂停) |
| **无执行控制** | 无法启动/停止队列处理 | 带确认的开始/暂停/停止控件 |
| **并发限制** | 同时运行太多会话 | 可配置的最大并发会话数 |
| **无可见性** | 不知道队列中有什么 | 统计卡片 + 带状态跟踪的项目列表 |
| **资源浪费** | 空闲会话消耗资源 | 带超时配置的会话池概览 |
---
## 概述
**位置**: `ccw/frontend/src/pages/QueuePage.tsx`(旧版),`ccw/frontend/src/components/terminal-dashboard/QueuePanel.tsx`(当前)
**用途**: 查看和管理问题执行队列,配备调度器控件、进度跟踪和会话池管理。
**访问方式**: 导航 → 问题 → 队列标签页 或 终端仪表板 → 队列浮动面板
**布局**:
```
+--------------------------------------------------------------------------+
| 队列面板标题栏 |
+--------------------------------------------------------------------------+
| 调度器状态栏 |
| +----------------+ +-------------+ +-------------------------------+ |
| | 状态徽章 | | 进度 | | 并发数 (2/2) | |
| +----------------+ +-------------+ +-------------------------------+ |
+--------------------------------------------------------------------------+
| 调度器控件 |
| +--------+ +--------+ +--------+ +-----------+ |
| | 开始 | | 暂停 | | 停止 | | 配置 | |
| +--------+ +--------+ +--------+ +-----------+ |
+--------------------------------------------------------------------------+
| 队列项目列表 |
| +---------------------------------------------------------------------+ |
| | QueueItemRow状态、issue_id、session_key、操作 | |
| | - 状态图标(待处理/执行中/已完成/被阻塞/失败) | |
| | - Issue ID / 项目 ID 显示 | |
| | - 会话绑定信息 | |
| | - 进度指示器(对于执行中的项目) | |
| +---------------------------------------------------------------------+ |
| | [更多队列项目...] | |
| +---------------------------------------------------------------------+ |
+--------------------------------------------------------------------------+
| 会话池概览(可选) |
| +--------------------------------------------------------------------------+
| | 活动会话 | 空闲会话 | 总会话数 |
| +--------------------------------------------------------------------------+
```
---
## 核心功能
| 功能 | 描述 |
|------|------|
| **调度器状态** | 实时状态指示器(空闲/运行/暂停),带视觉徽章 |
| **进度跟踪** | 显示队列总体完成百分比的进度条 |
| **开始/暂停/停止控件** | 控制队列执行,停止操作时带确认对话框 |
| **并发显示** | 显示当前活动会话数与最大并发会话数 |
| **队列项目列表** | 所有队列项目的可滚动列表附带状态、Issue ID 和会话绑定 |
| **状态图标** | 项目状态的视觉指示器(待处理/执行中/已完成/被阻塞/失败) |
| **会话池** | 活动会话、空闲会话和总会话数的概览 |
| **配置面板** | 调整最大并发会话数和超时设置 |
| **空状态** | 队列为空时的友好消息,附带添加项目的说明 |
---
## 组件层次结构
```
QueuePage旧版/ QueuePanel当前
├── QueuePanelHeader
│ ├── 标题
│ └── 标签切换器(队列 | 编排器)
├── SchedulerBar内联在 QueueListColumn 中)
│ ├── 状态徽章
│ ├── 进度 + 并发数
│ └── 控制按钮(播放/暂停/停止)
├── QueueItemsList
│ └── QueueItemRow重复
│ ├── 状态图标
│ ├── Issue ID / 项目 ID
│ ├── 会话绑定
│ └── 进度(对于执行中的项目)
└── SchedulerPanel独立
├── 状态部分
├── 进度条
├── 控制按钮
├── 配置部分
│ ├── 最大并发会话数
│ ├── 会话空闲超时
│ └── 恢复键绑定超时
└── 会话池概览
```
---
## Props API
### QueuePanel
| Prop | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| `embedded` | `boolean` | `false` | 面板是否嵌入在另一个组件中 |
### SchedulerPanel
| Prop | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| - | - | - | 此组件不接受任何 props所有数据来自 Zustand store |
### QueueListColumn
| Prop | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| - | - | - | 此组件不接受任何 props所有数据来自 Zustand store |
---
## 状态管理
### Zustand Stores
| Store | 选择器 | 用途 |
|-------|--------|------|
| `queueSchedulerStore` | `selectQueueSchedulerStatus` | 当前调度器状态(空闲/运行/暂停) |
| `queueSchedulerStore` | `selectSchedulerProgress` | 队列总体完成百分比 |
| `queueSchedulerStore` | `selectQueueItems` | 所有队列项目的列表 |
| `queueSchedulerStore` | `selectCurrentConcurrency` | 活动会话计数 |
| `queueSchedulerStore` | `selectSchedulerConfig` | 调度器配置 |
| `queueSchedulerStore` | `selectSessionPool` | 会话池概览 |
| `queueSchedulerStore` | `selectSchedulerError` | 错误消息(如果有) |
| `issueQueueIntegrationStore` | `selectAssociationChain` | 用于高亮显示的当前关联链 |
| `queueExecutionStore` | `selectByQueueItem` | 队列项目的执行数据 |
### 队列项目状态
```typescript
type QueueItemStatus =
| 'pending' // 等待执行
| 'executing' // 正在处理中
| 'completed' // 成功完成
| 'blocked' // 被依赖项阻塞
| 'failed'; // 失败并报错
```
### 调度器状态
```typescript
type QueueSchedulerStatus =
| 'idle' // 无项目或已停止
| 'running' // 活动处理项目
| 'paused'; // 临时暂停
```
---
## 使用示例
### 基本队列面板
```tsx
import { QueuePanel } from '@/components/terminal-dashboard/QueuePanel'
function QueueSection() {
return <QueuePanel />
}
```
### 独立调度器面板
```tsx
import { SchedulerPanel } from '@/components/terminal-dashboard/SchedulerPanel'
function SchedulerControls() {
return <SchedulerPanel />
}
```
### 嵌入式队列列表列
```tsx
import { QueueListColumn } from '@/components/terminal-dashboard/QueueListColumn'
function EmbeddedQueue() {
return <QueueListColumn />
}
```
### 队列 Store 操作
```tsx
import { useQueueSchedulerStore } from '@/stores/queueSchedulerStore'
function QueueActions() {
const startQueue = useQueueSchedulerStore((s) => s.startQueue)
const pauseQueue = useQueueSchedulerStore((s) => s.pauseQueue)
const stopQueue = useQueueSchedulerStore((s) => s.stopQueue)
const updateConfig = useQueueSchedulerStore((s) => s.updateConfig)
const handleStart = () => startQueue()
const handlePause = () => pauseQueue()
const handleStop = () => stopQueue()
const handleConfig = (config) => updateConfig(config)
return (
<div>
<button onClick={handleStart}></button>
<button onClick={handlePause}></button>
<button onClick={handleStop}></button>
<button onClick={() => handleConfig({ maxConcurrentSessions: 4 })}>
4
</button>
</div>
)
}
```
---
## 配置
### 调度器配置
| 设置 | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| `maxConcurrentSessions` | `number` | `2` | 同时运行的最大会话数 |
| `sessionIdleTimeoutMs` | `number` | `60000` | 空闲会话超时时间(毫秒) |
| `resumeKeySessionBindingTimeoutMs` | `number` | `300000` | 恢复键绑定超时时间(毫秒) |
### 队列项目结构
```typescript
interface QueueItem {
item_id: string;
issue_id?: string;
sessionKey?: string;
status: QueueItemStatus;
execution_order: number;
created_at?: number;
updated_at?: number;
}
```
---
## 可访问性
- **键盘导航**:
- <kbd>Tab</kbd> - 在队列项目和控件之间导航
- <kbd>Enter</kbd>/<kbd>Space</kbd> - 激活按钮
- <kbd>Escape</kbd> - 关闭对话框
- **ARIA 属性**:
- 控制按钮上的 `aria-label`
- 状态更新的 `aria-live` 区域
- 当前队列项目的 `aria-current`
- 队列项目列表上的 `role="list"`
- **屏幕阅读器支持**:
- 状态变化被宣布
- 进度更新被朗读
- 错误消息被宣布
---
## 相关链接
- [问题中心](/features/issue-hub) - 统一的问题、队列和发现管理
- [终端仪表板](/features/terminal) - 带集成队列面板的终端优先工作空间
- [发现](/features/discovery) - 发现会话跟踪
- [会话](/features/sessions) - 会话管理和详情

View File

@@ -0,0 +1,612 @@
# 终端仪表板
## 一句话概述
**终端仪表板提供以终端为首的工作空间,具有可调整大小的窗格、浮动面板和用于会话监控与编排的集成工具。**
---
## 解决的痛点
| 痛点 | 当前状态 | 终端仪表板解决方案 |
|------|----------|---------------------|
| **终端分散** | 多个终端窗口 | 统一的 tmux 风格网格布局 |
| **无上下文关联** | 无法将终端输出与问题关联 | 关联高亮提供程序 |
| **面板过多** | 固定布局浪费空间 | 浮动面板(互斥) |
| **缺少工具** | 在应用间切换 | 集成问题、队列、检查器、调度器 |
| **工作空间有限** | 无法同时查看代码和终端 | 可调整大小的三列布局 |
---
## 概述
**位置**: `ccw/frontend/src/pages/TerminalDashboardPage.tsx`
**用途**: 用于多终端会话管理的终端优先布局,配备集成工具和可调整大小的面板。
**访问方式**: 导航 → 终端仪表板 (`/terminal-dashboard`)
**布局**:
```
+--------------------------------------------------------------------------+
| 仪表板工具栏(面板切换、布局预设、全屏) |
+--------------------------------------------------------------------------+
| +----------------+-------------------------------------------+------------+ |
| | 会话 | 终端网格tmux 风格) | 文件 | |
| | 分组树 | +----------+ +----------+ | 侧边栏 | |
| | (可调整大小) | | 终端 1 | | 终端 2 | |(可调整大小)| |
| | | +----------+ +----------+ | | |
| | | +----------+ +----------+ | | |
| | | | 终端 3 | | 终端 4 | | | |
| | | +----------+ +----------+ | | |
| +----------------+-------------------------------------------+------------+ |
+--------------------------------------------------------------------------+
| [浮动面板: 问题+队列 或 检查器 或 执行 或 调度器] |
+--------------------------------------------------------------------------+
```
---
## 实时演示
:::demo TerminalDashboardOverview
# terminal-dashboard-overview.tsx
/**
* Terminal Dashboard Overview Demo
* Shows the three-column layout with resizable panes and toolbar
*/
export function TerminalDashboardOverview() {
const [fileSidebarOpen, setFileSidebarOpen] = React.useState(true)
const [sessionSidebarOpen, setSessionSidebarOpen] = React.useState(true)
const [activePanel, setActivePanel] = React.useState(null)
return (
<div className="h-[600px] flex flex-col bg-background">
{/* Toolbar */}
<div className="flex items-center justify-between px-3 py-2 border-b bg-muted/30">
<div className="flex items-center gap-2">
<span className="text-sm font-medium">Terminal Dashboard</span>
</div>
<div className="flex items-center gap-1">
{['Sessions', 'Files', 'Issues', 'Queue', 'Inspector', 'Scheduler'].map((item) => (
<button
key={item}
onClick={() => {
if (item === 'Sessions') setSessionSidebarOpen(!sessionSidebarOpen)
else if (item === 'Files') setFileSidebarOpen(!fileSidebarOpen)
else setActivePanel(activePanel === item.toLowerCase() ? null : item.toLowerCase())
}}
className={`px-2 py-1 text-xs rounded transition-colors ${
(item === 'Sessions' && sessionSidebarOpen) ||
(item === 'Files' && fileSidebarOpen) ||
activePanel === item.toLowerCase()
? 'bg-primary text-primary-foreground'
: 'hover:bg-accent'
}`}
>
{item}
</button>
))}
</div>
</div>
{/* Main Layout */}
<div className="flex-1 flex min-h-0">
{/* Session Sidebar */}
{sessionSidebarOpen && (
<div className="w-60 border-r flex flex-col">
<div className="px-3 py-2 text-xs font-semibold border-b bg-muted/30">
Session Groups
</div>
<div className="flex-1 p-2 space-y-1 text-sm overflow-auto">
{['Active Sessions', 'Completed', 'Archived'].map((group) => (
<div key={group}>
<div className="flex items-center gap-1 px-2 py-1 rounded hover:bg-accent cursor-pointer">
<span className="text-xs">▼</span>
<span>{group}</span>
</div>
<div className="ml-4 space-y-0.5">
<div className="px-2 py-1 text-xs text-muted-foreground hover:bg-accent rounded cursor-pointer">
Session 1
</div>
<div className="px-2 py-1 text-xs text-muted-foreground hover:bg-accent rounded cursor-pointer">
Session 2
</div>
</div>
</div>
))}
</div>
</div>
)}
{/* Terminal Grid */}
<div className="flex-1 bg-muted/20 p-2">
<div className="grid grid-cols-2 grid-rows-2 gap-2 h-full">
{[1, 2, 3, 4].map((i) => (
<div key={i} className="bg-background border rounded p-3 font-mono text-xs">
<div className="text-green-500 mb-2">$ Terminal {i}</div>
<div className="text-muted-foreground">
<div>Working directory: /project</div>
<div>Type a command to begin...</div>
</div>
</div>
))}
</div>
</div>
{/* File Sidebar */}
{fileSidebarOpen && (
<div className="w-64 border-l flex flex-col">
<div className="px-3 py-2 text-xs font-semibold border-b bg-muted/30">
Project Files
</div>
<div className="flex-1 p-2 text-sm overflow-auto">
<div className="space-y-1">
{['src', 'docs', 'tests', 'package.json', 'README.md'].map((item) => (
<div key={item} className="px-2 py-1 rounded hover:bg-accent cursor-pointer flex items-center gap-2">
<span className="text-xs text-muted-foreground">📁</span>
{item}
</div>
))}
</div>
</div>
</div>
)}
</div>
{/* Floating Panel */}
{activePanel && (
<div className="absolute top-12 right-4 w-80 bg-background border rounded-lg shadow-lg">
<div className="flex items-center justify-between px-3 py-2 border-b">
<span className="text-sm font-medium capitalize">{activePanel} Panel</span>
<button onClick={() => setActivePanel(null)} className="text-xs hover:bg-accent px-2 py-1 rounded">
</button>
</div>
<div className="p-4 text-sm text-muted-foreground">
{activePanel} content placeholder
</div>
</div>
)}
</div>
)
}
:::
---
## 核心功能
| 功能 | 描述 |
|------|------|
| **三列布局** | 使用 Allotment 的可调整大小窗格:会话树(左)、终端网格(中)、文件侧边栏(右) |
| **终端网格** | Tmux 风格的分割窗格带布局预设单格、水平分割、垂直分割、2x2 网格) |
| **会话分组树** | CLI 会话的分层视图,按标签分组 |
| **浮动面板** | 互斥的叠加面板(问题+队列、检查器、执行监控器、调度器) |
| **关联高亮** | 终端、问题和队列项之间的跨面板链接 |
| **布局预设** | 快速布局按钮单格窗格、水平分割、垂直分割、2x2 网格 |
| **启动 CLI** | 用于创建新 CLI 会话的配置模态框,可选择工具、模型和设置 |
| **全屏模式** | 沉浸模式隐藏应用框架(标题栏 + 侧边栏) |
| **功能标志** | 面板可见性由功能标志控制(队列、检查器、执行监控器) |
---
## 组件层次结构
```
TerminalDashboardPage
├── AssociationHighlightProvider上下文
├── DashboardToolbar
│ ├── 布局预设按钮(单格 | 水平分割 | 垂直分割 | 2x2 网格)
│ ├── 面板切换(会话 | 文件 | 问题 | 队列 | 检查器 | 执行 | 调度器)
│ ├── 全屏切换
│ └── 启动 CLI 按钮
├── Allotment三列布局
│ ├── SessionGroupTree
│ │ └── 会话分组项(可折叠)
│ ├── TerminalGrid
│ │ ├── GridGroupRenderer递归
│ │ └── TerminalPane
│ └── FileSidebarPanel
│ └── 文件树视图
└── FloatingPanel多个互斥
├── 问题+队列(分割面板)
│ ├── IssuePanel
│ └── QueueListColumn
├── QueuePanel功能标志
├── InspectorContent功能标志
├── ExecutionMonitorPanel功能标志
└── SchedulerPanel
```
---
## Props API
### TerminalDashboardPage
| Prop | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| - | - | - | 此页面组件不接受任何 props状态通过 hooks 和 Zustand stores 管理) |
### DashboardToolbar
| Prop | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| `activePanel` | `PanelId \| null` | `null` | 当前活动的浮动面板 |
| `onTogglePanel` | `(panelId: PanelId) => void` | - | 切换面板可见性的回调 |
| `isFileSidebarOpen` | `boolean` | `true` | 文件侧边栏可见性状态 |
| `onToggleFileSidebar` | `() => void` | - | 切换文件侧边栏回调 |
| `isSessionSidebarOpen` | `boolean` | `true` | 会话侧边栏可见性状态 |
| `onToggleSessionSidebar` | `() => void` | - | 切换会话侧边栏回调 |
| `isFullscreen` | `boolean` | `false` | 全屏模式状态 |
| `onToggleFullscreen` | `() => void` | - | 切换全屏回调 |
### FloatingPanel
| Prop | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| `isOpen` | `boolean` | `false` | 面板打开状态 |
| `onClose` | `() => void` | - | 关闭回调 |
| `title` | `string` | - | 面板标题 |
| `side` | `'left' \| 'right'` | `'left'` | 面板侧边 |
| `width` | `number` | `400` | 面板宽度(像素) |
| `children` | `ReactNode` | - | 面板内容 |
---
## 状态管理
### 本地状态
| 状态 | 类型 | 描述 |
|------|------|------|
| `activePanel` | `PanelId \| null` | 当前活动的浮动面板(互斥) |
| `isFileSidebarOpen` | `boolean` | 文件侧边栏可见性 |
| `isSessionSidebarOpen` | `boolean` | 会话侧边栏可见性 |
### Zustand Stores
| Store | 选择器 | 用途 |
|-------|--------|------|
| `workflowStore` | `selectProjectPath` | 文件侧边栏的当前项目路径 |
| `appStore` | `selectIsImmersiveMode` | 全屏模式状态 |
| `configStore` | `featureFlags` | 功能标志配置 |
| `terminalGridStore` | 网格布局和焦点窗格状态 |
| `executionMonitorStore` | 活动执行计数 |
| `queueSchedulerStore` | 调度器状态和设置 |
### 面板 ID 类型
```typescript
type PanelId = 'issues' | 'queue' | 'inspector' | 'execution' | 'scheduler';
```
---
## 使用示例
### 基本终端仪表板
```tsx
import { TerminalDashboardPage } from '@/pages/TerminalDashboardPage'
// 终端仪表板自动在 /terminal-dashboard 渲染
// 不需要 props - 布局状态内部管理
```
### 使用 FloatingPanel 组件
```tsx
import { FloatingPanel } from '@/components/terminal-dashboard/FloatingPanel'
import { IssuePanel } from '@/components/terminal-dashboard/IssuePanel'
function CustomLayout() {
const [isOpen, setIsOpen] = useState(false)
return (
<FloatingPanel
isOpen={isOpen}
onClose={() => setIsOpen(false)}
title="问题"
side="left"
width={700}
>
<IssuePanel />
</FloatingPanel>
)
}
```
---
## 交互演示
### 布局预设演示
:::demo TerminalLayoutPresets
# terminal-layout-presets.tsx
/**
* Terminal Layout Presets Demo
* Interactive layout preset buttons
*/
export function TerminalLayoutPresets() {
const [layout, setLayout] = React.useState('grid-2x2')
const layouts = {
single: 'grid-cols-1 grid-rows-1',
'split-h': 'grid-cols-2 grid-rows-1',
'split-v': 'grid-cols-1 grid-rows-2',
'grid-2x2': 'grid-cols-2 grid-rows-2',
}
return (
<div className="p-6 bg-background space-y-4">
<div className="flex items-center justify-between">
<h3 className="text-sm font-semibold">Terminal Layout Presets</h3>
<div className="flex gap-2">
{Object.keys(layouts).map((preset) => (
<button
key={preset}
onClick={() => setLayout(preset)}
className={`px-3 py-1.5 text-xs rounded transition-colors ${
layout === preset
? 'bg-primary text-primary-foreground'
: 'border hover:bg-accent'
}`}
>
{preset.replace('-', ' ').toUpperCase()}
</button>
))}
</div>
</div>
<div className={`grid gap-2 h-64 ${layouts[layout]}`}>
{Array.from({ length: layout === 'single' ? 1 : layout.includes('2x') ? 4 : 2 }).map((_, i) => (
<div key={i} className="bg-muted/20 border rounded p-4 font-mono text-xs">
<div className="text-green-500">$ Terminal {i + 1}</div>
<div className="text-muted-foreground mt-1">Ready for input...</div>
</div>
))}
</div>
</div>
)
}
:::
### 浮动面板演示
:::demo FloatingPanelsDemo
# floating-panels-demo.tsx
/**
* Floating Panels Demo
* Mutually exclusive overlay panels
*/
export function FloatingPanelsDemo() {
const [activePanel, setActivePanel] = React.useState(null)
const panels = [
{ id: 'issues', title: 'Issues + Queue', side: 'left', width: 700 },
{ id: 'queue', title: 'Queue', side: 'right', width: 400 },
{ id: 'inspector', title: 'Inspector', side: 'right', width: 360 },
{ id: 'execution', title: 'Execution Monitor', side: 'right', width: 380 },
{ id: 'scheduler', title: 'Scheduler', side: 'right', width: 340 },
]
return (
<div className="relative h-[500px] p-6 bg-background border rounded-lg">
<div className="flex items-center justify-between mb-4">
<h3 className="text-sm font-semibold">Floating Panels</h3>
<div className="flex gap-2">
{panels.map((panel) => (
<button
key={panel.id}
onClick={() => setActivePanel(activePanel === panel.id ? null : panel.id)}
className={`px-3 py-1.5 text-xs rounded transition-colors ${
activePanel === panel.id
? 'bg-primary text-primary-foreground'
: 'border hover:bg-accent'
}`}
>
{panel.title}
</button>
))}
</div>
</div>
<div className="h-[380px] bg-muted/20 border rounded flex items-center justify-center">
<p className="text-sm text-muted-foreground">
{activePanel ? `"${panels.find((p) => p.id === activePanel)?.title}" panel is open` : 'Click a button to open a floating panel'}
</p>
</div>
{/* Floating Panel Overlay */}
{activePanel && (
<div
className={`absolute top-16 border rounded-lg shadow-lg bg-background ${
panels.find((p) => p.id === activePanel)?.side === 'left' ? 'left-6' : 'right-6'
}`}
style={{ width: panels.find((p) => p.id === activePanel)?.width }}
>
<div className="flex items-center justify-between px-3 py-2 border-b">
<span className="text-sm font-medium">{panels.find((p) => p.id === activePanel)?.title}</span>
<button
onClick={() => setActivePanel(null)}
className="text-xs hover:bg-accent px-2 py-1 rounded"
>
</button>
</div>
<div className="p-4 text-sm text-muted-foreground">
<div className="space-y-2">
<div className="flex items-center gap-2">
<div className="w-2 h-2 rounded-full bg-blue-500"/>
<span>Item 1</span>
</div>
<div className="flex items-center gap-2">
<div className="w-2 h-2 rounded-full bg-green-500"/>
<span>Item 2</span>
</div>
<div className="flex items-center gap-2">
<div className="w-2 h-2 rounded-full bg-amber-500"/>
<span>Item 3</span>
</div>
</div>
</div>
</div>
)}
</div>
)
}
:::
### 可调整大小窗格演示
:::demo ResizablePanesDemo
# resizable-panes-demo.tsx
/**
* Resizable Panes Demo
* Simulates the Allotment resizable split behavior
*/
export function ResizablePanesDemo() {
const [leftWidth, setLeftWidth] = React.useState(240)
const [rightWidth, setRightWidth] = React.useState(280)
const [isDragging, setIsDragging] = React.useState(null)
const handleDragStart = (side) => (e) => {
setIsDragging(side)
e.preventDefault()
}
React.useEffect(() => {
const handleMouseMove = (e) => {
if (isDragging === 'left') {
setLeftWidth(Math.max(180, Math.min(320, e.clientX)))
} else if (isDragging === 'right') {
setRightWidth(Math.max(200, Math.min(400, window.innerWidth - e.clientX)))
}
}
const handleMouseUp = () => setIsDragging(null)
if (isDragging) {
window.addEventListener('mousemove', handleMouseMove)
window.addEventListener('mouseup', handleMouseUp)
return () => {
window.removeEventListener('mousemove', handleMouseMove)
window.removeEventListener('mouseup', handleMouseUp)
}
}
}, [isDragging])
return (
<div className="h-[400px] flex bg-background border rounded-lg overflow-hidden">
{/* Left Sidebar */}
<div style={{ width: leftWidth }} className="border-r flex flex-col">
<div className="px-3 py-2 text-xs font-semibold border-b bg-muted/30">
Session Groups
</div>
<div className="flex-1 p-2 text-sm space-y-1">
{['Active Sessions', 'Completed'].map((g) => (
<div key={g} className="px-2 py-1 hover:bg-accent rounded cursor-pointer">{g}</div>
))}
</div>
</div>
{/* Left Drag Handle */}
<div
onMouseDown={handleDragStart('left')}
className={`w-1 bg-border hover:bg-primary cursor-col-resize transition-colors ${
isDragging === 'left' ? 'bg-primary' : ''
}`}
/>
{/* Main Content */}
<div className="flex-1 bg-muted/20 flex items-center justify-center">
<span className="text-sm text-muted-foreground">Terminal Grid Area</span>
</div>
{/* Right Drag Handle */}
<div
onMouseDown={handleDragStart('right')}
className={`w-1 bg-border hover:bg-primary cursor-col-resize transition-colors ${
isDragging === 'right' ? 'bg-primary' : ''
}`}
/>
{/* Right Sidebar */}
<div style={{ width: rightWidth }} className="border-l flex flex-col">
<div className="px-3 py-2 text-xs font-semibold border-b bg-muted/30">
Project Files
</div>
<div className="flex-1 p-2 text-sm space-y-1">
{['src/', 'docs/', 'tests/'].map((f) => (
<div key={f} className="px-2 py-1 hover:bg-accent rounded cursor-pointer">{f}</div>
))}
</div>
</div>
</div>
)
}
:::
---
## 配置
### 功能标志
| 标志 | 控制 |
|------|------|
| `dashboardQueuePanelEnabled` | 队列面板可见性 |
| `dashboardInspectorEnabled` | 检查器面板可见性 |
| `dashboardExecutionMonitorEnabled` | 执行监控器面板可见性 |
### 布局预设
| 预设 | 布局 |
|------|------|
| **单格** | 一个终端窗格 |
| **水平分割** | 两个窗格并排 |
| **垂直分割** | 两个窗格垂直堆叠 |
| **2x2 网格** | 2x2 网格中的四个窗格 |
### 面板类型
| 面板 | 内容 | 位置 | 功能标志 |
|------|------|------|----------|
| **问题+队列** | 组合的问题面板 + 队列列表列 | 左侧(叠加) | - |
| **队列** | 完整的队列管理面板 | 右侧(叠加) | `dashboardQueuePanelEnabled` |
| **检查器** | 关联链检查器 | 右侧(叠加) | `dashboardInspectorEnabled` |
| **执行监控器** | 实时执行跟踪 | 右侧(叠加) | `dashboardExecutionMonitorEnabled` |
| **调度器** | 队列调度器控制 | 右侧(叠加) | - |
---
## 可访问性
- **键盘导航**:
- <kbd>Tab</kbd> - 在工具栏按钮之间导航
- <kbd>Enter</kbd>/<kbd>Space</kbd> - 激活工具栏按钮
- <kbd>Escape</kbd> - 关闭浮动面板
- <kbd>F11</kbd> - 切换全屏模式
- **ARIA 属性**:
- 工具栏按钮上的 `aria-label`
- 侧边栏切换上的 `aria-expanded`
- 非活动浮动面板上的 `aria-hidden`
- 浮动面板上的 `role="dialog"`
- **屏幕阅读器支持**:
- 切换面板时宣布面板状态
- 布局更改被宣布
- 面板打开/关闭时的焦点管理
---
## 相关链接
- [编排器](/features/orchestrator) - 可视化工作流编辑器
- [会话](/features/sessions) - 会话管理
- [问题中心](/features/issue-hub) - 问题、队列、发现
- [资源管理器](/features/explorer) - 文件资源管理器
- [队列](/features/queue) - 队列管理独立页面

53
docs/zh-CN/index.md Normal file
View File

@@ -0,0 +1,53 @@
---
layout: home
title: Claude Code Workflow
titleTemplate: Claude Code Workflow 文档
hero:
name: Claude Code Workflow
text: 高级 AI 驱动开发环境
tagline: 提升您的编码工作流程,实现智能化开发
image:
src: /logo.svg
alt: Claude Code Workflow
actions:
- theme: brand
text: 快速开始
link: /zh-CN/guide/ch01-what-is-claude-dms3
- theme: alt
text: 查看功能
link: /zh-CN/features/spec
features:
- title: 🤖 智能编排
details: Claude AI 驱动的任务编排,自动拆解复杂项目为可执行的步骤。
- title: ⚡ 内置技能
details: 27+ 个内置技能,涵盖代码审查、测试、重构等常见开发场景。
- title: 🔄 工作流系统
details: 四级工作流体系,从基础任务到复杂代理团队,灵活适应各种需求。
- title: 💾 持久化记忆
details: 跨会话的知识积累和上下文管理,让 AI 学习您的编码偏好。
- title: 🎨 可视化界面
details: 丰富的 Web 界面,包括仪表板、终端监控、问题追踪等实用工具。
- title: 🔌 MCP 集成
details: 支持 Model Context Protocol轻松扩展 AI 能力和工具集。
---
## 什么是 Claude Code Workflow
Claude Code Workflow (CCW) 是一个基于 Claude AI 的智能开发环境,通过工作流编排、代理协作和持久化记忆,帮助开发者更高效地完成编码任务。
### 核心特性
- **智能任务拆解**: 将复杂需求自动分解为可执行的子任务
- **代理协作系统**: 多个专业代理协同工作,覆盖代码、测试、文档等各个环节
- **上下文记忆**: 跨会话保持项目知识和编码决策
- **实时监控**: 终端流监控、问题追踪等可视化工具
- **CLI 工具集成**: 灵活的命令行工具,支持多种 AI 模型
## 快速链接
- [安装指南](/zh-CN/guide/installation)
- [第一个工作流](/zh-CN/guide/first-workflow)
- [核心功能](/zh-CN/features/spec)
- [组件文档](/zh-CN/components/)