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 }) => (
);
// 開關型輸入控制 (選填項目)
const ToggleInput = ({ label, value, onChange, unit, step = 1, isActive, onToggle, placeholder }) => (
);
// 顧問專用微調參數列
const ProInputRow = ({ label, value, onChange, unit, step = 0.1 }) => (
);
// 比較專用的列組件
const SummaryRow = ({ label, traditional, optimized, diff, isHighlight = false }) => (
{label}
規劃後
{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))} 萬
{/* 策略切換 */}
{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)}
);
}