feat(web/usercenter): Next.js 用户中心静态导出 + mock/http 双数据层 (tsk_3FIPC8lSnAfJ)

新建 web/usercenter/:Next.js App Router + output:'export' 纯静态导出,
直接复用 design/ui_kits/usercenter React 源码(概览/订阅/兑换/邀请/设置)。

阶段 A(mock,本提交):
- 复刻五大页面,明/暗 × zh/en 四态;colors_and_type.css 原样链入;
  顶栏主题切换 + 语言段控,移动端底部 Tab + 左右滑动切换。
- 设置页新增:偏好(语言/主题) + 设备管理(列表/移除/二次确认+刷新) +
  TOTP 2FA(绑定二维码占位+密钥/验证/解禁),登录二段式 TOTP。
- 数据层 lib/api:ApiClient 抽象 + MockClient/HttpClient 双实现,构建期
  NEXT_PUBLIC_API_MODE 切换;统一错误体 {code,message_zh,message_en} → 双语映射。
- 会话:access token 仅内存,refresh header token + localStorage,静默续期,
  登出失效(取舍:静态导出无服务端 cookie 能力,详见 README)。
- 安全:构建期注入 SRI(sha384);_headers 严格 CSP + 安全基线;
  红线词扫描(铁律13) CI 红线,零命中。

阶段 B(占位待联调):HttpClient 已写好域名池+退避重试+401 续期;
TOTP/登录二段式端点占位待 #1 契约增补;me/redeem/devices 切真实链路依赖 #2/#3/#4。

验证:npm run lint / redline / build 均通过,静态产物 out/ 无服务端依赖。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-06-13 15:23:18 +08:00
parent 30e73b31c2
commit e2646346a6
32 changed files with 7925 additions and 0 deletions
+35
View File
@@ -0,0 +1,35 @@
/* globals.css — 仅全局复位与视图切换动效;颜色/字体全部来自 colors_and_type.css(单一真相源)。 */
html,
body {
margin: 0;
}
body {
background: var(--bg);
font-family: var(--font-sans);
}
* {
-webkit-font-smoothing: antialiased;
}
button {
font-family: inherit;
}
@keyframes uc-in-l {
from {
opacity: 0;
transform: translateX(18px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes uc-in-r {
from {
opacity: 0;
transform: translateX(-18px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
+28
View File
@@ -0,0 +1,28 @@
import type { Metadata, Viewport } from 'next';
import './globals.css';
import { UIProvider } from '../lib/theme';
export const metadata: Metadata = {
title: '穿山甲 · 用户中心',
description: '管理订阅、兑换激活码、查看用量、邀请返利与账户安全设置。',
};
export const viewport: Viewport = {
width: 'device-width',
initialScale: 1,
};
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="zh" data-theme="light">
<head>
{/* 设计令牌单一真相源,原样链入(SRI 由构建期注入) */}
{/* eslint-disable-next-line @next/next/no-css-tags */}
<link rel="stylesheet" href="/colors_and_type.css" />
</head>
<body>
<UIProvider>{children}</UIProvider>
</body>
</html>
);
}
+5
View File
@@ -0,0 +1,5 @@
import UserCenter from '../components/UserCenter';
export default function Page() {
return <UserCenter />;
}