import React, { useState, useEffect } from 'react'; import { Calculator, TrendingUp, Flame, Lock, Activity, Lightbulb, ShieldCheck, FileText, Crown, Coins, PiggyBank, ArrowRight, UserCheck, Building2, Undo2, Sprout, Info, MousePointerClick, Settings2, Percent, Zap, MessageCircle, CheckCircle2, Sliders, Eye, EyeOff, Home, Repeat, Layers, ArrowLeftRight } from 'lucide-react'; // --- 共用元件 (Morandi Style) --- const Card = ({ children, className = "" }) => (
{children}
); const NumberInput = ({ label, value, onChange, unit, step = 1, min = 0, placeholder, disabled = false }) => (
onChange(Number(e.target.value))} placeholder={placeholder} disabled={disabled} className="w-full sm:w-28 px-3 py-1.5 bg-[#F9F7F5] border border-[#E0D8D0] rounded-lg text-right font-bold text-[#4A4A4A] focus:outline-none focus:border-[#8DA399] focus:ring-1 focus:ring-[#8DA399] transition-all placeholder-[#B0B0B0] text-sm" /> {unit}
); // 開關型輸入控制 (選填項目) const ToggleInput = ({ label, value, onChange, unit, step = 1, isActive, onToggle, placeholder }) => (
onChange(Number(e.target.value))} placeholder={placeholder} className="w-full sm:w-28 px-3 py-1.5 bg-[#F9F7F5] border border-[#E0D8D0] rounded-lg text-right font-bold text-[#4A4A4A] focus:outline-none focus:border-[#8DA399] focus:ring-1 focus:ring-[#8DA399] transition-all text-sm" /> {unit}
); // 顧問專用微調參數列 const ProInputRow = ({ label, value, onChange, unit, step = 0.1 }) => (
{label}
onChange(Number(e.target.value))} step={step} className="w-12 text-right text-xs font-bold text-slate-600 bg-transparent focus:outline-none" /> {unit}
); // 比較專用的列組件 const SummaryRow = ({ label, traditional, optimized, diff, isHighlight = false }) => (
{label}
一般
{traditional}
規劃後
{optimized}
{diff &&
{diff}
}
); // 莫蘭迪減壓勳章 const ImpactBadge = ({ percent, labelOverride }) => (
{labelOverride || "壓力減輕"}
{(percent || 0).toFixed(0)}%
); // --- 主程式 --- export default function AssetOptimizationSystem_Pro() { const [view, setView] = useState('landing'); const formatCurrency = (val) => new Intl.NumberFormat('zh-TW', { style: 'currency', currency: 'TWD', maximumFractionDigits: 0 }).format(val || 0); const formatWan = (val) => ((val || 0) / 10000).toFixed(0); // --- Landing Page --- if (view === 'landing') { return (
CONSULTANT MODE

資產優化.專業規劃系統

專業版介面 (參數全解鎖)

setView('buyer')} className="bg-white p-10 rounded-[2rem] shadow-sm border border-[#EBE6E1] hover:border-[#8DA399] hover:shadow-md transition-all duration-300 cursor-pointer group flex flex-col items-center text-center relative" >

買房規劃 (A計畫)

適用:首購、換屋、預售屋

setView('owner')} className="bg-white p-10 rounded-[2rem] shadow-sm border border-[#EBE6E1] hover:border-[#BFA6A2] hover:shadow-md transition-all duration-300 cursor-pointer group flex flex-col items-center text-center relative" >

資產活化 (B/C計畫)

