9223ceca50
- 规则重组:全局/ 下 8 个规则合并为 6 个(01+02→01,05+06→04),序号顺延 - 新增项目规则 05-多入口功能同步规范(UI/语音入口覆盖检查) - 新增 MCP 服务基础设施:Mcp/ 目录(DI 注册、端点扩展、动态工具描述符)、单元测试 - v1.3.0 工单文档:03 系列(会议任务拆分)、04(富文本描述与附件管理) - MCP 接口与前端集成指南:docs/manual/08、09
296 lines
11 KiB
Markdown
296 lines
11 KiB
Markdown
# 研发工单 v1.3.0 - 03-04 任务建议与确认 UI
|
||
|
||
> 父工单:[03-会议任务拆分](./03-会议任务拆分.md)
|
||
>
|
||
> 依赖:03-01、03-03(后端 API 就绪)
|
||
|
||
---
|
||
|
||
## 一、目标
|
||
|
||
实现会议任务拆分的完整前端 UI:在 TaskItem 中为 Meeting 类型待办项提供录音/纪要/拆分入口,实现建议审阅与确认对话框,打通从会议内容输入到批量创建子任务的端到端用户体验。
|
||
|
||
## 二、范围
|
||
|
||
**包含**:
|
||
- Meeting 类型待办项的特殊 UI(图标、录音/纪要/拆分入口)
|
||
- 录音控件的嵌入(调用 03-02 的 `AudioRecorder.vue` + `useAudioRecorder`)
|
||
- 纪要输入区域(textarea 保存会议文字内容)
|
||
- AI 拆分请求与加载状态
|
||
- 建议审阅对话框(`MeetingBreakdownDialog.vue`)
|
||
- 建议勾选、编辑、调整优先级、手动补充
|
||
- 确认后批量创建子任务
|
||
- 前端类型扩展(`taskType`、`meetingNotes`、`audioDuration`)
|
||
|
||
**不包含**:
|
||
- 录音控件本身(由 03-02 提供)
|
||
- 后端逻辑(由 03-01、03-03 提供)
|
||
|
||
## 三、前置条件
|
||
|
||
| 条件 | 说明 |
|
||
|---|---|
|
||
| 03-01 完成 | 后端 API 就绪(meeting 端点 + TaskType) |
|
||
| 03-02 完成 | AudioRecorder 组件和 useAudioRecorder 可用 |
|
||
| 03-03 完成 | breakdown/breakdown/confirm 端点可用 |
|
||
|
||
## 四、详细规格
|
||
|
||
### 4.1 前端类型扩展
|
||
|
||
```typescript
|
||
// src/Hua.Todo.Web/src/types/task.ts
|
||
|
||
/// <summary>待办项类型</summary>
|
||
type TaskType = 0 | 1; // 0=Normal, 1=Meeting
|
||
|
||
interface Task {
|
||
// ... 已有字段 ...
|
||
/** 待办项类型 */
|
||
taskType?: TaskType;
|
||
/** 会议纪要/转写文字 */
|
||
meetingNotes?: string;
|
||
/** 录音时长(秒) */
|
||
audioDuration?: number;
|
||
}
|
||
|
||
interface CreateTaskDto {
|
||
title: string;
|
||
priority: TaskPriority;
|
||
parentTaskId?: number;
|
||
/** 待办项类型,默认 0 */
|
||
taskType?: TaskType;
|
||
}
|
||
```
|
||
|
||
### 4.2 会议相关类型
|
||
|
||
```typescript
|
||
// 新增或扩展 meeting.ts 中的类型
|
||
|
||
/// <summary>会议任务拆分建议</summary>
|
||
interface MeetingTaskSuggestion {
|
||
title: string;
|
||
priority: TaskPriority;
|
||
reason: string;
|
||
}
|
||
|
||
/// <summary>拆分响应</summary>
|
||
interface BreakdownResponse {
|
||
taskId: number;
|
||
suggestions: MeetingTaskSuggestion[];
|
||
}
|
||
|
||
/// <summary>待确认的子任务项</summary>
|
||
interface PendingSubTask {
|
||
title: string;
|
||
priority: TaskPriority;
|
||
/** 是否被用户勾选 */
|
||
checked: boolean;
|
||
/** LLM 拆分的原始建议(含原因) */
|
||
suggestion?: MeetingTaskSuggestion;
|
||
/** 是否为用户手动添加的条目 */
|
||
isManual?: boolean;
|
||
}
|
||
```
|
||
|
||
### 4.3 TaskItem.vue 扩展
|
||
|
||
为 Meeting 类型的待办项显示额外操作入口:
|
||
|
||
```
|
||
┌──────────────────────────────────────────────┐
|
||
│ 📋 ☐ 周一产品评审会 🔴 H ··· │
|
||
│ 🎙 会议 · 📝 有纪要 · 0个子任务 │
|
||
│ [🎤] [📝] [🤖] │
|
||
│ ┌─ ✅ 整理需求文档 🔴 │ ← 已有子任务(若有)
|
||
│ └─ ☐ 安排评审会议 🟡 │
|
||
└──────────────────────────────────────────────┘
|
||
|
||
[🎤] = 录音按钮
|
||
[📝] = 打开纪要编辑区
|
||
[🤖] = AI 拆分(需有会议内容)
|
||
```
|
||
|
||
条件渲染逻辑:
|
||
- `task.taskType === 1`(Meeting)时,显示会议图标 `🎙` 标签
|
||
- 显示三个操作按钮在任务行右侧
|
||
- 拆分子任务入口:点击 `[🤖]` → 触发 `handleAiBreakdown()`
|
||
|
||
### 4.4 会议纪要编辑区(内联)
|
||
|
||
点击 `[📝]` 后展开内联编辑区:
|
||
|
||
```
|
||
┌──────────────────────────────────────────────┐
|
||
│ 📋 ☐ 周一产品评审会 │
|
||
│ │
|
||
│ 会议纪要: │
|
||
│ ┌──────────────────────────────────────┐ │
|
||
│ │ 今天的产品评审会主要讨论了三个议题: │ │
|
||
│ │ 第一,确定 Q3 产品路线图... │ │
|
||
│ │ 第二,... │ │
|
||
│ │ │ │
|
||
│ └──────────────────────────────────────┘ │
|
||
│ 录音时长:30分15秒 │
|
||
│ │
|
||
│ [🔊 开始录音] [🤖 AI拆分] [💾 保存纪要] │
|
||
└──────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 4.5 AI 拆分流程(前端)
|
||
|
||
```typescript
|
||
// 在 TaskItem.vue 或拆分逻辑中
|
||
|
||
async function handleAiBreakdown(task: Task) {
|
||
// 1. 检查是否有会议内容
|
||
if (!task.meetingNotes) {
|
||
showToast('请先输入纪要或上传录音', 'warning');
|
||
return;
|
||
}
|
||
|
||
// 2. 调用 AI 拆分
|
||
isLoading.value = true;
|
||
try {
|
||
const resp = await meetingApi.requestBreakdown(task.id);
|
||
if (resp.data.suggestions.length === 0) {
|
||
showToast('未从会议内容中提取到待办项,请确认纪要内容', 'info');
|
||
return;
|
||
}
|
||
|
||
// 3. 打开审阅对话框
|
||
openBreakdownDialog(task, resp.data.suggestions);
|
||
} catch (err) {
|
||
showToast('AI拆分失败,请稍后重试', 'error');
|
||
} finally {
|
||
isLoading.value = false;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4.6 MeetingBreakdownDialog.vue
|
||
|
||
审阅确认对话框:
|
||
|
||
```
|
||
┌──────────────────────────────────────────────┐
|
||
│ 会议任务拆分 — 周一产品评审会 [✕] │
|
||
│ │
|
||
│ AI 根据会议内容生成了以下待办项建议: │
|
||
│ 请勾选需要创建的条目,可编辑标题和优先级。 │
|
||
│ │
|
||
│ ┌──────────────────────────────────────┐ │
|
||
│ │ ☑ 整理产品需求文档 [🔴 高 ▼] │ │
|
||
│ │ 📝 会议中提到需要在本周五前完成 │ │
|
||
│ │ │ │
|
||
│ │ ☑ 安排技术方案评审 [🟡 中 ▼] │ │
|
||
│ │ 📝 张三负责在下周三前输出技术方案 │ │
|
||
│ │ │ │
|
||
│ │ ☑ 跟进客户反馈 [🟢 低 ▼] │ │
|
||
│ │ 📝 李四反馈了三个客户问题 │ │
|
||
│ │ │ │
|
||
│ │ ☐ 项目总结报告 [🟡 中 ▼] │ │
|
||
│ │ 📝 月末需要汇总各模块进度 │ │
|
||
│ └──────────────────────────────────────┘ │
|
||
│ │
|
||
│ [+ 手动添加待办项] │
|
||
│ │
|
||
│ 已选 3 项 │
|
||
│ [取消] [✅ 确认创建 (3)] │
|
||
└──────────────────────────────────────────────┘
|
||
```
|
||
|
||
交互:
|
||
- 每条建议默认勾选
|
||
- 点击标题可编辑(内联 input)
|
||
- 优先级下拉可调整
|
||
- 取消勾选的条目不会被创建
|
||
- `[+ 手动添加]` 新增空白条目
|
||
- 底部显示已选数量
|
||
|
||
### 4.7 确认创建
|
||
|
||
```typescript
|
||
async function confirmBreakdown() {
|
||
const selected = pendingSubTasks.value
|
||
.filter(s => s.checked)
|
||
.map(s => ({ title: s.title, priority: s.priority }));
|
||
|
||
if (selected.length === 0) {
|
||
showToast('请至少选择一个待办项', 'warning');
|
||
return;
|
||
}
|
||
|
||
isCreating.value = true;
|
||
try {
|
||
const resp = await meetingApi.confirmBreakdown(task.id, selected);
|
||
showToast(`已成功创建 ${resp.data.createdCount} 个待办项`, 'success');
|
||
closeDialog();
|
||
emit('updated'); // 刷新任务列表
|
||
} catch (err) {
|
||
showToast('创建失败,请重试', 'error');
|
||
} finally {
|
||
isCreating.value = false;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4.8 创建任务时的类型选择
|
||
|
||
在 `TaskList.vue` 的快速创建表单中增加类型选择:
|
||
|
||
```
|
||
┌──────────────────────────────────────────────┐
|
||
│ [+ 新待办项] [_____输入标题_____] │
|
||
│ 优先级: [🟡 中 ▼] 类型: [📋 普通 ▼] │
|
||
│ [🎙 会议] │
|
||
│ [+ 添加] │
|
||
└──────────────────────────────────────────────┘
|
||
```
|
||
|
||
默认类型为 `Normal`(普通),选择 `Meeting` 后创建的待办项为会议类型。
|
||
|
||
## 五、验收标准
|
||
|
||
| 验收项 | 验证方法 | 预期结果 |
|
||
|---|---|---|
|
||
| 创建 Meeting 类型 | 新建时选择"会议"类型 | 列表中显示 🎙 图标 |
|
||
| 会议操作按钮 | 展开 Meeting 类型任务 | 显示录音/纪要/拆分三个按钮 |
|
||
| 普通类型不显示 | 查看普通待办项 | 无会议相关按钮 |
|
||
| 录音入口 | 点击录音按钮 | 弹出/展开 AudioRecorder 组件 |
|
||
| 纪要编辑 | 输入会议纪要后保存 | `meetingNotes` 保存成功 |
|
||
| AI 拆分请求 | 点击 AI 拆分按钮 | 加载状态 → 审阅对话框弹出 |
|
||
| 无内容拒绝拆分 | 无纪要时点击拆分 | 提示"请先输入纪要" |
|
||
| 建议审阅 | 审阅对话框中勾选/取消/编辑 | 操作流畅,状态正确 |
|
||
| 手动添加 | 点击"+ 手动添加" | 新增空白条目,可编辑 |
|
||
| 批量创建 | 确认勾选的条目 | 子任务创建到父任务下 |
|
||
| 离线降级提示 | 离线时点击拆分 | 提示"AI 拆分仅在线可用" |
|
||
| 响应式 | 缩小浏览器窗口 | 对话框和控件正常显示 |
|
||
|
||
## 六、风险
|
||
|
||
| 风险 | 影响 | 应对 |
|
||
|---|---|---|
|
||
| 组件嵌套复杂 | TaskItem 已有子任务递归,再加会议 UI 后层级深 | 会议功能用可选插槽方式注入,不影响普通任务渲染 |
|
||
| 录音与拆分同时操作 | 用户可能在转写期间又点拆分 | 操作按钮在加载中时禁用 |
|
||
| 大量建议渲染 | LLM 返回 10+ 条建议时列表长 | 审阅列表设最大高度 + 滚动;建议上限 15 条 |
|
||
|
||
## 七、Touch List
|
||
|
||
| 文件路径 | 修改类型 |
|
||
|---|---|
|
||
| `src/Hua.Todo.Web/src/types/task.ts` | 修改(新增 TaskType、meetingNotes、audioDuration) |
|
||
| `src/Hua.Todo.Web/src/api/meeting.ts` | 新增 |
|
||
| `src/Hua.Todo.Web/src/components/AudioRecorder.vue` | 新增(由 03-02 产出,本工单集成) |
|
||
| `src/Hua.Todo.Web/src/components/MeetingBreakdownDialog.vue` | 新增 |
|
||
| `src/Hua.Todo.Web/src/components/TaskItem.vue` | 修改(Meeting 类型条件渲染) |
|
||
| `src/Hua.Todo.Web/src/components/TaskList.vue` | 修改(新建任务时类型选择) |
|
||
|
||
---
|
||
|
||
**工单编号**:03-04
|
||
**标题**:任务建议与确认 UI
|
||
**版本**:v1.3.0
|
||
**创建日期**:2026-06-16
|