9223ceca50
- 规则重组:全局/ 下 8 个规则合并为 6 个(01+02→01,05+06→04),序号顺延 - 新增项目规则 05-多入口功能同步规范(UI/语音入口覆盖检查) - 新增 MCP 服务基础设施:Mcp/ 目录(DI 注册、端点扩展、动态工具描述符)、单元测试 - v1.3.0 工单文档:03 系列(会议任务拆分)、04(富文本描述与附件管理) - MCP 接口与前端集成指南:docs/manual/08、09
7.4 KiB
7.4 KiB
研发工单 v1.3.0 - 03-01 会议数据模型与 API
父工单:03-会议任务拆分
一、目标
为"会议任务拆分"功能建立数据模型:扩展 TaskEntity 新增 TaskType 枚举和 MeetingNotes/AudioDuration 字段,定义完整的会议相关 API 端点与 DTO,完成数据库迁移。
二、范围
包含:
- 新增
TaskType枚举(Normal / Meeting) TaskEntity新增字段:TaskType、MeetingNotes、AudioDuration- EF Core 数据库迁移
- DTO 扩展:
CreateTaskDto、UpdateTaskDto、TaskDto新增对应字段 - 会议 API 端点骨架:
MeetingController+MeetingService - API 路径:
/api/meeting/{taskId}/transcribe、/api/meeting/{taskId}/notes - 会议相关 DTO 定义:
TranscribeRequest、TranscribeResponse、MeetingNotesRequest
不包含:
- AI 拆分逻辑(由 03-03 完成)
- STT 转写实现(由 03-02 完成)
- 前端组件(由 03-04 完成)
三、前置条件
| 条件 | 说明 |
|---|---|
| Hua.Todo v1.2.0 | 基础 Task CRUD 能力、父子任务、DynamicApi 中间件 |
| ABP 基类迁移(可选) | 若工单 09(v1.2.0)已完成,TaskEntity 已转为 ABP 基类,字段新增方式不同 |
四、详细规格
4.1 TaskType 枚举
/// <summary>待办项类型,区分普通待办项与会议</summary>
public enum TaskType
{
/// <summary>普通待办项(默认)</summary>
Normal = 0,
/// <summary>会议:包含录音/纪要,支持 AI 任务拆分</summary>
Meeting = 1
}
文件位置:src/Hua.Todo.Core/Entities/TaskType.cs
4.2 TaskEntity 新增字段
/// <summary>待办项类型</summary>
public TaskType TaskType { get; set; } = TaskType.Normal;
/// <summary>会议纪要/转写文字(仅 Meeting 类型有值)</summary>
[MaxLength(20000)]
public string? MeetingNotes { get; set; }
/// <summary>录音时长(秒),仅 Meeting 类型有值</summary>
public double? AudioDuration { get; set; }
4.3 EF Core 配置(TodoDbContext.cs)
builder.Entity<TaskEntity>(b =>
{
// ... 现有配置 ...
b.Property(x => x.TaskType)
.HasDefaultValue(TaskType.Normal)
.HasConversion<int>(); // 枚举存为整数
b.Property(x => x.MeetingNotes)
.HasMaxLength(20000); // 最多约 20000 字符
b.Property(x => x.AudioDuration)
.IsRequired(false);
});
4.4 数据库迁移
dotnet ef migrations add AddMeetingFieldsToTasks
迁移应在 Hua.Todo.Application/Migrations/ 目录生成。
4.5 DTO 扩展
CreateTaskDto 新增:
/// <summary>待办项类型(0=Normal, 1=Meeting),默认 Normal</summary>
public TaskType TaskType { get; set; } = TaskType.Normal;
TaskDto 新增:
/// <summary>待办项类型</summary>
public TaskType TaskType { get; set; }
/// <summary>会议纪要/转写文字</summary>
public string? MeetingNotes { get; set; }
/// <summary>录音时长(秒)</summary>
public double? AudioDuration { get; set; }
4.6 会议 DTO
/// <summary>转写请求</summary>
public class TranscribeRequest
{
public IFormFile Audio { get; set; } = null!;
public string? Format { get; set; }
}
/// <summary>转写响应</summary>
public class TranscribeResponse
{
public int TaskId { get; set; }
public string Transcript { get; set; } = string.Empty;
public double AudioDuration { get; set; }
}
/// <summary>保存会议纪要请求</summary>
public class MeetingNotesRequest
{
public string Notes { get; set; } = string.Empty;
}
/// <summary>会议纪要响应</summary>
public class MeetingNotesResponse
{
public int TaskId { get; set; }
public string MeetingNotes { get; set; } = string.Empty;
}
4.7 API 端点
POST /api/meeting/{taskId}/transcribe
- 接收:multipart/form-data(音频文件)
- 返回:
TranscribeResponse - 业务:音频上传后异步转写,结果存回
TaskEntity.MeetingNotes - 当前骨架:返回占位文字,具体转写逻辑由 03-02 实现
POST /api/meeting/{taskId}/notes
- 接收:
MeetingNotesRequest - 返回:
MeetingNotesResponse - 业务:保存/更新会议纪要
4.8 MeetingService 骨架
/// <summary>会议业务服务</summary>
public class MeetingService
{
private readonly ITaskRepository _taskRepo;
public MeetingService(ITaskRepository taskRepo)
{
_taskRepo = taskRepo;
}
/// <summary>验证 taskId 对应的待办项存在且为 Meeting 类型</summary>
public async Task<TaskEntity> GetMeetingTaskOrThrow(int taskId)
{
var task = await _taskRepo.GetAsync(taskId);
if (task == null)
throw new NotFoundException($"任务 {taskId} 不存在");
if (task.TaskType != TaskType.Meeting)
throw new BusinessException($"任务 {taskId} 不是会议类型");
return task;
}
/// <summary>保存会议纪要</summary>
public async Task<TaskEntity> SaveNotes(int taskId, string notes)
{
var task = await GetMeetingTaskOrThrow(taskId);
task.MeetingNotes = notes;
task.UpdatedAt = DateTime.UtcNow;
await _taskRepo.UpdateAsync(task);
return task;
}
/// <summary>保存转写结果与音频时长</summary>
public async Task<TaskEntity> SaveTranscript(int taskId, string transcript, double audioDuration)
{
var task = await GetMeetingTaskOrThrow(taskId);
task.MeetingNotes = transcript;
task.AudioDuration = audioDuration;
task.UpdatedAt = DateTime.UtcNow;
await _taskRepo.UpdateAsync(task);
return task;
}
}
五、验收标准
| 验收项 | 验证方法 | 预期结果 |
|---|---|---|
| TaskType 枚举可用 | 编译通过 | TaskType.Normal / TaskType.Meeting 可正常赋值 |
| DB 迁移可执行 | dotnet ef database update |
Tasks 表新增 TaskType/MeetingNotes/AudioDuration 列 |
| 创建 Meeting 类型任务 | POST /api/task 带 taskType:1 |
返回的 TaskDto 中 taskType=1 |
| 保存会议纪要 | POST /api/meeting/{id}/notes |
meetingNotes 字段更新成功 |
| 非 Meeting 类型调用会议 API | 普通任务调 /api/meeting/{id}/notes |
返回业务异常 |
| 现有代码兼容 | 运行所有已有测试 | 不破坏现有业务 |
六、风险
| 风险 | 影响 | 应对 |
|---|---|---|
| TaskEntity 已重构为 ABP 基类 | 字段新增方式不同 | 通过 ABP 的 ExtraProperties 或标准字段新增,迁移方式略有调整 |
| 字段长度限制 | 超长会议纪要截断 | MeetingNotes 设 MaxLength(20000),前端也做长度限制 |
七、Touch List
| 文件路径 | 修改类型 | 是否共享 |
|---|---|---|
src/Hua.Todo.Core/Entities/TaskType.cs |
新增 | 否 |
src/Hua.Todo.Core/Entities/TaskEntity.cs |
修改 | 是 |
src/Hua.Todo.Application/Data/TodoDbContext.cs |
修改 | 是 |
src/Hua.Todo.Application/Models/TaskModels.cs |
修改 | 是 |
src/Hua.Todo.Application/Meeting/MeetingController.cs |
新增 | 否 |
src/Hua.Todo.Application/Meeting/MeetingService.cs |
新增 | 否 |
src/Hua.Todo.Application/Meeting/Models/MeetingDtos.cs |
新增 | 否 |
src/Hua.Todo.Web/src/types/task.ts |
修改 | 是 |
Migrations/AddMeetingFieldsToTasks.cs |
新增 | 是 |
工单编号:03-01 标题:会议数据模型与 API 版本:v1.3.0 创建日期:2026-06-16