# DC模块 Tool-B 开发计? > **文档版本?* V2.0 (MVP完成) > **创建日期?* 2025-12-02 > **完成日期?* 2025-12-03 > **实际周期?* 2个工作日 > **状态:** ?MVP完成 --- ## 🎉 MVP完成通告?025-12-03? **Tool B病历结构化机器人MVP版本已完成!** - ?前端5步工作流完整实现(~1400行) - ?8个API端点全部对接并测试通过 - ?LLM双模型提取验证成功(DeepSeek-V3 + Qwen-Max?- ?真实数据测试?条病理报告提取成?- ?Excel导出功能可用 - ⚠️ 4个技术债务待处理(见`07-技术债务/Tool-B技术债务清单.md`? **完成详情?* 参见 `06-开发记?Tool-B-MVP完成总结-2025-12-03.md` --- ## 原始开发计? > **目标?* 完成Tool-B(病历结构化机器人)的前端开发和完整功能集成 --- ## 📋 一、项目当前状态调研总结 ### 1.1 后端代码状??100%完成 #### 通用能力平台(可复用?基于 `backend/src/common/` 平台基础设施,已完整实现? | 能力模块 | 导入路径 | 功能说明 | 状?| |---------|---------|---------|------| | **存储服务** | `@/common/storage` | 文件上传/下载(Local ?OSS?| ?完成 | | **日志系统** | `@/common/logging` | 结构化日志(Winston?| ?完成 | | **缓存服务** | `@/common/cache` | 缓存(Memory ?Redis?| ?完成 | | **异步任务** | `@/common/jobs` | 长时间任务队?| ?完成 | | **LLM工厂** | `@/common/llm/adapters/LLMFactory` | 统一LLM调用(DeepSeek/Qwen/GPT/Claude?| ?完成 | | **数据?* | `@/config/database` | Prisma连接?| ?完成 | **复用策略**?- ?Tool B后端代码?00%复用平台能力 - ?前端开发应参考后端模式,复用前端共享组件 --- #### Tool B后端实现状? **代码位置**:`backend/src/modules/dc/tool-b/` | 文件 | 功能 | 代码?| 状?| 复用能力 | |-----|------|--------|------|---------| | **services/HealthCheckService.ts** | Excel健康检?| ~190?| ?完成 | storage, logger, cache, prisma | | **services/TemplateService.ts** | 预设模板管理 | ~243?| ?完成 | logger, prisma | | **services/DualModelExtractionService.ts** | 双模型提?| ~390?| ?完成 | LLMFactory, logger, prisma | | **services/ConflictDetectionService.ts** | 冲突检测算?| ~215?| ?完成 | logger | | **controllers/ExtractionController.ts** | API控制?| ~388?| ?完成 | 全部服务 | | **routes/index.ts** | 路由配置 | ~115?| ?完成 | - | | **index.ts** | 模块入口 | ~117?| ?完成 | - | **总计**:约1,658行,7个文件,100%完成 --- #### API端点清单 **Base URL**: `/api/v1/dc/tool-b` | 方法 | 路径 | 功能 | 请求?| 响应 | 状?| |------|------|------|--------|------|------| | **POST** | `/health-check` | Excel列健康检?| `{fileKey, columnName}` | 健康度报?| ?完成 | | **GET** | `/templates` | 获取预设模板列表 | - | 模板数组 | ?完成 | | **POST** | `/tasks` | 创建提取任务 | `{projectName, fileKey, textColumn, diseaseType, reportType}` | `{taskId}` | ?完成 | | **GET** | `/tasks/:taskId/progress` | 查询任务进度 | - | 进度详情 | ?完成 | | **GET** | `/tasks/:taskId/items` | 获取验证网格数据 | `?status=conflict&page=1` | 分页数据 | ?完成 | | **POST** | `/items/:itemId/resolve` | 裁决冲突 | `{resolvedData}` | 成功状?| ?完成 | **预设模板**?个)?1. 肺癌病理报告(`lung_cancer/pathology`? 5个字?2. 糖尿病入院记录(`diabetes/admission`? 5个字?3. 高血压门诊病历(`hypertension/outpatient`? 5个字? --- ### 1.2 数据库状??已验证完成(2025-12-02? **Schema**: `dc_schema`(独立隔离) | 表名 | 用?| 字段?| 关键字段 | 状?| 数据?| |------|------|--------|---------|------|--------| | **dc_health_checks** | 健康检查记?| 10 | status, emptyRate, avgLength | ?已创?| 2?| | **dc_templates** | 预设模板 | 7 | diseaseType, reportType, fields | ?已创?| **3?* | | **dc_extraction_tasks** | 提取任务 | 21 | status, totalCount, processedCount | ?已创?| 1?| | **dc_extraction_items** | 提取明细 | 15 | resultA, resultB, conflictFields | ?已创?| 4?| **?验证结果?025-12-02?*?- ?**dc_schema已存?* - ?**4个表全部创建成功** - ?**3个预设模板已初始?*? 1. 肺癌病理报告 (lung_cancer/pathology) 2. 糖尿病入院记?(diabetes/admission) 3. 高血压门诊病?(hypertension/outpatient) - ?**有测试数据可用于开发调?* **验证脚本**?```bash cd backend node scripts/check-dc-tables.mjs # 执行数据库表检查脚?``` **结论**:✅ 数据库完全准备就绪,可以开始前端开发! --- ### 1.3 前端代码状??0%(仅Placeholder? **代码位置**:`frontend-v2/src/modules/dc/` ``` frontend-v2/src/modules/dc/ ├── index.tsx # ?仅Placeholder?4行) ├── components/ # 📁 ?├── pages/ # 📁 空文件夹结构 ? ├── tool-a/ # 📁 ?? ├── tool-b/ # 📁 ?? └── tool-c/ # 📁 ?└── types/ # 📁 ?``` **当前内容**?```typescript // frontend-v2/src/modules/dc/index.tsx import Placeholder from '@/shared/components/Placeholder' const DCModule = () => { return ( ) } export default DCModule ``` --- ### 1.4 前端架构设计 ?已明? #### 系统级架?- **导航模式**:顶部导?- **路由路径**:`/data-cleaning` - **技术栈**:React 19 + TypeScript + Vite + Ant Design 5 #### DC模块架构方案 **选择:方案A - 独立Portal页面**(推荐) ``` /data-cleaning (Portal工作?- 总览? ├── 快速启动区?个工具卡片) ? ├── [超级合并器] ?/data-cleaning/tool-a ? ├── [病历结构化] ?/data-cleaning/tool-b ? └── [数据编辑器] ?/data-cleaning/tool-c ├── 最近任务列表(实时进度? └── 数据资产库(文件管理? /data-cleaning/tool-b (Tool B - 全屏5步流? ├── Step 1: 上传与健康检? ├── Step 2: 智能模板配置 ├── Step 3: 双盲提取进度 ├── Step 4: 冲突验证网格 ?核心 └── Step 5: 结果导出 ``` **参考模?*?- ASL模块(`frontend-v2/src/modules/asl/`? - 有完整的布局、页面、组件结? - 使用React Router嵌套路由 - 左侧导航 + 右侧内容? --- ## 🎯 二、开发计划总览 ### 2.1 开发阶段划? | 阶段 | 任务 | 预计工时 | 优先?| 目标 | |------|------|---------|--------|------| | **Phase 1** | Portal工作台页?| 4-6h | P0 | DC模块入口 | | **Phase 2** | Tool B - Step 1&2 | 6h | P0 | 上传+配置 | | **Phase 3** | Tool B - Step 3 | 3h | P0 | 进度监控 | | **Phase 4** | Tool B - Step 4 | 9h | P0 | 冲突验证网格?| | **Phase 5** | Tool B - Step 5 | 3h | P0 | 结果导出 | | **Phase 6** | 集成测试 | 4h | P1 | 端到端验?| **总计**:约29-31小时?-5个工作日? --- ### 2.2 里程碑时间表 | 里程?| 完成标志 | 预计完成 | |--------|---------|---------| | **M1: Portal上线** | 用户可访问DC模块入口 | Day 1 | | **M2: Tool B可用** | Step1-5全部完成 | Day 4 | | **M3: 集成测试通过** | 端到端流程测试通过 | Day 5 | | **M4: 文档完善** | 开发文档和用户文档 | Day 6 | --- ## 📐 三、Phase 1: Portal工作台开发(Day 1? ### 3.1 目标 创建DC模块的入口页面,适配系统顶部导航,提供工具启动、任务监控和文件管理功能? ### 3.2 设计参?- **原型文件**:`docs/03-业务模块/DC-数据清洗整理/03-UI设计/智能数据清洗工作台V2.html` - **PRD文档**:`docs/03-业务模块/DC-数据清洗整理/01-需求分?PRD:智能数据清洗工作台 (The Data Cleaning Portal).md` ### 3.3 功能清单 #### 3.3.1 快速启动区?个工具卡片) **组件**:`components/ToolCard.tsx` ```typescript interface ToolCardProps { id: 'tool-a' | 'tool-b' | 'tool-c'; title: string; description: string; icon: ReactNode; color: 'blue' | 'purple' | 'emerald'; status: 'ready' | 'disabled'; onClick: () => void; } ``` **卡片内容**?1. **Tool A - 超级合并?* - 图标:FileSpreadsheet(蓝色) - 描述?解决多源数据时间轴对齐难? - 状态:disabled(暂未开发) 2. **Tool B - 病历结构化机器人** ?本次开? - 图标:Bot(紫色) - 描述?利用大模型提取非结构化文? - 状态:ready - 点击跳转:`/data-cleaning/tool-b` 3. **Tool C - 科研数据编辑?* - 图标:Table2(绿色) - 描述?Excel风格的在线清洗工? - 状态:disabled(暂未开发) --- #### 3.3.2 最近任务列?**组件**:`components/TaskList.tsx` **API**:`GET /api/v1/dc/tasks/recent`(需后端新增? **数据结构**?```typescript interface Task { id: string; name: string; tool: 'tool-a' | 'tool-b' | 'tool-c'; status: 'pending' | 'processing' | 'completed' | 'failed'; progress: number; // 0-100 createdAt: string; completedAt?: string; } ``` **功能**?- 显示最?0条任?- 实时轮询进度(processing状态时,每5秒轮询) - 智能流转按钮? - Tool A完成 ?[下载] + [去AI提取](跳Tool B? - Tool B完成 ?[下载] + [去清洗](跳Tool C? - Tool C完成 ?[下载] --- #### 3.3.3 数据资产?**组件**:`components/AssetLibrary.tsx` **API**:`GET /api/v1/dc/assets`(需后端新增? **Tab分类**?- **全部**:所有文?- **处理结果**:工具A/B/C生成的文件(绿色/蓝色图标?- **原始上传**:用户直接上传的底表(灰色图标) **功能**?- 文件卡片显示(文件名、行数、标签、修改时间) - 快捷操作:[下载] [去处理] [分析] - 底部固定按钮:[+ 上传原始文件到库] --- ### 3.4 技术实? #### 3.4.1 目录结构 ``` frontend-v2/src/modules/dc/ ├── pages/ ? └── Portal.tsx # ?Portal主页?├── components/ ? ├── ToolCard.tsx # 工具卡片 ? ├── TaskList.tsx # 任务列表 ? └── AssetLibrary.tsx # 数据资产?├── hooks/ ? ├── useRecentTasks.ts # 任务列表Hook ? └── useAssets.ts # 资产列表Hook ├── services/ ? └── portalApi.ts # Portal API封装 └── types/ └── portal.ts # Portal类型定义 ``` --- #### 3.4.2 路由配置 ```typescript // frontend-v2/src/modules/dc/index.tsx import { Routes, Route } from 'react-router-dom'; import Portal from './pages/Portal'; import ToolBModule from './pages/tool-b'; const DCModule = () => { return ( } /> } /> {/* 未来扩展 */} } /> } /> ); }; export default DCModule; ``` --- #### 3.4.3 API对接 **需要后端新增的API**?```typescript // GET /api/v1/dc/tasks/recent interface GetRecentTasksResponse { tasks: Task[]; } // GET /api/v1/dc/assets interface GetAssetsResponse { assets: Asset[]; } ``` **临时方案**(后端API未开发时): - 使用Mock数据 - 后续替换为真实API --- ### 3.5 验收标准 - [ ] Portal页面可访问(`http://localhost:3000/data-cleaning`?- [ ] 3个工具卡片正确显?- [ ] Tool B卡片可点击跳转(其他两个显示disabled?- [ ] 任务列表显示Mock数据 - [ ] 数据资产库Tab切换正常 - [ ] 整体样式符合系统设计规范 --- ## 🛠?四、Phase 2: Tool B - Step 1&2(Day 2? ### 4.1 Step 1: 文件上传与健康检查(3小时? #### 4.1.1 页面设计 **组件**:`pages/tool-b/Step1Upload.tsx` **UI参?*:原型V4?60-310? **布局**?1. 文件信息卡片(显示已上传文件?2. 列选择下拉?3. 健康检查结果卡片(动态显示) --- #### 4.1.2 功能实现 **1. Excel文件上传** ```typescript // 使用Ant Design Upload组件 import { Upload } from 'antd'; // 上传到Storage const handleUpload = async (file: File) => { const formData = new FormData(); formData.append('file', file); const response = await fetch('/api/v1/storage/upload', { method: 'POST', body: formData }); const { fileKey } = await response.json(); setFileKey(fileKey); // 保存fileKey用于后续步骤 }; ``` **2. 列选择与健康检?* ```typescript const [columns, setColumns] = useState([]); const [selectedColumn, setSelectedColumn] = useState(''); const [healthResult, setHealthResult] = useState(null); // 自动检测列名(可选:从后端获取) useEffect(() => { if (fileKey) { // TODO: 调用API获取Excel列名 // 或前端解析Excel(使用xlsx库) } }, [fileKey]); // 健康检?const handleHealthCheck = async (columnName: string) => { setIsChecking(true); try { const response = await fetch('/api/v1/dc/tool-b/health-check', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ fileKey, columnName }) }); const result = await response.json(); setHealthResult(result.data); } finally { setIsChecking(false); } }; ``` **3. 健康度显?* ```typescript // 根据status显示不同样式 {healthResult?.status === 'good' && ( } message="健康度优秀,适合提取" description={
平均字符: {healthResult.avgLength} 空值率: {(healthResult.emptyRate * 100).toFixed(1)}% 预计Token: {healthResult.estimatedTokens.toLocaleString()}
} /> )} {healthResult?.status === 'bad' && ( } message="警告:该列不适合AI处理" description={healthResult.message} /> )} ``` --- ### 4.2 Step 2: 智能模板配置?小时? #### 4.2.1 页面设计 **组件**:`pages/tool-b/Step2Schema.tsx` **UI参?*:原型V4?13-372? **布局**?1. 疾病类型与报告类型选择(级联) 2. 字段列表(左侧,可编辑) 3. Prompt预览(右侧,代码高亮? --- #### 4.2.2 功能实现 **1. 获取模板列表** ```typescript const [templates, setTemplates] = useState([]); const [diseaseType, setDiseaseType] = useState(''); const [reportType, setReportType] = useState(''); const [fields, setFields] = useState([]); useEffect(() => { // 获取所有模? fetch('/api/v1/dc/tool-b/templates') .then(res => res.json()) .then(data => setTemplates(data.data.templates)); }, []); // 当选择疾病类型和报告类型时,自动加载字?useEffect(() => { if (diseaseType && reportType) { const template = templates.find( t => t.diseaseType === diseaseType && t.reportType === reportType ); if (template) { setFields(template.fields); } } }, [diseaseType, reportType, templates]); ``` **2. 字段编辑** ```typescript // 添加字段 const handleAddField = () => { setFields([...fields, { id: `custom_${Date.now()}`, name: '新字?, desc: '字段描述', width: 'w-32' }]); }; // 删除字段 const handleDeleteField = (id: string) => { setFields(fields.filter(f => f.id !== id)); }; // 编辑字段 const handleEditField = (id: string, key: 'name' | 'desc', value: string) => { setFields(fields.map(f => f.id === id ? { ...f, [key]: value } : f )); }; ``` **3. Prompt预览** ```typescript // 动态生成Prompt预览 const generatePrompt = () => { return `You are an expert in ${diseaseType.replace('_', ' ')} pathology. Extract fields in JSON format: { ${fields.map(f => ` "${f.name}": "string", // ${f.desc}`).join('\n')} } Original text: {originalText} Output JSON only.`; }; // 使用代码高亮库(如react-syntax-highlighter? {generatePrompt()} ``` --- ### 4.3 验收标准 **Step 1:** - [ ] Excel上传成功,获取fileKey - [ ] 列名列表正确显示 - [ ] 健康检查API调用成功 - [ ] 健康度卡片根据结果正确显示(绿色/红色?- [ ] Token预估数值正?- [ ] 空值率>50%时禁止进入下一? **Step 2:** - [ ] 模板列表加载成功 - [ ] 疾病类型和报告类型选择框正?- [ ] 选择模板后字段自动加?- [ ] 字段支持添加/删除/编辑 - [ ] Prompt预览实时更新 - [ ] 代码高亮正确显示 --- ## ⚙️ 五、Phase 3: Tool B - Step 3(Day 3上午? ### 5.1 处理进度监控?小时? #### 5.1.1 页面设计 **组件**:`pages/tool-b/Step3Processing.tsx` **UI参?*:原型V4?75-400? **布局**?1. 圆形进度环(双模型动画) 2. 进度百分比和文本 3. 日志滚动区域 --- #### 5.1.2 功能实现 **1. 创建任务** ```typescript const handleStartExtraction = async () => { const response = await fetch('/api/v1/dc/tool-b/tasks', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ projectName: 'Test Project', sourceFileKey: fileKey, textColumn: selectedColumn, diseaseType, reportType, modelA: 'deepseek-v3', modelB: 'qwen-max' }) }); const { taskId } = await response.json(); setTaskId(taskId); // 开始轮? startPolling(taskId); }; ``` **2. 进度轮询** ```typescript const startPolling = (taskId: string) => { const interval = setInterval(async () => { const response = await fetch(`/api/v1/dc/tool-b/tasks/${taskId}/progress`); const data = await response.json(); setProgress(data.progress); // 百分? setLogs(prevLogs => [...prevLogs, data.latestLog]); // 新增日志 if (data.status === 'completed') { clearInterval(interval); // 跳转到Step 4 setTimeout(() => navigate(`/data-cleaning/tool-b/verify/${taskId}`), 800); } else if (data.status === 'failed') { clearInterval(interval); message.error('提取任务失败'); } }, 5000); // ?秒轮? return () => clearInterval(interval); }; ``` **3. 进度动画** ```typescript // 使用Ant Design Progress组件或自定义SVG (
{percent}%
双盲提取?/div>
)} strokeColor={{ '0%': '#9333ea', '100%': '#4f46e5' }} /> // 双模型动画(两个小球跳动?
``` **4. 日志显示** ```typescript
{logs.map((log, i) => (
[{log.timestamp}] {log.message}
))}
_
``` --- ### 5.2 验收标准 - [ ] 点击"开始提?后成功创建任?- [ ] 获取到taskId - [ ] 进度轮询正常(每5秒) - [ ] 进度条实时更?- [ ] 日志滚动区域正常显示 - [ ] 任务完成后自动跳转到Step 4 - [ ] 任务失败时显示错误提? --- ## 🎯 六、Phase 4: Tool B - Step 4(Day 3下午+Day 4)⭐ 核心 ### 6.1 冲突验证网格?小时? 这是整个Tool B最复杂、最核心的页面! #### 6.1.1 页面设计 **组件**:`pages/tool-b/Step4Verify.tsx` **UI参?*:原型V4?02-569? **布局**?``` ┌─────────────────────────────────────────────────??Toolbar: 统计信息 + [导出][完成] ?├─────────────────────────────────────────────────?? ?? 全景验证网格(表格) ?? ┌────┬────────────┬────────┬────────┬──────? ?? ?# ?原文摘要 ?字段1 ?字段2 ?状?? ?? ├────┼────────────┼────────┼────────┼──────? ?? ?1 ?病理诊断.. ?冲突单元格(A/B按钮)│待裁决│ ?? ?2 ?送检组织.. ?绿色(一致)?绿色 ?通过 ? ?? └────┴────────────┴────────┴────────┴──────? ?? ?└─────────────────────────────────────────────────? ?点击?┌──────────────────────────────────??侧边栏(Drawer? ??─────────────────────────────── ??病历原文详情 ?? ??病理诊断?右肺上叶)浸润性腺?.. ??肿瘤大小 3.2*2.5*2.0cm... ??... ?? ??[关闭] ?└──────────────────────────────────?``` --- #### 6.1.2 技术选型 **方案选择**? **Option 1: Ant Design Table**(推荐,数据?1000行) - 优点:开箱即用,API友好,样式统一 - 缺点:数据量大时可能卡顿 - 适用场景:大部分场景(预计数据量<500行) **Option 2: TanStack Table**(高性能,数据量>1000行) - 优点:虚拟滚动,性能极佳 - 缺点:Headless需自己实现UI - 适用场景:处理大数据? **决策**:先用Ant Design Table,如性能不佳再迁移到TanStack Table --- #### 6.1.3 核心数据结构 ```typescript interface VerifyRow { id: string; rowIndex: number; originalText: string; // 原文摘要(前50字) fullText: string; // 原文全文(侧边栏显示? results: Record; status: 'clean' | 'conflict' | 'resolved'; conflictFields: string[]; // 冲突字段名称列表 } ``` --- #### 6.1.4 功能实现 **1. 获取验证数据** ```typescript const [rows, setRows] = useState([]); const [pagination, setPagination] = useState({ page: 1, pageSize: 20, total: 0 }); useEffect(() => { fetch(`/api/v1/dc/tool-b/tasks/${taskId}/items?status=conflict&page=${pagination.page}`) .then(res => res.json()) .then(data => { setRows(data.data.items); setPagination({ ...pagination, total: data.data.pagination.total }); }); }, [taskId, pagination.page]); ``` **2. 表格列配?* ```typescript const columns: ColumnsType = [ { title: '#', dataIndex: 'rowIndex', width: 60, fixed: 'left', }, { title: '原文摘要', dataIndex: 'originalText', width: 200, render: (text, record) => (
{text}
), }, // 动态字段列(根据模板生成) ...fields.map(field => ({ title: field.name, dataIndex: ['results', field.name], width: 180, render: (cellData: { A: string; B: string; chosen: string | null }, record: VerifyRow) => { const isConflict = cellData.A !== cellData.B && cellData.chosen === null; if (isConflict) { return handleAdopt(record.id, field.name, value)} />; } return ; }, })), { title: '状?, dataIndex: 'status', width: 100, fixed: 'right', render: (status) => { if (status === 'clean' || status === 'resolved') { return 通过; } return 待裁?/Tag>; }, }, ]; ``` **3. 冲突单元格组?* ?核心 ```typescript // components/ConflictCell.tsx interface ConflictCellProps { fieldName: string; valueA: string; valueB: string; onAdopt: (value: string) => void; } const ConflictCell: React.FC = ({ fieldName, valueA, valueB, onAdopt }) => { return (
{/* 选项A - DeepSeek */} {/* 选项B - Qwen */}
); }; ``` **4. 裁决逻辑** ```typescript const handleAdopt = async (itemId: string, fieldName: string, value: string) => { // 乐观更新UI setRows(prevRows => prevRows.map(row => { if (row.id !== itemId) return row; const newResults = { ...row.results }; newResults[fieldName].chosen = value; // 检查该行是否还有未解决的冲? const hasConflict = Object.values(newResults).some( cell => cell.chosen === null && cell.A !== cell.B ); return { ...row, results: newResults, status: hasConflict ? 'conflict' : 'resolved', }; }) ); // 调用API try { await fetch(`/api/v1/dc/tool-b/items/${itemId}/resolve`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ resolvedData: { [fieldName]: value } }) }); } catch (error) { message.error('裁决失败'); // 回滚UI // TODO: 实现回滚逻辑 } }; ``` **5. 侧边栏原文显?* ```typescript const [selectedRowId, setSelectedRowId] = useState(null); // 点击行时打开侧边?const onRow = (record: VerifyRow) => ({ onClick: () => setSelectedRowId(record.id), }); // Drawer组件 setSelectedRowId(null)} > {(() => { const row = rows.find(r => r.id === selectedRowId); if (!row) return null; return (

{row.fullText}

{Object.keys(row.results).map(fieldName => ( {fieldName} ))}
); })()}
``` **6. Toolbar统计** ```typescript const conflictCount = rows.filter(r => r.status === 'conflict').length; const resolvedCount = rows.filter(r => r.status === 'resolved').length; const cleanCount = rows.filter(r => r.status === 'clean').length;
总数? {rows.length}
{conflictCount > 0 ? (
{conflictCount} 条冲突待裁决
) : (
所有冲突已解决
)}
``` --- ### 6.2 验收标准 **数据加载**?- [ ] 成功获取验证数据 - [ ] 表格列根据模板动态生?- [ ] 分页功能正常 **冲突单元?*?- [ ] 冲突单元格显示A/B两个按钮 - [ ] 按钮显示正确的值和模型标识(DS/QW?- [ ] 点击按钮后采纳?- [ ] UI乐观更新(立即生效) - [ ] API调用成功 **侧边?*?- [ ] 点击行时侧边栏滑?- [ ] 显示完整病历原文 - [ ] 显示字段标签(冲突字段高亮) - [ ] 点击关闭按钮或外部区域关闭侧边栏 **Toolbar**?- [ ] 冲突数统计正?- [ ] 实时更新(裁决后减少?- [ ] 导出按钮可点?- [ ] 完成按钮跳转到Step 5 --- ## 📦 七、Phase 5: Tool B - Step 5(Day 5上午? ### 7.1 结果导出?小时? #### 7.1.1 页面设计 **组件**:`pages/tool-b/Step5Result.tsx` **UI参?*:原型V4?72-607? **布局**?1. 完成图标和标?2. 统计卡片?个) 3. 操作按钮(下载、流转) --- #### 7.1.2 功能实现 **1. 统计数据获取** ```typescript const [stats, setStats] = useState({ totalCount: 0, cleanCount: 0, conflictCount: 0, failedCount: 0, totalTokens: 0, totalCost: 0, }); useEffect(() => { fetch(`/api/v1/dc/tool-b/tasks/${taskId}/progress`) .then(res => res.json()) .then(data => setStats(data.data)); }, [taskId]); ``` **2. Excel导出** ```typescript const handleExport = async () => { try { const response = await fetch(`/api/v1/dc/tool-b/tasks/${taskId}/export`, { method: 'POST' }); const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `extraction_result_${taskId}.xlsx`; a.click(); message.success('导出成功'); } catch (error) { message.error('导出失败'); } }; ``` **3. 流转到工具C** ```typescript const handleGoToToolC = () => { // 跳转到工具C,传递taskId navigate(`/data-cleaning/tool-c?sourceTaskId=${taskId}`); }; ``` --- ### 7.2 验收标准 - [ ] 统计卡片数据正确显示 - [ ] Token消耗和成本计算正确 - [ ] 下载按钮触发Excel导出 - [ ] Excel文件包含4个Sheet(完整结果、无冲突、冲突项、失败项?- [ ] 流转到工具C按钮可点击(提示暂未开发) - [ ] 返回Portal按钮可点? --- ## 🧪 八、Phase 6: 集成测试(Day 5下午? ### 8.1 端到端测试清? #### 8.1.1 完整流程测试 **测试场景**:肺癌病理报告提? **测试步骤**?1. [ ] 访问Portal页面(`/data-cleaning`?2. [ ] 点击Tool B卡片,跳转到Step 1 3. [ ] 上传测试Excel文件(包含病理报告列?4. [ ] 选择"病理报告"列,触发健康检?5. [ ] 验证健康度显示为"绿色 - 优秀" 6. [ ] 进入Step 2,选择"肺癌 + 病理报告" 7. [ ] 验证字段自动加载?个字段) 8. [ ] 编辑一个字段(修改描述?9. [ ] 进入Step 3,点?开始提? 10. [ ] 验证进度条开始更?11. [ ] 验证日志滚动显示 12. [ ] 等待任务完成(或模拟完成?13. [ ] 自动跳转到Step 4 14. [ ] 验证验证网格加载数据 15. [ ] 找到一个冲突单元格,点?DS"按钮采纳 16. [ ] 验证冲突数减1 17. [ ] 点击某行,验证侧边栏显示原文 18. [ ] 点击"完成并入?,跳转到Step 5 19. [ ] 验证统计卡片数据正确 20. [ ] 点击"下载",验证Excel下载成功 --- #### 8.1.2 异常场景测试 **测试场景1:健康检查失?* - [ ] 上传Excel,选择空值率>50%的列 - [ ] 验证健康度显示为"红色 - 警告" - [ ] 验证"下一?按钮被禁? **测试场景2:任务失?* - [ ] 模拟API返回失败状?- [ ] 验证错误提示显示 - [ ] 验证可以重新尝试 **测试场景3:网络错?* - [ ] 断网后点?下一? - [ ] 验证错误提示显示 - [ ] 重新联网后可继续 --- ### 8.2 性能测试 **测试场景**:大数据量验证网? **测试步骤**?1. [ ] 加载500行数?2. [ ] 验证表格滚动流畅(无卡顿?3. [ ] 验证分页功能正常 4. [ ] 验证排序/筛选功能(如实现) **性能指标**?- [ ] 首屏加载时间 < 2?- [ ] 表格滚动帧率 > 30fps - [ ] 裁决操作响应时间 < 500ms --- ### 8.3 兼容性测? **浏览?*?- [ ] Chrome 120+ - [ ] Edge 120+ - [ ] Firefox 120+ - [ ] Safari 17+(Mac? **分辨?*?- [ ] 1920x1080(常规) - [ ] 1440x900(笔记本?- [ ] 2560x1440(高分屏? --- ## 📝 九、文档完善(Day 6? ### 9.1 开发文? **需要补充的文档**?1. [ ] **前端代码结构说明**(`docs/03-业务模块/DC-数据清洗整理/02-技术设?前端架构设计.md`?2. [ ] **组件使用文档**(`frontend-v2/src/modules/dc/README.md`?3. [ ] **API对接文档**(补充到现有API设计文档?4. [ ] **本开发计划的完成总结**(`docs/03-业务模块/DC-数据清洗整理/06-开发记?Tool-B开发完成总结.md`? --- ### 9.2 用户文档(可选) **需要创建的文档**?1. [ ] **Tool B使用指南**(`docs/03-业务模块/DC-数据清洗整理/07-用户手册/Tool-B使用指南.md`?2. [ ] **常见问题FAQ**(`docs/03-业务模块/DC-数据清洗整理/07-用户手册/FAQ.md`? --- ## 🎯 十、关键技术要? ### 10.1 必须遵守的规? #### 云原生规??强制 参考:`docs/04-开发规?08-云原生开发规?md` **禁止**?- ?使用`fs.writeFile()`等本地文件操?- ?使用全局变量缓存数据 - ?硬编码配置(IP、密钥等?- ?同步长任务(>10秒) - ?重复实现平台能力 **必须**?- ?使用`storage`服务存储文件 - ?使用`cache`服务缓存数据 - ?使用环境变量配置 - ?异步任务 + 进度轮询 - ?复用平台基础设施 --- ### 10.2 复用策略 #### 后端复用(参考) ```typescript // ?正确:复用平台能?import { storage } from '@/common/storage'; import { logger } from '@/common/logging'; import { cache } from '@/common/cache'; import { LLMFactory } from '@/common/llm/adapters/LLMFactory'; ``` #### 前端复用(需实现?```typescript // 复用ASL模块的组件和Hook import { usePolling } from '@/shared/hooks/usePolling'; import { FileUploader } from '@/shared/components/FileUploader'; import { ProgressBar } from '@/shared/components/ProgressBar'; ``` --- ### 10.3 状态管? **推荐方案**:React Query(ASL模块使用? ```typescript // 使用React Query管理API调用 import { useQuery, useMutation } from '@tanstack/react-query'; // 获取任务进度 const { data: progress } = useQuery({ queryKey: ['task-progress', taskId], queryFn: () => fetch(`/api/v1/dc/tool-b/tasks/${taskId}/progress`).then(res => res.json()), refetchInterval: 5000, // ?秒轮? enabled: !!taskId && status === 'processing', }); // 裁决冲突 const resolveMutation = useMutation({ mutationFn: ({ itemId, resolvedData }) => fetch(`/api/v1/dc/tool-b/items/${itemId}/resolve`, { method: 'POST', body: JSON.stringify({ resolvedData }), }), onSuccess: () => { queryClient.invalidateQueries(['task-items', taskId]); message.success('裁决成功'); }, }); ``` --- ### 10.4 TypeScript类型定义 **统一类型文件**:`frontend-v2/src/modules/dc/types/toolB.ts` ```typescript // 健康检查结?export interface HealthCheckResult { status: 'good' | 'bad'; emptyRate: number; avgLength: number; totalRows: number; estimatedTokens: number; message: string; } // 模板定义 export interface Template { id: string; diseaseType: string; reportType: string; displayName: string; fields: Field[]; } export interface Field { id: string; name: string; desc: string; width?: string; } // 任务状?export interface Task { id: string; projectName: string; status: 'pending' | 'processing' | 'completed' | 'failed'; totalCount: number; processedCount: number; cleanCount: number; conflictCount: number; failedCount: number; totalTokens: number; totalCost: number; } // 验证?export interface VerifyRow { id: string; rowIndex: number; originalText: string; fullText: string; results: Record; status: 'clean' | 'conflict' | 'resolved'; conflictFields: string[]; } ``` --- ## 📊 十一、风险评估与应对 ### 11.1 技术风? | 风险 | 概率 | 影响 | 应对措施 | |------|------|------|---------| | **数据库表未创?* | ?| ?| 立即执行`npx prisma db push`验证 | | **后端API未测?* | ?| ?| 开发前先用REST Client测试6个端?| | **性能问题(大数据量)** | ?| ?| 预留TanStack Table迁移方案 | | **Excel解析失败** | ?| ?| 使用xlsx库,增加错误处理 | | **LLM调用超时** | ?| ?| 后端已实现重试机?| --- ### 11.2 时间风险 | 风险 | 概率 | 影响 | 应对措施 | |------|------|------|---------| | **Step 4开发超?* | ?| ?| 预留2天(9小时),可拆分子任务 | | **集成测试发现问题** | ?| ?| 预留1天缓冲时?| | **原型与需求不?* | ?| ?| 开发前与产品确认原?| --- ### 11.3 依赖风险 | 风险 | 概率 | 影响 | 应对措施 | |------|------|------|---------| | **后端API变更** | ?| ?| 使用TypeScript类型,编译时检?| | **平台能力Bug** | ?| ?| 已完整测试,风险?| | **设计变更** | ?| ?| 组件化设计,易于修改 | --- ## 🎉 十二、预期成? ### 12.1 交付物清? **代码**?- [ ] Portal工作台页面(完整?- [ ] Tool B 5个Step页面(完整) - [ ] 共享组件库(TaskList、AssetLibrary、ConflictCell等) - [ ] API服务封装(toolBApi.ts、portalApi.ts?- [ ] TypeScript类型定义(完整) - [ ] 样式文件(TailwindCSS + Ant Design? **文档**?- [ ] 前端架构设计文档 - [ ] 组件使用文档 - [ ] API对接文档 - [ ] 开发完成总结 - [ ] 用户使用指南(可选) **测试**?- [ ] 端到端测试报?- [ ] 性能测试报告 - [ ] 兼容性测试报? --- ### 12.2 功能完整? **Portal工作?*?- ?3个工具卡片(Tool B可用?- ?最近任务列表(实时轮询?- ?数据资产库(Tab切换? **Tool B - 病历结构化机器人**?- ?Step 1: Excel上传 + 健康检?- ?Step 2: 智能模板配置?个预设模板) - ?Step 3: 双盲提取进度监控 - ?Step 4: 冲突验证网格(支持裁决) - ?Step 5: 结果导出(Excel + 流转? --- ### 12.3 代码质量 **代码规范**?- ?遵守云原生开发规?- ?TypeScript类型安全 - ?ESLint无错?- ?代码注释完善 **性能指标**?- ?首屏加载 < 2s - ?表格滚动流畅 - ?裁决响应 < 500ms - ?内存占用 < 200MB **用户体验**?- ?流畅?步流?- ?实时进度反馈 - ?直观的冲突验证界?- ?友好的错误提? --- ## 🚀 十三、下一步行? ### 13.1 立即执行(Day 0? **1. 验证数据库表** ```bash cd AIclinicalresearch/backend npx prisma db push --skip-generate npx prisma studio # 可视化验?``` **2. 测试后端API** ```bash # 启动后端服务 npm run dev # 使用REST Client测试6个API端点 # 或使用Postman/Insomnia ``` **3. Git提交计划** ```bash # 建议每完成一个Phase就提?git commit -m "feat(dc): Complete Portal page (Phase 1)" git commit -m "feat(dc/tool-b): Complete Step1&2 (Phase 2)" git commit -m "feat(dc/tool-b): Complete Step4 conflict grid (Phase 4)" ``` --- ### 13.2 开发启动(Day 1? **任务1:创建Portal页面骨架** ```bash cd frontend-v2/src/modules/dc mkdir -p pages components hooks services types # 创建Portal.tsx touch pages/Portal.tsx # 创建路由配置 # 修改 index.tsx ``` **任务2:实?个工具卡?* ```bash # 创建ToolCard组件 touch components/ToolCard.tsx ``` **任务3:实现任务列表(使用Mock数据?* ```bash # 创建TaskList组件 touch components/TaskList.tsx # 创建useRecentTasks Hook touch hooks/useRecentTasks.ts ``` --- ### 13.3 持续跟进 **每日检查点**?- [ ] 代码是否Git提交 - [ ] Todo列表是否更新 - [ ] 遇到的问题是否记?- [ ] API调用是否正常 **每周检查点**?- [ ] 功能完成度是否符合预?- [ ] 是否需要调整计?- [ ] 是否需要额外资? --- ## 📞 十四、联系与支持 ### 14.1 技术支? **遇到问题?*?1. 查阅平台基础设施文档(`backend/src/common/README.md`?2. 查阅云原生开发规范(`docs/04-开发规?08-云原生开发规?md`?3. 参考ASL模块代码(`frontend-v2/src/modules/asl/`?4. 查看后端API代码(`backend/src/modules/dc/tool-b/`? ### 14.2 代码审查 **提交前自检**?- [ ] 是否遵守云原生规?- [ ] 是否复用平台能力 - [ ] TypeScript类型是否完整 - [ ] 是否有TODO/FIXME注释 - [ ] 是否有console.log(应使用logger? --- ## 🎯 十五、总结 ### 核心目标 完成DC模块Tool B的前端开发,实现从文件上传到结果导出的完?步流程,特别?*冲突验证网格**这一核心功能? ### 关键成功因素 1. ?**后端?00%完成**,前端可专注UI和交?2. ?**平台能力完善**,可直接复用,无需重复开?3. ?**设计文档齐全**,有清晰的原型和需?4. ?**参考模块成?*,ASL模块可作为参?5. ?**架构方案明确**,采用方案A(独立Portal? ### 预期收益 - **用户价?*:提供AI驱动的病历结构化能力,双模型交叉验证提高数据质量 - **技术价?*:完整的前端模块化架构,可复用组件库 - **商业价?*:Tool B可独立销售,满足医疗数据处理需? --- **开发计划制定完成!** ? **下一?*:验证数据库??测试后端API ?开始Phase 1(Portal页面开发) **预计完成时间**?-6个工作日 **祝开发顺利!** 🚀