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

@@ -0,0 +1,54 @@
import { Component, type ReactNode } from 'react';
import { Button, Result } from 'antd';
interface Props {
children: ReactNode;
pageLevel?: boolean;
}
interface State {
hasError: boolean;
error: Error | null;
}
export class ErrorBoundary extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error: Error): State {
return { hasError: true, error };
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
console.error('ErrorBoundary caught:', error, errorInfo);
}
handleReset = () => {
this.setState({ hasError: false, error: null });
};
render() {
if (this.state.hasError) {
return (
<Result
status="error"
title={this.props.pageLevel ? '页面加载出错' : '出了点问题'}
subTitle={this.props.pageLevel
? `错误信息:${this.state.error?.message || '未知错误'}`
: '请刷新页面重试'}
extra={[
<Button key="retry" type="primary" onClick={this.handleReset}>
</Button>,
<Button key="home" onClick={() => window.location.hash = '/'}>
</Button>,
]}
/>
);
}
return this.props.children;
}
}