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%)
43 KiB
DC璅∪<EFBFBD> Tool-B 撘<><E69298>𤏸恣<F0A48FB8>?
*<EFBFBD><EFBFBD>﹝<EFBFBD><EFBFBD>𧋦嚗? V2.0 (MVP摰峕<E691B0>)
*<EFBFBD>𥕦遣<EFBFBD>交<EFBFBD>嚗? 2025-12-02
*摰峕<EFBFBD><EFBFBD>交<EFBFBD>嚗? 2025-12-03
*摰鮋<EFBFBD><EFBFBD>冽<EFBFBD>嚗? 2銝芸極雿𨀣𠯫
<EFBFBD>嗆<EFBFBD><EFBFBD><EFBFBD> <20>?MVP摰峕<E691B0>
<EFBFBD><EFBFBD> MVP摰峕<E691B0><E5B395>𡁜<EFBFBD>嚗?025-12-03嚗?
Tool B<><42><EFBFBD>蝏𤘪<E89D8F><F0A498AA>𡝗㦤<F0A19D97>其犖MVP<56><50>𧋦撌脣<E6928C><E884A3>琜<EFBFBD>
- <EFBFBD>?<3F>滨垢5甇亙極雿𨀣<E99BBF>摰峕㟲摰䂿緵嚗ǚ1400銵䕘<E98AB5>
- <EFBFBD>?8銝服PI蝡舐<E89DA1><E88890>券<EFBFBD>撖寞𦻖撟嗆<E6929F>霂閖<E99C82>朞<EFBFBD>
- <EFBFBD>?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>舐鍂
- <EFBFBD>𩤃<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`
<EFBFBD>笔<EFBFBD>撘<EFBFBD><EFBFBD>𤏸恣<EFBFBD>?
*<EFBFBD>格<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>
<EFBFBD><EFBFBD> 銝<><E98A9D><EFBFBD>★<EFBFBD>桀<EFBFBD><E6A180>滨𠶖<E6BBA8><F0A0B696><EFBFBD><EFBFBD>娍<EFBFBD>餌<EFBFBD>
1.1 <20>𡒊垢隞<E59EA2><E99A9E><EFBFBD>嗆<EFBFBD>?<3F>?100%摰峕<E691B0>
<EFBFBD>𡁶鍂<EFBFBD>賢<EFBFBD>撟喳蝱嚗<EFBFBD>虾憭滨鍂嚗?<3F>箔<EFBFBD> backend/src/common/ 撟喳蝱<E596B3>箇<EFBFBD>霈暹鴌嚗<E9B48C>歇摰峕㟲摰䂿緵嚗?
| <EFBFBD>賢<EFBFBD>璅∪<EFBFBD> | 撖澆<EFBFBD>頝臬<EFBFBD> | <EFBFBD>蠘<EFBFBD>霂湔<EFBFBD> | <EFBFBD>嗆<EFBFBD>? |
|---|---|---|---|
| 摮睃<EFBFBD><EFBFBD>滚𦛚 | @/common/storage |
<EFBFBD><EFBFBD>辣銝𠹺<EFBFBD>/銝贝蝸嚗𡿨ocal <20>?OSS嚗? | <EFBFBD>?摰峕<E691B0> |
| <EFBFBD>亙<EFBFBD>蝟餌<EFBFBD> | @/common/logging |
蝏𤘪<EFBFBD><EFBFBD>𡝗𠯫敹梹<EFBFBD>Winston嚗? | <EFBFBD>?摰峕<E691B0> |
| 蝻枏<EFBFBD><EFBFBD>滚𦛚 | @/common/cache |
蝻枏<EFBFBD>嚗㇈emory <20>?Redis嚗? | <EFBFBD>?摰峕<E691B0> |
| 撘<EFBFBD>郊隞餃𦛚 | @/common/jobs |
<EFBFBD>踵𧒄<EFBFBD>港遙<EFBFBD>⊿<EFBFBD><EFBFBD>? | <EFBFBD>?摰峕<E691B0> |
| LLM撌亙<EFBFBD> | @/common/llm/adapters/LLMFactory |
蝏煺<EFBFBD>LLM靚<EFBFBD>鍂嚗㇄eepSeek/Qwen/GPT/Claude嚗? | <EFBFBD>?摰峕<E691B0> |
| *<EFBFBD>唳旿摨? | @/config/database |
Prisma餈墧𦻖瘙? | <EFBFBD>?摰峕<E691B0> |
憭滨鍂蝑𣇉裦嚗?- <20>?Tool B<>𡒊垢隞<E59EA2><E99A9E>撌?00%憭滨鍂撟喳蝱<E596B3>賢<EFBFBD>
- <EFBFBD>?<3F>滨垢撘<E59EA2><E69298>穃<EFBFBD><E7A983><EFBFBD><EFBFBD><EFBFBD><EFBFBD>蝡舀芋撘𧶏<E69298>憭滨鍂<E6BBA8>滨垢<E6BBA8>曹澈蝏<E6BE88>辣
Tool B<>𡒊垢摰䂿緵<E482BF>嗆<EFBFBD>?
隞<EFBFBD><EFBFBD>雿滨蔭嚗䫤backend/src/modules/dc/tool-b/`
| <EFBFBD><EFBFBD>辣 | <EFBFBD>蠘<EFBFBD> | 隞<EFBFBD><EFBFBD><EFBFBD>? | <EFBFBD>嗆<EFBFBD>? | 憭滨鍂<EFBFBD>賢<EFBFBD> |
|---|---|---|---|---|
| services/HealthCheckService.ts | Excel<EFBFBD>亙熒璉<EFBFBD><EFBFBD>? | ~190銵? | <EFBFBD>?摰峕<E691B0> | storage, logger, cache, prisma |
| services/TemplateService.ts | 憸<EFBFBD>挽璅⊥踎蝞∠<EFBFBD> | ~243銵? | <EFBFBD>?摰峕<E691B0> | logger, prisma |
| services/DualModelExtractionService.ts | <EFBFBD>峕芋<EFBFBD>𧢲<EFBFBD><EFBFBD>? | ~390銵? | <EFBFBD>?摰峕<E691B0> | LLMFactory, logger, prisma |
| services/ConflictDetectionService.ts | <EFBFBD>脩<EFBFBD>璉<EFBFBD>瘚讠<EFBFBD>瘜? | ~215銵? | <EFBFBD>?摰峕<E691B0> | logger |
| controllers/ExtractionController.ts | API<EFBFBD>批<EFBFBD><EFBFBD>? | ~388銵? | <EFBFBD>?摰峕<E691B0> | <EFBFBD>券<EFBFBD><EFBFBD>滚𦛚 |
| routes/index.ts | 頝舐眏<EFBFBD>滨蔭 | ~115銵? | <EFBFBD>?摰峕<E691B0> | - |
| index.ts | 璅∪<EFBFBD><EFBFBD>亙藁 | ~117銵? | <EFBFBD>?摰峕<E691B0> | - |
<EFBFBD>餉恣嚗𡁶漲1,658銵䕘<E98AB5>7銝芣<E98A9D>隞塚<E99A9E>100%摰峕<E691B0>
API蝡舐<EFBFBD>皜<EFBFBD><EFBFBD>
Base URL: /api/v1/dc/tool-b
| <EFBFBD>寞<EFBFBD> | 頝臬<EFBFBD> | <EFBFBD>蠘<EFBFBD> | 霂瑟<EFBFBD>雿? | <EFBFBD>滚<EFBFBD> | <EFBFBD>嗆<EFBFBD>? |
|---|---|---|---|---|---|
| POST | /health-check |
Excel<EFBFBD>堒<EFBFBD>摨瑟<EFBFBD><EFBFBD>? | {fileKey, columnName} |
<EFBFBD>亙熒摨行𥁒<EFBFBD>? | <EFBFBD>?摰峕<E691B0> |
| GET | /templates |
<EFBFBD>瑕<EFBFBD>憸<EFBFBD>挽璅⊥踎<EFBFBD>𡑒” | - | 璅⊥踎<EFBFBD>啁<EFBFBD> | <EFBFBD>?摰峕<E691B0> |
| POST | /tasks |
<EFBFBD>𥕦遣<EFBFBD>𣂼<EFBFBD>隞餃𦛚 | {projectName, fileKey, textColumn, diseaseType, reportType} |
{taskId} |
<EFBFBD>?摰峕<E691B0> |
| GET | /tasks/:taskId/progress |
<EFBFBD>亥砭隞餃𦛚餈𥕦漲 | - | 餈𥕦漲霂行<EFBFBD> | <EFBFBD>?摰峕<E691B0> |
| GET | /tasks/:taskId/items |
<EFBFBD>瑕<EFBFBD>撉諹<EFBFBD>蝵烐聢<EFBFBD>唳旿 | ?status=conflict&page=1 |
<EFBFBD><EFBFBD>△<EFBFBD>唳旿 | <EFBFBD>?摰峕<E691B0> |
| POST | /items/:itemId/resolve |
鋆<EFBFBD><EFBFBD><EFBFBD>脩<EFBFBD> | {resolvedData} |
<EFBFBD>𣂼<EFBFBD><EFBFBD>嗆<EFBFBD>? | <EFBFBD>?摰峕<E691B0> |
憸<EFBFBD>挽璅⊥踎嚗?銝迎<E98A9D>嚗?1. <20>箇<EFBFBD><E7AE87><EFBFBD><EFBFBD><EFBFBD>亙<EFBFBD>嚗Ǒlung_cancer/pathology嚗? 5銝芸<E98A9D>畾?2. 蝟硋倏<E7A18B><E5808F><EFBFBD><EFBFBD>Z扇敶𤏪<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>
| 銵典<EFBFBD> | <EFBFBD>券<EFBFBD>? | 摮埈挾<EFBFBD>? | <EFBFBD>喲睸摮埈挾 | <EFBFBD>嗆<EFBFBD>? | <EFBFBD>唳旿<EFBFBD>? |
|---|---|---|---|---|---|
| dc_health_checks | <EFBFBD>亙熒璉<EFBFBD><EFBFBD>亥扇敶? | 10 | status, emptyRate, avgLength | <EFBFBD>?撌脣<E6928C>撱? | 2<EFBFBD>? |
| dc_templates | 憸<EFBFBD>挽璅⊥踎 | 7 | diseaseType, reportType, fields | <EFBFBD>?撌脣<E6928C>撱? | *3<EFBFBD>? |
| dc_extraction_tasks | <EFBFBD>𣂼<EFBFBD>隞餃𦛚 | 21 | status, totalCount, processedCount | <EFBFBD>?撌脣<E6928C>撱? | 1<EFBFBD>? |
| dc_extraction_items | <EFBFBD>𣂼<EFBFBD><EFBFBD>𡒊<EFBFBD> | 15 | resultA, resultB, conflictFields | <EFBFBD>?撌脣<E6928C>撱? | 4<EFBFBD>? |
**<2A>?撉諹<E69289>蝏𤘪<E89D8F>嚗?025-12-02嚗?*嚗?- <20>?*dc_schema撌脣<EFBFBD><EFBFBD>?
- <EFBFBD>?4銝芾”<EFBFBD>券<EFBFBD><EFBFBD>𥕦遣<EFBFBD>𣂼<EFBFBD>
- <EFBFBD>?**3銝芷<E98A9D>霈暹芋<E69AB9>踹歇<E8B8B9>嘥<EFBFBD><E598A5>?*嚗? 1. <20>箇<EFBFBD><E7AE87><EFBFBD><EFBFBD><EFBFBD>亙<EFBFBD> (lung_cancer/pathology) 2. 蝟硋倏<E7A18B><E5808F><EFBFBD><EFBFBD>Z扇敶?(diabetes/admission) 3. 擃䁅<E69383><E48185>钅秄霂羓<E99C82><E7BE93>?(hypertension/outpatient)
- <EFBFBD>?**<2A>㗇<EFBFBD>霂閙㺭<E99699>桀虾<E6A180>其<EFBFBD>撘<EFBFBD><E69298>𤏸<EFBFBD>霂?*
撉諹<EFBFBD><EFBFBD>𡁏𧋦嚗?bash cd backend node scripts/check-dc-tables.mjs # <20>扯<EFBFBD><E689AF>唳旿摨栞”璉<E2809D><E79289>亥<EFBFBD><E4BAA5>?
蝏栞捏嚗尠<EFBFBD> <20>唳旿摨枏<E691A8><E69E8F>典<EFBFBD>憭<EFBFBD>停蝏迎<E89D8F><E8BF8E>臭誑撘<E8AA91>憪见<E686AA>蝡臬<E89DA1><E887AC>𡢅<EFBFBD>
1.3 <20>滨垢隞<E59EA2><E99A9E><EFBFBD>嗆<EFBFBD>?<3F>?0%嚗<><E59A97>Placeholder嚗?
隞<EFBFBD><EFBFBD>雿滨蔭嚗䫤frontend-v2/src/modules/dc/`
frontend-v2/src/modules/dc/
<0A>鎿<EFBFBD><E98EBF><EFBFBD> index.tsx # <20>?隞<>laceholder嚗?4銵䕘<E98AB5>
<0A>鎿<EFBFBD><E98EBF><EFBFBD> components/ # <20><> 蝛?<3F>鎿<EFBFBD><E98EBF><EFBFBD> pages/ # <20><> 蝛箸<E89D9B>隞嗅允蝏𤘪<E89D8F>
<0A>? <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>蝖?
蝟餌<EFBFBD>蝥扳沲<EFBFBD>?- **撖潸⏛璅∪<E79285>**嚗𡁻▲<F0A181BB>典紡<E585B8>?- **頝舐眏頝臬<E9A09D>**嚗䫤/data-cleaning`
- **<2A><><EFBFBD>舀<EFBFBD>**嚗鑹eact 19 + TypeScript + Vite + Ant Design 5
DC璅∪<EFBFBD><EFBFBD>嗆<EFBFBD><EFBFBD>寞<EFBFBD>
<EFBFBD>㗇𥋘嚗𡁏䲮獢㇁ - <20>祉<EFBFBD>Portal憿菟𢒰嚗<EFBFBD>綫<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>撖澆枂
**<2A><><EFBFBD><EFBFBD>芋<EFBFBD>?*嚗?- ASL璅∪<E79285>嚗Ǒfrontend-v2/src/modules/asl/`嚗? - <20>匧<EFBFBD><E58CA7>渡<EFBFBD>撣<EFBFBD><E692A3><EFBFBD><EFBFBD>△<EFBFBD>U<EFBFBD><EFBCB5><EFBFBD>隞嗥<E99A9E><E597A5>? - 雿輻鍂React Router撋<72><E6928B>頝舐眏
- 撌虫儒撖潸⏛ + <20>喃儒<E59683><E58492>捆<EFBFBD>?
<EFBFBD>㴓 鈭䎚<E988AD><E48E9A><EFBFBD><EFBFBD>𤏸恣<F0A48FB8>埝<EFBFBD>餉<EFBFBD>
2.1 撘<><E69298>煾𧫴畾萄<E795BE><E89084>?
| <EFBFBD>嗆挾 | 隞餃𦛚 | 憸<EFBFBD>恣撌交𧒄 | 隡睃<EFBFBD>蝥? | <EFBFBD>格<EFBFBD> |
|---|---|---|---|---|
| Phase 1 | Portal撌乩<EFBFBD><EFBFBD>圈△<EFBFBD>? | 4-6h | P0 | DC璅∪<EFBFBD><EFBFBD>亙藁 |
| Phase 2 | Tool B - Step 1&2 | 6h | P0 | 銝𠹺<EFBFBD>+<2B>滨蔭 |
| Phase 3 | Tool B - Step 3 | 3h | P0 | 餈𥕦漲<EFBFBD>烐綉 |
| Phase 4 | Tool B - Step 4 | 9h | P0 | <EFBFBD>脩<EFBFBD>撉諹<EFBFBD>蝵烐聢潃? |
| Phase 5 | Tool B - Step 5 | 3h | P0 | 蝏𤘪<EFBFBD>撖澆枂 |
| Phase 6 | <EFBFBD><EFBFBD><EFBFBD>瘚贝<EFBFBD> | 4h | P1 | 蝡臬<EFBFBD>蝡舫<EFBFBD>霂? |
<EFBFBD>餉恣嚗𡁶漲29-31撠𤩺𧒄嚗?-5銝芸極雿𨀣𠯫嚗?
2.2 <20>𣬚<EFBFBD>蝣烐𧒄<E78390>渲”
| <EFBFBD>𣬚<EFBFBD>蝣? | 摰峕<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | 憸<EFBFBD>恣摰峕<EFBFBD> |
|---|---|---|
| M1: Portal銝羓瑪 | <EFBFBD>冽<EFBFBD><EFBFBD>航挪<EFBFBD>唏C璅∪<EFBFBD><EFBFBD>亙藁 | Day 1 |
| M2: Tool B<>舐鍂 | Step1-5<>券<EFBFBD>摰峕<E691B0> | Day 4 |
| M3: <20><><EFBFBD>瘚贝<E7989A><E8B49D>朞<EFBFBD> | 蝡臬<EFBFBD>蝡舀<EFBFBD>蝔𧢲<EFBFBD>霂閖<EFBFBD>朞<EFBFBD> | Day 5 |
| M4: <20><>﹝摰<EFB99D><E691B0> | 撘<EFBFBD><EFBFBD>烐<EFBFBD>獢<EFBFBD><EFBFBD><EFBFBD>冽<EFBFBD><EFBFBD><EFBFBD>﹝ | Day 6 |
<EFBFBD><EFBFBD> 銝剹<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>g<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>?- <EFBFBD>笔<EFBFBD><EFBFBD><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>
蝏<EFBFBD>辣嚗䫤components/ToolCard.tsx`
interface ToolCardProps {
id: 'tool-a' | 'tool-b' | 'tool-c';
title: string;
description: string;
icon: ReactNode;
color: 'blue' | 'purple' | 'emerald';
status: 'ready' | 'disabled';
onClick: () => void;
}
<EFBFBD>∠<EFBFBD><EFBFBD><EFBFBD>捆嚗?1. *Tool A - 頞<>漣<EFBFBD><E6BCA3>僎<EFBFBD>?
- <EFBFBD>暹<EFBFBD>嚗鎄ileSpreadsheet嚗<EFBFBD><EFBFBD><EFBFBD>莎<EFBFBD>
- <EFBFBD>讛膩嚗?閫<><E996AB>憭𡁏<E686AD><F0A1818F>唳旿<E594B3>園𡢿頧游笆朣鞾𠗕憸?
- <EFBFBD>嗆<EFBFBD><EFBFBD><EFBFBD>disabled嚗<EFBFBD><EFBFBD><EFBFBD>芸<EFBFBD><EFBFBD>𡢅<EFBFBD>
-
Tool B - <20><><EFBFBD>蝏𤘪<E89D8F><F0A498AA>𡝗㦤<F0A19D97>其犖 潃?<3F>祆活撘<E6B4BB><E69298>? - <20>暹<EFBFBD>嚗鋳ot嚗<74>換<EFBFBD>莎<EFBFBD>
- <EFBFBD>讛膩嚗?<3F>拍鍂憭扳芋<E689B3>𧢲<EFBFBD><F0A7A2B2>㚚<EFBFBD>蝏𤘪<E89D8F><F0A498AA>𡝗<EFBFBD><F0A19D97>?
- <EFBFBD>嗆<EFBFBD><EFBFBD><EFBFBD>ready
- <EFBFBD>孵稬頝唾蓮嚗䫤/data-cleaning/tool-b`
-
*Tool C - 蝘𤑳<E89D98><F0A491B3>唳旿蝻𤥁<E89DBB><F0A4A581>?
- <EFBFBD>暹<EFBFBD>嚗関able2嚗<EFBFBD>遛<EFBFBD>莎<EFBFBD>
- <EFBFBD>讛膩嚗?Excel憌擧聢<E693A7><E881A2>銁蝥踵<E89DA5>瘣堒極<E5A092>?
- <EFBFBD>嗆<EFBFBD><EFBFBD><EFBFBD>disabled嚗<EFBFBD><EFBFBD><EFBFBD>芸<EFBFBD><EFBFBD>𡢅<EFBFBD>
3.3.2 <20><>餈睲遙<E79DB2>∪<EFBFBD>銵?蝏<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蝘坿蔭霂g<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/ <0A>鎿<EFBFBD><E98EBF><EFBFBD> pages/ <0A>? <20>婙<EFBFBD><E5A999><EFBFBD> Portal.tsx # 潃?Portal銝駁△<E9A781>?<3F>鎿<EFBFBD><E98EBF><EFBFBD> components/ <0A>? <20>鎿<EFBFBD><E98EBF><EFBFBD> ToolCard.tsx # 撌亙<E6928C><E4BA99>∠<EFBFBD> <0A>? <20>鎿<EFBFBD><E98EBF><EFBFBD> TaskList.tsx # 隞餃𦛚<E9A483>𡑒” <0A>? <20>婙<EFBFBD><E5A999><EFBFBD> AssetLibrary.tsx # <20>唳旿韏<E697BF>漣摨?<3F>鎿<EFBFBD><E98EBF><EFBFBD> hooks/ <0A>? <20>鎿<EFBFBD><E98EBF><EFBFBD> useRecentTasks.ts # 隞餃𦛚<E9A483>𡑒”Hook <0A>? <20>婙<EFBFBD><E5A999><EFBFBD> useAssets.ts # 韏<>漣<EFBFBD>𡑒”Hook <0A>鎿<EFBFBD><E98EBF><EFBFBD> services/ <0A>? <20>婙<EFBFBD><E5A999><EFBFBD> portalApi.ts # Portal API撠<49><E692A0> <0A>婙<EFBFBD><E5A999><EFBFBD> types/ <0A>婙<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撖寞𦻖
<EFBFBD><EFBFBD>閬<EFBFBD><EFBFBD>蝡舀鰵憓䂿<EFBFBD>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>?
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>亙熒摨行遬蝷?
// <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 憿菟𢒰霈曇恣
蝏<EFBFBD>辣嚗䫤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>𡑒”
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>
// 瘛餃<E7989B>摮埈挾
const handleAddField = () => {
setFields([...fields, {
id: `custom_${Date.now()}`,
name: '<27>啣<EFBFBD>畾?,
desc: '摮埈挾<EFBFBD>讛膩',
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>
// <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銝𠹺<EFBFBD><EFBFBD>𣂼<EFBFBD>嚗諹繮<EFBFBD>餻ileKey
- <EFBFBD>堒<EFBFBD><EFBFBD>𡑒”甇<EFBFBD>&<EFBFBD>曄內
- <EFBFBD>亙熒璉<EFBFBD><EFBFBD>丕PI靚<EFBFBD>鍂<EFBFBD>𣂼<EFBFBD>
- <EFBFBD>亙熒摨血㨃<EFBFBD><EFBFBD>覔<EFBFBD>桃<EFBFBD><EFBFBD>𨀣迤蝖格遬蝷綽<EFBFBD>蝏輯𠧧/蝥Z𠧧嚗?- [ ] Token憸<6E>摯<EFBFBD>啣<EFBFBD>潭迤蝖?- [ ] 蝛箏<E89D9B>潛<EFBFBD>>50%<25>嗥<EFBFBD>甇Z<E79487><EFBCBA>乩<EFBFBD>銝<EFBFBD>甇? Step 2:
- 璅⊥踎<EFBFBD>𡑒”<EFBFBD>㰘蝸<EFBFBD>𣂼<EFBFBD>
- <EFBFBD>曄<EFBFBD>蝐餃<EFBFBD><EFBFBD>峕𥁒<EFBFBD>羓掩<EFBFBD>钅<EFBFBD>㗇𥋘獢<EFBFBD>迤撣?- [ ] <20>㗇𥋘璅⊥踎<E28AA5>𤾸<EFBFBD>畾菔䌊<E88F94>典<EFBFBD>頧?- [ ] 摮埈挾<E59F88>舀<EFBFBD>瘛餃<E7989B>/<2F>𣳇膄/蝻𤥁<E89DBB>
- Prompt憸<EFBFBD><EFBFBD>摰墧𧒄<EFBFBD>湔鰵
- 隞<EFBFBD><EFBFBD>擃䀝漁甇<EFBFBD>&<EFBFBD>曄內
<EFBFBD>辷<EFBFBD> 鈭𢛵<E988AD><F0A29BB5>hase 3: Tool B - Step 3嚗㇄ay 3銝𠰴<E98A9D>嚗?
5.1 憭<><E686AD>餈𥕦漲<F0A595A6>烐綉嚗?撠𤩺𧒄嚗?
5.1.1 憿菟𢒰霈曇恣
蝏<EFBFBD>辣嚗䫤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>𥕦遣隞餃𦛚
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. 餈𥕦漲頧株砭
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>函𤫇
// 雿輻鍂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>曄內
<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>
- <EFBFBD>孵稬"撘<>憪𧢲<E686AA><F0A7A2B2>?<3F>擧<EFBFBD><E693A7>笔<EFBFBD>撱箔遙<E7AE94>?- [ ] <20>瑕<EFBFBD><E79195>配askId
- 餈𥕦漲頧株砭甇<EFBFBD>虜嚗<EFBFBD><EFBFBD>5蝘𡜐<EFBFBD>
- 餈𥕦漲<EFBFBD>∪<EFBFBD><EFBFBD>嗆凒<EFBFBD>?- [ ] <20>亙<EFBFBD>皛𡁜𢆡<F0A1819C>箏<EFBFBD>甇<EFBFBD>虜<EFBFBD>曄內
- 隞餃𦛚摰峕<EFBFBD><EFBFBD>舘䌊<EFBFBD>刻歲頧砍<EFBFBD>Step 4
- 隞餃𦛚憭梯揖<EFBFBD>嗆遬蝷粹<EFBFBD>霂舀<EFBFBD>蝷?
<EFBFBD>㴓 <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>g<EFBFBD>
6.1.1 憿菟𢒰霈曇恣
蝏<EFBFBD>辣嚗䫤pages/tool-b/Step4Verify.tsx`
**UI<55><49><EFBFBD>?*嚗𡁜<E59A97><F0A1819C>鰦4蝚?02-569銵?
**撣<><E692A3>**嚗? <20>𢞖<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><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><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>
<EFBFBD>寞<EFBFBD><EFBFBD>㗇𥋘嚗? Option 1: Ant Design Table嚗<EFBFBD>綫<EFBFBD>琜<EFBFBD><EFBFBD>唳旿<EFBFBD>?1000銵䕘<E98AB5>
- 隡条<EFBFBD>嚗𡁜<EFBFBD>蝞勗朖<EFBFBD>剁<EFBFBD>API<EFBFBD>见末嚗峕甅撘讐<EFBFBD>銝<EFBFBD>
- 蝻箇<EFBFBD>嚗𡁏㺭<EFBFBD>桅<EFBFBD>憭扳𧒄<EFBFBD>航<EFBFBD><EFBFBD>⊿▼
- <EFBFBD><EFBFBD>鍂<EFBFBD>箸艶嚗𡁜之<EFBFBD>典<EFBFBD><EFBFBD>箸艶嚗<EFBFBD><EFBFBD>霈⊥㺭<EFBFBD>桅<EFBFBD><500銵䕘<E98AB5>
Option 2: TanStack Table嚗<EFBFBD><EFBFBD><EFBFBD>扯<EFBFBD>嚗峕㺭<EFBFBD>桅<EFBFBD>>1000銵䕘<E98AB5>
- 隡条<EFBFBD>嚗朞<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>剁<EFBFBD><EFBFBD>扯<EFBFBD><EFBFBD><EFBFBD>蔔
- 蝻箇<EFBFBD>嚗䥅eadless<EFBFBD><EFBFBD><EFBFBD>芸楛摰䂿緵UI
- <EFBFBD><EFBFBD>鍂<EFBFBD>箸艶嚗𡁜<EFBFBD><EFBFBD><EFBFBD>之<EFBFBD>唳旿<EFBFBD>? **<2A>喟<EFBFBD>**嚗𡁜<E59A97><F0A1819C>杗nt Design Table嚗<65><E59A97><EFBFBD>扯<EFBFBD>銝滢蔔<E6BBA2>滩<EFBFBD>蝘餃<E89D98>TanStack Table
6.1.3 <20>詨<EFBFBD><E8A9A8>唳旿蝏𤘪<E89D8F>
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>唳旿
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>蝵?
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"><EFBFBD>朞<EFBFBD></Tag>;
}
return <Tag color="warning" className="animate-pulse">敺<EFBFBD><EFBFBD><EFBFBD>?/Tag>;
},
},
];
*3. <20>脩<EFBFBD><E884A9>訫<EFBFBD><E8A8AB>潛<EFBFBD>隞? 潃?<3F>詨<EFBFBD>
// 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>
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>遬蝷?
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蝏蠘恣
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">
<EFBFBD>餅㺭<EFBFBD>? <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> <EFBFBD>∪<EFBFBD>蝒<EFBFBD><EFBFBD>鋆<EFBFBD><EFBFBD>
</div>
) : (
<div className="bg-emerald-50 px-3 py-1.5 rounded text-emerald-700">
<CheckCircle2 size={16} className="inline mr-1" />
<EFBFBD><EFBFBD><EFBFBD>匧<EFBFBD>蝒<EFBFBD>歇閫<EFBFBD><EFBFBD>
</div>
)}
<Button onClick={handleExport}>撖澆枂敶枏<EFBFBD>蝏𤘪<EFBFBD></Button>
<Button type="primary" onClick={handleComplete}>摰峕<EFBFBD>撟嗅<EFBFBD>摨?/Button>
</div>
6.2 撉峕𤣰<E5B395><F0A4A3B0><EFBFBD>
<EFBFBD>唳旿<EFBFBD>㰘蝸嚗?- [ ] <20>𣂼<EFBFBD><F0A382BC>瑕<EFBFBD>撉諹<E69289><E8ABB9>唳旿
- 銵冽聢<EFBFBD>埈覔<EFBFBD>格芋<EFBFBD>踹𢆡<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?- [ ] <20><>△<EFBFBD>蠘<EFBFBD>甇<EFBFBD>虜
**<2A>脩<EFBFBD><E884A9>訫<EFBFBD><E8A8AB>?*嚗?- [ ] <20>脩<EFBFBD><E884A9>訫<EFBFBD><E8A8AB>潭遬蝷態/B銝支葵<E694AF>厰僼
- <EFBFBD>厰僼<EFBFBD>曄內甇<EFBFBD>&<EFBFBD><EFBFBD><EFBFBD>澆<EFBFBD>璅∪<EFBFBD><EFBFBD><EFBFBD><EFBFBD>嚗㇄S/QW嚗?- [ ] <20>孵稬<E5ADB5>厰僼<E58EB0>𡡞<EFBFBD>蝥喳<E89DA5>?- [ ] UI銋鞱<E98A8B><E99EB1>湔鰵嚗<E9B0B5><E59A97><EFBFBD>喟<EFBFBD><E5969F><EFBFBD><EFBFBD>
- API靚<EFBFBD>鍂<EFBFBD>𣂼<EFBFBD>
**靘扯器<E689AF>?*嚗?- [ ] <20>孵稬銵峕𧒄靘扯器<E689AF>𤩺<EFBFBD><F0A4A9BA>?- [ ] <20>曄內摰峕㟲<E5B395><E39FB2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
- <EFBFBD>曄內摮埈挾<EFBFBD><EFBFBD>倌嚗<EFBFBD><EFBFBD>蝒<EFBFBD><EFBFBD>畾菟<EFBFBD>鈭殷<EFBFBD>
- <EFBFBD>孵稬<EFBFBD>喲𡡒<EFBFBD>厰僼<EFBFBD>硋<EFBFBD><EFBFBD>典躹<EFBFBD>笔<EFBFBD><EFBFBD>凋儒颲寞<EFBFBD>
Toolbar嚗?- [ ] <20>脩<EFBFBD><E884A9>啁<EFBFBD>霈⊥迤蝖?- [ ] 摰墧𧒄<E5A2A7>湔鰵嚗<E9B0B5><E59A97><EFBFBD>喳<EFBFBD><E596B3>誩<EFBFBD>嚗?- [ ] 撖澆枂<E6BE86>厰僼<E58EB0>舐<EFBFBD><E88890>?- [ ] 摰峕<E691B0><E5B395>厰僼頝唾蓮<E594BE>訕tep 5
<EFBFBD>𣑐 銝<><E98A9D><EFBFBD>hase 5: Tool B - Step 5嚗㇄ay 5銝𠰴<E98A9D>嚗?
7.1 蝏𤘪<E89D8F>撖澆枂嚗?撠𤩺𧒄嚗?
7.1.1 憿菟𢒰霈曇恣
蝏<EFBFBD>辣嚗䫤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>
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撖澆枂
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>嵩
const handleGoToToolC = () => {
// 頝唾蓮<E594BE>啣極<E595A3>嵩嚗䔶<E59A97><E494B6>㦙askId
navigate(`/data-cleaning/tool-c?sourceTaskId=${taskId}`);
};
7.2 撉峕𤣰<E5B395><F0A4A3B0><EFBFBD>
- 蝏蠘恣<EFBFBD>∠<EFBFBD><EFBFBD>唳旿甇<EFBFBD>&<EFBFBD>曄內
- Token瘨<EFBFBD><EFBFBD>堒<EFBFBD><EFBFBD>鞉𧋦霈∠<EFBFBD>甇<EFBFBD>&
- 銝贝蝸<EFBFBD>厰僼閫血<EFBFBD>Excel撖澆枂
- Excel<EFBFBD><EFBFBD>辣<EFBFBD><EFBFBD>鉄4銝杵heet嚗<EFBFBD><EFBFBD><EFBFBD>渡<EFBFBD><EFBFBD>栶<EFBFBD><EFBFBD><EFBFBD><EFBFBD>脩<EFBFBD><EFBFBD><EFBFBD><EFBFBD>蝒<EFBFBD>★<EFBFBD><EFBFBD>仃韐仿★嚗?- [ ] 瘚<>蓮<EFBFBD>啣極<E595A3>嵩<EFBFBD>厰僼<E58EB0>舐<EFBFBD><E88890>鳴<EFBFBD><E9B3B4>鞟內<E99E9F><E585A7>𧊋撘<F0A78A8B><E69298>𡢅<EFBFBD>
- 餈𥪜<EFBFBD>Portal<EFBFBD>厰僼<EFBFBD>舐<EFBFBD><EFBFBD>?
<EFBFBD>妒 <20>怒<EFBFBD><E68092>hase 6: <20><><EFBFBD>瘚贝<E7989A>嚗㇄ay 5銝见<E98A9D>嚗?
8.1 蝡臬<E89DA1>蝡舀<E89DA1>霂閙<E99C82><E99699>?
8.1.1 摰峕㟲瘚<E39FB2><E7989A>瘚贝<E7989A>
瘚贝<EFBFBD><EFBFBD>箸艶嚗朞<EFBFBD><EFBFBD>𣬚<EFBFBD><EFBFBD><EFBFBD>𥁒<EFBFBD>𦠜<EFBFBD><EFBFBD>? 瘚贝<EFBFBD>甇仿炊嚗?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>
*瘚贝<EFBFBD><EFBFBD>箸艶1嚗𡁜<EFBFBD>摨瑟<EFBFBD><EFBFBD>亙仃韐?
- 銝𠹺<EFBFBD>Excel嚗屸<EFBFBD>㗇𥋘蝛箏<EFBFBD>潛<EFBFBD>>50%<25><><EFBFBD>
- 撉諹<EFBFBD><EFBFBD>亙熒摨行遬蝷箔蛹"蝥Z𠧧 - 霅血<E99C85>"
- 撉諹<EFBFBD>"銝衤<E98A9D>甇?<3F>厰僼鋡怎<E98BA1><E6808E>? *瘚贝<EFBFBD><EFBFBD>箸艶2嚗帋遙<EFBFBD>∪仃韐?
- 璅⊥<EFBFBD>API餈𥪜<EFBFBD>憭梯揖<EFBFBD>嗆<EFBFBD>?- [ ] 撉諹<E69289><E8ABB9>躰秤<E8BAB0>鞟內<E99E9F>曄內
- 撉諹<EFBFBD><EFBFBD>臭誑<EFBFBD>齿鰵撠肽<EFBFBD>
*瘚贝<EFBFBD><EFBFBD>箸艶3嚗𡁶<EFBFBD>蝏𣈯<EFBFBD>霂?
- <EFBFBD>剔<EFBFBD><EFBFBD>𡒊<EFBFBD><EFBFBD>?銝衤<E98A9D>甇?
- 撉諹<EFBFBD><EFBFBD>躰秤<EFBFBD>鞟內<EFBFBD>曄內
- <EFBFBD>齿鰵<EFBFBD>𠉛<EFBFBD><EFBFBD>𤾸虾蝏抒賒
8.2 <20>扯<EFBFBD>瘚贝<E7989A>
瘚贝<EFBFBD><EFBFBD>箸艶嚗𡁜之<EFBFBD>唳旿<EFBFBD>誯<EFBFBD>霂<EFBFBD><EFBFBD><EFBFBD>? 瘚贝<EFBFBD>甇仿炊嚗?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
- 鋆<EFBFBD><EFBFBD><EFBFBD>滢<EFBFBD><EFBFBD>滚<EFBFBD><EFBFBD>園𡢿 < 500ms
8.3 <20>澆捆<E6BE86>扳<EFBFBD>霂?
**瘚讛<E7989A><E8AE9B>?*嚗?- [ ] Chrome 120+
- Edge 120+
- Firefox 120+
- Safari 17+嚗㇈ac嚗? **<2A><>儘<EFBFBD>?*嚗?- [ ] 1920x1080嚗<30>虜閫<E8999C><E996AB>
- 1440x900嚗<EFBFBD><EFBFBD>霈唳𧋦嚗?- [ ] 2560x1440嚗<30><E59A97><EFBFBD><EFBFBD><EFBFBD>嚗?
<EFBFBD><EFBFBD> 銋腈<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. [ ] **<2A>砍<EFBFBD><E7A08D>𤏸恣<F0A48FB8>垍<EFBFBD>摰峕<E691B0><E5B395>餌<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嚗?
<EFBFBD>㴓 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>格<EFBFBD><E6A0BC>航<EFBFBD><E888AA>?
10.1 敹<>◆<EFBFBD>萄<EFBFBD><E89084><EFBFBD><EFBFBD><EFBFBD>?
鈭穃<EFBFBD><EFBFBD>蠘<EFBFBD><EFBFBD>?潃?撘箏<E69298>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>docs/04-撘<><E69298>𤏸<EFBFBD><F0A48FB8>?08-鈭穃<E988AD><E7A983>笔<EFBFBD><E7AC94>𤏸<EFBFBD><F0A48FB8>?md
蝳<EFBFBD>迫嚗?- <20>?雿輻鍂fs.writeFile()蝑㗇𧋦<EFBFBD>唳<EFBFBD>隞嗆<EFBFBD>雿?- <20>?雿輻鍂<E8BCBB>典<EFBFBD><E585B8>㗛<EFBFBD>蝻枏<E89DBB><E69E8F>唳旿
- <EFBFBD>?蝖祉<E89D96><E7A589><EFBFBD><EFBFBD>蝵殷<E89DB5>IP<49><50><EFBFBD><EFBFBD>亦<EFBFBD>嚗?- <20>?<3F>峕郊<E5B395>蹂遙<E8B982>∴<EFBFBD>>10蝘𡜐<E89D98>
- <EFBFBD>?<3F>滚<EFBFBD>摰䂿緵撟喳蝱<E596B3>賢<EFBFBD>
**敹<>◆**嚗?- <20>?雿輻鍂storage<EFBFBD>滚𦛚摮睃<EFBFBD><EFBFBD><EFBFBD>辣
- <EFBFBD>?雿輻鍂
cache<EFBFBD>滚𦛚蝻枏<EFBFBD><EFBFBD>唳旿 - <EFBFBD>?雿輻鍂<E8BCBB>臬<EFBFBD><E887AC>㗛<EFBFBD><E3979B>滨蔭
- <EFBFBD>?撘<>郊隞餃𦛚 + 餈𥕦漲頧株砭
- <EFBFBD>?憭滨鍂撟喳蝱<E596B3>箇<EFBFBD>霈暹鴌
10.2 憭滨鍂蝑𣇉裦
<EFBFBD>𡒊垢憭滨鍂嚗<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// <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';
<EFBFBD>滨垢憭滨鍂嚗<EFBFBD><EFBFBD>摰䂿緵嚗?```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>
蝏煺<EFBFBD>蝐餃<EFBFBD><EFBFBD><EFBFBD>辣嚗䫤frontend-v2/src/modules/dc/types/toolB.ts`
// <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[];
}
<EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>抵<EFBFBD>隡唬<E99AA1>摨𥪜笆
11.1 <20><><EFBFBD>舫<EFBFBD><E888AB>?
| 憌𡡞埯 | 璁<EFBFBD><EFBFBD> | 敶勗<EFBFBD> | 摨𥪜笆<EFBFBD>芣鴌 |
|---|---|---|---|
| *<EFBFBD>唳旿摨栞”<EFBFBD>芸<EFBFBD>撱? | 銝? | 擃? | 蝡见朖<EFBFBD>扯<EFBFBD>npx prisma db push撉諹<EFBFBD> |
| *<EFBFBD>𡒊垢API<EFBFBD>芣<EFBFBD>霂? | 銝? | 擃? | 撘<EFBFBD><EFBFBD>穃<EFBFBD><EFBFBD><EFBFBD>鍂REST Client瘚贝<E7989A>6銝芰垢<E88AB0>? |
| <EFBFBD>扯<EFBFBD><EFBFBD>桅<EFBFBD>嚗<EFBFBD>之<EFBFBD>唳旿<EFBFBD>𧶏<EFBFBD> | 雿? | 銝? | 憸<EFBFBD><EFBFBD>TanStack Table餈<65>宏<EFBFBD>寞<EFBFBD> |
| Excel閫<EFBFBD><EFBFBD>憭梯揖 | 雿? | 銝? | 雿輻鍂xlsx摨橒<EFBFBD>憓𧼮<EFBFBD><EFBFBD>躰秤憭<EFBFBD><EFBFBD> |
| LLM靚<EFBFBD>鍂頞<EFBFBD>𧒄 | 雿? | 銝? | <EFBFBD>𡒊垢撌脣<EFBFBD><EFBFBD>圈<EFBFBD>霂閙㦤<EFBFBD>? |
11.2 <20>園𡢿憌𡡞埯
| 憌𡡞埯 | 璁<EFBFBD><EFBFBD> | 敶勗<EFBFBD> | 摨𥪜笆<EFBFBD>芣鴌 |
|---|---|---|---|
| *Step 4撘<34><E69298>𤏸<EFBFBD><F0A48FB8>? | 銝? | 擃? | 憸<EFBFBD><EFBFBD>2憭抬<EFBFBD>9撠𤩺𧒄嚗㚁<EFBFBD><EFBFBD>舀<EFBFBD><EFBFBD><EFBFBD><EFBFBD>隞餃𦛚 |
| <EFBFBD><EFBFBD><EFBFBD>瘚贝<EFBFBD><EFBFBD>𤑳緵<EFBFBD>桅<EFBFBD> | 銝? | 銝? | 憸<EFBFBD><EFBFBD>1憭拍<EFBFBD><EFBFBD>脫𧒄<EFBFBD>? |
| *<EFBFBD>笔<EFBFBD>銝𡡞<EFBFBD>瘙<EFBFBD><EFBFBD>蝚? | 雿? | 擃? | 撘<EFBFBD><EFBFBD>穃<EFBFBD>銝𦒘漣<EFBFBD><EFBFBD>&霈文<EFBFBD><EFBFBD>? |
11.3 靘肽<E99D98>憌𡡞埯
| 憌𡡞埯 | 璁<EFBFBD><EFBFBD> | 敶勗<EFBFBD> | 摨𥪜笆<EFBFBD>芣鴌 |
|---|---|---|---|
| <EFBFBD>𡒊垢API<EFBFBD>䀹凒 | 雿? | 擃? | 雿輻鍂TypeScript蝐餃<EFBFBD>嚗𣬚<EFBFBD>霂烐𧒄璉<EFBFBD><EFBFBD>? |
| 撟喳蝱<EFBFBD>賢<EFBFBD>Bug | 雿? | 銝? | 撌脣<EFBFBD><EFBFBD>湔<EFBFBD>霂𤏪<EFBFBD>憌𡡞埯雿? |
| 霈曇恣<EFBFBD>䀹凒 | 雿? | 銝? | 蝏<EFBFBD>辣<EFBFBD>𤥁挽霈∴<EFBFBD><EFBFBD>㮖<EFBFBD>靽格㺿 |
<EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
12.1 鈭支<E988AD><E694AF>拇<EFBFBD><E68B87>?
**隞<><E99A9E>**嚗?- [ ] Portal撌乩<E6928C><E4B9A9>圈△<E59C88>g<EFBFBD>摰峕㟲嚗?- [ ] Tool B 5銝杵tep憿菟𢒰嚗<F0A292B0><E59A97><EFBFBD>湛<EFBFBD>
- <EFBFBD>曹澈蝏<EFBFBD>辣摨橒<EFBFBD>TaskList<EFBFBD><EFBFBD>ssetLibrary<EFBFBD><EFBFBD>onflictCell蝑㚁<EFBFBD>
- API<EFBFBD>滚𦛚撠<EFBFBD><EFBFBD>嚗ōoolBApi.ts<74><73>ortalApi.ts嚗?- [ ] TypeScript蝐餃<E89D90>摰帋<E691B0>嚗<EFBFBD><E59A97><EFBFBD>湛<EFBFBD>
- <EFBFBD>瑕<EFBFBD><EFBFBD><EFBFBD>辣嚗㇍ailwindCSS + Ant Design嚗? **<2A><>﹝**嚗?- [ ] <20>滨垢<E6BBA8>嗆<EFBFBD>霈曇恣<E69B87><E681A3>﹝
- 蝏<EFBFBD>辣雿輻鍂<EFBFBD><EFBFBD>﹝
- API撖寞𦻖<EFBFBD><EFBFBD>﹝
- 撘<EFBFBD><EFBFBD>穃<EFBFBD><EFBFBD>鞉<EFBFBD>餌<EFBFBD>
- <EFBFBD>冽<EFBFBD>雿輻鍂<EFBFBD><EFBFBD><EFBFBD>嚗<EFBFBD>虾<EFBFBD>㚁<EFBFBD>
**瘚贝<E7989A>**嚗?- [ ] 蝡臬<E89DA1>蝡舀<E89DA1>霂閙𥁒<E99699>?- [ ] <20>扯<EFBFBD>瘚贝<E7989A><E8B49D>亙<EFBFBD>
- <EFBFBD>澆捆<EFBFBD>扳<EFBFBD>霂閙𥁒<EFBFBD>?
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>
- <EFBFBD>?Step 3: <20>𣬚𤩅<F0A3AC9A>𣂼<EFBFBD>餈𥕦漲<F0A595A6>烐綉
- <EFBFBD>?Step 4: <20>脩<EFBFBD>撉諹<E69289>蝵烐聢嚗<E881A2>𣈲<EFBFBD><F0A388B2><EFBFBD><EFBFBD>喉<EFBFBD>
- <EFBFBD>?Step 5: 蝏𤘪<E89D8F>撖澆枂嚗𠄌xcel + 瘚<>蓮嚗?
12.3 隞<><E99A9E>韐券<E99F90>
**隞<><E99A9E>閫<EFBFBD><E996AB>**嚗?- <20>?<3F>萄<EFBFBD>鈭穃<E988AD><E7A983>笔<EFBFBD><E7AC94>𤏸<EFBFBD><F0A48FB8>?- <20>?TypeScript蝐餃<E89D90>摰匧<E691B0>
- <EFBFBD>?ESLint<6E>𣳇<EFBFBD>霂?- <20>?隞<><E99A9E>瘜券<E7989C>摰<EFBFBD><E691B0>
**<2A>扯<EFBFBD><E689AF><EFBFBD><EFBFBD>**嚗?- <20>?擐硋<E69390><E7A18B>㰘蝸 < 2s
- <EFBFBD>?銵冽聢皛𡁜𢆡瘚<F0A286A1><E7989A>
- <EFBFBD>?鋆<><E98B86><EFBFBD>滚<EFBFBD> < 500ms
- <EFBFBD>?<3F><><EFBFBD><EFBFBD>删鍂 < 200MB
**<2A>冽<EFBFBD>雿㯄<E99BBF>**嚗?- <20>?瘚<><E7989A><EFBFBD>?甇交<E79487>蝔?- <20>?摰墧𧒄餈𥕦漲<F0A595A6>漤<EFBFBD>
- <EFBFBD>?<3F>渲<EFBFBD><E6B8B2><EFBFBD><EFBFBD>蝒<EFBFBD><E89D92>霂<EFBFBD><E99C82><EFBFBD>?- <20>?<3F>见末<E8A781><E69CAB><EFBFBD>霂舀<E99C82>蝷?
<EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>銝<EFBFBD>甇亥<E79487><E4BAA5>?
13.1 蝡见朖<E8A781>扯<EFBFBD>嚗㇄ay 0嚗?
1. 撉諹<E69289><E8ABB9>唳旿摨栞”
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>
# 撱箄悅瘥誩<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嚗𡁜<EFBFBD>撱摺ortal憿菟𢒰撉冽沲
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嚗𡁜<EFBFBD><EFBFBD>?銝芸極<E88AB8>瑕㨃<E79195>?
# <20>𥕦遣ToolCard蝏<64>辣
touch components/ToolCard.tsx
*隞餃𦛚3嚗𡁜<EFBFBD><EFBFBD>唬遙<EFBFBD>∪<EFBFBD>銵剁<EFBFBD>雿輻鍂Mock<EFBFBD>唳旿嚗?
# <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<EFBFBD>𡑒”<EFBFBD>臬炏<EFBFBD>湔鰵
- <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>䔮憸䀹糓<EFBFBD>西扇敶?- [ ] 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>皞?
<EFBFBD><EFBFBD> <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>摰⊥䰻
**<2A>𣂷漱<F0A382B7>滩䌊璉<E48C8A>**嚗?- [ ] <20>臬炏<E887AC>萄<EFBFBD>鈭穃<E988AD><E7A983>蠘<EFBFBD><E8A098>?- [ ] <20>臬炏憭滨鍂撟喳蝱<E596B3>賢<EFBFBD>
- TypeScript蝐餃<EFBFBD><EFBFBD>臬炏摰峕㟲
- <EFBFBD>臬炏<EFBFBD>凤ODO/FIXME瘜券<E7989C>
- <EFBFBD>臬炏<EFBFBD>実onsole.log嚗<67><E59A97>雿輻鍂logger嚗?
<EFBFBD>㴓 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>餌<EFBFBD>
<EFBFBD>詨<EFBFBD><EFBFBD>格<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>?
<EFBFBD>喲睸<EFBFBD>𣂼<EFBFBD><EFBFBD>删<EFBFBD>
- <EFBFBD>?**<2A>𡒊垢撌?00%摰峕<E691B0>**嚗<><E59A97>蝡臬虾銝𤘪釣UI<55>䔶漱鈭?2. <20>?**撟喳蝱<E596B3>賢<EFBFBD>摰<EFBFBD><E691B0>**嚗<>虾<EFBFBD>湔𦻖憭滨鍂嚗峕<E59A97><E5B395><EFBFBD><EFBFBD>滚<EFBFBD>撘<EFBFBD><E69298>?3. <20>?霈曇恣<EFBFBD><EFBFBD>﹝朣𣂼<EFBFBD>嚗峕<EFBFBD>皜<EFBFBD>苊<EFBFBD><EFBFBD><EFBFBD><EFBFBD>见<EFBFBD><EFBFBD><EFBFBD>瘙?4. <20>?<EFBFBD><EFBFBD><EFBFBD><EFBFBD>芋<EFBFBD>埈<EFBFBD><EFBFBD>?*嚗淾SL璅∪<E79285><E288AA>臭<EFBFBD>銝箏<E98A9D><E7AE8F>?5. <20>?<EFBFBD>嗆<EFBFBD><EFBFBD>寞<EFBFBD><EFBFBD>𡒊&**嚗屸<E59A97><E5B1B8>冽䲮獢㇁嚗<E38781>𡠺蝡閪ortal嚗?
憸<EFBFBD><EFBFBD><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>瘙?
撘<EFBFBD><EFBFBD>𤏸恣<EFBFBD>鍦<EFBFBD>摰𡁜<EFBFBD><EFBFBD>琜<EFBFBD> <20>? **銝衤<E98A9D>甇?*嚗𡁻<E59A97>霂<EFBFBD>㺭<EFBFBD>桀<EFBFBD>銵?<3F>?瘚贝<E7989A><E8B49D>𡒊垢API <20>?撘<>憪閪hase 1嚗㇊ortal憿菟𢒰撘<F0A292B0><E69298>𡢅<EFBFBD>
憸<EFBFBD>恣摰峕<EFBFBD><EFBFBD>園𡢿嚗?-6銝芸極雿𨀣𠯫
蟡嘥<EFBFBD><EFBFBD>煾◇<EFBFBD>抬<EFBFBD> <20><>