Files
TrueGrowth/docs/MANUAL_TEST_ANALYSIS.md

671 lines
23 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.
# Opentu Manual 测试覆盖度分析与扩展计划
> 生成时间2026-01-27
> 分析范围:整个项目的 Manual 测试覆盖度
> 重点模块AI 输入栏(底部对话模块)及其配套功能
---
## 📊 目前已完成的测试覆盖
### ✅ 已测试模块100% 完成)
| 模块 | 静态截图 | 动态 GIF | 测试代码 | 状态 |
|------|---------|---------|---------|------|
| **工具箱操作** | ✅ | ✅ | ✅ | 🎉 完成 |
| **素材库管理** | ✅ | ✅ | ✅ | 🎉 完成 |
| **项目管理** | ✅ | ✅ | ✅ | 🎉 完成 |
| **备份/恢复** | ✅ | ✅ | ✅ | 🎉 完成 |
### ⚠️ 部分完成的测试代码已有GIF 未生成)
| 模块 | 静态截图 | 动态 GIF | 测试代码 | GIF 生成 | 状态 |
|------|---------|---------|---------|---------|------|
| **思维导图** | ⚠️ | ✅ | ✅ | ⏳ | 67% |
| **画笔绘制** | ✅ | ✅ | ✅ | ⏳ | 67% |
| **AI 图片生成** | ✅ | ✅ | ✅ | ⏳ | 67% |
| **画布导航** | ✅ | ✅ | ✅ | ⏳ | 67% |
| **形状工具** | ✅ | ✅ | ✅ | ⏳ | 67% |
---
## 🚨 **缺失的核心测试AI 输入栏模块**
### 🎯 模块概述
**AI 输入栏**AIInputBar是 Opentu 最核心的交互组件,位于画布底部中央,类似 Google Mixboard 的交互模式。它是用户与 AI 功能交互的主入口。
**相关文件**
```
packages/drawnix/src/components/ai-input-bar/
├── AIInputBar.tsx (主组件1872 行)
├── ModelDropdown.tsx (模型选择器)
├── ParametersDropdown.tsx (参数配置器)
├── GenerationTypeDropdown.tsx (生成类型选择)
├── CountDropdown.tsx (数量选择)
├── PromptHistoryPopover.tsx (历史提示词)
├── PromptSuggestionPanel.tsx (智能提示面板)
├── SizeDropdown.tsx (尺寸选择)
├── KeyboardDropdown.tsx (键盘导航)
└── ModelSelector.tsx (模型选择器)
```
---
## 🔍 AI 输入栏功能详细分解
### 1⃣ **核心功能组(基础交互)**
#### 📋 功能清单
| 功能点 | 优先级 | 测试难度 | 预计时长 | 依赖 API |
|--------|--------|---------|---------|---------|
| **输入框聚焦/失焦** | P0 | 简单 | 5 秒 | ❌ |
| **文本输入** | P0 | 简单 | 10 秒 | ❌ |
| **输入框展开/收缩** | P0 | 简单 | 8 秒 | ❌ |
| **发送按钮交互** | P0 | 简单 | 5 秒 | ❌ |
| **清空输入** | P1 | 简单 | 3 秒 | ❌ |
#### 🎬 测试思路
```typescript
test('AI 输入栏基础交互演示', async ({ page }) => {
// 1. 等待页面加载
await page.goto('http://localhost:7200/');
await page.waitForTimeout(1500);
// 2. 显示提示:找到 AI 输入栏
await showKeyHint(page, '底部 AI 输入栏', 1500);
const aiInputBar = page.getByTestId('ai-input-bar');
// 3. 点击输入框聚焦
await clickWithEffect(page, aiInputBar.locator('input'), '点击输入框', 1000);
// 4. 输入文本
await showKeyHint(page, '输入提示词', 1000);
await page.keyboard.type('一只可爱的猫咪', { delay: 100 });
await page.waitForTimeout(1000);
// 5. 展示输入框展开效果
await showKeyHint(page, '输入框自动展开', 1500);
// 6. 清空输入Ctrl+A + Backspace
await showKeyHint(page, '清空输入', 1000);
await page.keyboard.press('Control+A');
await page.keyboard.press('Backspace');
await page.waitForTimeout(1000);
// 7. 失焦收缩
await page.keyboard.press('Escape');
await showKeyHint(page, '输入框收缩', 1500);
});
```
---
### 2⃣ **模型选择组(关键配置)**
#### 📋 功能清单
| 功能点 | 优先级 | 测试难度 | 预计时长 | 子功能 |
|--------|--------|---------|---------|--------|
| **模型下拉菜单** | P0 | 中等 | 15 秒 | 展开、搜索、选择 |
| **模型健康状态** | P1 | 简单 | 5 秒 | 显示模型可用性 |
| **模型快捷代码** | P2 | 简单 | 5 秒 | `#imagen3` 显示 |
| **模型分类筛选** | P1 | 中等 | 10 秒 | 图片/视频/Agent |
#### 🎬 测试思路
```typescript
test('模型选择器演示', async ({ page }) => {
await page.goto('http://localhost:7200/');
const aiInputBar = page.getByTestId('ai-input-bar');
// 1. 打开模型下拉菜单
await showKeyHint(page, '选择生成模型', 1500);
const modelDropdown = aiInputBar.locator('.model-dropdown__trigger');
await clickWithEffect(page, modelDropdown, '打开模型列表', 1500);
// 2. 展示模型列表(滚动浏览)
await showKeyHint(page, '浏览可用模型', 1500);
const modelList = page.locator('.model-dropdown__menu');
await modelList.evaluate(el => {
el.scrollBy({ top: 100, behavior: 'smooth' });
});
await page.waitForTimeout(1000);
// 3. 健康状态展示
await showKeyHint(page, '模型健康状态', 1500);
// 4. 选择模型
const imagen3 = page.locator('.model-dropdown__item').filter({ hasText: 'imagen3' });
await clickWithEffect(page, imagen3, '选择 Imagen 3', 1500);
// 5. 显示快捷代码
await showKeyHint(page, '模型快捷代码 #imagen3', 1500);
});
```
---
### 3⃣ **参数配置组(高级功能)**
#### 📋 功能清单
| 功能点 | 优先级 | 测试难度 | 预计时长 | 配置项 |
|--------|--------|---------|---------|--------|
| **参数下拉菜单** | P0 | 中等 | 15 秒 | 展开、平铺展示 |
| **尺寸选择** | P0 | 简单 | 8 秒 | 1:1, 16:9, 4:3 等 |
| **数量选择** | P0 | 简单 | 8 秒 | 1-20 张 |
| **生成类型** | P0 | 简单 | 8 秒 | 图片/视频/Agent |
| **键盘导航** | P2 | 复杂 | 10 秒 | 上下左右键 |
#### 🎬 测试思路
```typescript
test('参数配置演示', async ({ page }) => {
await page.goto('http://localhost:7200/');
const aiInputBar = page.getByTestId('ai-input-bar');
// 1. 打开参数配置
await showKeyHint(page, '配置生成参数', 1500);
const paramsBtn = aiInputBar.locator('.parameters-dropdown__trigger');
await clickWithEffect(page, paramsBtn, '打开参数配置', 1500);
// 2. 展示参数分组(平铺显示)
await showKeyHint(page, '所有参数平铺展示', 1500);
const paramsPanel = page.locator('.parameters-dropdown__menu');
// 3. 选择尺寸
await showKeyHint(page, '选择图片尺寸', 1000);
const size16_9 = paramsPanel.locator('[data-param-value="16:9"]');
await clickWithEffect(page, size16_9, '选择 16:9', 1000);
// 4. 选择数量
await showKeyHint(page, '选择生成数量', 1000);
const count4 = paramsPanel.locator('[data-param-value="4"]');
await clickWithEffect(page, count4, '选择 4 张', 1000);
// 5. 关闭参数面板
await page.keyboard.press('Escape');
await showKeyHint(page, '配置已保存', 1500);
});
```
---
### 4⃣ **内容选择组(多模态输入)**
#### 📋 功能清单
| 功能点 | 优先级 | 测试难度 | 预计时长 | 子功能 |
|--------|--------|---------|---------|--------|
| **上传图片** | P0 | 中等 | 10 秒 | 文件选择、预览 |
| **从素材库选择** | P0 | 中等 | 12 秒 | 打开模态框、选择 |
| **画布元素选择** | P0 | 复杂 | 15 秒 | 自动捕获选中内容 |
| **已选内容预览** | P0 | 简单 | 8 秒 | 缩略图展示 |
| **移除选中内容** | P1 | 简单 | 5 秒 | 点击 X 移除 |
#### 🎬 测试思路
```typescript
test('多模态内容选择演示', async ({ page }) => {
await page.goto('http://localhost:7200/');
const aiInputBar = page.getByTestId('ai-input-bar');
// 1. 上传图片(模拟)
await showKeyHint(page, '上传参考图片', 1500);
const uploadBtn = aiInputBar.locator('.ai-input-bar__upload-btn');
await clickWithEffect(page, uploadBtn, '上传图片', 1000);
// 注意:实际文件上传需要特殊处理
await showKeyHint(page, '(演示:文件选择器)', 1500);
// 2. 从素材库选择
await showKeyHint(page, '从素材库选择', 1500);
const libraryBtn = aiInputBar.locator('.ai-input-bar__library-btn');
await clickWithEffect(page, libraryBtn, '打开素材库', 1500);
// 假设素材库已打开
const firstAsset = page.getByTestId('media-library-grid')
.locator('.asset-item').first();
if (await firstAsset.isVisible()) {
await clickWithEffect(page, firstAsset, '选择素材', 1000);
const confirmBtn = page.getByRole('button', { name: '确认' });
await clickWithEffect(page, confirmBtn, '确认', 1000);
}
// 3. 展示已选内容预览
await showKeyHint(page, '已选内容预览', 1500);
const preview = aiInputBar.locator('.selected-content-preview');
// 4. 移除内容
const removeBtn = preview.locator('.remove-btn').first();
if (await removeBtn.isVisible()) {
await clickWithEffect(page, removeBtn, '移除', 1000);
}
});
```
---
### 5⃣ **智能提示组(体验优化)**
#### 📋 功能清单
| 功能点 | 优先级 | 测试难度 | 预计时长 | 特性 |
|--------|--------|---------|---------|------|
| **历史提示词** | P1 | 中等 | 12 秒 | 悬浮展示、选择 |
| **预设提示词** | P1 | 简单 | 10 秒 | 分类展示 |
| **置顶提示词** | P2 | 简单 | 5 秒 | Pin 功能 |
| **删除历史** | P2 | 简单 | 5 秒 | 删除操作 |
| **灵感面板** | P1 | 中等 | 15 秒 | 空画布时显示 |
#### 🎬 测试思路
```typescript
test('智能提示面板演示', async ({ page }) => {
await page.goto('http://localhost:7200/');
const aiInputBar = page.getByTestId('ai-input-bar');
// 1. 显示灵感面板(空画布)
await showKeyHint(page, '灵感提示面板', 1500);
const inspirationBoard = page.locator('.inspiration-board');
if (await inspirationBoard.isVisible()) {
await showKeyHint(page, '选择预设提示词', 1500);
const card = inspirationBoard.locator('.inspiration-card').first();
await clickWithEffect(page, card, '选择灵感', 1500);
}
// 2. 打开历史提示词
await showKeyHint(page, '查看历史提示词', 1500);
const historyBtn = aiInputBar.locator('.prompt-history-popover__trigger');
await page.hover(historyBtn.locator('button'));
await page.waitForTimeout(800); // 悬浮延迟
// 3. 展示历史列表
await showKeyHint(page, '历史记录与预设', 1500);
const historyPanel = page.locator('.prompt-list-panel');
// 4. 置顶操作
const pinBtn = historyPanel.locator('.pin-btn').first();
if (await pinBtn.isVisible()) {
await clickWithEffect(page, pinBtn, '置顶', 1000);
}
// 5. 选择提示词
const promptItem = historyPanel.locator('.prompt-item').first();
await clickWithEffect(page, promptItem, '使用提示词', 1000);
});
```
---
### 6⃣ **工作流集成组(高级场景)**
#### 📋 功能清单
| 功能点 | 优先级 | 测试难度 | 预计时长 | 说明 |
|--------|--------|---------|---------|------|
| **发送后打开 ChatDrawer** | P0 | 中等 | 10 秒 | 自动打开对话抽屉 |
| **Agent 模式** | P1 | 复杂 | 20 秒 | AI 自动选择工具 |
| **工作流显示** | P1 | 中等 | 15 秒 | 显示执行步骤 |
| **任务状态同步** | P1 | 复杂 | 15 秒 | 实时更新状态 |
| **错误处理** | P2 | 中等 | 10 秒 | API 失败提示 |
#### 🎬 测试思路
```typescript
test('AI 工作流完整演示', async ({ page }) => {
await page.goto('http://localhost:7200/');
const aiInputBar = page.getByTestId('ai-input-bar');
// 1. 输入提示词
await showKeyHint(page, '输入生成请求', 1500);
await clickWithEffect(page, aiInputBar.locator('input'), '输入', 1000);
await page.keyboard.type('生成一只猫咪', { delay: 100 });
// 2. 配置参数(快速)
await showKeyHint(page, '配置生成参数', 1000);
// ... 选择模型、尺寸等
// 3. 发送请求
await showKeyHint(page, '发送生成请求', 1500);
const sendBtn = aiInputBar.locator('.ai-input-bar__send-btn');
await clickWithEffect(page, sendBtn, '发送', 1500);
// 4. 自动打开 ChatDrawer
await showKeyHint(page, '对话抽屉自动打开', 1500);
const chatDrawer = page.getByTestId('chat-drawer');
await page.waitForSelector('[data-testid="chat-drawer"]', {
state: 'visible',
timeout: 3000
});
// 5. 展示工作流执行
await showKeyHint(page, '工作流执行中', 2000);
// 注意:实际 AI 生成会很慢,测试中可能需要 mock
// 6. 关闭抽屉
await page.keyboard.press('Escape');
await showKeyHint(page, '关闭对话抽屉', 1000);
});
```
---
## 🎯 ChatDrawer对话抽屉功能分解
### 1⃣ **基础交互**
| 功能点 | 优先级 | 测试难度 | 预计时长 |
|--------|--------|---------|---------|
| **打开/关闭抽屉** | P0 | 简单 | 8 秒 |
| **拖动调整宽度** | P1 | 中等 | 10 秒 |
| **会话列表** | P0 | 中等 | 15 秒 |
| **新建会话** | P0 | 简单 | 5 秒 |
| **切换会话** | P0 | 简单 | 8 秒 |
| **删除会话** | P1 | 简单 | 5 秒 |
### 2⃣ **消息交互**
| 功能点 | 优先级 | 测试难度 | 预计时长 |
|--------|--------|---------|---------|
| **显示用户消息** | P0 | 简单 | 5 秒 |
| **显示 AI 响应** | P0 | 中等 | 10 秒 |
| **工作流消息** | P1 | 复杂 | 20 秒 |
| **重试失败任务** | P1 | 中等 | 12 秒 |
| **插入到画布** | P0 | 中等 | 10 秒 |
| **下载结果** | P1 | 简单 | 5 秒 |
### 3⃣ **高级功能**
| 功能点 | 优先级 | 测试难度 | 预计时长 |
|--------|--------|---------|---------|
| **模型切换** | P1 | 简单 | 8 秒 |
| **Mermaid 渲染** | P2 | 中等 | 10 秒 |
| **代理日志** | P2 | 中等 | 10 秒 |
| **会话搜索** | P2 | 中等 | 10 秒 |
---
## 📈 测试优先级矩阵
### 🔥 P0 级(必须测试,核心功能)
```
优先执行顺序:
1. AI 输入栏基础交互 ⏱️ 8 秒
2. 模型选择器 ⏱️ 15 秒
3. 参数配置 ⏱️ 15 秒
4. 多模态内容选择 ⏱️ 12 秒
5. 发送 + ChatDrawer 打开 ⏱️ 10 秒
6. ChatDrawer 基础交互 ⏱️ 15 秒
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
总计时长:~75 秒1 分 15 秒)
```
### ⚡ P1 级(重要功能,增强体验)
```
1. 智能提示面板 ⏱️ 15 秒
2. 工作流完整演示 ⏱️ 20 秒
3. 会话管理 ⏱️ 15 秒
4. ChatDrawer 拖动调整 ⏱️ 10 秒
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
总计时长:~60 秒1 分钟)
```
### 🎨 P2 级(锦上添花,可选)
```
1. 键盘快捷键导航 ⏱️ 10 秒
2. 历史提示词置顶/删除 ⏱️ 8 秒
3. Mermaid 流程图渲染 ⏱️ 10 秒
4. 代理日志查看 ⏱️ 10 秒
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
总计时长:~38 秒
```
---
## 🎬 推荐测试计划
### 📅 阶段 1核心功能覆盖Week 1
#### Day 1-2: AI 输入栏基础
```
✅ test('AI 输入栏基础交互演示') - 8 秒
✅ test('模型选择器演示') - 15 秒
✅ test('参数配置演示') - 15 秒
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
合计 GIF: ~38 秒
```
#### Day 3-4: 内容选择与工作流
```
✅ test('多模态内容选择演示') - 12 秒
✅ test('AI 工作流完整演示') - 20 秒
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
合计 GIF: ~32 秒
```
#### Day 5: ChatDrawer 基础
```
✅ test('ChatDrawer 基础交互演示') - 15 秒
✅ test('会话管理演示') - 15 秒
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
合计 GIF: ~30 秒
```
### 📅 阶段 2体验优化Week 2
#### Day 1-2: 智能提示
```
✅ test('智能提示面板演示') - 15 秒
✅ test('灵感面板演示') - 12 秒
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
合计 GIF: ~27 秒
```
#### Day 3-4: 高级功能
```
✅ test('ChatDrawer 高级功能演示') - 20 秒
✅ test('工作流重试与插入演示') - 15 秒
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
合计 GIF: ~35 秒
```
---
## 🛠️ 技术实现建议
### 1. Mock API 响应
由于 AI 生成需要较长时间10-60 秒),测试中建议 mock
```typescript
// 在测试开始前注入 mock
await page.route('**/api/generation/**', route => {
route.fulfill({
status: 200,
body: JSON.stringify({
id: 'mock-task-id',
status: 'completed',
result_url: 'https://example.com/mock-image.png',
}),
});
});
```
### 2. Service Worker 通信
AI 输入栏通过 Service Worker 处理任务,测试时需要:
```typescript
// 等待 SW 就绪
await page.waitForFunction(() => {
return navigator.serviceWorker.controller !== null;
});
// 监听 SW 消息
await page.evaluate(() => {
window.__swMessages = [];
navigator.serviceWorker.addEventListener('message', (event) => {
window.__swMessages.push(event.data);
});
});
```
### 3. 文件上传测试
对于图片上传功能:
```typescript
// 方式 1: 使用测试图片文件
await page.setInputFiles(
'input[type="file"]',
'apps/web-e2e/fixtures/test-image.png'
);
// 方式 2: 创建临时 Blob仅演示界面
await page.evaluate(() => {
const input = document.querySelector('input[type="file"]');
const dataTransfer = new DataTransfer();
const file = new File(['mock'], 'test.png', { type: 'image/png' });
dataTransfer.items.add(file);
input.files = dataTransfer.files;
input.dispatchEvent(new Event('change', { bubbles: true }));
});
```
---
## 📊 最终测试覆盖度预期
### 完成阶段 1 后
```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
静态截图: ████████████████████████████████ 100% (21/21)
动态 GIF: ████████████████████████████░░░░ 80% (15/19)
测试代码: ████████████████████████████░░░░ 80% (13/16)
已生成 GIF: ██████████████░░░░░░░░░░░░░░░░░░ 50% (10/19)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
总进度: ███████████████████████████████░ 90%
```
### 完成阶段 2 后
```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
静态截图: ████████████████████████████████ 100% (21/21)
动态 GIF: ████████████████████████████████ 100% (19/19)
测试代码: ████████████████████████████████ 100% (16/16)
已生成 GIF: ████████████████████████████████ 100% (19/19)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
总进度: ████████████████████████████████ 100%
🎊 完整测试体系达成!
```
---
## 📦 其他需要补充的测试模块
### 🎨 绘图工具详细测试
| 模块 | 当前状态 | 缺失测试 |
|------|---------|---------|
| **铅笔工具** | 有基础 GIF | 压感、橡皮擦、设置面板 |
| **形状工具** | 有基础 GIF | 圆角调整、布尔运算、组合 |
| **文本工具** | ❌ | 字体、大小、颜色、对齐 |
| **渐变编辑器** | ❌ | 多色渐变、角度调整 |
### 🖼️ 画布操作测试
| 模块 | 当前状态 | 缺失测试 |
|------|---------|---------|
| **缩放平移** | 有基础 GIF | 快捷键、手势、小地图 |
| **多选操作** | ❌ | 框选、Shift 多选、群组 |
| **图层管理** | ❌ | 上移、下移、置顶、置底 |
| **对齐分布** | ❌ | 左对齐、居中、等间距 |
### 🔧 工具箱详细测试
| 模块 | 当前状态 | 缺失测试 |
|------|---------|---------|
| **工具列表** | ✅ 完成 | - |
| **工具窗口** | ✅ 完成 | - |
| **自定义工具** | ❌ | 添加、配置、删除 |
| **工具设置** | ❌ | iframe 配置、权限设置 |
### 📚 其他功能模块
| 模块 | 优先级 | 预计时长 |
|------|--------|---------|
| **应用设置** | P1 | 15 秒 |
| **语言切换** | P2 | 5 秒 |
| **快捷键面板** | P2 | 10 秒 |
| **版本更新提示** | P2 | 5 秒 |
| **性能面板** | P2 | 8 秒 |
| **小地图** | P1 | 10 秒 |
| **导出功能** | P1 | 12 秒 |
---
## 🎯 总结与建议
### ✅ 已完成的优势
1.**核心项目管理功能**:工具箱、素材库、项目管理、备份恢复全覆盖
2.**测试框架完善**DSL 配置 + 手动录制双轨系统
3.**视觉效果统一**:品牌色、动画、标注完全一致
4.**代码质量高**:清晰注释、容错处理、可维护性强
### 🚨 最大缺口AI 交互模块
**AI 输入栏 + ChatDrawer** 是 Opentu 的核心竞争力,但目前 **0% 测试覆盖**
**重要性评分**:⭐⭐⭐⭐⭐ (5/5)
**紧急程度**:🔥🔥🔥🔥🔥 (5/5)
**用户影响**:🎯🎯🎯🎯🎯 (5/5)
### 📋 行动建议
#### 短期(本周)
1. ✅ 完成 AI 输入栏基础交互测试3 个 GIF~38 秒)
2. ✅ 完成 ChatDrawer 基础交互测试2 个 GIF~30 秒)
3. ✅ 添加 Mock API 支持,避免长时间等待
#### 中期(下周)
1. ✅ 完成智能提示面板测试2 个 GIF~27 秒)
2. ✅ 完成工作流高级功能测试2 个 GIF~35 秒)
3. ✅ 补充文本工具、多选、图层管理测试
#### 长期(本月内)
1. ✅ 达成 100% Manual 测试覆盖
2. ✅ 建立 CI/CD 自动化测试流程
3. ✅ 完善国际化(英文)测试
---
## 🔗 相关文档
- `docs/CODING_RULES.md` - 编码规则
- `docs/FEATURE_FLOWS.md` - 功能流程
- `apps/web-e2e/src/manual-gen/gif-recordings.manual.spec.ts` - 现有 GIF 测试
- `packages/drawnix/src/components/ai-input-bar/` - AI 输入栏源码
- `packages/drawnix/src/components/chat-drawer/` - ChatDrawer 源码
---
**生成时间**2026-01-27
**分析师**Claude Sonnet 4.5
**版本**v1.0