適用:有房貸壓力、增值提領

); } return (
{view === 'buyer' ? : }
); } // ---------------------------------------------------------------------- // 情境 A: 首購族 (顧問版 - 參數全開) // ---------------------------------------------------------------------- function BuyerCalculator({ formatCurrency, formatWan }) { const [price, setPrice] = useState(2000); const [loanPct, setLoanPct] = useState(80); const [year, setYear] = useState(30); const [rate, setRate] = useState(2.3); const [grace, setGrace] = useState(3); // 新增:資金實力 (自備款比例) const [cashPct, setCashPct] = useState(20); // 預設 20% // 策略選擇:split (分流) vs leverage (槓桿) const [planType, setPlanType] = useState('split'); // Pro Params const [yieldRate, setYieldRate] = useState(8.0); const [policyRate, setPolicyRate] = useState(4.0); // 保單質借利率 const [res, setRes] = useState({}); useEffect(() => { // 1. 一般規劃 (Baseline) const tradDownPayment = price * 10000 * (cashPct / 100); const tradLoanAmt = (price * 10000) - tradDownPayment; const mRate = rate / 100 / 12; const remainM = (year - grace) * 12; const graceMonths = grace * 12; // 一般規劃的月付 const tradGracePay = tradLoanAmt * mRate; const tradFullPay = (tradLoanAmt * mRate * Math.pow(1 + mRate, remainM)) / (Math.pow(1 + mRate, remainM) - 1); // 2. 優化規劃 // 無論哪種策略,我們都建議只付 "最低頭期款" (通常 20%) const minDownPayment = price * 10000 * 0.2; const optLoanAmt = price * 10000 * 0.8; // 貸 8 成 const optFullPay = (optLoanAmt * mRate * Math.pow(1 + mRate, remainM)) / (Math.pow(1 + mRate, remainM) - 1); const optGracePay = optLoanAmt * mRate; // 投資效益計算 let investedCapital = 0; let policyCost = 0; // 質借利息成本 let monthlyPassive = 0; if (planType === 'split') { // 策略 A: 現金分流 (Split) investedCapital = Math.max(0, tradDownPayment - minDownPayment); monthlyPassive = (investedCapital * (yieldRate / 100)) / 12; } else { // 策略 B: 雙重槓桿 (Leverage) investedCapital = tradDownPayment; const borrowedDownPayment = minDownPayment; policyCost = (borrowedDownPayment * (policyRate / 100)) / 12; monthlyPassive = (investedCapital * (yieldRate / 100)) / 12; } // 淨月付 (優化後) const netGrace = Math.max(0, (optGracePay + policyCost) - monthlyPassive); const netFull = Math.max(0, (optFullPay + policyCost) - monthlyPassive); // 總成本比較 (30年) const totalTrad = tradDownPayment + (tradGracePay * graceMonths) + (tradFullPay * remainM); // 優化總成本 (現金流出觀點) // 這裡只計算流出的錢,保留的本金不算成本 // 如果是雙重槓桿,本金雖然還在,但它是質押的,所以我們這裡用比較直觀的「總現金流出差異」來呈現省下的錢 const totalOpt = minDownPayment + (netGrace * graceMonths) + (netFull * remainM); const totalSaved = totalTrad - totalOpt; const savePercent = totalTrad > 0 ? (totalSaved / totalTrad) * 100 : 0; // 退休後續領 (假設本金還在) const monthlyPassiveAfterLoan = monthlyPassive - policyCost; setRes({ tradGracePay, tradFullPay, optFullPay, optGracePay, monthlyPassive, policyCost, netGrace, netFull, totalTrad, totalOpt, totalSaved, investedCapital, minDownPayment, monthlyPassiveAfterLoan, savePercent }); }, [price, cashPct, year, rate, grace, yieldRate, policyRate, planType]); return (
{/* Input - 顧問控制面板 */}

參數設定 (Control Panel)

客戶購屋條件
{/* 新增:資金實力設定 */}
相當於自備款:{formatWan(price * 10000 * (cashPct/100))} 萬
A計畫策略選擇
{/* 策略切換 */}
{planType === 'split' ? (
只付2成頭款,剩餘自備款做配置。
) : (
自備款全額運作,另借頭款 (套利模式)。
)}
{planType === 'leverage' && ( )}
實際運作本金 {formatWan(res.investedCapital)} 萬
{/* Output - 客戶展示區 */}

規劃效益報告

