Files
sundynix-agentix/sundynix-admin/src/App.tsx
T
Blizzard b1fea23a0c feat(site): 官网定价页 —— 套餐由后台配置驱动,公开可见
官网加「定价」菜单与页面。数据来自 GET /api/v1/pricing(**不挂鉴权**):
运营改价、上下架、调发放节奏都在管理端完成,官网跟着变,不用发版;
未登录就能看到价格,这是转化的前提,也是官网存在的意义。

接口只吐在售项与展示字段,成本、权重、租户信息一律不出去。

结账仍在 Web 面完成(那里有登录态、租户上下文与支付轮询),官网只负责
「看价 → 去买」。同一套支付流程不在两处各实现一遍——这也是本次订阅开发
一直遵循的那条线:积分包与订阅共用一个支付弹窗,桌面端不重复购买入口。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 16:59:58 +08:00

66 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useEffect, useState } from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { AppShell } from "./shell/AppShell";
import { Login } from "./Login";
import { me, clearToken, type AuthUser } from "./api";
// 官网落地页(融进本工程,src/site/),挂根 /。
import { SiteLayout } from "./site/components/layout/site-layout";
import HomePage from "./site/pages/home";
import DownloadPage from "./site/pages/download";
import PricingPage from "./site/pages/pricing";
import NotFoundPage from "./site/pages/not-found";
// 后台鉴权门:只在访问 /admin 时跑 me()(官网公开、不打鉴权)。
// 未登录 → Login;登录后 → AppShell(其内部再渲染 /admin/* 子路由)。
function AdminGate() {
const [user, setUser] = useState<AuthUser | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
me()
.then(setUser)
.catch(() => setUser(null))
.finally(() => setLoading(false));
const onLogout = () => setUser(null);
window.addEventListener("sdx:logout", onLogout);
return () => window.removeEventListener("sdx:logout", onLogout);
}, []);
if (loading) {
return <div className="flex h-screen w-screen items-center justify-center text-sm text-gray-400"></div>;
}
if (!user) {
return <Login onAuthed={setUser} />;
}
return (
<AppShell
user={user}
onLogout={() => {
clearToken();
setUser(null);
}}
/>
);
}
// 用 BrowserRouter(路径式):/ = 官网、/admin = 运维后台。
// gateway 的 NoRoute 对非 /api、非文件路径回退 index.html,故深链/刷新都能工作。
export default function App() {
return (
<BrowserRouter>
<Routes>
{/* 后台:/admin 前缀,最具体,优先匹配 */}
<Route path="/admin/*" element={<AdminGate />} />
{/* 官网:根 / + /download,公开;未知路径落官网 404(保留 header/footer */}
<Route element={<SiteLayout />}>
<Route index element={<HomePage />} />
<Route path="pricing" element={<PricingPage />} />
<Route path="download" element={<DownloadPage />} />
<Route path="*" element={<NotFoundPage />} />
</Route>
</Routes>
</BrowserRouter>
);
}