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 && (
)}
{[
{ 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
| Customer |
Part No |
Stage |
EAU |
{PARSED_DIT_DATA.map((row, i) => (
| {row.customer} |
{row.pn} |
{row.stage} |
{row.eau.toLocaleString()} |
))}
訂單解析結果 (預覽)
Detected CP950
| Customer |
Part No |
Status |
Qty |
{PARSED_ORDER_DATA.map((row, i) => (
| {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
| OP編號 |
Customer |
Part No. |
EAU |
Sample Order |
Order Status |
{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 (
|
{row.id}
|
{row.customer}
{row.stage}
|
{row.pn} |
{row.eau.toLocaleString()} |
{/* Sample Column */}
{finalSample ? (
{finalSample.order_no}
) : (
-
)}
|
{/* Order Column */}
{finalOrder ? (
{finalOrder.order_no}
) : (
-
)}
|
)
})}
)}
);
}