'grok建议功能'
This commit is contained in:
131
app/[locale]/tools/page.tsx
Normal file
131
app/[locale]/tools/page.tsx
Normal file
@@ -0,0 +1,131 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "@/i18n/navigation";
|
||||
import Footer from "@/app/components/Footer";
|
||||
|
||||
const RATES = [
|
||||
{ from: "CNY", to: "USD", rate: 0.14 },
|
||||
{ from: "CNY", to: "EUR", rate: 0.13 },
|
||||
{ from: "CNY", to: "THB", rate: 5.2 },
|
||||
{ from: "USD", to: "CNY", rate: 7.2 },
|
||||
];
|
||||
|
||||
export default function ToolsPage() {
|
||||
const { t } = useTranslation("tools");
|
||||
const [income, setIncome] = useState(100000);
|
||||
const [cnyAmount, setCnyAmount] = useState(10000);
|
||||
const [visaDate, setVisaDate] = useState("2025-06-15");
|
||||
|
||||
const taxEstimate = Math.round(income * 0.15);
|
||||
const cnyToUsd = (v: number) => (v * 0.14).toFixed(2);
|
||||
const daysLeft = Math.ceil(
|
||||
(new Date(visaDate).getTime() - Date.now()) / (1000 * 60 * 60 * 24)
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-[#fafafa] dark:bg-gray-950">
|
||||
<div className="max-w-4xl mx-auto px-4 sm:px-6 py-12">
|
||||
<div className="mb-10">
|
||||
<h1 className="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100">
|
||||
{t("title")}
|
||||
</h1>
|
||||
<p className="mt-1 text-gray-500 dark:text-gray-400">
|
||||
{t("subtitle")}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-6">
|
||||
<section className="rounded-2xl bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 p-6">
|
||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-4">
|
||||
💱 {t("exchange")}
|
||||
</h2>
|
||||
<div className="grid grid-cols-2 sm:grid-cols-4 gap-4">
|
||||
{RATES.map((r) => (
|
||||
<div
|
||||
key={`${r.from}-${r.to}`}
|
||||
className="p-4 rounded-xl bg-gray-50 dark:bg-gray-800"
|
||||
>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400">
|
||||
{r.from} → {r.to}
|
||||
</p>
|
||||
<p className="mt-1 text-lg font-bold text-gray-900 dark:text-gray-100">
|
||||
{r.rate}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="mt-4 p-4 rounded-xl bg-gray-50 dark:bg-gray-800">
|
||||
<label className="block text-xs text-gray-500 dark:text-gray-400 mb-2">CNY → USD</label>
|
||||
<div className="flex gap-2 items-center">
|
||||
<input
|
||||
type="number"
|
||||
value={cnyAmount}
|
||||
onChange={(e) => setCnyAmount(Number(e.target.value) || 0)}
|
||||
className="flex-1 rounded-lg border border-gray-200 dark:border-gray-700 px-3 py-2 text-sm bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100"
|
||||
/>
|
||||
<span className="text-gray-400">≈</span>
|
||||
<span className="font-semibold text-gray-900 dark:text-gray-100">${cnyToUsd(cnyAmount)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<p className="mt-3 text-xs text-gray-400 dark:text-gray-500">
|
||||
{t("disclaimer")}
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section className="rounded-2xl bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 p-6">
|
||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-4">
|
||||
📊 {t("tax")}
|
||||
</h2>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
{t("incomeCountry")} (年收入 ¥)
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
value={income}
|
||||
onChange={(e) => setIncome(Number(e.target.value))}
|
||||
className="w-full rounded-lg border border-gray-200 dark:border-gray-700 px-4 py-2 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100"
|
||||
/>
|
||||
</div>
|
||||
<div className="p-4 rounded-xl bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800/50">
|
||||
<p className="text-sm text-amber-800 dark:text-amber-200">
|
||||
{t("estimate")}: 约 ¥{taxEstimate.toLocaleString()}/年
|
||||
</p>
|
||||
<p className="mt-1 text-xs text-amber-600 dark:text-amber-300">
|
||||
{t("taxDisclaimer")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="rounded-2xl bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 p-6">
|
||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-4">
|
||||
🛂 {t("visa")}
|
||||
</h2>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
{t("visaExpiry")}
|
||||
</label>
|
||||
<input
|
||||
type="date"
|
||||
value={visaDate}
|
||||
onChange={(e) => setVisaDate(e.target.value)}
|
||||
className="w-full rounded-lg border border-gray-200 dark:border-gray-700 px-4 py-2 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100"
|
||||
/>
|
||||
</div>
|
||||
<div className="p-4 rounded-xl bg-emerald-50 dark:bg-emerald-900/20 border border-emerald-200 dark:border-emerald-800/50">
|
||||
<p className="text-lg font-semibold text-emerald-800 dark:text-emerald-200">
|
||||
{daysLeft > 0 ? `${daysLeft} ${t("daysLeft")}` : t("expired")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user