import React, { useState, useEffect } from 'react'; import { UploadCloud, FileSpreadsheet, ArrowRight, CheckCircle2, AlertCircle, Settings2, Table2, CalendarClock, Columns, Download, Bot, ChevronRight, ChevronDown, Trash2, Info } from 'lucide-react'; // --- 类型定义 --- type Step = 'upload' | 'anchor' | 'columns' | 'processing' | 'result'; interface FileItem { id: string; name: string; size: string; rows: number; status: 'ready' | 'error'; columns: string[]; } const ToolA_SuperMerger = () => { const [currentStep, setCurrentStep] = useState('upload'); // 模拟已上传的文件 const [files, setFiles] = useState([ { id: 'f1', name: '2023_住院记录_主表.xlsx', size: '2.4 MB', rows: 3500, status: 'ready', columns: ['住院号', '姓名', '入院日期', '出院日期', '主诊断', '科室'] }, { id: 'f2', name: '检验科_血常规.xlsx', size: '15.1 MB', rows: 45000, status: 'ready', columns: ['病人ID', '报告时间', '白细胞', '红细胞', '血红蛋白', '审核医生'] }, { id: 'f3', name: '超声检查报告.xlsx', size: '8.2 MB', rows: 12000, status: 'ready', columns: ['申请号', 'PatientNo', '检查时间', '超声描述', '超声提示'] }, ]); // 配置状态 const [mainFileId, setMainFileId] = useState('f1'); const [idColumn, setIdColumn] = useState('住院号'); const [timeColumn, setTimeColumn] = useState('入院日期'); const [timeWindow, setTimeWindow] = useState('window'); // 'window' | 'nearest' // 模拟列选择状态 (默认全选) const [selectedCols, setSelectedCols] = useState>({ 'f1': ['住院号', '入院日期', '主诊断'], 'f2': ['白细胞', '红细胞'], 'f3': ['超声提示'] }); // 处理列勾选切换 const toggleColumn = (fileId: string, col: string) => { setSelectedCols(prev => { const currentCols = prev[fileId] || []; const isSelected = currentCols.includes(col); let newCols; if (isSelected) { newCols = currentCols.filter(c => c !== col); } else { newCols = [...currentCols, col]; } return { ...prev, [fileId]: newCols }; }); }; // 处理状态 const [progress, setProgress] = useState(0); // 模拟处理动画 useEffect(() => { if (currentStep === 'processing') { const interval = setInterval(() => { setProgress(prev => { if (prev >= 100) { clearInterval(interval); setCurrentStep('result'); return 100; } return prev + 2; }); }, 50); return () => clearInterval(interval); } }, [currentStep]); // --- 渲染函数 --- // 步骤导航条 const renderSteps = () => (
{[ { id: 'upload', label: '1. 上传数据' }, { id: 'anchor', label: '2. 定基准(骨架)' }, { id: 'columns', label: '3. 选列(血肉)' }, { id: 'result', label: '4. 结果报告' } ].map((step, idx, arr) => (
s.id === currentStep) > idx || currentStep === 'result') ? 'bg-emerald-500 text-white' : 'bg-slate-200 text-slate-500'}`}> {(arr.findIndex(s => s.id === currentStep) > idx || currentStep === 'result') && step.id !== currentStep ? : idx + 1}
{step.label}
{idx < arr.length - 1 && (
s.id === currentStep) > idx ? 'bg-emerald-500' : 'bg-slate-200'}`}>
)}
))}
); return (
{/* Header */}

超级合并器

基于访视(Visit)的智能对齐引擎

{/* Body */}
{renderSteps()} {/* Step 1: Upload */} {currentStep === 'upload' && (

点击或拖拽上传 Excel 文件

支持 .xlsx, .csv 格式。建议上传 1 个主表(如住院记录)和多个辅表(如化验、检查单)。

已加载文件 ({files.length})

{files.map(file => (
{file.name}
{file.size} • {file.rows.toLocaleString()} 行
表头解析成功
))}
)} {/* Step 2: Anchor (骨架配置) */} {currentStep === 'anchor' && (
为什么要选主表? 主表决定了最终大表有多少行(即有多少次就诊记录)。辅表的数据将根据 ID时间 挂载到主表上。
{/* 2.1 选主表 */}

A 选择主表 (Visit Base)

{files.map(file => ( ))}
{/* 2.2 关键列映射 */}

B 关键列对齐

系统将自动在其他表中寻找同名或相似列进行对齐。

)} {/* Step 3: Columns (列选择 - 核心需求) */} {currentStep === 'columns' && (

定义输出结构

勾选您希望保留在最终大表中的列。未勾选的列将被丢弃。

{/* 左侧:源列树状选择 */}
源文件与列 全选
{files.map(file => (
{file.name} {file.id === mainFileId && '(主表)'}
{file.columns.map(col => ( ))}
))}
{/* 右侧:结果预览 (Schema Preview) */}
最终大表结构预览 (模拟一行数据)
{/* 主表列 */} {files.filter(f => f.id === mainFileId).map(f => ( f.columns.filter(c => selectedCols[f.id]?.includes(c)).map((col, idx) => (
{col}
{col === '住院号' ? 'ZY001' : (col === '姓名' ? '张三' : '...')}
)) ))} {/* 辅表列 */} {files.filter(f => f.id !== mainFileId).map(f => ( f.columns.filter(c => selectedCols[f.id]?.includes(c)).map(col => (
{col}
--
)) ))}
横向扩展:共选中 {Object.values(selectedCols).flat().length} 列
)} {/* Step 4: Processing */} {currentStep === 'processing' && (

正在智能合并数据...

正在基于时间窗匹配 {files.length} 个文件的 60,500 条记录

{progress}% 完成

)} {/* Step 5: Result (报告与出口) */} {currentStep === 'result' && (
3,450
成功生成就诊记录 (行)
12
ID 格式错误丢弃
42
生成总列数
黄金前 5 行预览 (Top 5 Preview)
{selectedCols['f1'].slice(0,3).map(c => )} {[1,2,3,4,5].map(i => ( ))}
{c}白细胞 超声提示
ZY00{i} 2023-01-0{i} 肺癌 {4+i}.5 {i%2===0 ? '结节' : '无异常'}
)}
{/* Footer Navigation */} {currentStep !== 'processing' && currentStep !== 'result' && (
)}
); }; export default ToolA_SuperMerger;