Files
AIclinicalresearch/docs/03-业务模块/DC-数据清洗整理/04-开发计划/DC模块Tool-B开发计划.md
HaHafeng 1b53ab9d52 feat(aia): Complete AIA V2.0 with universal streaming capabilities
Major Changes:
- Add StreamingService with OpenAI Compatible format
- Upgrade Chat component V2 with Ant Design X integration
- Implement AIA module with 12 intelligent agents
- Update API routes to unified /api/v1 prefix
- Update system documentation

Backend (~1300 lines):
- common/streaming: OpenAI Compatible adapter
- modules/aia: 12 agents, conversation service, streaming integration
- Update route versions (RVW, PKB to v1)

Frontend (~3500 lines):
- modules/aia: AgentHub + ChatWorkspace (100% prototype restoration)
- shared/Chat: AIStreamChat, ThinkingBlock, useAIStream Hook
- Update API endpoints to v1

Documentation:
- AIA module status guide
- Universal capabilities catalog
- System overview updates
- All module documentation sync

Tested: Stream response verified, authentication working
Status: AIA V2.0 core completed (85%)
2026-01-14 19:15:01 +08:00

1353 lines
43 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
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.
# DC璅<E79285> Tool-B 撘<><E69298>𤏸恣<F0A48FB8>?
> **<2A><><EFBFBD><EFB99D>𧋦嚗?* V2.0 (MVP摰峕<E691B0>)
> **<2A>𥕦遣<F0A595A6><EFBFBD>嚗?* 2025-12-02
> **摰峕<E691B0><E5B395><EFBFBD>嚗?* 2025-12-03
> **摰鮋<E691B0><E9AE8B><EFBFBD>嚗?* 2銝芸極雿𨀣𠯫
> **<2A><EFBFBD><E59786><EFBFBD>** <20>?MVP摰峕<E691B0>
---
## <20><> MVP摰峕<E691B0><E5B395>𡁜<EFBFBD>嚗?025-12-03嚗?
**Tool B<><42><EFBFBD>蝏𤘪<E89D8F><F0A498AA>𡝗㦤<F0A19D97>其犖MVP<56><50>𧋦撌脣<E6928C><E884A3><EFBFBD>**
- <20>?<3F>滨垢5甇亙極雿𨀣<E99BBF>摰峕㟲摰䂿緵嚗ǚ1400銵䕘<E98AB5>
- <20>?8銝服PI蝡舐<E89DA1><E88890><EFBFBD>撖寞𦻖撟嗆<E6929F>霂閖<E99C82><EFBFBD>
- <20>?LLM<4C>峕芋<E5B395>𧢲<EFBFBD><F0A7A2B2><EFBFBD><EFBFBD><E99C82><EFBFBD><EFBFBD><EFBFBD>DeepSeek-V3 + Qwen-Max嚗?- <20>?<3F><EFBFBD><E7AC94>唳旿瘚贝<E7989A>嚗?<3F><EFBFBD><E288A0><EFBFBD>𥁒<EFBFBD>𦠜<EFBFBD><F0A6A09C>𡝗<EFBFBD><F0A19D97>?- <20>?Excel撖澆枂<E6BE86><EFBFBD><E8A098>舐鍂
- <20>𩤃<EFBFBD> 4銝芣<E98A9D><E88AA3><EFBFBD>箏𦛚敺<F0A69B9A><E695BA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>07-<2D><><EFBFBD><EFBFBD>箏𦛚/Tool-B<><42><EFBFBD><EFBFBD>箏𦛚皜<F0A69B9A><E79A9C>.md`嚗?
**摰峕<E691B0>霂行<E99C82>嚗?* <20><><EFBFBD> `06-撘<><E69298>𤏸扇敶?Tool-B-MVP摰峕<E691B0><E5B395><EFBFBD>-2025-12-03.md`
---
## <20><EFBFBD><EFBFBD><E69298>𤏸恣<F0A48FB8>?
> **<2A><EFBFBD>嚗?* 摰峕<E691B0>Tool-B嚗<42><E59A97><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>箏膥鈭綽<E988AD><E7B6BD><EFBFBD><EFBFBD>蝡臬<E89DA1><E887AC><EFBFBD>摰峕㟲<E5B395><EFBFBD><E8A098><EFBFBD><EFBFBD>
---
## <20><><><E98A9D><EFBFBD><EFBFBD><EFBFBD><E6A180>滨𠶖<E6BBA8><F0A0B696><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
### 1.1 <20>𡒊垢隞<E59EA2><E99A9E><EFBFBD><EFBFBD>?<3F>?100%摰峕<E691B0>
#### <20>𡁶鍂<F0A181B6><EFBFBD>撟喳蝱嚗<E89DB1>虾憭滨鍂嚗?<3F><EFBFBD> `backend/src/common/` 撟喳蝱<E596B3><EFBFBD>霈暹鴌嚗<E9B48C>歇摰峕㟲摰䂿緵嚗?
| <20><EFBFBD><E79285> | 撖澆<E69296>頝臬<E9A09D> | <20><EFBFBD>霂湔<E99C82> | <20><EFBFBD>?|
|---------|---------|---------|------|
| **摮睃<E691AE><E79D83>滚𦛚** | `@/common/storage` | <20><>辣銝𠹺<E98A9D>/銝贝蝸嚗𡿨ocal <20>?OSS嚗?| <20>?摰峕<E691B0> |
| **<EFBFBD><EFBFBD>蝟餌<EFBFBD>** | `@/common/logging` | 蝏𤘪<E89D8F><F0A498AA>𡝗𠯫敹梹<E695B9>Winston嚗?| <20>?摰峕<E691B0> |
| **蝻枏<E89DBB><E69E8F>滚𦛚** | `@/common/cache` | 蝻枏<E89DBB>嚗㇈emory <20>?Redis嚗?| <20>?摰峕<E691B0> |
| **撘<>郊隞餃𦛚** | `@/common/jobs` | <20>踵𧒄<E8B8B5>港遙<E6B8AF><EFBFBD><E28ABF>?| <20>?摰峕<E691B0> |
| **LLM撌亙<E6928C>** | `@/common/llm/adapters/LLMFactory` | 蝏煺<E89D8F>LLM靚<4D>鍂嚗㇄eepSeek/Qwen/GPT/Claude嚗?| <20>?摰峕<E691B0> |
| **<EFBFBD>唳旿摨?* | `@/config/database` | Prisma餈墧𦻖瘙?| <20>?摰峕<E691B0> |
**憭滨鍂蝑𣇉裦**嚗?- <20>?Tool B<>𡒊垢隞<E59EA2><E99A9E>撌?00%憭滨鍂撟喳蝱<E596B3><EFBFBD>
- <20>?<3F>滨垢撘<E59EA2><E69298><EFBFBD><E7A983><EFBFBD><EFBFBD><EFBFBD><EFBFBD>蝡舀芋撘𧶏<E69298>憭滨鍂<E6BBA8>滨垢<E6BBA8>曹澈蝏<E6BE88>
---
#### Tool B<>𡒊垢摰䂿緵<E482BF><EFBFBD>?
**隞<><E99A9E>雿滨蔭**嚗䫤backend/src/modules/dc/tool-b/`
| <20><>辣 | <20><EFBFBD> | 隞<><E99A9E><EFBFBD>?| <20><EFBFBD>?| 憭滨鍂<E6BBA8><EFBFBD> |
|-----|------|--------|------|---------|
| **services/HealthCheckService.ts** | Excel<65>亙熒璉<E78692><E79289>?| ~190銵?| <20>?摰峕<E691B0> | storage, logger, cache, prisma |
| **services/TemplateService.ts** | 憸<>挽璅⊥踎蝞∠<E89D9E> | ~243銵?| <20>?摰峕<E691B0> | logger, prisma |
| **services/DualModelExtractionService.ts** | <20>峕芋<E5B395>𧢲<EFBFBD><F0A7A2B2>?| ~390銵?| <20>?摰峕<E691B0> | LLMFactory, logger, prisma |
| **services/ConflictDetectionService.ts** | <20><EFBFBD><EFBFBD>瘚讠<E7989A>瘜?| ~215銵?| <20>?摰峕<E691B0> | logger |
| **controllers/ExtractionController.ts** | API<50><EFBFBD><E689B9>?| ~388銵?| <20>?摰峕<E691B0> | <20><EFBFBD><E588B8>滚𦛚 |
| **routes/index.ts** | 頝舐眏<E88890>滨蔭 | ~115銵?| <20>?摰峕<E691B0> | - |
| **index.ts** | 璅<E79285><E288AA>亙藁 | ~117銵?| <20>?摰峕<E691B0> | - |
**<2A>餉恣**嚗𡁶漲1,658銵䕘<E98AB5>7銝芣<E98A9D>隞塚<E99A9E>100%摰峕<E691B0>
---
#### API蝡舐<E89DA1><EFBFBD><E79A9C>
**Base URL**: `/api/v1/dc/tool-b`
| <20><EFBFBD> | 頝臬<E9A09D> | <20><EFBFBD> | 霂瑟<E99C82>雿?| <20><EFBFBD> | <20><EFBFBD>?|
|------|------|------|--------|------|------|
| **POST** | `/health-check` | Excel<65><EFBFBD>摨瑟<E691A8><E7919F>?| `{fileKey, columnName}` | <20>亙熒摨行𥁒<E8A18C>?| <20>?摰峕<E691B0> |
| **GET** | `/templates` | <20><EFBFBD><EFBFBD>挽璅⊥踎<E28AA5>𡑒” | - | 璅⊥踎<E28AA5><EFBFBD> | <20>?摰峕<E691B0> |
| **POST** | `/tasks` | <20>𥕦遣<F0A595A6>𣂼<EFBFBD>隞餃𦛚 | `{projectName, fileKey, textColumn, diseaseType, reportType}` | `{taskId}` | <20>?摰峕<E691B0> |
| **GET** | `/tasks/:taskId/progress` | <20>亥砭隞餃𦛚餈𥕦漲 | - | 餈𥕦漲霂行<E99C82> | <20>?摰峕<E691B0> |
| **GET** | `/tasks/:taskId/items` | <20><EFBFBD>撉諹<E69289>蝵烐聢<E78390>唳旿 | `?status=conflict&page=1` | <20><><EFBFBD>唳旿 | <20>?摰峕<E691B0> |
| **POST** | `/items/:itemId/resolve` | 鋆<><E98B86><EFBFBD><EFBFBD> | `{resolvedData}` | <20>𣂼<EFBFBD><F0A382BC><EFBFBD>?| <20>?摰峕<E691B0> |
**憸<>挽璅⊥踎**嚗?銝迎<E98A9D>嚗?1. <20><EFBFBD><E7AE87><EFBFBD><EFBFBD><EFBFBD><EFBFBD>嚗Ǒlung_cancer/pathology`嚗? 5銝芸<E98A9D>畾?2. 蝟硋倏<E7A18B><E5808F><EFBFBD><EFBFBD>扇敶𤏪<E695B6>`diabetes/admission`嚗? 5銝芸<E98A9D>畾?3. 擃䁅<E69383><E48185>钅秄霂羓<E99C82><E7BE93><EFBFBD><EFBFBD>`hypertension/outpatient`嚗? 5銝芸<E98A9D>畾?
---
### 1.2 <20>唳旿摨梶𠶖<E6A2B6>?<3F>?撌脤<E6928C><EFBFBD><E99C82><EFBFBD><EFBFBD>2025-12-02嚗?
**Schema**: `dc_schema`<EFBFBD>𡠺蝡钅<EFBFBD>蝳鳴<EFBFBD>
| 銵典<E98AB5> | <20><EFBFBD>?| 摮埈挾<E59F88>?| <20>喲睸摮埈挾 | <20><EFBFBD>?| <20>唳旿<E594B3>?|
|------|------|--------|---------|------|--------|
| **dc_health_checks** | <20>亙熒璉<E78692><E79289>亥扇敶?| 10 | status, emptyRate, avgLength | <20>?撌脣<E6928C>撱?| 2<>?|
| **dc_templates** | 憸<>挽璅⊥踎 | 7 | diseaseType, reportType, fields | <20>?撌脣<E6928C>撱?| **3<>?* |
| **dc_extraction_tasks** | <20>𣂼<EFBFBD>隞餃𦛚 | 21 | status, totalCount, processedCount | <20>?撌脣<E6928C>撱?| 1<>?|
| **dc_extraction_items** | <20>𣂼<EFBFBD><F0A382BC>𡒊<EFBFBD> | 15 | resultA, resultB, conflictFields | <20>?撌脣<E6928C>撱?| 4<>?|
**<EFBFBD>?撉諹<E69289>蝏𤘪<E89D8F>嚗?025-12-02嚗?*嚗?- <20>?**dc_schema撌脣<E6928C><E884A3>?*
- <20>?**4銝芾”<E88ABE><EFBFBD><E588B8>𥕦遣<F0A595A6>𣂼<EFBFBD>**
- <20>?**3銝芷<E98A9D>霈暹芋<E69AB9>踹歇<E8B8B9><EFBFBD><E598A5>?*嚗? 1. <20><EFBFBD><E7AE87><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (lung_cancer/pathology)
2. 蝟硋倏<E7A18B><E5808F><EFBFBD><EFBFBD>扇敶?(diabetes/admission)
3. 擃䁅<E69383><E48185>钅秄霂羓<E99C82><E7BE93>?(hypertension/outpatient)
- <20>?**<2A><EFBFBD>霂閙㺭<E99699>桀虾<E6A180><EFBFBD><EFBFBD><E69298>𤏸<EFBFBD>霂?*
**撉諹<E69289><E8ABB9>𡁏𧋦**嚗?```bash
cd backend
node scripts/check-dc-tables.mjs # <20><EFBFBD><E689AF>唳旿摨栞”璉<E2809D><E79289><EFBFBD><E4BAA5>?```
**蝏栞捏**嚗尠<E59A97> <20>唳旿摨枏<E691A8><E69E8F><EFBFBD><EFBFBD>停蝏迎<E89D8F><E8BF8E>臭誑撘<E8AA91>憪见<E686AA>蝡臬<E89DA1><E887AC>𡢅<EFBFBD>
---
### 1.3 <20>滨垢隞<E59EA2><E99A9E><EFBFBD><EFBFBD>?<3F>?0%嚗<><E59A97>Placeholder嚗?
**隞<><E99A9E>雿滨蔭**嚗䫤frontend-v2/src/modules/dc/`
```
frontend-v2/src/modules/dc/
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> index.tsx # <20>?隞<>laceholder嚗?4銵䕘<E98AB5>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> components/ # <20><> 蝛?<3F><EFBFBD><E98EBF><EFBFBD> pages/ # <20><> 蝛箸<E89D9B>隞嗅允蝏𤘪<E89D8F>
<EFBFBD>? <20><EFBFBD><E98EBF><EFBFBD> tool-a/ # <20><> 蝛?<3F>? <20><EFBFBD><E98EBF><EFBFBD> tool-b/ # <20><> 蝛?<3F>? <20><EFBFBD><E5A999><EFBFBD> tool-c/ # <20><> 蝛?<3F><EFBFBD><E5A999><EFBFBD> types/ # <20><> 蝛?```
**敶枏<E695B6><E69E8F><EFBFBD>捆**嚗?```typescript
// frontend-v2/src/modules/dc/index.tsx
import Placeholder from '@/shared/components/Placeholder'
const DCModule = () => {
return (
<Placeholder
title="<22>唳旿皜<E697BF><E79A9C><E79285>"
description="<22><EFBFBD><EFBFBD><E996AB>銝哨<E98A9D><EFBFBD><E692A0>靘𥟇惣<F0A59F87>賣㺭<E8B3A3><EFBFBD>瘣堒<E798A3><E5A092><EFBFBD>撌亙<E6928C>"
moduleName="DC - Data Cleaning"
/>
)
}
export default DCModule
```
---
### 1.4 <20>滨垢<E6BBA8><EFBFBD>霈曇恣 <20>?撌脫<E6928C>蝖?
#### 蝟餌<E89D9F>蝥扳沲<E689B3>?- **撖潸⏛璅<E79285>**嚗𡁻▲<F0A181BB>典紡<E585B8>?- **頝舐眏頝臬<E9A09D>**嚗䫤/data-cleaning`
- **<2A><><EFBFBD><EFBFBD>**嚗鑹eact 19 + TypeScript + Vite + Ant Design 5
#### DC璅<E79285><E288AA><EFBFBD><E59786><EFBFBD>
**<EFBFBD>㗇𥋘嚗𡁏䲮獢㇁ - <20><EFBFBD>Portal憿菟𢒰**嚗<><EFBFBD><EFBFBD>
```
/data-cleaning (Portal撌乩<E6928C><E4B9A9>?- <20><EFBFBD>憿?
<20><EFBFBD><E98EBF><EFBFBD> 敹恍<E695B9>笔鍳<E7AC94>典躹嚗?銝芸極<E88AB8>瑕㨃<E79195><E3A883><EFBFBD>
<20>? <20><EFBFBD><E98EBF><EFBFBD> [頞<><EFBFBD><E6BCA3><EFBFBD><20>?/data-cleaning/tool-a
<20>? <20><EFBFBD><E98EBF><EFBFBD> [<5B><><EFBFBD>蝏𤘪<E89D8F><F0A498AA>𨭐 <20>?/data-cleaning/tool-b
<20>? <20><EFBFBD><E5A999><EFBFBD> [<5B>唳旿蝻𤥁<E89DBB><F0A4A581><20>?/data-cleaning/tool-c
<20><EFBFBD><E98EBF><EFBFBD> <20><>餈睲遙<E79DB2><EFBFBD>銵剁<E98AB5>摰墧𧒄餈𥕦漲嚗? <20><EFBFBD><E5A999><EFBFBD> <20>唳旿韏<E697BF>漣摨橒<E691A8><E6A992><EFBFBD>辣蝞∠<E89D9E>嚗?
/data-cleaning/tool-b (Tool B - <20><EFBFBD>5甇交<E79487>蝔?
<20><EFBFBD><E98EBF><EFBFBD> Step 1: 銝𠹺<E98A9D>銝𤾸<E98A9D>摨瑟<E691A8><E7919F>? <20><EFBFBD><E98EBF><EFBFBD> Step 2: <20><EFBFBD>璅⊥踎<E28AA5>滨蔭
<20><EFBFBD><E98EBF><EFBFBD> Step 3: <20>𣬚𤩅<F0A3AC9A>𣂼<EFBFBD>餈𥕦漲
<20><EFBFBD><E98EBF><EFBFBD> Step 4: <20><EFBFBD>撉諹<E69289>蝵烐聢 潃?<3F><EFBFBD>
<20><EFBFBD><E5A999><EFBFBD> Step 5: 蝏𤘪<E89D8F>撖澆枂
```
**<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?*嚗?- ASL璅<E79285>嚗Ǒfrontend-v2/src/modules/asl/`嚗? - <20><EFBFBD><E58CA7><EFBFBD><EFBFBD><E692A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBCB5><EFBFBD>隞嗥<E99A9E><E597A5>? - 雿輻鍂React Router撋<72><E6928B>頝舐眏
- 撌虫儒撖潸⏛ + <20>喃儒<E59683><E58492><EFBFBD>?
---
## <20>㴓 鈭䎚<E988AD><E48E9A><EFBFBD><EFBFBD>𤏸恣<F0A48FB8><EFBFBD><EFBFBD>
### 2.1 撘<><E69298>煾𧫴畾萄<E795BE><E89084>?
| <20>嗆挾 | 隞餃𦛚 | 憸<>恣撌交𧒄 | 隡睃<E99AA1>蝥?| <20><EFBFBD> |
|------|------|---------|--------|------|
| **Phase 1** | Portal撌乩<E6928C><E4B9A9>圈△<E59C88>?| 4-6h | P0 | DC璅<E79285><E288AA>亙藁 |
| **Phase 2** | Tool B - Step 1&2 | 6h | P0 | 銝𠹺<E98A9D>+<2B>滨蔭 |
| **Phase 3** | Tool B - Step 3 | 3h | P0 | 餈𥕦漲<F0A595A6>烐綉 |
| **Phase 4** | Tool B - Step 4 | 9h | P0 | <20><EFBFBD>撉諹<E69289>蝵烐聢潃?|
| **Phase 5** | Tool B - Step 5 | 3h | P0 | 蝏𤘪<E89D8F>撖澆枂 |
| **Phase 6** | <20><><EFBFBD>瘚贝<E7989A> | 4h | P1 | 蝡臬<E89DA1>蝡舫<E89DA1>霂?|
**<2A>餉恣**嚗𡁶漲29-31撠𤩺𧒄嚗?-5銝芸極雿𨀣𠯫嚗?
---
### 2.2 <20>𣬚<EFBFBD>蝣烐𧒄<E78390>渲”
| <20>𣬚<EFBFBD>蝣?| 摰峕<E691B0><E5B395><EFBFBD><EFBFBD> | 憸<>恣摰峕<E691B0> |
|--------|---------|---------|
| **M1: Portal銝羓瑪** | <20><EFBFBD><E586BD>航挪<E888AA>唏C璅<E79285><E288AA>亙藁 | Day 1 |
| **M2: Tool B<>舐鍂** | Step1-5<><EFBFBD>摰峕<E691B0> | Day 4 |
| **M3: <20><><EFBFBD>瘚贝<E7989A><E8B49D><EFBFBD>** | 蝡臬<E89DA1>蝡舀<E89DA1>蝔𧢲<E89D94>霂閖<E99C82><EFBFBD> | Day 5 |
| **M4: <20><>﹝摰<EFB99D><E691B0>** | 撘<><E69298><EFBFBD><EFBFBD><E78DA2><EFBFBD><EFBFBD><E586BD><EFBFBD>﹝ | Day 6 |
---
## <20><> 銝剹<E98A9D><E589B9>hase 1: Portal撌乩<E6928C><E4B9A9><EFBFBD><E595A3>𡢅<EFBFBD>Day 1嚗?
### 3.1 <20><EFBFBD>
<EFBFBD>𥕦遣DC璅<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>蝟餌<EFBFBD>憿園<EFBFBD>撖潸⏛嚗峕<EFBFBD>靘𥕦極<EFBFBD>瑕鍳<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>辣蝞∠<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
### 3.2 霈曇恣<E69B87><E681A3><EFBFBD>?- **<2A><EFBFBD><E7AC94><EFBFBD>辣**嚗䫤docs/03-銝𡁜𦛚璅<E79285>/DC-<2D>唳旿皜<E697BF><E79A9C><EFBFBD><EFBFBD>/03-UI霈曇恣/<2F><EFBFBD><E7AE84>唳旿皜<E697BF><E79A9C>撌乩<E6928C><E4B9A9>訓2.html`
- **PRD<52><44>﹝**嚗䫤docs/03-銝𡁜𦛚璅<E79285>/DC-<2D>唳旿皜<E697BF><E79A9C><EFBFBD><EFBFBD>/01-<2D><><EFBFBD><E79899><EFBFBD>?PRD嚗𡁏惣<F0A1818F>賣㺭<E8B3A3><EFBFBD>瘣堒極雿𨅯蝱 (The Data Cleaning Portal).md`
### 3.3 <20><EFBFBD><EFBFBD><E79A9C>
#### 3.3.1 敹恍<E695B9>笔鍳<E7AC94>典躹嚗?銝芸極<E88AB8>瑕㨃<E79195><E3A883><EFBFBD>
**蝏<>辣**嚗䫤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;
}
```
**<2A><EFBFBD><E288A0><EFBFBD>捆**嚗?1. **Tool A - 頞<><EFBFBD><E6BCA3><EFBFBD>?*
- <20><EFBFBD>嚗鎄ileSpreadsheet嚗<74><E59A97><EFBFBD><EFBFBD>
- <20>讛膩嚗?閫<><E996AB>憭𡁏<E686AD><F0A1818F>唳旿<E594B3>園𡢿頧游笆朣鞾𠗕憸?
- <20><EFBFBD><E59786><EFBFBD>disabled嚗<64><E59A97><EFBFBD><EFBFBD><E88AB8>𡢅<EFBFBD>
2. **Tool B - <20><><EFBFBD>蝏𤘪<E89D8F><F0A498AA>𡝗㦤<F0A19D97>其犖** 潃?<3F>祆活撘<E6B4BB><E69298>? - <20><EFBFBD>嚗鋳ot嚗<74><EFBFBD><EFBFBD>
- <20>讛膩嚗?<3F>拍鍂憭扳芋<E689B3>𧢲<EFBFBD><F0A7A2B2><EFBFBD>蝏𤘪<E89D8F><F0A498AA>𡝗<EFBFBD><F0A19D97>?
- <20><EFBFBD><E59786><EFBFBD>ready
- <20>孵稬頝唾蓮嚗䫤/data-cleaning/tool-b`
3. **Tool C - 蝘𤑳<E89D98><F0A491B3>唳旿蝻𤥁<E89DBB><F0A4A581>?*
- <20><EFBFBD>嚗関able2嚗<32><EFBFBD><EFBFBD>
- <20>讛膩嚗?Excel憌擧聢<E693A7><E881A2>銁蝥踵<E89DA5>瘣堒極<E5A092>?
- <20><EFBFBD><E59786><EFBFBD>disabled嚗<64><E59A97><EFBFBD><EFBFBD><E88AB8>𡢅<EFBFBD>
---
#### 3.3.2 <20><>餈睲遙<E79DB2><EFBFBD>銵?**蝏<>辣**嚗䫤components/TaskList.tsx`
**API**嚗䫤GET /api/v1/dc/tasks/recent`嚗<><E59A97><EFBFBD>𡒊垢<F0A1928A><EFBFBD>嚗?
**<2A>唳旿蝏𤘪<E89D8F>**嚗?```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;
}
```
**<2A><EFBFBD>**嚗?- <20>曄內<E69B84><E585A7>餈?0<>∩遙<E288A9>?- 摰墧𧒄頧株砭餈𥕦漲嚗īrocessing<6E><EFBFBD><E59786>𧒄嚗峕<E59A97>5蝘坿蔭霂<E99C82>
- <20><EFBFBD><EFBFBD><EFBFBD>厰僼嚗? - Tool A摰峕<E691B0> <20>?[銝贝蝸] + [<5B>翠I<E7BFA0>𣂼<EFBFBD>]嚗<>歲Tool B嚗? - Tool B摰峕<E691B0> <20>?[銝贝蝸] + [<5B><EFBFBD>瘣㻩嚗<E3BBA9>歲Tool C嚗? - Tool C摰峕<E691B0> <20>?[銝贝蝸]
---
#### 3.3.3 <20>唳旿韏<E697BF>漣摨?**蝏<>辣**嚗䫤components/AssetLibrary.tsx`
**API**嚗䫤GET /api/v1/dc/assets`嚗<><E59A97><EFBFBD>𡒊垢<F0A1928A><EFBFBD>嚗?
**Tab<61><62>掩**嚗?- **<2A><EFBFBD>**嚗𡁏<E59A97><F0A1818F><EFBFBD>隞?- **憭<><E686AD>蝏𤘪<E89D8F>**嚗𡁜極<F0A1819C>嫂/B/C<><43><EFBFBD><EFBFBD><EFBFBD><EFBFBD>隞塚<E99A9E>蝏輯𠧧/<2F>肽𠧧<E882BD><EFBFBD>嚗?- **<2A><EFBFBD>銝𠹺<E98A9D>**嚗𡁶鍂<F0A181B6>瑞凒<E7919E><EFBFBD>隡删<E99AA1>摨閗”嚗<E2809D><E59A97><EFBFBD>脣㦛<E884A3><E3A69B><EFBFBD>
**<2A><EFBFBD>**嚗?- <20><><EFBFBD><EFBFBD><E288A0>曄內嚗<E585A7><E59A97>隞嗅<E99A9E><E59785><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E5959C><EFBFBD>蝑整<E89D91><E695B4><EFBFBD>寞𧒄<E5AF9E><EFBFBD>
- 敹急㭘<E680A5><EFBFBD>嚗靀銝贝蝸] [<5B><EFBFBD><E9A483><EFBFBD> [<5B><><EFBFBD>]
- 摨閖<E691A8><E99696><EFBFBD><E7AE8F>厰僼嚗靀+ 銝𠹺<E98A9D><F0A0B9BA><EFBFBD><E7AC94><EFBFBD><EFBFBD><EFBFBD>]
---
### 3.4 <20><><EFBFBD><EFBFBD><E887AC>?
#### 3.4.1 <20><EFBFBD>蝏𤘪<E89D8F>
```
frontend-v2/src/modules/dc/
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> pages/
<EFBFBD>? <20><EFBFBD><E5A999><EFBFBD> Portal.tsx # 潃?Portal銝駁△<E9A781>?<3F><EFBFBD><E98EBF><EFBFBD> components/
<EFBFBD>? <20><EFBFBD><E98EBF><EFBFBD> ToolCard.tsx # 撌亙<E6928C><E4BA99><EFBFBD>
<EFBFBD>? <20><EFBFBD><E98EBF><EFBFBD> TaskList.tsx # 隞餃𦛚<E9A483>𡑒”
<EFBFBD>? <20><EFBFBD><E5A999><EFBFBD> AssetLibrary.tsx # <20>唳旿韏<E697BF>漣摨?<3F><EFBFBD><E98EBF><EFBFBD> hooks/
<EFBFBD>? <20><EFBFBD><E98EBF><EFBFBD> useRecentTasks.ts # 隞餃𦛚<E9A483>𡑒”Hook
<EFBFBD>? <20><EFBFBD><E5A999><EFBFBD> useAssets.ts # 韏<><EFBFBD>𡑒”Hook
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> services/
<EFBFBD>? <20><EFBFBD><E5A999><EFBFBD> portalApi.ts # Portal API撠<49><E692A0>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> types/
<20><EFBFBD><E5A999><EFBFBD> portal.ts # Portal蝐餃<E89D90>摰帋<E691B0>
```
---
#### 3.4.2 頝舐眏<E88890>滨蔭
```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 (
<Routes>
<Route path="" element={<Portal />} />
<Route path="tool-b/*" element={<ToolBModule />} />
{/* <20>芣䔉<E88AA3><EFBFBD> */}
<Route path="tool-a/*" element={<ToolAPlaceholder />} />
<Route path="tool-c/*" element={<ToolCPlaceholder />} />
</Routes>
);
};
export default DCModule;
```
---
#### 3.4.3 API撖寞𦻖
**<2A><><EFBFBD><E996AC>蝡舀鰵憓䂿<E68693>API**嚗?```typescript
// GET /api/v1/dc/tasks/recent
interface GetRecentTasksResponse {
tasks: Task[];
}
// GET /api/v1/dc/assets
interface GetAssetsResponse {
assets: Asset[];
}
```
**銝湔𧒄<E6B994><EFBFBD>**嚗<><E59A97>蝡涉PI<50><EFBFBD><E88AB8>烐𧒄嚗㚁<E59A97>
- 雿輻鍂Mock<63>唳旿
- <20>𡒊賒<F0A1928A>踵揢銝箇<E98A9D>摰麫PI
---
### 3.5 撉峕𤣰<E5B395><F0A4A3B0><EFBFBD>
- [ ] Portal憿菟𢒰<E88F9F>航挪<E888AA><EFBFBD>`http://localhost:3000/data-cleaning`嚗?- [ ] 3銝芸極<E88AB8>瑕㨃<E79195><E3A883>迤蝖格遬蝷?- [ ] Tool B<><EFBFBD><E288A0><EFBFBD><E88890>餉歲頧穿<E9A0A7><E7A9BF><EFBFBD>銝支葵<E694AF>曄內disabled嚗?- [ ] 隞餃𦛚<E9A483>𡑒”<F0A19192>曄內Mock<63>唳旿
- [ ] <20>唳旿韏<E697BF>漣摨孏ab<61><62>揢甇<E68FA2>
- [ ] <20><EFBFBD><E6B8AF><EFBFBD>蝚血<E89D9A>蝟餌<E89D9F>霈曇恣閫<E681A3><E996AB>
---
## <20><>儭?<3F><EFBFBD><E49C98>hase 2: Tool B - Step 1&2嚗㇄ay 2嚗?
### 4.1 Step 1: <20><>辣銝𠹺<E98A9D>銝𤾸<E98A9D>摨瑟<E691A8><E7919F><EFBFBD>3撠𤩺𧒄嚗?
#### 4.1.1 憿菟𢒰霈曇恣
**蝏<>辣**嚗䫤pages/tool-b/Step1Upload.tsx`
**UI<55><49><EFBFBD>?*嚗𡁜<E59A97><F0A1819C>鰦4蝚?60-310銵?
**撣<><E692A3>**嚗?1. <20><>辣靽⊥<E99DBD><E28AA5><EFBFBD><EFBFBD>遬蝷箏歇銝𠹺<E98A9D><F0A0B9BA><EFBFBD>辣嚗?2. <20><EFBFBD>㗇𥋘銝𧢲<E98A9D>獢?3. <20>亙熒璉<E78692><E79289><EFBFBD><E4BAA6>𨅯㨃<F0A885AF><E3A883><EFBFBD><EFBFBD><EFBFBD><E586BD>遬蝷綽<E89DB7>
---
#### 4.1.2 <20><EFBFBD>摰䂿緵
**1. Excel<65><6C>辣銝𠹺<E98A9D>**
```typescript
// 雿輻鍂Ant Design Upload蝏<64>
import { Upload } from 'antd';
// 銝𠹺<E98A9D><F0A0B9BA>訕torage
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); // 靽嘥<E99DBD>fileKey<65><EFBFBD><E585B6>𡒊賒甇仿炊
};
```
**2. <20><EFBFBD>㗇𥋘銝𤾸<E98A9D>摨瑟<E691A8><E7919F>?*
```typescript
const [columns, setColumns] = useState<string[]>([]);
const [selectedColumn, setSelectedColumn] = useState('');
const [healthResult, setHealthResult] = useState<HealthCheckResult | null>(null);
// <20>芸𢆡璉<F0A286A1>瘚见<E7989A><E8A781><EFBFBD><E3B5AA><EFBFBD><EFBFBD>隞𤾸<E99A9E>蝡航繮<E888AA><EFBFBD>
useEffect(() => {
if (fileKey) {
// TODO: 靚<>鍂API<50><EFBFBD>Excel<65><EFBFBD>
// <20><EFBFBD>蝡航圾<E888AA>𨆼xcel嚗<6C><EFBFBD>肝lsx摨橒<E691A8>
}
}, [fileKey]);
// <20>亙熒璉<E78692><E79289>?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. <20>亙熒摨行遬蝷?*
```typescript
// <20>寞旿status<75>曄內銝滚<E98A9D><E6BB9A><EFBFBD>
{healthResult?.status === 'good' && (
<Alert
type="success"
icon={<CheckCircle2 />}
message="<22>亙熒摨虫<E691A8><EFBFBD>嚗屸<E59A97><E5B1B8><EFBFBD><EFBFBD>𣂼<EFBFBD>"
description={
<div className="mt-2">
<span><EFBFBD>: {healthResult.avgLength}</span>
<span className="ml-4"><EFBFBD><EFBFBD>: {(healthResult.emptyRate * 100).toFixed(1)}%</span>
<span className="ml-4 text-purple-600 font-bold">
<EFBFBD>Token: {healthResult.estimatedTokens.toLocaleString()}
</span>
</div>
}
/>
)}
{healthResult?.status === 'bad' && (
<Alert
type="error"
icon={<AlertTriangle />}
message="霅血<E99C85>嚗朞砲<E69C9E>𦯀<EFBFBD><F0A6AF80><EFBFBD><EFBFBD>AI憭<49><E686AD>"
description={healthResult.message}
/>
)}
```
---
### 4.2 Step 2: <20><EFBFBD>璅⊥踎<E28AA5>滨蔭嚗?撠𤩺𧒄嚗?
#### 4.2.1 憿菟𢒰霈曇恣
**蝏<>辣**嚗䫤pages/tool-b/Step2Schema.tsx`
**UI<55><49><EFBFBD>?*嚗𡁜<E59A97><F0A1819C>鰦4蝚?13-372銵?
**撣<><E692A3>**嚗?1. <20><EFBFBD>蝐餃<E89D90>銝擧𥁒<E693A7>羓掩<E7BE93><EFBFBD>㗇𥋘嚗<F0A58B98><EFBFBD><EFBFBD>
2. 摮埈挾<E59F88>𡑒”嚗<E2809D>椰靘改<E99D98><E694B9><EFBFBD>颲𡢅<E9A2B2>
3. Prompt憸<74><E686B8><EFBFBD>𢰧靘改<E99D98><EFBFBD><E99A9E>擃䀝漁嚗?
---
#### 4.2.2 <20><EFBFBD>摰䂿緵
**1. <20><EFBFBD>璅⊥踎<E28AA5>𡑒”**
```typescript
const [templates, setTemplates] = useState<Template[]>([]);
const [diseaseType, setDiseaseType] = useState('');
const [reportType, setReportType] = useState('');
const [fields, setFields] = useState<Field[]>([]);
useEffect(() => {
// <20><EFBFBD><E79195><EFBFBD><EFBFBD>㗇芋<E39787>? fetch('/api/v1/dc/tool-b/templates')
.then(res => res.json())
.then(data => setTemplates(data.data.templates));
}, []);
// 敶㯄<E695B6>㗇𥋘<E39787><EFBFBD>蝐餃<E89D90><E9A483>峕𥁒<E5B395>羓掩<E7BE93>𧢲𧒄嚗諹䌊<E8ABB9><EFBFBD>頧賢<E9A0A7>畾?useEffect(() => {
if (diseaseType && reportType) {
const template = templates.find(
t => t.diseaseType === diseaseType && t.reportType === reportType
);
if (template) {
setFields(template.fields);
}
}
}, [diseaseType, reportType, templates]);
```
**2. 摮埈挾蝻𤥁<E89DBB>**
```typescript
// 瘛餃<E7989B>摮埈挾
const handleAddField = () => {
setFields([...fields, {
id: `custom_${Date.now()}`,
name: '<27><EFBFBD>畾?,
desc: '摮埈挾<E59F88>讛膩',
width: 'w-32'
}]);
};
// <20>𣳇膄摮埈挾
const handleDeleteField = (id: string) => {
setFields(fields.filter(f => f.id !== id));
};
// 蝻𤥁<E89DBB>摮埈挾
const handleEditField = (id: string, key: 'name' | 'desc', value: string) => {
setFields(fields.map(f =>
f.id === id ? { ...f, [key]: value } : f
));
};
```
**3. Prompt憸<74><E686B8>**
```typescript
// <20><EFBFBD><E586BD><EFBFBD><EFBFBD>辥rompt憸<74><E686B8>
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.`;
};
// 雿輻鍂隞<E98D82><E99A9E>擃䀝漁摨橒<E691A8><EFBFBD>eact-syntax-highlighter嚗?<SyntaxHighlighter language="javascript" style={atomOneDark}>
{generatePrompt()}
</SyntaxHighlighter>
```
---
### 4.3 撉峕𤣰<E5B395><F0A4A3B0><EFBFBD>
**Step 1:**
- [ ] Excel銝𠹺<E98A9D><F0A0B9BA>𣂼<EFBFBD>嚗諹繮<E8ABB9>餻ileKey
- [ ] <20><EFBFBD><E5A092>𡑒”甇<E2809D><EFBFBD>曄內
- [ ] <20>亙熒璉<E78692><E79289>丕PI靚<49><EFBFBD>𣂼<EFBFBD>
- [ ] <20>亙熒摨血㨃<E8A180><E3A883><EFBFBD><EFBFBD><E6A183>𨀣迤蝖格遬蝷綽<E89DB7>蝏輯𠧧/蝥Z𠧧嚗?- [ ] Token憸<6E><EFBFBD><EFBFBD>潭迤蝖?- [ ] 蝛箏<E89D9B><EFBFBD>>50%<25><EFBFBD><E79487><EFBCBA><EFBFBD><EFBFBD>甇?
**Step 2:**
- [ ] 璅⊥踎<E28AA5>𡑒”<F0A19192>㰘蝸<E3B098>𣂼<EFBFBD>
- [ ] <20><EFBFBD>蝐餃<E89D90><E9A483>峕𥁒<E5B395>羓掩<E7BE93><EFBFBD>㗇𥋘獢<F0A58B98>迤撣?- [ ] <20>㗇𥋘璅⊥踎<E28AA5>𤾸<EFBFBD>畾菔䌊<E88F94><EFBFBD>頧?- [ ] 摮埈挾<E59F88><EFBFBD>瘛餃<E7989B>/<2F>𣳇膄/蝻𤥁<E89DBB>
- [ ] Prompt憸<74><E686B8>摰墧𧒄<E5A2A7>湔鰵
- [ ] 隞<><E99A9E>擃䀝漁甇<E6BC81><EFBFBD>曄內
---
## <20><EFBFBD> 鈭𢛵<E988AD><F0A29BB5>hase 3: Tool B - Step 3嚗㇄ay 3銝𠰴<E98A9D>嚗?
### 5.1 憭<><E686AD>餈𥕦漲<F0A595A6>烐綉嚗?撠𤩺𧒄嚗?
#### 5.1.1 憿菟𢒰霈曇恣
**蝏<>辣**嚗䫤pages/tool-b/Step3Processing.tsx`
**UI<55><49><EFBFBD>?*嚗𡁜<E59A97><F0A1819C>鰦4蝚?75-400銵?
**撣<><E692A3>**嚗?1. <20><>耦餈𥕦漲<F0A595A6><EFBFBD><E88D94>峕芋<E5B395>见𢆡<E8A781><EFBFBD>
2. 餈𥕦漲<F0A595A6><EFBFBD>瘥𥪜<E798A5><F0A5AA9C><EFBFBD>𧋦
3. <20><EFBFBD>皛𡁜𢆡<F0A1819C><EFBFBD>
---
#### 5.1.2 <20><EFBFBD>摰䂿緵
**1. <20>𥕦遣隞餃𦛚**
```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); // <20><EFBFBD>瘥? setLogs(prevLogs => [...prevLogs, data.latestLog]); // <20><EFBFBD><E595A3><EFBFBD>
if (data.status === 'completed') {
clearInterval(interval);
// 頝唾蓮<E594BE>訕tep 4
setTimeout(() => navigate(`/data-cleaning/tool-b/verify/${taskId}`), 800);
} else if (data.status === 'failed') {
clearInterval(interval);
message.error('<27>𣂼<EFBFBD>隞餃𦛚憭梯揖');
}
}, 5000); // 瘥?蝘坿蔭霂?
return () => clearInterval(interval);
};
```
**3. 餈𥕦漲<F0A595A6>函𤫇**
```typescript
// 雿輻鍂Ant Design Progress蝏<73><EFBFBD>𤥁䌊摰帋<E691B0>SVG
<Progress
type="circle"
percent={progress}
format={percent => (
<div>
<div className="text-2xl font-bold">{percent}%</div>
<div className="text-sm text-gray-500"><EFBFBD>𣬚𤩅<EFBFBD>𣂼<EFBFBD>?/div>
</div>
)}
strokeColor={{
'0%': '#9333ea',
'100%': '#4f46e5'
}}
/>
// <20>峕芋<E5B395>见𢆡<E8A781><EFBFBD>銝支葵撠讐<E692A0>頝喳𢆡嚗?<div className="flex gap-2">
<div className="w-3 h-3 bg-blue-500 rounded-full animate-bounce" />
<div className="w-3 h-3 bg-orange-500 rounded-full animate-bounce delay-200" />
</div>
```
**4. <20><EFBFBD><E4BA99>曄內**
```typescript
<div className="h-40 overflow-y-auto bg-slate-50 p-4 rounded font-mono text-xs">
{logs.map((log, i) => (
<div key={i} className="mb-1 text-slate-600">
<span className="text-slate-400">[{log.timestamp}]</span> {log.message}
</div>
))}
<div className="animate-pulse text-purple-500">_</div>
</div>
```
---
### 5.2 撉峕𤣰<E5B395><F0A4A3B0><EFBFBD>
- [ ] <20>孵稬"撘<>憪𧢲<E686AA><F0A7A2B2>?<3F><EFBFBD><E693A7><EFBFBD>撱箔遙<E7AE94>?- [ ] <20><EFBFBD><E79195>配askId
- [ ] 餈𥕦漲頧株砭甇<E7A0AD>虜嚗<E8999C><E59A97>5蝘𡜐<E89D98>
- [ ] 餈𥕦漲<F0A595A6><EFBFBD><E288AA>嗆凒<E59786>?- [ ] <20><EFBFBD>皛𡁜𢆡<F0A1819C><EFBFBD><EFBFBD><EFBFBD>曄內
- [ ] 隞餃𦛚摰峕<E691B0><E5B395>舘䌊<E88898>刻歲頧砍<E9A0A7>Step 4
- [ ] 隞餃𦛚憭梯揖<E6A2AF>嗆遬蝷粹<E89DB7>霂舀<E99C82>蝷?
---
## <20><20><EFBFBD><E58786>hase 4: Tool B - Step 4嚗㇄ay 3銝见<E98A9D>+Day 4嚗争<E59A97> <20><EFBFBD>
### 6.1 <20><EFBFBD>撉諹<E69289>蝵烐聢嚗?撠𤩺𧒄嚗?
餈蹱糓<EFBFBD>港葵Tool B<><42>憭齿<E686AD><E9BDBF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E8A9A8><EFBFBD><EFBFBD><EFBFBD>
#### 6.1.1 憿菟𢒰霈曇恣
**蝏<>辣**嚗䫤pages/tool-b/Step4Verify.tsx`
**UI<55><49><EFBFBD>?*嚗𡁜<E59A97><F0A1819C>鰦4蝚?02-569銵?
**撣<><E692A3>**嚗?```
<EFBFBD>𢞖<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>?Toolbar: 蝏蠘恣靽⊥<E99DBD> + [撖澆枂][摰峕<E691B0>] <20>?<3F><EFBFBD><E98EBF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>? <20>?<3F>? <20>冽艶撉諹<E69289>蝵烐聢嚗<E881A2><EFBFBD><EFBFBD> <20>?<3F>? <20>𢞖<EFBFBD><F0A29E96><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E7A082><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E7A082><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E7A082><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E7A082><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>? <20>?<3F>? <20>?# <20>?<3F><><EFBFBD><EFBFBD><EFBFBD> <20>?摮埈挾1 <20>?摮埈挾2 <20>?<3F><EFBFBD>?<3F>? <20>?<3F>? <20><EFBFBD><E98EBF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E6BD91><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E6BD91><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E6BD91><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E6BD91><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>? <20>?<3F>? <20>?1 <20>?<3F><><EFBFBD>霂𦠜鱏.. <20>?<3F><EFBFBD><E884A9><EFBFBD><E8A8AB><EFBFBD>A/B<>厰僼嚗争<E59A97><EFBFBD><E695BA><EFBFBD><EFBFBD> <20>?<3F>? <20>?2 <20>?<3F><><EFBFBD><EFBFBD><E89D8F>.. <20>?蝏輯𠧧嚗<F0A0A7A7><E59A97><EFBFBD><EFBFBD><E6B99B>?蝏輯𠧧 <20>?<3F><EFBFBD> <20>? <20>?<3F>? <20><EFBFBD><E5A999><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E6B0AF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E6B0AF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E6B0AF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E6B0AF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>? <20>?<3F>? <20>?<3F><EFBFBD><E5A999><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>? <20>?<3F>孵稬銵?<3F>𢞖<EFBFBD><F0A29E96><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>?靘扯器<E689AF>𧶏<EFBFBD>Drawer嚗? <20>?<3F>?<3F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>?<3F>?<3F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>霂行<E99C82> <20>?<3F>? <20>?<3F>?<3F><><EFBFBD>霂𦠜鱏嚗?<3F><EFBFBD>銝𠰴蠏)瘚豢隋<E8B1A2><EFBFBD><E689AF>?.. <20>?<3F>?<3F>輻𠈔憭批<E686AD> 3.2*2.5*2.0cm... <20>?<3F>?... <20>?<3F>? <20>?<3F>?[<5B>喲𡡒] <20>?<3F><EFBFBD><E5A999><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?```
---
#### 6.1.2 <20><><EFBFBD><EFBFBD><EFBFBD>
**<2A><EFBFBD><E5AF9E>㗇𥋘**嚗?
**Option 1: Ant Design Table**嚗<><EFBFBD><EFBFBD><E7909C>唳旿<E594B3>?1000銵䕘<E98AB5>
- 隡条<E99AA1>嚗𡁜<E59A97>蝞勗朖<E58B97><EFBFBD>API<50>见末嚗峕甅撘讐<E69298><EFBFBD>
- 蝻箇<E89DBB>嚗𡁏㺭<F0A1818F><EFBFBD>憭扳𧒄<E689B3><EFBFBD><E888AA>⊿▼
- <20><><EFBFBD>箸艶嚗𡁜之<F0A1819C><EFBFBD><E585B8>箸艶嚗<E889B6><E59A97>霈⊥㺭<E28AA5><EFBFBD><500銵䕘<E98AB5>
**Option 2: TanStack Table**嚗<><E59A97><EFBFBD><EFBFBD>嚗峕㺭<E5B395><EFBFBD>>1000銵䕘<E98AB5>
- 隡条<E99AA1>嚗朞<E59A97><E69C9E><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E58981><EFBFBD><E689AF><EFBFBD>
- 蝻箇<E89DBB>嚗䥅eadless<73><73><EFBFBD>芸楛摰䂿緵UI
- <20><><EFBFBD>箸艶嚗𡁜<E59A97><F0A1819C><EFBFBD><EFBFBD>唳旿<E594B3>?
**<2A><EFBFBD>**嚗𡁜<E59A97><F0A1819C>杗nt Design Table嚗<65><E59A97><EFBFBD><EFBFBD>銝滢蔔<E6BBA2><EFBFBD>蝘餃<E89D98>TanStack Table
---
#### 6.1.3 <20><EFBFBD><E8A9A8>唳旿蝏𤘪<E89D8F>
```typescript
interface VerifyRow {
id: string;
rowIndex: number;
originalText: string; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E59A97>50摮梹<E691AE>
fullText: string; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>儒颲寞<E9A2B2><E5AF9E>曄內嚗? results: Record<string, {
A: string; // DeepSeek蝏𤘪<E89D8F>
B: string; // Qwen蝏𤘪<E89D8F>
chosen: string | null; // <20><EFBFBD><E586BD><EFBFBD><EFBFBD><E78699><EFBFBD><EFBFBD>null=<3D>芾圾<E88ABE><EFBFBD>
}>;
status: 'clean' | 'conflict' | 'resolved';
conflictFields: string[]; // <20><EFBFBD>摮埈挾<E59F88>滨妍<E6BBA8>𡑒”
}
```
---
#### 6.1.4 <20><EFBFBD>摰䂿緵
**1. <20><EFBFBD>撉諹<E69289><E8ABB9>唳旿**
```typescript
const [rows, setRows] = useState<VerifyRow[]>([]);
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. 銵冽聢<E586BD><EFBFBD>蝵?*
```typescript
const columns: ColumnsType<VerifyRow> = [
{
title: '#',
dataIndex: 'rowIndex',
width: 60,
fixed: 'left',
},
{
title: '<27><><EFBFBD><EFBFBD><EFBFBD>',
dataIndex: 'originalText',
width: 200,
render: (text, record) => (
<div className="flex items-center gap-2">
<FileText size={14} className="text-slate-300" />
<Tooltip title={text}>
<span className="truncate w-40">{text}</span>
</Tooltip>
</div>
),
},
// <20><EFBFBD><E586BD><EFBFBD>畾萄<E795BE><EFBFBD><EFBFBD>格芋<E6A0BC><EFBFBD><E8BCBB><EFBFBD>
...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 <ConflictCell
fieldName={field.name}
valueA={cellData.A}
valueB={cellData.B}
onAdopt={(value) => handleAdopt(record.id, field.name, value)}
/>;
}
return <CleanCell value={cellData.chosen || cellData.A} />;
},
})),
{
title: '<27><EFBFBD>?,
dataIndex: 'status',
width: 100,
fixed: 'right',
render: (status) => {
if (status === 'clean' || status === 'resolved') {
return <Tag color="success"><3E><EFBFBD></Tag>;
}
return <Tag color="warning" className="animate-pulse">敺<><E695BA><EFBFBD>?/Tag>;
},
},
];
```
**3. <20><EFBFBD><E884A9><EFBFBD><E8A8AB><EFBFBD>隞?* 潃?<3F><EFBFBD>
```typescript
// components/ConflictCell.tsx
interface ConflictCellProps {
fieldName: string;
valueA: string;
valueB: string;
onAdopt: (value: string) => void;
}
const ConflictCell: React.FC<ConflictCellProps> = ({ fieldName, valueA, valueB, onAdopt }) => {
return (
<div className="flex flex-col gap-1.5 bg-orange-50 p-2 rounded">
{/* <20>厰★A - DeepSeek */}
<button
className="text-left text-xs px-2 py-1.5 rounded border border-blue-200 bg-white hover:bg-blue-50 hover:border-blue-400 transition-all flex justify-between group"
onClick={() => onAdopt(valueA)}
>
<Tooltip title={valueA}>
<span className="truncate max-w-[100px]">{valueA}</span>
</Tooltip>
<Badge className="text-[10px] text-blue-400 group-hover:text-blue-600">DS</Badge>
</button>
{/* <20>厰★B - Qwen */}
<button
className="text-left text-xs px-2 py-1.5 rounded border border-orange-200 bg-white hover:bg-orange-50 hover:border-orange-400 transition-all flex justify-between group"
onClick={() => onAdopt(valueB)}
>
<Tooltip title={valueB}>
<span className="truncate max-w-[100px]">{valueB}</span>
</Tooltip>
<Badge className="text-[10px] text-orange-400 group-hover:text-orange-600">QW</Badge>
</button>
</div>
);
};
```
**4. 鋆<><E98B86><EFBFBD><EFBFBD>**
```typescript
const handleAdopt = async (itemId: string, fieldName: string, value: string) => {
// 銋鞱<E98A8B><E99EB1>湔鰵UI
setRows(prevRows =>
prevRows.map(row => {
if (row.id !== itemId) return row;
const newResults = { ...row.results };
newResults[fieldName].chosen = value;
// 璉<><E79289>亥砲銵峕糓<E5B395>西<EFBFBD><E8A5BF>㗇𧊋閫<F0A78A8B><E996AB><EFBFBD><EFBFBD><EFBFBD>蝒? 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('鋆<><E98B86>憭梯揖');
// <20><EFBFBD>UI
// TODO: 摰䂿緵<E482BF><EFBFBD><E5A2A7><EFBFBD>
}
};
```
**5. 靘扯器<E689AF><EFBFBD><E8AAA9><EFBFBD>遬蝷?*
```typescript
const [selectedRowId, setSelectedRowId] = useState<string | null>(null);
// <20>孵稬銵峕𧒄<E5B395><EFBFBD>靘扯器<E689AF>?const onRow = (record: VerifyRow) => ({
onClick: () => setSelectedRowId(record.id),
});
// Drawer蝏<72>
<Drawer
title="<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>霂行<E99C82>"
placement="right"
width={400}
open={!!selectedRowId}
onClose={() => setSelectedRowId(null)}
>
{(() => {
const row = rows.find(r => r.id === selectedRowId);
if (!row) return null;
return (
<div className="prose">
<p className="whitespace-pre-wrap font-serif leading-7">
{row.fullText}
</p>
<Divider />
<div className="flex flex-wrap gap-2">
{Object.keys(row.results).map(fieldName => (
<Tag
key={fieldName}
color={row.conflictFields.includes(fieldName) ? 'orange' : 'default'}
>
{fieldName}
</Tag>
))}
</div>
</div>
);
})()}
</Drawer>
```
**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;
<div className="flex items-center gap-4 mb-4">
<div className="bg-slate-100 px-3 py-1.5 rounded">
<20>餅㺭<E9A485>? <strong>{rows.length}</strong>
</div>
{conflictCount > 0 ? (
<div className="bg-orange-50 px-3 py-1.5 rounded text-orange-700 animate-pulse">
<AlertTriangle size={16} className="inline mr-1" />
<strong>{conflictCount}</strong> <20><EFBFBD><EFBFBD><E89D92><EFBFBD><E98B86>
</div>
) : (
<div className="bg-emerald-50 px-3 py-1.5 rounded text-emerald-700">
<CheckCircle2 size={16} className="inline mr-1" />
<20><><EFBFBD><EFBFBD><EFBFBD>歇閫<E6AD87><E996AB>
</div>
)}
<Button onClick={handleExport}>撖澆枂敶枏<E695B6>蝏𤘪<E89D8F></Button>
<Button type="primary" onClick={handleComplete}>摰峕<E691B0>撟嗅<E6929F>摨?/Button>
</div>
```
---
### 6.2 撉峕𤣰<E5B395><F0A4A3B0><EFBFBD>
**<2A>唳旿<E594B3>㰘蝸**嚗?- [ ] <20>𣂼<EFBFBD><F0A382BC><EFBFBD>撉諹<E69289><E8ABB9>唳旿
- [ ] 銵冽聢<E586BD>埈覔<E59F88>格芋<E6A0BC>踹𢆡<E8B8B9><F0A286A1><EFBFBD><EFBFBD>?- [ ] <20><><EFBFBD><EFBFBD><EFBFBD>
**<2A><EFBFBD><E884A9><EFBFBD><E8A8AB>?*嚗?- [ ] <20><EFBFBD><E884A9><EFBFBD><E8A8AB>潭遬蝷態/B銝支葵<E694AF>厰僼
- [ ] <20>厰僼<E58EB0>曄內甇<E585A7><EFBFBD><EFBC86><EFBFBD><EFBFBD><E79285><E288AA><EFBFBD><EFBFBD>嚗㇄S/QW嚗?- [ ] <20>孵稬<E5ADB5>厰僼<E58EB0>𡡞<EFBFBD>蝥喳<E89DA5>?- [ ] UI銋鞱<E98A8B><E99EB1>湔鰵嚗<E9B0B5><E59A97><EFBFBD><EFBFBD><E5969F><EFBFBD><EFBFBD>
- [ ] API靚<49><EFBFBD>𣂼<EFBFBD>
**靘扯器<E689AF>?*嚗?- [ ] <20>孵稬銵峕𧒄靘扯器<E689AF>𤩺<EFBFBD><F0A4A9BA>?- [ ] <20>曄內摰峕㟲<E5B395><E39FB2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
- [ ] <20>曄內摮埈挾<E59F88><E68CBE>倌嚗<E5808C><E59A97><EFBFBD><E89D92>畾菟<E795BE>鈭殷<E988AD>
- [ ] <20>孵稬<E5ADB5>喲𡡒<E596B2>厰僼<E58EB0><EFBFBD><E7A18B>典躹<E585B8><EFBFBD><E7AC94>凋儒颲寞<E9A2B2>
**Toolbar**嚗?- [ ] <20><EFBFBD><E884A9><EFBFBD>霈⊥迤蝖?- [ ] 摰墧𧒄<E5A2A7>湔鰵嚗<E9B0B5><E59A97><EFBFBD><EFBFBD><E596B3><EFBFBD>嚗?- [ ] 撖澆枂<E6BE86>厰僼<E58EB0><EFBFBD><E88890>?- [ ] 摰峕<E691B0><E5B395>厰僼頝唾蓮<E594BE>訕tep 5
---
## <20>𣑐 銝<><E98A9D><EFBFBD>hase 5: Tool B - Step 5嚗㇄ay 5銝𠰴<E98A9D>嚗?
### 7.1 蝏𤘪<E89D8F>撖澆枂嚗?撠𤩺𧒄嚗?
#### 7.1.1 憿菟𢒰霈曇恣
**蝏<>辣**嚗䫤pages/tool-b/Step5Result.tsx`
**UI<55><49><EFBFBD>?*嚗𡁜<E59A97><F0A1819C>鰦4蝚?72-607銵?
**撣<><E692A3>**嚗?1. 摰峕<E691B0><E5B395><EFBFBD><E69AB9><EFBFBD>憸?2. 蝏蠘恣<E8A098><EFBFBD>嚗?銝迎<E98A9D>
3. <20><EFBFBD><E6BBA2>厰僼嚗<E583BC><E59A97>頧賬<E9A0A7><E8B3AC><EFBFBD>頧穿<E9A0A7>
---
#### 7.1.2 <20><EFBFBD>摰䂿緵
**1. 蝏蠘恣<E8A098>唳旿<E594B3><EFBFBD>**
```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('撖澆枂<E6BE86>𣂼<EFBFBD>');
} catch (error) {
message.error('撖澆枂憭梯揖');
}
};
```
**3. 瘚<><EFBFBD>啣極<E595A3>**
```typescript
const handleGoToToolC = () => {
// 頝唾蓮<E594BE>啣極<E595A3>嵩嚗䔶<E59A97><E494B6>㦙askId
navigate(`/data-cleaning/tool-c?sourceTaskId=${taskId}`);
};
```
---
### 7.2 撉峕𤣰<E5B395><F0A4A3B0><EFBFBD>
- [ ] 蝏蠘恣<E8A098><EFBFBD><E288A0>唳旿甇<E697BF><EFBFBD>曄內
- [ ] Token瘨<6E><E798A8><EFBFBD><E5A092>鞉𧋦霈∠<E99C88><EFBFBD>
- [ ] 銝贝蝸<E8B49D>厰僼閫血<E996AB>Excel撖澆枂
- [ ] Excel<65><6C><EFBFBD><E8BEA3>鉄4銝杵heet嚗<74><E59A97><EFBFBD><EFBFBD><E6B8A1><EFBFBD><E6A0B6><EFBFBD><EFBFBD><EFBFBD><E884A9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E29885>仃韐仿★嚗?- [ ] 瘚<><EFBFBD>啣極<E595A3><EFBFBD>厰僼<E58EB0><EFBFBD><E88890><EFBFBD><E9B3B4>鞟內<E99E9F><E585A7>𧊋撘<F0A78A8B><E69298>𡢅<EFBFBD>
- [ ] 餈𥪜<E9A488>Portal<61>厰僼<E58EB0><EFBFBD><E88890>?
---
## <20><20><EFBFBD><E68092>hase 6: <20><><EFBFBD>瘚贝<E7989A>嚗㇄ay 5銝见<E98A9D>嚗?
### 8.1 蝡臬<E89DA1>蝡舀<E89DA1>霂閙<E99C82><E99699>?
#### 8.1.1 摰峕㟲瘚<E39FB2><E7989A>瘚贝<E7989A>
**瘚贝<E7989A><E8B49D>箸艶**嚗朞<E59A97><E69C9E>𣬚<EFBFBD><F0A3AC9A><EFBFBD>𥁒<EFBFBD>𦠜<EFBFBD><F0A6A09C>?
**瘚贝<E7989A>甇仿炊**嚗?1. [ ] 霈輸䔮Portal憿菟𢒰嚗Ǒ/data-cleaning`嚗?2. [ ] <20>孵稬Tool B<><EFBFBD>嚗諹歲頧砍<E9A0A7>Step 1
3. [ ] 銝𠹺<E98A9D>瘚贝<E7989A>Excel<65><6C>辣嚗<E8BEA3><E59A97><EFBFBD><EFBFBD><E6808E><EFBFBD>𥁒<EFBFBD>𠰴<EFBFBD>嚗?4. [ ] <20>㗇𥋘"<22><><EFBFBD><EFBFBD><EFBFBD>"<22><EFBFBD>閫血<E996AB><E8A180>亙熒璉<E78692><E79289>?5. [ ] 撉諹<E69289><E8ABB9>亙熒摨行遬蝷箔蛹"蝏輯𠧧 - 隡条<E99AA1>"
6. [ ] 餈𥕦<E9A488>Step 2嚗屸<E59A97>㗇𥋘"<22><EFBFBD> + <20><><EFBFBD><EFBFBD><EFBFBD>"
7. [ ] 撉諹<E69289>摮埈挾<E59F88>芸𢆡<E88AB8>㰘蝸嚗?銝芸<E98A9D>畾蛛<E795BE>
8. [ ] 蝻𤥁<E89DBB><EFBFBD>銝芸<E98A9D>畾蛛<E795BE>靽格㺿<E6A0BC>讛膩嚗?9. [ ] 餈𥕦<E9A488>Step 3嚗𣬚<E59A97><F0A3AC9A>?撘<>憪𧢲<E686AA><F0A7A2B2>?
10. [ ] 撉諹<E69289>餈𥕦漲<F0A595A6><EFBFBD>憪𧢲凒<F0A7A2B2>?11. [ ] 撉諹<E69289><E8ABB9><EFBFBD>皛𡁜𢆡<F0A1819C>曄內
12. [ ] 蝑匧<E89D91>隞餃𦛚摰峕<E691B0><EFBFBD><E59A97>璅⊥<E79285>摰峕<E691B0>嚗?13. [ ] <20>芸𢆡頝唾蓮<E594BE>訕tep 4
14. [ ] 撉諹<E69289>撉諹<E69289>蝵烐聢<E78390>㰘蝸<E3B098>唳旿
15. [ ] <20><EFBFBD><EFBFBD>銝芸<E98A9D><EFBFBD><E89D92><EFBFBD><EFBFBD>聢嚗𣬚<E59A97><F0A3AC9A>?DS"<22>厰僼<E58EB0><E583BC>
16. [ ] 撉諹<E69289><E8ABB9><EFBFBD><E884A9><EFBFBD>1
17. [ ] <20>孵稬<E5ADB5><EFBFBD>嚗屸<E59A97><EFBFBD>儒颲寞<E9A2B2><E5AF9E>曄內<E69B84><E585A7><EFBFBD>
18. [ ] <20>孵稬"摰峕<E691B0>撟嗅<E6929F>摨?嚗諹歲頧砍<E9A0A7>Step 5
19. [ ] 撉諹<E69289>蝏蠘恣<E8A098><EFBFBD><E288A0>唳旿甇<E697BF>
20. [ ] <20>孵稬"銝贝蝸"嚗屸<E59A97><EFBFBD>xcel銝贝蝸<E8B49D>𣂼<EFBFBD>
---
#### 8.1.2 撘<><EFBFBD>箸艶瘚贝<E7989A>
**瘚贝<E7989A><E8B49D>箸艶1嚗𡁜<E59A97>摨瑟<E691A8><E7919F>亙仃韐?*
- [ ] 銝𠹺<E98A9D>Excel嚗屸<E59A97>㗇𥋘蝛箏<E89D9B><EFBFBD>>50%<25><><EFBFBD>
- [ ] 撉諹<E69289><E8ABB9>亙熒摨行遬蝷箔蛹"蝥Z𠧧 - 霅血<E99C85>"
- [ ] 撉諹<E69289>"銝衤<E98A9D>甇?<3F>厰僼鋡怎<E98BA1><E6808E>?
**瘚贝<E7989A><E8B49D>箸艶2嚗帋遙<E5B88B>仃韐?*
- [ ] 璅⊥<E79285>API餈𥪜<E9A488>憭梯揖<E6A2AF><EFBFBD>?- [ ] 撉諹<E69289><E8ABB9>躰秤<E8BAB0>鞟內<E99E9F>曄內
- [ ] 撉諹<E69289><E8ABB9>臭誑<E887AD>齿鰵撠肽<E692A0>
**瘚贝<E7989A><E8B49D>箸艶3嚗𡁶<E59A97>蝏𣈯<E89D8F>霂?*
- [ ] <20><EFBFBD><E58994>𡒊<EFBFBD><F0A1928A>?銝衤<E98A9D>甇?
- [ ] 撉諹<E69289><E8ABB9>躰秤<E8BAB0>鞟內<E99E9F>曄內
- [ ] <20>齿鰵<E9BDBF>𠉛<EFBFBD><F0A0899B>𤾸虾蝏抒賒
---
### 8.2 <20><EFBFBD>瘚贝<E7989A>
**瘚贝<E7989A><E8B49D>箸艶**嚗𡁜之<F0A1819C>唳旿<E594B3><EFBFBD><EFBFBD><E99C82><EFBFBD>?
**瘚贝<E7989A>甇仿炊**嚗?1. [ ] <20>㰘蝸500銵峕㺭<E5B395>?2. [ ] 撉諹<E69289>銵冽聢皛𡁜𢆡瘚<F0A286A1><E7989A><EFBFBD><E59A97><EFBFBD>⊿▼嚗?3. [ ] 撉諹<E69289><E8ABB9><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
4. [ ] 撉諹<E69289><E8ABB9><EFBFBD>/蝑偦<E89D91><EFBFBD><E58CA7><EFBFBD><EFBFBD><E68692><EFBFBD><EFBFBD>
**<2A><EFBFBD><E689AF><EFBFBD><EFBFBD>**嚗?- [ ] 擐硋<E69390><E7A18B>㰘蝸<E3B098>園𡢿 < 2蝘?- [ ] 銵冽聢皛𡁜𢆡撣抒<E692A3> > 30fps
- [ ] 鋆<><E98B86><EFBFBD><EFBFBD><E6BBA2><EFBFBD><E6BB9A>園𡢿 < 500ms
---
### 8.3 <20>澆捆<E6BE86><EFBFBD>霂?
**瘚讛<E7989A><E8AE9B>?*嚗?- [ ] Chrome 120+
- [ ] Edge 120+
- [ ] Firefox 120+
- [ ] Safari 17+嚗㇈ac嚗?
**<2A><><EFBFBD>?*嚗?- [ ] 1920x1080嚗<30>虜閫<E8999C><E996AB>
- [ ] 1440x900嚗<30><E59A97>霈唳𧋦嚗?- [ ] 2560x1440嚗<30><E59A97><EFBFBD><EFBFBD><EFBFBD>嚗?
---
## <20><> 銋腈<E98A8B><E88588><EFBFBD><EFBFBD><E78DA2><EFBFBD><EFBFBD><EFBFBD>Day 6嚗?
### 9.1 撘<><E69298><EFBFBD>獢?
**<2A><><EFBFBD><EFBFBD><E28098><EFBFBD><EFBFBD><EFBFBD>﹝**嚗?1. [ ] **<2A>滨垢隞<E59EA2><E99A9E>蝏𤘪<E89D8F>霂湔<E99C82>**嚗Ǒdocs/03-銝𡁜𦛚璅<E79285>/DC-<2D>唳旿皜<E697BF><E79A9C><EFBFBD><EFBFBD>/02-<2D><><EFBFBD>航挽霈?<3F>滨垢<E6BBA8><EFBFBD>霈曇恣.md`嚗?2. [ ] **蝏<>辣雿輻鍂<E8BCBB><E98D82>﹝**嚗Ǒfrontend-v2/src/modules/dc/README.md`嚗?3. [ ] **API撖寞𦻖<E5AF9E><F0A6BB96>﹝**嚗<><EFBFBD><E28098><EFBFBD><EFBFBD><EFBFBD>API霈曇恣<E69B87><E681A3>﹝嚗?4. [ ] **<EFBFBD><EFBFBD><EFBFBD>𤏸恣<EFBFBD><EFBFBD>摰峕<EFBFBD><EFBFBD><EFBFBD>**嚗Ǒdocs/03-銝𡁜𦛚璅<E79285>/DC-<2D>唳旿皜<E697BF><E79A9C><EFBFBD><EFBFBD>/06-撘<><E69298>𤏸扇敶?Tool-B撘<42><E69298><EFBFBD><E7A983><EFBFBD><EFBFBD>.md`嚗?
---
### 9.2 <20><EFBFBD><E586BD><EFBFBD>﹝嚗<EFB99D><EFBFBD><EFBFBD>
**<2A><><EFBFBD><E996AC>撱箇<E692B1><E7AE87><EFBFBD>﹝**嚗?1. [ ] **Tool B雿輻鍂<E8BCBB><E98D82><EFBFBD>**嚗Ǒdocs/03-銝𡁜𦛚璅<E79285>/DC-<2D>唳旿皜<E697BF><E79A9C><EFBFBD><EFBFBD>/07-<2D><EFBFBD><E586BD><EFBFBD>/Tool-B雿輻鍂<E8BCBB><E98D82><EFBFBD>.md`嚗?2. [ ] **撣貉<E692A3><E8B289><EFBFBD>FAQ**嚗Ǒdocs/03-銝𡁜𦛚璅<E79285>/DC-<2D>唳旿皜<E697BF><E79A9C><EFBFBD><EFBFBD>/07-<2D><EFBFBD><E586BD><EFBFBD>/FAQ.md`嚗?
---
## <20><20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E6A0BC><EFBFBD><E888AA>?
### 10.1 敹<><EFBFBD><EFBFBD><E89084><EFBFBD><EFBFBD><EFBFBD>?
#### 鈭穃<E988AD><E7A983><EFBFBD><E8A098>?潃?撘箏<E69298>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>`docs/04-撘<><E69298>𤏸<EFBFBD><F0A48FB8>?08-鈭穃<E988AD><E7A983><EFBFBD><E7AC94>𤏸<EFBFBD><F0A48FB8>?md`
**蝳<>迫**嚗?- <20>?雿輻鍂`fs.writeFile()`蝑㗇𧋦<E39787><EFBFBD>隞嗆<E99A9E>雿?- <20>?雿輻鍂<E8BCBB><EFBFBD><E585B8><EFBFBD>蝻枏<E89DBB><E69E8F>唳旿
- <20>?蝖祉<E89D96><E7A589><EFBFBD><EFBFBD>蝵殷<E89DB5>IP<49><50><EFBFBD><EFBFBD><EFBFBD>嚗?- <20>?<3F>峕郊<E5B395>蹂遙<E8B982><EFBFBD>>10蝘𡜐<E89D98>
- <20>?<3F><EFBFBD>摰䂿緵撟喳蝱<E596B3><EFBFBD>
**敹<>◆**嚗?- <20>?雿輻鍂`storage`<60>滚𦛚摮睃<E691AE><E79D83><EFBFBD>
- <20>?雿輻鍂`cache`<60>滚𦛚蝻枏<E89DBB><E69E8F>唳旿
- <20>?雿輻鍂<E8BCBB><EFBFBD><E887AC><EFBFBD><E3979B>滨蔭
- <20>?撘<>郊隞餃𦛚 + 餈𥕦漲頧株砭
- <20>?憭滨鍂撟喳蝱<E596B3><EFBFBD>霈暹鴌
---
### 10.2 憭滨鍂蝑𣇉裦
#### <20>𡒊垢憭滨鍂嚗<E98D82><E59A97><EFBFBD><EFBFBD><EFBFBD>
```typescript
// <20>?甇<>嚗𡁜<E59A97><F0A1819C>典像<E585B8><EFBFBD><E59597>?import { storage } from '@/common/storage';
import { logger } from '@/common/logging';
import { cache } from '@/common/cache';
import { LLMFactory } from '@/common/llm/adapters/LLMFactory';
```
#### <20>滨垢憭滨鍂嚗<E98D82><E59A97>摰䂿緵嚗?```typescript
// 憭滨鍂ASL璅<E79285><E288AA><EFBFBD><EFBFBD>隞嗅<E99A9E>Hook
import { usePolling } from '@/shared/hooks/usePolling';
import { FileUploader } from '@/shared/components/FileUploader';
import { ProgressBar } from '@/shared/components/ProgressBar';
```
---
### 10.3 <20><EFBFBD><E59786><EFBFBD>?
**<2A><EFBFBD><E588BB><EFBFBD>**嚗鑹eact Query嚗㇁SL璅<E79285>雿輻鍂嚗?
```typescript
// 雿輻鍂React Query蝞∠<E89D9E>API靚<49>
import { useQuery, useMutation } from '@tanstack/react-query';
// <20><EFBFBD>隞餃𦛚餈𥕦漲
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',
});
// 鋆<><E98B86><EFBFBD><EFBFBD>
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('鋆<><E98B86><EFBFBD>𣂼<EFBFBD>');
},
});
```
---
### 10.4 TypeScript蝐餃<E89D90>摰帋<E691B0>
**蝏煺<E89D8F>蝐餃<E89D90><E9A483><EFBFBD>辣**嚗䫤frontend-v2/src/modules/dc/types/toolB.ts`
```typescript
// <20>亙熒璉<E78692><E79289><EFBFBD><E4BAA6>?export interface HealthCheckResult {
status: 'good' | 'bad';
emptyRate: number;
avgLength: number;
totalRows: number;
estimatedTokens: number;
message: string;
}
// 璅⊥踎摰帋<E691B0>
export interface Template {
id: string;
diseaseType: string;
reportType: string;
displayName: string;
fields: Field[];
}
export interface Field {
id: string;
name: string;
desc: string;
width?: string;
}
// 隞餃𦛚<E9A483><EFBFBD>?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;
}
// 撉諹<E69289>銵?export interface VerifyRow {
id: string;
rowIndex: number;
originalText: string;
fullText: string;
results: Record<string, {
A: string;
B: string;
chosen: string | null;
}>;
status: 'clean' | 'conflict' | 'resolved';
conflictFields: string[];
}
```
---
## <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>隡唬<E99AA1>摨𥪜笆
### 11.1 <20><><EFBFBD><EFBFBD><E888AB>?
| 憌𡡞埯 | 璁<><E79281> | 敶勗<E695B6> | 摨𥪜笆<F0A5AA9C>芣鴌 |
|------|------|------|---------|
| **<EFBFBD>唳旿摨栞”<EFBFBD><EFBFBD>撱?* | 銝?| 擃?| 蝡见朖<E8A781><EFBFBD>`npx prisma db push`撉諹<EFBFBD> |
| **<EFBFBD>𡒊垢API<EFBFBD><EFBFBD>霂?* | 銝?| 擃?| 撘<><E69298><EFBFBD><E7A983><EFBFBD>鍂REST Client瘚贝<E7989A>6銝芰垢<E88AB0>?|
| **<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>唳旿<EFBFBD>𧶏<EFBFBD>** | 雿?| 銝?| 憸<><E686B8>TanStack Table餈<65><EFBFBD><EFBFBD> |
| **Excel閫<6C><E996AB>憭梯揖** | 雿?| 銝?| 雿輻鍂xlsx摨橒<E691A8>憓𧼮<E68693><F0A7BCAE>躰秤憭<E7A7A4><E686AD> |
| **LLM靚<4D>鍂頞<E98D82>𧒄** | 雿?| 銝?| <20>𡒊垢撌脣<E6928C><E884A3><EFBFBD>霂閙㦤<E99699>?|
---
### 11.2 <20>園𡢿憌𡡞埯
| 憌𡡞埯 | 璁<><E79281> | 敶勗<E695B6> | 摨𥪜笆<F0A5AA9C>芣鴌 |
|------|------|------|---------|
| **Step 4撘<34><E69298>𤏸<EFBFBD><F0A48FB8>?* | 銝?| 擃?| 憸<><E686B8>2憭抬<E686AD>9撠𤩺𧒄嚗㚁<E59A97><E39A81><EFBFBD><E88880><EFBFBD><EFBFBD>隞餃𦛚 |
| **<EFBFBD><EFBFBD><EFBFBD>瘚贝<EFBFBD><EFBFBD>𤑳緵<EFBFBD><EFBFBD>** | 銝?| 銝?| 憸<><E686B8>1憭拍<E686AD><E68B8D>脫𧒄<E884AB>?|
| **<EFBFBD><EFBFBD>銝𡡞<EFBFBD><EFBFBD><EFBFBD>蝚?* | 雿?| 擃?| 撘<><E69298><EFBFBD>銝𦒘漣<F0A69298><E6BCA3>霈文<E99C88><E69687>?|
---
### 11.3 靘肽<E99D98>憌𡡞埯
| 憌𡡞埯 | 璁<><E79281> | 敶勗<E695B6> | 摨𥪜笆<F0A5AA9C>芣鴌 |
|------|------|------|---------|
| **<EFBFBD>𡒊垢API<EFBFBD>䀹凒** | 雿?| 擃?| 雿輻鍂TypeScript蝐餃<E89D90>嚗𣬚<E59A97>霂烐𧒄璉<F0A79284><E79289>?|
| **撟喳蝱<E596B3><EFBFBD>Bug** | 雿?| 銝?| 撌脣<E6928C><E884A3><EFBFBD>霂𤏪<E99C82>憌𡡞埯雿?|
| **霈曇恣<E69B87>䀹凒** | 雿?| 銝?| 蝏<><EFBFBD>𤥁挽霈∴<E99C88><E288B4><EFBFBD>靽格㺿 |
---
## <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
### 12.1 鈭支<E988AD><E694AF><EFBFBD><E68B87>?
**隞<><E99A9E>**嚗?- [ ] Portal撌乩<E6928C><E4B9A9>圈△<E59C88><EFBFBD>摰峕㟲嚗?- [ ] Tool B 5銝杵tep憿菟𢒰嚗<F0A292B0><E59A97><EFBFBD><EFBFBD>
- [ ] <20>曹澈蝏<E6BE88>辣摨橒<E691A8>TaskList<73><74>ssetLibrary<72><79>onflictCell蝑㚁<E89D91>
- [ ] API<50>滚𦛚撠<F0A69B9A><E692A0>嚗ōoolBApi.ts<74><73>ortalApi.ts嚗?- [ ] TypeScript蝐餃<E89D90>摰帋<E691B0><EFBFBD><E59A97><EFBFBD><EFBFBD>
- [ ] <20><EFBFBD><E79195><EFBFBD>辣嚗㇍ailwindCSS + Ant Design嚗?
**<2A><>﹝**嚗?- [ ] <20>滨垢<E6BBA8><EFBFBD>霈曇恣<E69B87><E681A3>
- [ ]<>辣雿輻鍂<E8BCBB><E98D82>
- [ ] API撖寞𦻖<E5AF9E><F0A6BB96>
- [ ]<><E69298><EFBFBD><E7A983><EFBFBD><EFBFBD>
- [ ] <20><EFBFBD>雿輻鍂<E8BCBB><E98D82><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
**瘚贝<E7989A>**嚗?- [ ] 蝡臬<E89DA1>蝡舀<E89DA1>霂閙𥁒<E99699>?- [ ] <20><EFBFBD>瘚贝<E7989A><E8B49D><EFBFBD>
- [ ] <20>澆捆<E6BE86><EFBFBD>霂閙𥁒<E99699>?
---
### 12.2 <20><EFBFBD>摰峕㟲<E5B395>?
**Portal撌乩<E6928C><E4B9A9>?*嚗?- <20>?3銝芸極<E88AB8>瑕㨃<E79195><E3A883><EFBFBD>Tool B<>舐鍂嚗?- <20>?<3F><>餈睲遙<E79DB2><EFBFBD>銵剁<E98AB5>摰墧𧒄頧株砭嚗?- <20>?<3F>唳旿韏<E697BF>漣摨橒<E691A8>Tab<61><62>揢嚗?
**Tool B - <20><><EFBFBD>蝏𤘪<E89D8F><F0A498AA>𡝗㦤<F0A19D97>其犖**嚗?- <20>?Step 1: Excel銝𠹺<E98A9D> + <20>亙熒璉<E78692><E79289>?- <20>?Step 2: <20><EFBFBD>璅⊥踎<E28AA5>滨蔭嚗?銝芷<E98A9D>霈暹芋<E69AB9><EFBFBD>
- <20>?Step 3: <20>𣬚𤩅<F0A3AC9A>𣂼<EFBFBD>餈𥕦漲<F0A595A6>烐綉
- <20>?Step 4: <20><EFBFBD>撉諹<E69289>蝵烐聢嚗<E881A2>𣈲<EFBFBD><F0A388B2><EFBFBD><EFBFBD><EFBFBD>
- <20>?Step 5: 蝏𤘪<E89D8F>撖澆枂嚗𠄌xcel + 瘚<>蓮嚗?
---
### 12.3 隞<><E99A9E>韐券<E99F90>
**隞<><E99A9E><EFBFBD><E996AB>**嚗?- <20>?<3F><EFBFBD>鈭穃<E988AD><E7A983><EFBFBD><E7AC94>𤏸<EFBFBD><F0A48FB8>?- <20>?TypeScript蝐餃<E89D90>摰匧<E691B0>
- <20>?ESLint<6E>𣳇<EFBFBD>霂?- <20>?隞<><E99A9E>瘜券<E7989C><EFBFBD><E691B0>
**<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>**嚗?- <20>?擐硋<E69390><E7A18B>㰘蝸 < 2s
- <20>?銵冽聢皛𡁜𢆡瘚<F0A286A1><E7989A>
- <20>?鋆<><E98B86><EFBFBD><EFBFBD> < 500ms
- <20>?<3F><><EFBFBD><EFBFBD>删鍂 < 200MB
**<EFBFBD><EFBFBD>雿㯄<EFBFBD>**嚗?- <20>?瘚<><E7989A><EFBFBD>?甇交<E79487>蝔?- <20>?摰墧𧒄餈𥕦漲<F0A595A6><EFBFBD>
- <20>?<3F><EFBFBD><E6B8B2><EFBFBD><EFBFBD><EFBFBD><E89D92><EFBFBD><E99C82><EFBFBD>?- <20>?<3F>见末<E8A781><E69CAB><EFBFBD>霂舀<E99C82>蝷?
---
## <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>甇亥<E79487><E4BAA5>?
### 13.1 蝡见朖<E8A781><EFBFBD>嚗㇄ay 0嚗?
**1. 撉諹<E69289><E8ABB9>唳旿摨栞”**
```bash
cd AIclinicalresearch/backend
npx prisma db push --skip-generate
npx prisma studio # <20><EFBFBD><E888AA><EFBFBD>霂?```
**2. 瘚贝<E7989A><E8B49D>𡒊垢API**
```bash
# <20>臬𢆡<E887AC>𡒊垢<F0A1928A>滚𦛚
npm run dev
# 雿輻鍂REST Client瘚贝<E7989A>6銝服PI蝡舐<E89DA1>
# <20>碶蝙<E7A2B6>沌ostman/Insomnia
```
**3. Git<69>𣂷漱霈<E99C88>**
```bash
# 撱箄悅瘥誩<E798A5><E8AAA9>𣂷<EFBFBD>銝枉hase撠望<E692A0>鈭?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 撘<><E69298>穃鍳<E7A983><EFBFBD>Day 1嚗?
**隞餃𦛚1嚗𡁜<E59A97>撱摺ortal憿菟𢒰撉冽沲**
```bash
cd frontend-v2/src/modules/dc
mkdir -p pages components hooks services types
# <20>𥕦遣Portal.tsx
touch pages/Portal.tsx
# <20>𥕦遣頝舐眏<E88890>滨蔭
# 靽格㺿 index.tsx
```
**隞餃𦛚2嚗𡁜<E59A97><F0A1819C>?銝芸極<E88AB8>瑕㨃<E79195>?*
```bash
# <20>𥕦遣ToolCard蝏<64>
touch components/ToolCard.tsx
```
**隞餃𦛚3嚗𡁜<E59A97><F0A1819C>唬遙<E594AC><EFBFBD>銵剁<E98AB5>雿輻鍂Mock<63>唳旿嚗?*
```bash
# <20>𥕦遣TaskList蝏<74>
touch components/TaskList.tsx
# <20>𥕦遣useRecentTasks Hook
touch hooks/useRecentTasks.ts
```
---
### 13.3 <20><>賒頝蠘<E9A09D>
**瘥𤩺𠯫璉<F0A0AFAB><E79289><EFBFBD>**嚗?- [ ] 隞<><E99A9E><EFBFBD>臬炏Git<69>𣂷漱
- [ ] Todo<64>𡑒”<F0A19192>臬炏<E887AC>湔鰵
- [ ] <20><><EFBFBD><EFBFBD><EFBFBD>䔮憸䀹糓<E480B9>西扇敶?- [ ] API靚<49><EFBFBD>臬炏甇<E7828F>
**瘥誩𪂹璉<F0AA82B9><E79289><EFBFBD>**嚗?- [ ] <20><EFBFBD>摰峕<E691B0>摨行糓<E8A18C>衣泵<E8A1A3><E6B3B5><EFBFBD><EFBFBD>?- [ ] <20>臬炏<E887AC><E7828F><EFBFBD><E996AC><EFBFBD>渲恣<E6B8B2>?- [ ] <20>臬炏<E887AC><E7828F><EFBFBD><E996AC>憭𤥁<E686AD>皞?
---
## <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>蝟颱<E89D9F><E9A2B1><EFBFBD>
### 14.1 <20><><EFBFBD>舀𣈲<E88880>?
**<2A><><EFBFBD><EFBFBD><EFBFBD><E6A185>?*嚗?1. <20>仿<EFBFBD>撟喳蝱<E596B3><EFBFBD>霈暹鴌<E69AB9><E9B48C>﹝嚗Ǒbackend/src/common/README.md`嚗?2. <20>仿<EFBFBD>鈭穃<E988AD><E7A983><EFBFBD><E7AC94>𤏸<EFBFBD><F0A48FB8><EFBFBD><EFBFBD>`docs/04-撘<><E69298>𤏸<EFBFBD><F0A48FB8>?08-鈭穃<E988AD><E7A983><EFBFBD><E7AC94>𤏸<EFBFBD><F0A48FB8>?md`嚗?3. <20><><EFBFBD><EFBFBD>SL璅<E79285><EFBFBD><E99A9E>嚗Ǒfrontend-v2/src/modules/asl/`嚗?4. <20><EFBFBD><E4BAA6>𡒊垢API隞<49><E99A9E>嚗Ǒbackend/src/modules/dc/tool-b/`嚗?
### 14.2 隞<><E99A9E>摰⊥䰻
**<EFBFBD>𣂷漱<EFBFBD>滩䌊璉<EFBFBD>**嚗?- [ ] <20>臬炏<E887AC><EFBFBD>鈭穃<E988AD><E7A983><EFBFBD><E8A098>?- [ ] <20>臬炏憭滨鍂撟喳蝱<E596B3><EFBFBD>
- [ ] TypeScript蝐餃<E89D90><E9A483>臬炏摰峕㟲
- [ ] <20>臬炏<E887AC>凤ODO/FIXME瘜券<E7989C>
- [ ] <20>臬炏<E887AC>実onsole.log嚗<67><E59A97>雿輻鍂logger嚗?
---
## <20><20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
### <20><EFBFBD><E8A9A8><EFBFBD>
摰峕<EFBFBD>DC璅<EFBFBD>Tool B<><42><EFBFBD>蝡臬<E89DA1><E887AC>𡢅<EFBFBD>摰䂿緵隞擧<E99A9E>隞嗡<E99A9E>隡惩<E99AA1>蝏𤘪<E89D8F>撖澆枂<E6BE86><E69E82><EFBFBD><EFBFBD>?甇交<E79487>蝔页<E89D94><E9A1B5><EFBFBD><E5ADB5>?*<2A><EFBFBD>撉諹<E69289>蝵烐聢**餈嗘<E9A488><E59798><EFBFBD><E8A9A8><EFBFBD><E8A098>?
### <20>喲睸<E596B2>𣂼<EFBFBD><F0A382BC><EFBFBD>
1. <20>?**<2A>𡒊垢撌?00%摰峕<E691B0>**嚗<><E59A97>蝡臬虾銝𤘪釣UI<55>䔶漱鈭?2. <20>?**撟喳蝱<E596B3><EFBFBD><EFBFBD><E691B0>**嚗<><EFBFBD>湔𦻖憭滨鍂嚗峕<E59A97><E5B395><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E69298>?3. <20>?**霈曇恣<E69B87><E681A3>﹝朣𣂼<E69CA3>**嚗峕<E59A97><EFBFBD><EFBFBD><E88B8A><EFBFBD><EFBFBD><EFBFBD><E8A781><EFBFBD>瘙?4. <20>?**<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E59F88>?*嚗淾SL璅<E79285><E288AA><EFBFBD>銝箏<E98A9D><E7AE8F>?5. <20>?**<2A><EFBFBD><E59786><EFBFBD><E5AF9E>𡒊**嚗屸<E59A97><E5B1B8>冽䲮獢㇁嚗<E38781>𡠺蝡閪ortal嚗?
### 憸<><E686B8><EFBFBD><EFBFBD>
- **<2A><EFBFBD>隞瑕<E99A9E>?*嚗𡁏<E59A97>靘𡩅I撽勗𢆡<E58B97><F0A286A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E59A97><E79285>鈭文<E988AD>撉諹<E69289><E8ABB9><EFBFBD><E99EBE>唳旿韐券<E99F90>
- **<2A><><EFBFBD>臭遠<E887AD>?*嚗𡁜<E59A97><F0A1819C><EFBFBD><E6B8A1>滨垢璅<E79285><E288AA>𡝗沲<F0A19D97><E6B2B2><EFBFBD><EFBFBD><EFBFBD><E887AC><EFBFBD>隞嗅<E99A9E>
- **<2A><><EFBFBD>隞瑕<E99A9E>?*嚗関ool B<>舐𡠺蝡钅<E89DA1><E99285><EFBFBD>皛∟雲<E2889F><EFBFBD><E9A48C>唳旿憭<E697BF><E686AD><EFBFBD><EFBFBD>瘙?
---
**撘<><E69298>𤏸恣<F0A48FB8><EFBFBD>摰𡁜<E691B0><F0A1819C><EFBFBD>** <20>?
**銝衤<E98A9D>甇?*嚗𡁻<E59A97><EFBFBD><EFBFBD><EFBFBD>銵?<3F>?瘚贝<E7989A><E8B49D>𡒊垢API <20>?撘<>憪閪hase 1嚗㇊ortal憿菟𢒰撘<F0A292B0><E69298>𡢅<EFBFBD>
**憸<>恣摰峕<E691B0><E5B395>園𡢿**嚗?-6銝芸極雿𨀣𠯫
**蟡嘥<E89FA1><E598A5>煾◇<E785BE><EFBFBD>** <20><>