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

43 KiB
Raw Blame History

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>扇敶𤏪<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>扇敶?(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><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><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>
  1. 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`
  2. *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蝘坿蔭霂<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><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><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><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>

  1. <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><>