import React, { useState, useEffect } from 'react'; import { Upload, FileText, Database, CheckCircle, XCircle, AlertTriangle, BarChart2, PieChart, Activity, ArrowRight, Search, Filter, Download, RefreshCw, FileSpreadsheet, Info } from 'lucide-react'; import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip as RechartsTooltip, Legend, ResponsiveContainer, PieChart as RePieChart, Pie, Cell } from 'recharts'; // --- 真實模擬資料 (源自使用者上傳檔案) --- // 1. DIT Report (模擬解析後的結構) // 來源: DIT report (by Focus Item)_app_樣本.xlsx const PARSED_DIT_DATA = [ { id: 'OP0000012868', customer: '光寶科技股份有限公司', pn: 'GBU610', eau: 20000, stage: 'Design Win', date: '2025-02-04' }, { id: 'OP0000012869', customer: 'LITEON (PMS)', pn: 'PMSM808LL_R2', eau: 55000, stage: 'Design-In', date: '2025-07-28' }, { id: 'OP0000012870', customer: '台達電子', pn: 'PEC3205ES-AU', eau: 100000, stage: 'Sample Provide', date: '2025-08-15' }, // 故意用簡稱測試模糊比對 { id: 'OP0000012871', customer: '合美企業', pn: 'PJT7828', eau: 5000, stage: 'Negotiation', date: '2025-08-10' }, { id: 'OP0000012872', customer: '申浦电子', pn: 'ER1604FCT', eau: 30000, stage: 'Design Win', date: '2025-07-30' }, ]; // 2. Sample Data (模擬解析後的結構) // 來源: 樣品申請紀錄_樣本.xlsx const PARSED_SAMPLE_DATA = [ { id: 'S202512490-02', order_no: 'S202512490', customer: '台達電子工業股份有限公司', pn: 'PEC3205ES-AU', qty: 20, date: '2025-12-19' }, { id: 'S202512490-03', order_no: 'S202512490', customer: '台達電子工業股份有限公司', pn: 'PDZ9.1B-AU', qty: 20, date: '2025-12-19' }, ]; // 3. Order Data (模擬解析後的結構) // 來源: 訂單樣本_20251217.xlsx const PARSED_ORDER_DATA = [ { id: '1125025312-1', order_no: '1125025312', customer: '合美企業有限公司', pn: 'PJT7828', qty: 1200, status: 'Shipped', amount: 10800 }, { id: '1125062105-1', order_no: '1125062105', customer: '申浦电子', pn: 'ER1604FCT', qty: 800, status: 'Backlog', amount: 3200 }, ]; // --- 模糊比對模擬結果 --- const SIMULATED_REVIEWS = [ { id: 101, score: 88, dit: { id: 'OP0000012870', cust: '台達電子', pn: 'PEC3205ES-AU' }, match_target: { id: 'S202512490', cust: '台達電子工業股份有限公司', pn: 'PEC3205ES-AU', type: 'SAMPLE' }, type: 'SAMPLE', reason: 'Customer Name Partial Match (88%)' }, { id: 102, score: 92, dit: { id: 'OP0000012871', cust: '合美企業', pn: 'PJT7828' }, match_target: { id: '1125025312', cust: '合美企業有限公司', pn: 'PJT7828', type: 'ORDER' }, type: 'ORDER', reason: 'Corporate Suffix Mismatch' } ]; // --- 輔助元件 --- const Card = ({ children, className = "" }) => (
{children}
); const Badge = ({ children, type = "neutral" }) => { const styles = { neutral: "bg-slate-100 text-slate-600", success: "bg-emerald-100 text-emerald-700", warning: "bg-amber-100 text-amber-700", danger: "bg-rose-100 text-rose-700", info: "bg-blue-100 text-blue-700" }; return ( {children} ); }; // --- 主應用程式 --- export default function App() { const [activeTab, setActiveTab] = useState('import'); const [isProcessing, setIsProcessing] = useState(false); const [processingStep, setProcessingStep] = useState(''); const [filesLoaded, setFilesLoaded] = useState(false); // 狀態管理 const [reviews, setReviews] = useState([]); const [processedCount, setProcessedCount] = useState(0); // Dashboard 數據 const [dashboardData, setDashboardData] = useState({ totalDit: 5, matchedSample: 0, matchedOrder: 1, // '申浦电子' 是 Exact Match conversionRate: 20.0 }); // 模擬載入使用者的真實檔案 const loadUserFiles = () => { setFilesLoaded(true); }; // 模擬 ETL 執行 const runEtl = () => { if (!filesLoaded) { alert("請先載入檔案!"); return; } setIsProcessing(true); // 模擬後端處理步驟 const steps = [ "正在讀取 DIT Report... 偵測到表頭在第 16 行", "正在讀取 樣品紀錄... 偵測到表頭在第 9 行", "正在讀取 訂單明細... 編碼識別為 CP950", "執行資料標準化 (Normalization)...", "執行模糊比對 (Fuzzy Matching)...", "運算完成!" ]; let stepIndex = 0; const interval = setInterval(() => { if (stepIndex >= steps.length) { clearInterval(interval); setIsProcessing(false); setReviews(SIMULATED_REVIEWS); // 載入模擬的比對結果 setActiveTab('review'); } else { setProcessingStep(steps[stepIndex]); stepIndex++; } }, 800); }; // 處理審核動作 const handleReviewAction = (id, action) => { const reviewItem = reviews.find(r => r.id === id); setReviews(prev => prev.filter(r => r.id !== id)); if (action === 'accept') { setProcessedCount(prev => prev + 1); // 更新 Dashboard 數據 (模擬) if (reviewItem.type === 'ORDER') { setDashboardData(prev => ({ ...prev, matchedOrder: prev.matchedOrder + 1, conversionRate: ((prev.matchedOrder + 1) / prev.totalDit * 100).toFixed(1) })); } else if (reviewItem.type === 'SAMPLE') { setDashboardData(prev => ({ ...prev, matchedSample: prev.matchedSample + 1 })); } } }; // 漏斗圖資料 const funnelData = [ { name: 'DIT 案件', value: dashboardData.totalDit, fill: '#6366f1' }, { name: '成功送樣', value: dashboardData.matchedSample, fill: '#8b5cf6' }, { name: '取得訂單', value: dashboardData.matchedOrder, fill: '#10b981' }, ]; return (
{/* Top Navigation */}
S
SalesPipeline On-Premise Simulator
{[ { id: 'import', icon: Database, label: '資料匯入' }, { id: 'review', icon: CheckCircle, label: '比對審核', badge: reviews.length }, { id: 'dashboard', icon: BarChart2, label: '分析儀表板' } ].map(tab => ( ))}
系統運作中
{/* --- View 1: Import --- */} {activeTab === 'import' && (

原始資料匯入中心

系統將自動偵測 Excel/CSV 檔頭位置並進行智慧欄位對應。

{/* Progress Log */} {isProcessing && (

{processingStep}

)}
{[ { type: 'dit', title: '1. DIT Report', file: 'DIT report_app_樣本.xlsx', desc: '含 Metadata (前16行)', count: '5 筆 (測試)' }, { type: 'sample', title: '2. 樣品紀錄', file: '樣品申請紀錄_樣本.xlsx', desc: '含檔頭 (前9行)', count: '2 筆 (測試)' }, { type: 'order', title: '3. 訂單明細', file: '訂單樣本_20251217.xlsx', desc: '標準格式', count: '2 筆 (測試)' }, ].map(file => (
{filesLoaded ? : }
{filesLoaded && Ready}

{file.title}

{filesLoaded ? file.file : "等待上傳..."}

{file.desc}

{filesLoaded && (
預覽筆數 {file.count}
)}
))}
{/* Data Preview (Mocked from User Files) */} {filesLoaded && (

DIT 解析結果 (預覽)

Auto-Skipped Header
{PARSED_DIT_DATA.map((row, i) => ( ))}
Customer Part No Stage EAU
{row.customer} {row.pn} {row.stage} {row.eau.toLocaleString()}

訂單解析結果 (預覽)

Detected CP950
{PARSED_ORDER_DATA.map((row, i) => ( ))}
Customer Part No Status Qty
{row.customer} {row.pn} {row.status} {row.qty.toLocaleString()}
)}
)} {/* --- View 2: Review --- */} {activeTab === 'review' && (

模糊比對審核工作台 待審核: {reviews.length}

系統發現以下案件名稱相似,請人工確認關聯性。

{reviews.length === 0 ? (

所有案件已審核完畢!

您的資料比對已完成,請查看分析儀表板。

) : (
{reviews.map(item => (
{/* Left: DIT */}
DIT (設計導入) OP編號: {item.dit.id}
Customer Name
{item.dit.cust}
Part Number
{item.dit.pn}
{/* Middle: Score & Reason */}
{item.score}%
相似度
{item.reason}
{/* Right: Target (Sample/Order) */}
{item.type === 'ORDER' ? 'Order (訂單)' : 'Sample (樣品)'} 來源單號: {item.match_target.id}
Customer Name
{item.match_target.cust}
Part Number
{item.match_target.pn}
{/* Actions */}
))}
)}
)} {/* --- View 3: Dashboard --- */} {activeTab === 'dashboard' && (

業務轉換率戰情室

數據來源:DIT Report, 樣品紀錄, 訂單明細 (2025-12-17)

{/* KPI Cards */}
DIT 總案件數
{dashboardData.totalDit}
Raw Data Count
成功送樣數
{dashboardData.matchedSample}
{processedCount > 0 ? `(含人工審核 +1)` : ''}
取得訂單 (Backlog)
{dashboardData.matchedOrder}
Match Rate: {dashboardData.conversionRate}%
預估營收 (Revenue)
$14,000
Based on matched orders
{/* Funnel Chart */}

DIT 轉換漏斗 (Funnel Analysis)

{funnelData.map((entry, index) => ( ))}
{/* Status Pie Chart */}

訂單狀態佔比

{/* Attribution Table Preview */}

DIT 歸因明細表 (LIFO 邏輯)

Hover to see order details
{PARSED_DIT_DATA.map((row, i) => { // 簡單模擬關聯邏輯 (Find exact matches or partial matches) const matchedOrder = PARSED_ORDER_DATA.find(o => o.customer.includes(row.customer) || row.customer.includes(o.customer.substring(0, 2))); const matchedSample = PARSED_SAMPLE_DATA.find(s => s.customer.includes(row.customer) || row.customer.includes(s.customer.substring(0, 2))); // 人工審核修正 (台達電子 & 合美) const isReviewedSample = (row.customer === '台達電子' && processedCount > 0) ? {order_no: 'S202512490'} : null; const isReviewedOrder = (row.customer === '合美企業' && processedCount > 1) ? {order_no: '1125025312'} : null; // 決定顯示內容 const finalSample = matchedSample || isReviewedSample; const finalOrder = matchedOrder || isReviewedOrder; return ( {/* Sample Column */} {/* Order Column */} ) })}
OP編號 Customer Part No. EAU Sample Order Order Status
{row.id} {row.customer}
{row.stage}
{row.pn} {row.eau.toLocaleString()} {finalSample ? (
{finalSample.order_no}
) : ( - )}
{finalOrder ? (
{finalOrder.order_no}
) : ( - )}
)}
); }