feat(web): Q3 前端体验优化 — ErrorBoundary + 5 hooks + 共享类型 + i18n 基础
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled

- ErrorBoundary 组件:全局错误捕获与优雅降级
- 提取 5 个自定义 hooks:useCountUp, useDarkMode, useDebouncedValue, usePaginatedData, useApiRequest
- 从 11 个 API 文件提取 PaginatedResponse 共享类型到 api/types.ts
- 统一 API 错误处理(api/errors.ts)
- client.ts 迁移到 axios adapter 模式(替代废弃的 CancelToken)
- 添加 react-i18next 国际化基础设施 + zh-CN 语言包
This commit is contained in:
iven
2026-04-17 19:40:58 +08:00
parent 6a44cbecf3
commit 9d18b7e079
25 changed files with 324 additions and 52 deletions

View File

@@ -29,12 +29,18 @@ importers:
axios:
specifier: ^1.15.0
version: 1.15.0
i18next:
specifier: ^26.0.5
version: 26.0.5(typescript@6.0.2)
react:
specifier: ^19.2.4
version: 19.2.5
react-dom:
specifier: ^19.2.4
version: 19.2.5(react@19.2.5)
react-i18next:
specifier: ^17.0.4
version: 17.0.4(i18next@26.0.5(typescript@6.0.2))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@6.0.2)
react-router-dom:
specifier: ^7.14.0
version: 7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
@@ -1562,10 +1568,21 @@ packages:
hermes-parser@0.25.1:
resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==}
html-parse-stringify@3.0.1:
resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==}
html2canvas@1.4.1:
resolution: {integrity: sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==}
engines: {node: '>=8.0.0'}
i18next@26.0.5:
resolution: {integrity: sha512-9uHb4T27TdV36phJXcbpnRPt5yzAfqHXVrdASvmHZyPuZJtrLythd+GyXhiaHV5LlpuuskbAqhwPjmfTbKbi8w==}
peerDependencies:
typescript: ^5 || ^6
peerDependenciesMeta:
typescript:
optional: true
iconv-lite@0.6.3:
resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
engines: {node: '>=0.10.0'}
@@ -1840,6 +1857,22 @@ packages:
peerDependencies:
react: ^19.2.5
react-i18next@17.0.4:
resolution: {integrity: sha512-hQipmK4EF0y6RO6tt6WuqnmWpWYEXmQUUzecmMBuNsIgYd3smXcG4GtYPWhvgxn0pqMOItKlEO8H24HCs5hc3g==}
peerDependencies:
i18next: '>= 26.0.1'
react: '>= 16.8.0'
react-dom: '*'
react-native: '*'
typescript: ^5 || ^6
peerDependenciesMeta:
react-dom:
optional: true
react-native:
optional: true
typescript:
optional: true
react-is@18.3.1:
resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
@@ -2051,6 +2084,10 @@ packages:
yaml:
optional: true
void-elements@3.1.0:
resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==}
engines: {node: '>=0.10.0'}
which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
@@ -3845,11 +3882,21 @@ snapshots:
dependencies:
hermes-estree: 0.25.1
html-parse-stringify@3.0.1:
dependencies:
void-elements: 3.1.0
html2canvas@1.4.1:
dependencies:
css-line-break: 2.1.0
text-segmentation: 1.0.3
i18next@26.0.5(typescript@6.0.2):
dependencies:
'@babel/runtime': 7.29.2
optionalDependencies:
typescript: 6.0.2
iconv-lite@0.6.3:
dependencies:
safer-buffer: 2.1.2
@@ -4068,6 +4115,17 @@ snapshots:
react: 19.2.5
scheduler: 0.27.0
react-i18next@17.0.4(i18next@26.0.5(typescript@6.0.2))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@6.0.2):
dependencies:
'@babel/runtime': 7.29.2
html-parse-stringify: 3.0.1
i18next: 26.0.5(typescript@6.0.2)
react: 19.2.5
use-sync-external-store: 1.6.0(react@19.2.5)
optionalDependencies:
react-dom: 19.2.5(react@19.2.5)
typescript: 6.0.2
react-is@18.3.1: {}
react-router-dom@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5):
@@ -4228,6 +4286,8 @@ snapshots:
fsevents: 2.3.3
jiti: 2.6.1
void-elements@3.1.0: {}
which@2.0.2:
dependencies:
isexe: 2.0.0