{/* 明確區分寬限期與本利攤還 */} {grace > 0 && ( )}
保留本金
{formatWan(res.investedCapital)} 萬
{planType === 'split' ? '自有資金保留' : '全額投入運作'}
繳清後月領
{res.monthlyPassiveAfterLoan > 0 ? "+" : ""}{formatCurrency(res.monthlyPassiveAfterLoan)}
); } // ---------------------------------------------------------------------- // 情境 B: 有房族 (顧問版 - 參數全開 + 開關控制) // ---------------------------------------------------------------------- function OwnerCalculator({ formatCurrency, formatWan }) { // Input States const [buyPrice, setBuyPrice] = useState(2000); const [currentVal, setCurrentVal] = useState(2500); const [isDebtFree, setIsDebtFree] = useState(false); const [remainLoan, setRemainLoan] = useState(1000); const [origPay, setOrigPay] = useState(45000); const [remainYears, setRemainYears] = useState(20); // Toggles for Optional Inputs (New!) const [showBuyPrice, setShowBuyPrice] = useState(false); const [showRemainLoan, setShowRemainLoan] = useState(false); // 房貸剩餘本金改為選填 const [showRemainYears, setShowRemainYears] = useState(false); const [strategy, setStrategy] = useState('stable'); const [activeAmount, setActiveAmount] = useState(800); // Pro Params (獨立設定) const [bTerm, setBTerm] = useState(30); const [bRate, setBRate] = useState(2.5); const [bReturn, setBReturn] = useState(8.0); const [cRate, setCRate] = useState(3.0); const [cReturn, setCReturn] = useState(8.0); const [res, setRes] = useState({}); useEffect(() => { const actualRemainLoan = showRemainLoan ? remainLoan : 0; const actualOrigPay = isDebtFree ? 0 : origPay; // 最大額度計算 const maxLimit = showRemainLoan ? Math.max(0, (currentVal * 0.8) - actualRemainLoan) : 0; const loanAmt = activeAmount * 10000; let monthlyCost = 0; let monthlyIncome = 0; let retainedCapital = 0; let spread = 0; if (strategy === 'stable') { // B計畫 const mCostRate = bRate / 100 / 12; const mIncomeRate = bReturn / 100 / 12; if (mCostRate > 0) { monthlyCost = (loanAmt * mCostRate * Math.pow(1 + mCostRate, bTerm * 12)) / (Math.pow(1 + mCostRate, bTerm * 12) - 1); } monthlyIncome = loanAmt * mIncomeRate; retainedCapital = activeAmount * 10000; spread = bReturn - bRate; } else { // C計畫 const mCostRate = cRate / 100 / 12; const mIncomeRate = cReturn / 100 / 12; monthlyCost = loanAmt * mCostRate; monthlyIncome = loanAmt * mIncomeRate; retainedCapital = 0; spread = cReturn - cRate; } const netCashFlow = monthlyIncome - monthlyCost; const newPay = Math.max(0, actualOrigPay - netCashFlow); const projectYears = showRemainYears ? remainYears : 20; // 傳統總支出 const sunkCost = showBuyPrice ? (buyPrice - actualRemainLoan) * 10000 : 0; const futureTradPay = actualOrigPay * 12 * projectYears; const totalTradPay = sunkCost + futureTradPay; // 優化後總支出 const futureOptPay = Math.max(0, futureTradPay - (netCashFlow * 12 * projectYears)); const totalOptPay = sunkCost + futureOptPay; const totalSaved = netCashFlow * 12 * projectYears; const savePercent = totalTradPay > 0 ? (totalSaved / totalTradPay) * 100 : 0; const futurePassive = netCashFlow; const appreciation = showBuyPrice ? Math.max(0, currentVal - buyPrice) : 0; setRes({ maxLimit: Math.round(maxLimit), netCashFlow: Math.round(netCashFlow), newPay: Math.round(newPay), totalSaved: Math.round(totalSaved), totalTradPay: Math.round(totalTradPay), totalOptPay: Math.round(totalOptPay), savePercent: savePercent, futurePassive: Math.round(futurePassive), retainedCapital: Math.round(retainedCapital), isIncomeMode: isDebtFree, spread: spread.toFixed(1), appreciation: Math.round(appreciation), projectYears }); }, [buyPrice, currentVal, remainLoan, origPay, strategy, activeAmount, isDebtFree, remainYears, bTerm, bRate, bReturn, cRate, cReturn, showBuyPrice, showRemainYears, showRemainLoan]); return (
{/* Input - 顧問控制面板 */}

參數設定 (Control Panel)

基礎現況
setShowBuyPrice(!showBuyPrice)} /> {showBuyPrice && res.appreciation > 0 && (
已增值 {res.appreciation} 萬
)} setShowRemainLoan(!showRemainLoan)} disabled={isDebtFree} /> setShowRemainYears(!showRemainYears)} /> {/* 無貸款開關 */}
{/* 策略參數區 */}
策略參數
{showRemainLoan && (
建議上限:{res.maxLimit} 萬
)} {strategy === 'stable' ? (
) : (
)}
操作利差 (Spread) {res.spread}%
{/* Output - 客戶展示區 */}

減壓效益總報告

{res.isIncomeMode ? ( <> ) : ( <> )}
{/* 動態顯示:如果是穩健型(增貸),顯示保留本金 */} {strategy === 'stable' ? (
額外保留本金
{formatWan(res.retainedCapital)} 萬
) : (
資金池規模
{formatWan(activeAmount)} 萬
)}
繳清後月領
+{formatCurrency(res.futurePassive)}
); }