8c0ad4bab5
Complete Phase 6 design specification: - Technology stack: React 18 + TypeScript + Ant Design - Project structure and file organization - Design system (colors, typography, spacing) - Authentication flow design - Workspace management UI - Subscription management interface - Admin dashboard design - Responsive design (mobile/tablet/desktop) - 8-week development roadmap - Testing strategy and performance optimization Ready to start Phase 6 frontend development!
679 lines
18 KiB
Markdown
679 lines
18 KiB
Markdown
# Phase 6: 前端完善 - 详细设计文档
|
||
|
||
> 版本:v1.0
|
||
> 创建时间:2026-06-17
|
||
> 负责人:小虾 🦐
|
||
> 预计时间:4-6 周
|
||
|
||
---
|
||
|
||
## 📋 目标
|
||
|
||
在 Phase 4 完成的后端 API 基础上,构建完整的前端用户界面,让用户可以通过图形化界面使用所有 SaaS 功能。
|
||
|
||
---
|
||
|
||
## 🎯 核心目标
|
||
|
||
1. **用户认证界面** - 注册/登录/密码管理
|
||
2. **工作空间管理** - 创建/管理工作空间和成员
|
||
3. **订阅管理界面** - 查看/升级/管理订阅
|
||
4. **Admin 后台** - 系统管理和数据监控
|
||
5. **响应式设计** - 支持桌面/平板/移动端
|
||
|
||
---
|
||
|
||
## 🛠️ 技术栈选型
|
||
|
||
### 前端框架
|
||
**选择:React 18 + TypeScript**
|
||
|
||
**理由:**
|
||
- 生态成熟,组件丰富
|
||
- TypeScript 提供类型安全
|
||
- 与后端 API 配合良好
|
||
- 社区活跃,文档完善
|
||
|
||
**替代方案:**
|
||
- Vue 3 + TypeScript(更简单,但生态相对小)
|
||
- Next.js 14(支持 SSR,适合 SEO)
|
||
|
||
### UI 组件库
|
||
**选择:Ant Design 5.x**
|
||
|
||
**理由:**
|
||
- 企业级 UI 组件
|
||
- 中文文档完善
|
||
- 开箱即用的表单/表格/布局
|
||
- 符合国内用户习惯
|
||
|
||
**替代方案:**
|
||
- Material-UI(更现代,但学习曲线陡)
|
||
- Chakra UI(轻量,但组件不够丰富)
|
||
- shadcn/ui(新兴,基于 Tailwind)
|
||
|
||
### 状态管理
|
||
**选择:Zustand**
|
||
|
||
**理由:**
|
||
- 轻量简单
|
||
- TypeScript 友好
|
||
- 无需 Provider 包裹
|
||
- 学习成本低
|
||
|
||
**替代方案:**
|
||
- Redux Toolkit(功能强大,但复杂)
|
||
- Jotai/Recoil(原子化状态,适合大型应用)
|
||
|
||
### 路由
|
||
**选择:React Router v6**
|
||
|
||
### HTTP 客户端
|
||
**选择:Axios + React Query**
|
||
|
||
**理由:**
|
||
- Axios:成熟稳定,拦截器方便
|
||
- React Query:自动缓存、重试、分页支持
|
||
|
||
### 表单管理
|
||
**选择:React Hook Form + Zod**
|
||
|
||
**理由:**
|
||
- React Hook Form:性能优秀,API 简洁
|
||
- Zod:TypeScript 友好的 schema 验证
|
||
|
||
### 样式方案
|
||
**选择:CSS Modules + Tailwind CSS**
|
||
|
||
### 构建工具
|
||
**选择:Vite**
|
||
|
||
**理由:**
|
||
- 开发服务器极快
|
||
- 原生 ES 模块支持
|
||
- 完美支持 React + TypeScript
|
||
|
||
---
|
||
|
||
## 📐 项目结构
|
||
|
||
```
|
||
apps/web/
|
||
├── src/
|
||
│ ├── api/ # API 调用封装
|
||
│ │ ├── auth.ts # 认证相关 API
|
||
│ │ ├── workspace.ts # 工作空间 API
|
||
│ │ ├── subscription.ts
|
||
│ │ └── client.ts # Axios 实例配置
|
||
│ ├── components/ # 可复用组件
|
||
│ │ ├── common/ # 通用组件
|
||
│ │ │ ├── Button/
|
||
│ │ │ ├── Modal/
|
||
│ │ │ └── Table/
|
||
│ │ ├── layout/ # 布局组件
|
||
│ │ │ ├── Header/
|
||
│ │ │ ├── Sidebar/
|
||
│ │ │ └── Footer/
|
||
│ │ └── business/ # 业务组件
|
||
│ │ ├── WorkspaceCard/
|
||
│ │ ├── MemberList/
|
||
│ │ └── SubscriptionPlan/
|
||
│ ├── pages/ # 页面组件
|
||
│ │ ├── auth/ # 认证页面
|
||
│ │ │ ├── Login.tsx
|
||
│ │ │ ├── Register.tsx
|
||
│ │ │ ├── ForgotPassword.tsx
|
||
│ │ │ └── ResetPassword.tsx
|
||
│ │ ├── workspace/ # 工作空间页面
|
||
│ │ │ ├── List.tsx
|
||
│ │ │ ├── Detail.tsx
|
||
│ │ │ └── Members.tsx
|
||
│ │ ├── subscription/ # 订阅页面
|
||
│ │ │ ├── Plans.tsx
|
||
│ │ │ ├── Upgrade.tsx
|
||
│ │ │ └── Billing.tsx
|
||
│ │ ├── admin/ # 管理后台
|
||
│ │ │ ├── Dashboard.tsx
|
||
│ │ │ ├── Users.tsx
|
||
│ │ │ └── Analytics.tsx
|
||
│ │ └── profile/ # 个人中心
|
||
│ │ ├── Settings.tsx
|
||
│ │ └── Account.tsx
|
||
│ ├── hooks/ # 自定义 Hooks
|
||
│ │ ├── useAuth.ts
|
||
│ │ ├── useWorkspace.ts
|
||
│ │ └── useSubscription.ts
|
||
│ ├── store/ # 状态管理
|
||
│ │ ├── authStore.ts
|
||
│ │ ├── workspaceStore.ts
|
||
│ │ └── uiStore.ts
|
||
│ ├── types/ # TypeScript 类型定义
|
||
│ │ ├── auth.ts
|
||
│ │ ├── workspace.ts
|
||
│ │ └── api.ts
|
||
│ ├── utils/ # 工具函数
|
||
│ │ ├── request.ts # HTTP 请求封装
|
||
│ │ ├── storage.ts # LocalStorage 封装
|
||
│ │ ├── validator.ts # 表单验证
|
||
│ │ └── format.ts # 格式化函数
|
||
│ ├── router/ # 路由配置
|
||
│ │ └── index.tsx
|
||
│ ├── styles/ # 全局样式
|
||
│ │ ├── global.css
|
||
│ │ └── variables.css
|
||
│ ├── App.tsx
|
||
│ ├── main.tsx
|
||
│ └── vite-env.d.ts
|
||
├── public/
|
||
│ └── assets/
|
||
├── index.html
|
||
├── vite.config.ts
|
||
├── tsconfig.json
|
||
├── tailwind.config.js
|
||
└── package.json
|
||
```
|
||
|
||
---
|
||
|
||
## 🎨 设计规范
|
||
|
||
### 1. 色彩系统
|
||
|
||
**主色调:**
|
||
```css
|
||
--primary: #1890ff; /* 品牌蓝 */
|
||
--primary-hover: #40a9ff;
|
||
--primary-active: #096dd9;
|
||
|
||
--success: #52c41a; /* 成功绿 */
|
||
--warning: #faad14; /* 警告黄 */
|
||
--error: #ff4d4f; /* 错误红 */
|
||
--info: #1890ff; /* 信息蓝 */
|
||
```
|
||
|
||
**中性色:**
|
||
```css
|
||
--text-primary: #262626;
|
||
--text-secondary: #595959;
|
||
--text-disabled: #bfbfbf;
|
||
|
||
--bg-primary: #ffffff;
|
||
--bg-secondary: #fafafa;
|
||
--bg-tertiary: #f5f5f5;
|
||
|
||
--border: #d9d9d9;
|
||
--divider: #f0f0f0;
|
||
```
|
||
|
||
### 2. 字体规范
|
||
|
||
**字体家族:**
|
||
```css
|
||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI',
|
||
'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei',
|
||
sans-serif;
|
||
```
|
||
|
||
**字号:**
|
||
```css
|
||
--text-xs: 12px; /* 辅助文字 */
|
||
--text-sm: 14px; /* 正文 */
|
||
--text-base: 16px; /* 正文加重 */
|
||
--text-lg: 18px; /* 小标题 */
|
||
--text-xl: 20px; /* 标题 */
|
||
--text-2xl: 24px; /* 大标题 */
|
||
```
|
||
|
||
### 3. 间距系统
|
||
|
||
```css
|
||
--space-xs: 4px;
|
||
--space-sm: 8px;
|
||
--space-md: 16px;
|
||
--space-lg: 24px;
|
||
--space-xl: 32px;
|
||
--space-2xl: 48px;
|
||
```
|
||
|
||
### 4. 圆角
|
||
|
||
```css
|
||
--radius-sm: 2px;
|
||
--radius-md: 4px;
|
||
--radius-lg: 8px;
|
||
--radius-xl: 12px;
|
||
--radius-full: 9999px;
|
||
```
|
||
|
||
### 5. 阴影
|
||
|
||
```css
|
||
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.08);
|
||
--shadow-md: 0 4px 8px rgba(0, 0, 0, 0.12);
|
||
--shadow-lg: 0 8px 16px rgba(0, 0, 0, 0.16);
|
||
```
|
||
|
||
---
|
||
|
||
## 🔐 认证流程设计
|
||
|
||
### 1. 注册流程
|
||
|
||
**页面:** `/register`
|
||
|
||
**步骤:**
|
||
1. 用户填写邮箱、用户名、密码
|
||
2. 前端验证(密码强度、邮箱格式)
|
||
3. 调用 `POST /api/v1/auth/register`
|
||
4. 显示"验证邮件已发送"提示
|
||
5. 用户点击邮件链接 → 跳转到验证页面
|
||
6. 自动登录 → 跳转到工作空间列表
|
||
|
||
**表单验证:**
|
||
```typescript
|
||
const registerSchema = z.object({
|
||
email: z.string().email('请输入有效的邮箱地址'),
|
||
username: z.string()
|
||
.min(3, '用户名至少 3 个字符')
|
||
.max(20, '用户名最多 20 个字符')
|
||
.regex(/^[a-zA-Z0-9_]+$/, '用户名只能包含字母、数字和下划线'),
|
||
password: z.string()
|
||
.min(8, '密码至少 8 个字符')
|
||
.regex(/[A-Z]/, '密码必须包含大写字母')
|
||
.regex(/[a-z]/, '密码必须包含小写字母')
|
||
.regex(/[0-9]/, '密码必须包含数字'),
|
||
confirmPassword: z.string()
|
||
}).refine(data => data.password === data.confirmPassword, {
|
||
message: '两次密码输入不一致',
|
||
path: ['confirmPassword'],
|
||
});
|
||
```
|
||
|
||
### 2. 登录流程
|
||
|
||
**页面:** `/login`
|
||
|
||
**步骤:**
|
||
1. 用户输入邮箱和密码
|
||
2. 调用 `POST /api/v1/auth/login`
|
||
3. 保存 token 到 localStorage
|
||
4. 设置 Axios 默认 Authorization header
|
||
5. 跳转到工作空间列表或上次访问页面
|
||
|
||
**Remember Me 功能:**
|
||
- 勾选时:token 保存 30 天
|
||
- 不勾选:token 保存到 sessionStorage
|
||
|
||
### 3. Token 管理
|
||
|
||
**自动刷新:**
|
||
```typescript
|
||
// axios 拦截器
|
||
axios.interceptors.response.use(
|
||
response => response,
|
||
async error => {
|
||
if (error.response?.status === 401) {
|
||
// Token 过期,尝试刷新
|
||
const refreshToken = storage.get('refresh_token');
|
||
if (refreshToken) {
|
||
try {
|
||
const { access_token } = await refreshAccessToken(refreshToken);
|
||
storage.set('access_token', access_token);
|
||
// 重试原请求
|
||
return axios(error.config);
|
||
} catch {
|
||
// 刷新失败,跳转登录
|
||
router.push('/login');
|
||
}
|
||
}
|
||
}
|
||
return Promise.reject(error);
|
||
}
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
## 🏢 工作空间管理设计
|
||
|
||
### 1. 工作空间列表
|
||
|
||
**页面:** `/workspaces`
|
||
|
||
**布局:**
|
||
```
|
||
┌─────────────────────────────────────────┐
|
||
│ Header (用户头像、通知、设置) │
|
||
├─────────────────────────────────────────┤
|
||
│ ┌─────────────────────────────────┐ │
|
||
│ │ 我的工作空间 [+ 创建] │ │
|
||
│ ├─────────────────────────────────┤ │
|
||
│ │ ┌──────┐ ┌──────┐ ┌──────┐ │ │
|
||
│ │ │ WS 1 │ │ WS 2 │ │ WS 3 │ │ │
|
||
│ │ │ Free │ │ Pro │ │ Free │ │ │
|
||
│ │ │ 3人 │ │ 12人 │ │ 1人 │ │ │
|
||
│ │ └──────┘ └──────┘ └──────┘ │ │
|
||
│ └─────────────────────────────────┘ │
|
||
└─────────────────────────────────────────┘
|
||
```
|
||
|
||
**功能:**
|
||
- 显示所有工作空间
|
||
- 显示订阅计划(Free/Pro/Enterprise)
|
||
- 显示成员数量
|
||
- 快速切换工作空间
|
||
- 创建新工作空间
|
||
|
||
### 2. 工作空间详情
|
||
|
||
**页面:** `/workspaces/:id`
|
||
|
||
**标签页:**
|
||
- **概览** - 基本信息、配额使用情况
|
||
- **成员** - 成员列表、邀请、权限管理
|
||
- **订阅** - 当前计划、升级选项
|
||
- **设置** - 工作空间名称、删除
|
||
|
||
**概览页示例:**
|
||
```typescript
|
||
interface WorkspaceOverview {
|
||
name: string;
|
||
plan: 'free' | 'pro' | 'enterprise';
|
||
memberCount: number;
|
||
projectCount: number;
|
||
storageUsed: number;
|
||
storageLimit: number;
|
||
quotaStatus: 'normal' | 'warning' | 'critical' | 'exceeded';
|
||
}
|
||
```
|
||
|
||
### 3. 成员管理
|
||
|
||
**功能:**
|
||
- 邀请成员(输入邮箱 + 选择角色)
|
||
- 成员列表(头像、姓名、邮箱、角色、加入时间)
|
||
- 修改角色(Owner/Admin/Member/Viewer)
|
||
- 移除成员
|
||
- 待处理邀请列表
|
||
|
||
**权限矩阵显示:**
|
||
```
|
||
┌────────────┬──────┬───────┬────────┬────────┐
|
||
│ 操作 │ Owner│ Admin │ Member │ Viewer │
|
||
├────────────┼──────┼───────┼────────┼────────┤
|
||
│ 邀请成员 │ ✓ │ ✓ │ ✗ │ ✗ │
|
||
│ 移除成员 │ ✓ │ ✓ │ ✗ │ ✗ │
|
||
│ 创建项目 │ ✓ │ ✓ │ ✓ │ ✗ │
|
||
│ 删除项目 │ ✓ │ ✓ │ 自己 │ ✗ │
|
||
└────────────┴──────┴───────┴────────┴────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 💳 订阅管理设计
|
||
|
||
### 1. 套餐选择页面
|
||
|
||
**页面:** `/subscription/plans`
|
||
|
||
**布局:**
|
||
```
|
||
┌───────────┬───────────┬───────────┐
|
||
│ Free │ Pro │ Enterprise│
|
||
├───────────┼───────────┼───────────┤
|
||
│ ¥0/月 │ ¥99/月 │ ¥999/月 │
|
||
│ 3 项目 │ 无限项目 │ 无限项目 │
|
||
│ 10GB │ 100GB │ 1TB │
|
||
│ 邮件支持 │ 优先支持 │ 专属支持 │
|
||
│ │ │ 定制开发 │
|
||
│ [当前] │ [升级] │ [联系] │
|
||
└───────────┴───────────┴───────────┘
|
||
```
|
||
|
||
**对比表格:**
|
||
```typescript
|
||
interface PlanFeature {
|
||
name: string;
|
||
free: boolean | string;
|
||
pro: boolean | string;
|
||
enterprise: boolean | string;
|
||
}
|
||
|
||
const features: PlanFeature[] = [
|
||
{ name: '项目数量', free: '3', pro: '无限', enterprise: '无限' },
|
||
{ name: '存储空间', free: '10GB', pro: '100GB', enterprise: '1TB' },
|
||
{ name: '成员数量', free: '3', pro: '20', enterprise: '无限' },
|
||
{ name: 'API 调用', free: '1000/天', pro: '10000/天', enterprise: '无限' },
|
||
{ name: '技术支持', free: '邮件', pro: '邮件+工单', enterprise: '专属客服' },
|
||
];
|
||
```
|
||
|
||
### 2. 升级流程
|
||
|
||
**步骤:**
|
||
1. 选择套餐 → 确认升级
|
||
2. 显示订单信息(价格、有效期)
|
||
3. 选择支付方式(支付宝/微信/信用卡)
|
||
4. 跳转支付页面
|
||
5. 支付成功 → 自动升级 → 显示成功页面
|
||
|
||
### 3. 账单页面
|
||
|
||
**页面:** `/subscription/billing`
|
||
|
||
**内容:**
|
||
- 当前订阅信息
|
||
- 下次续费日期和金额
|
||
- 历史账单列表
|
||
- 发票申请入口
|
||
|
||
---
|
||
|
||
## 🎛️ Admin 后台设计
|
||
|
||
### 1. Dashboard
|
||
|
||
**页面:** `/admin/dashboard`
|
||
|
||
**仪表盘指标:**
|
||
```
|
||
┌──────────┬──────────┬──────────┬──────────┐
|
||
│ 总用户数 │ 付费用户 │ 月收入 │ 活跃用户 │
|
||
│ 1,234 │ 156 │ ¥15,444 │ 892 │
|
||
└──────────┴──────────┴──────────┴──────────┘
|
||
|
||
┌─────────────────────────────────────────┐
|
||
│ 用户增长趋势图 │
|
||
│ ┌────────────────────────────────────┐ │
|
||
│ │ ╱╲ │ │
|
||
│ │ ╱ ╲ ╱╲ │ │
|
||
│ │ ╱╲ ╱ ╲ ╱ ╲ ╱╲ │ │
|
||
│ │ ╱ ╲╱ ╲ ╱ ╲ ╱ ╲ │ │
|
||
│ │ ╱ ╲╱ ╲╱ ╲ │ │
|
||
│ └────────────────────────────────────┘ │
|
||
└─────────────────────────────────────────┘
|
||
```
|
||
|
||
### 2. 用户管理
|
||
|
||
**页面:** `/admin/users`
|
||
|
||
**功能:**
|
||
- 用户列表(搜索、筛选、分页)
|
||
- 用户详情(基本信息、工作空间、订阅状态)
|
||
- 封禁/解封用户
|
||
- 手动验证邮箱
|
||
- 重置密码
|
||
|
||
### 3. 系统监控
|
||
|
||
**页面:** `/admin/monitoring`
|
||
|
||
**监控指标:**
|
||
- API 响应时间
|
||
- 数据库连接池状态
|
||
- Redis 连接状态
|
||
- 错误日志
|
||
- 慢查询日志
|
||
|
||
---
|
||
|
||
## 📱 响应式设计
|
||
|
||
### 断点定义
|
||
|
||
```css
|
||
/* Mobile */
|
||
@media (max-width: 640px) { }
|
||
|
||
/* Tablet */
|
||
@media (min-width: 641px) and (max-width: 1024px) { }
|
||
|
||
/* Desktop */
|
||
@media (min-width: 1025px) { }
|
||
```
|
||
|
||
### 移动端适配
|
||
|
||
**导航:**
|
||
- 桌面端:侧边栏 + 顶部栏
|
||
- 移动端:底部导航栏 + 汉堡菜单
|
||
|
||
**表格:**
|
||
- 桌面端:完整表格
|
||
- 移动端:卡片列表
|
||
|
||
**表单:**
|
||
- 全宽输入框
|
||
- 大号按钮(易于点击)
|
||
|
||
---
|
||
|
||
## 🧪 测试策略
|
||
|
||
### 1. 单元测试
|
||
|
||
**工具:** Vitest + Testing Library
|
||
|
||
**覆盖范围:**
|
||
- 工具函数(100%)
|
||
- Hooks(80%+)
|
||
- 组件(核心组件 80%+)
|
||
|
||
### 2. E2E 测试
|
||
|
||
**工具:** Playwright
|
||
|
||
**关键流程:**
|
||
- 用户注册 → 邮箱验证 → 登录
|
||
- 创建工作空间 → 邀请成员
|
||
- 升级订阅
|
||
|
||
### 3. 可访问性测试
|
||
|
||
- 键盘导航支持
|
||
- ARIA 标签
|
||
- 颜色对比度(WCAG AA)
|
||
|
||
---
|
||
|
||
## 🚀 性能优化
|
||
|
||
### 1. 代码分割
|
||
|
||
```typescript
|
||
// 路由懒加载
|
||
const Login = lazy(() => import('./pages/auth/Login'));
|
||
const Dashboard = lazy(() => import('./pages/admin/Dashboard'));
|
||
```
|
||
|
||
### 2. 图片优化
|
||
|
||
- 使用 WebP 格式
|
||
- 懒加载图片
|
||
- 响应式图片
|
||
|
||
### 3. 缓存策略
|
||
|
||
**React Query 配置:**
|
||
```typescript
|
||
const queryClient = new QueryClient({
|
||
defaultOptions: {
|
||
queries: {
|
||
staleTime: 5 * 60 * 1000, // 5 分钟
|
||
cacheTime: 10 * 60 * 1000, // 10 分钟
|
||
refetchOnWindowFocus: false,
|
||
},
|
||
},
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## 📅 开发排期
|
||
|
||
### Week 1-2: 基础搭建
|
||
- [ ] 项目初始化(Vite + React + TypeScript)
|
||
- [ ] 安装配置依赖(Ant Design, React Router, etc.)
|
||
- [ ] 搭建基础布局(Header, Sidebar, Footer)
|
||
- [ ] API 客户端封装
|
||
- [ ] 路由配置
|
||
|
||
### Week 3: 认证页面
|
||
- [ ] 登录页面
|
||
- [ ] 注册页面
|
||
- [ ] 忘记密码页面
|
||
- [ ] 邮箱验证页面
|
||
- [ ] Token 管理
|
||
|
||
### Week 4: 工作空间管理
|
||
- [ ] 工作空间列表页面
|
||
- [ ] 工作空间详情页面
|
||
- [ ] 成员管理页面
|
||
- [ ] 邀请成员功能
|
||
|
||
### Week 5: 订阅管理
|
||
- [ ] 套餐选择页面
|
||
- [ ] 升级流程
|
||
- [ ] 账单页面
|
||
- [ ] 配额展示
|
||
|
||
### Week 6: Admin 后台
|
||
- [ ] Dashboard 仪表盘
|
||
- [ ] 用户管理
|
||
- [ ] 系统监控
|
||
|
||
### Week 7: 个人中心
|
||
- [ ] 个人设置页面
|
||
- [ ] 账号安全
|
||
- [ ] 通知设置
|
||
|
||
### Week 8: 测试和优化
|
||
- [ ] E2E 测试
|
||
- [ ] 性能优化
|
||
- [ ] 可访问性优化
|
||
- [ ] Bug 修复
|
||
|
||
---
|
||
|
||
## 🎯 成功指标
|
||
|
||
- [ ] 所有页面加载时间 < 2s
|
||
- [ ] Lighthouse 性能分数 > 90
|
||
- [ ] 核心流程 E2E 测试覆盖率 100%
|
||
- [ ] 移动端体验良好(无横向滚动)
|
||
- [ ] 无 Console 错误和警告
|
||
|
||
---
|
||
|
||
## 📝 备注
|
||
|
||
- 优先保证桌面端体验,移动端作为补充
|
||
- UI 设计遵循 Ant Design 规范,保持一致性
|
||
- 所有文字支持国际化(i18n)准备
|
||
- 表单验证使用 Zod,前后端类型一致
|
||
|
||
---
|
||
|
||
**老大确认后,我就开始 Phase 6 的开发工作!** 🦐💪
|