250 lines
7.7 KiB
Markdown
250 lines
7.7 KiB
Markdown
# PMFlow 前端实现总结
|
||
|
||
> 项目路径:`./frontend`
|
||
> 技术栈:Vite + React 18 + TypeScript + shadcn/ui + Tailwind CSS
|
||
|
||
---
|
||
|
||
## 一、技术选型
|
||
|
||
| 类别 | 技术 | 版本 | 用途 |
|
||
|------|------|------|------|
|
||
| 构建 | Vite | 5.x | 开发服务器、打包 |
|
||
| 框架 | React | 18.3 | UI 渲染 |
|
||
| 语言 | TypeScript | 5.6 | 类型安全 |
|
||
| 路由 | React Router | 6.28 | 路由、导航守卫 |
|
||
| 请求 | TanStack Query | 5.x | 服务端状态、缓存、错误处理 |
|
||
| 请求 | Axios | 1.7 | HTTP 客户端 |
|
||
| 状态 | Zustand | 4.5 | 全局状态(含持久化) |
|
||
| UI | shadcn/ui | - | 组件库(Radix UI 底座) |
|
||
| 样式 | Tailwind CSS | 3.4 | 原子化 CSS |
|
||
| 图表 | Recharts | 2.13 | 图表 |
|
||
| 图标 | Lucide React | 0.46 | 图标 |
|
||
| 工具 | clsx + tailwind-merge | - | 类名合并 |
|
||
|
||
---
|
||
|
||
## 二、项目目录结构
|
||
|
||
```
|
||
frontend/
|
||
├── public/
|
||
│ └── vite.svg
|
||
├── src/
|
||
│ ├── components/
|
||
│ │ ├── layout/
|
||
│ │ │ ├── Layout.tsx # 主布局(侧栏 + 顶栏 + 主区域)
|
||
│ │ │ ├── Sidebar.tsx # 侧边栏(导航、暗色模式切换)
|
||
│ │ │ └── TopBar.tsx # 顶栏(用户头像、通知、退出)
|
||
│ │ ├── ui/ # shadcn/ui 组件
|
||
│ │ │ ├── button.tsx
|
||
│ │ │ ├── card.tsx
|
||
│ │ │ ├── input.tsx
|
||
│ │ │ ├── dialog.tsx
|
||
│ │ │ ├── table.tsx
|
||
│ │ │ └── dropdown-menu.tsx
|
||
│ │ └── ThemeInit.tsx # 暗色模式初始化
|
||
│ ├── hooks/
|
||
│ │ └── useTheme.ts # 主题切换 Hook
|
||
│ ├── lib/
|
||
│ │ ├── api.ts # Axios 实例 + 拦截器
|
||
│ │ └── utils.ts # cn() 等工具
|
||
│ ├── pages/
|
||
│ │ ├── LoginPage.tsx
|
||
│ │ ├── DashboardPage.tsx # 团队负载看板
|
||
│ │ ├── ProjectsPage.tsx
|
||
│ │ ├── ProjectBoardPage.tsx
|
||
│ │ ├── CharterDetailPage.tsx
|
||
│ │ ├── SkillsPage.tsx
|
||
│ │ └── UserProfilePage.tsx
|
||
│ ├── router/
|
||
│ │ └── index.tsx # 路由配置 + 路由守卫
|
||
│ ├── stores/
|
||
│ │ └── auth.ts # 登录态(Zustand + 持久化)
|
||
│ ├── index.css # Tailwind + CSS 变量
|
||
│ ├── main.tsx
|
||
│ └── vite-env.d.ts
|
||
├── .env.example
|
||
├── .gitignore
|
||
├── components.json # shadcn 配置
|
||
├── Dockerfile
|
||
├── nginx.conf
|
||
├── package.json
|
||
├── postcss.config.js
|
||
├── tailwind.config.js
|
||
├── tsconfig.json
|
||
└── vite.config.ts
|
||
```
|
||
|
||
---
|
||
|
||
## 三、核心实现
|
||
|
||
### 3.1 Axios 封装 (`src/lib/api.ts`)
|
||
|
||
| 能力 | 实现方式 |
|
||
|------|----------|
|
||
| 基础 URL | `VITE_API_BASE_URL` 或开发时 `/api`(代理)、生产时 `http://localhost:8000` |
|
||
| JWT 自动附加 | `request` 拦截器从 `localStorage.pmflow_token` 读取并设置 `Authorization: Bearer <token>` |
|
||
| 401 处理 | `response` 拦截器:清除 token,重定向到 `/login?redirect=<当前路径>` |
|
||
| 错误提示 | 解析 `detail`(字符串或数组),统一 `console.error` 并 `Promise.reject` |
|
||
|
||
### 3.2 TanStack Query 配置 (`src/main.tsx`)
|
||
|
||
- `retry: 1`
|
||
- `refetchOnWindowFocus: false`
|
||
- `mutations.onError`:全局错误日志
|
||
|
||
### 3.3 路由与守卫 (`src/router/index.tsx`)
|
||
|
||
- 使用 `createBrowserRouter` 配置路由
|
||
- `AuthGuard`:检查 `useAuthStore().token`,未登录则 `<Navigate to="/login?redirect=...">`
|
||
- 登录页 `/login` 为公开路由,其余均需认证
|
||
|
||
**路由表:**
|
||
|
||
| 路径 | 说明 |
|
||
|------|------|
|
||
| `/login` | 登录页 |
|
||
| `/dashboard` | 团队负载看板 |
|
||
| `/projects` | 项目列表 |
|
||
| `/projects/:id/board` | 项目看板 |
|
||
| `/projects/:id/charter/:charterId` | 需求宪章详情 |
|
||
| `/skills` | 人员能力管理 |
|
||
| `/users/:id/profile` | 个人中心 |
|
||
|
||
### 3.4 认证状态 (`src/stores/auth.ts`)
|
||
|
||
- Zustand + `persist`,存储到 `localStorage`(`pmflow-auth`)
|
||
- 字段:`token`、`user`(含 `id`、`username`、`name`、`email`、`role`)
|
||
- 方法:`setAuth`、`logout`、`isAuthenticated`
|
||
|
||
### 3.5 暗色模式 (`src/hooks/useTheme.ts` + `ThemeInit.tsx`)
|
||
|
||
- 主题存于 `localStorage.pmflow_theme`,可选 `light` / `dark`
|
||
- 默认跟随 `prefers-color-scheme`
|
||
- 通过 `<html class="light">` / `<html class="dark">` 切换
|
||
- Tailwind 使用 `darkMode: ["class"]` 与 CSS 变量
|
||
|
||
### 3.6 布局 (`src/components/layout/`)
|
||
|
||
- **Layout**:flex 布局,左侧 Sidebar、右侧 TopBar + `<Outlet />` 主区域
|
||
- **Sidebar**:PMFlow logo、`NavLink` 导航、暗色模式按钮
|
||
- **TopBar**:通知图标、用户头像下拉(个人中心、退出登录)
|
||
|
||
### 3.7 Vite 代理 (`vite.config.ts`)
|
||
|
||
```ts
|
||
proxy: {
|
||
"/api": {
|
||
target: "http://localhost:8000",
|
||
changeOrigin: true,
|
||
rewrite: (path) => path.replace(/^\/api/, ""), // /api/auth/login -> /auth/login
|
||
},
|
||
}
|
||
```
|
||
|
||
前端请求 `/api/xxx` 会被代理到 `http://localhost:8000/xxx`。
|
||
|
||
---
|
||
|
||
## 四、页面与 API 对接
|
||
|
||
### 4.1 登录页 (`LoginPage.tsx`)
|
||
|
||
- 表单:`username`、`password`
|
||
- 请求:`POST /auth/login`,`Content-Type: application/x-www-form-urlencoded`
|
||
- 响应:`{ access_token, token_type, user }`,写入 `useAuthStore`,再 `navigate(redirect)`
|
||
- 已登录时直接跳转到 `redirect` 或 `/dashboard`
|
||
|
||
### 4.2 团队负载看板 (`DashboardPage.tsx`)
|
||
|
||
- 请求:`GET /skills/workload/team`
|
||
- 后端返回:`{ items: WorkloadItem[], total: number }`,前端取 `items` 或兼容数组
|
||
- 图表:Recharts 横向柱状图(工时)
|
||
- 表格:成员、任务数、工时
|
||
|
||
### 4.3 能力管理页 (`SkillsPage.tsx`)
|
||
|
||
- 请求:`GET /skills/tags`
|
||
- 表格展示:名称、分类、描述
|
||
|
||
### 4.4 其他页面
|
||
|
||
- `ProjectsPage`、`ProjectBoardPage`、`CharterDetailPage`、`UserProfilePage`:占位结构,待对接 API
|
||
|
||
---
|
||
|
||
## 五、shadcn/ui 组件
|
||
|
||
基于 Radix UI + Tailwind,已引入:
|
||
|
||
- **Button**:多种 variant / size
|
||
- **Card**:CardHeader、CardTitle、CardDescription、CardContent、CardFooter
|
||
- **Input**:基础输入框
|
||
- **Dialog**:弹窗
|
||
- **Table**:TableHeader、TableBody、TableRow、TableCell 等
|
||
- **DropdownMenu**:下拉菜单
|
||
|
||
工具函数 `cn()` 来自 `@/lib/utils`,用于合并 `clsx` 与 `tailwind-merge`。
|
||
|
||
---
|
||
|
||
## 六、部署
|
||
|
||
### 6.1 本地开发
|
||
|
||
```bash
|
||
cd frontend
|
||
npm install
|
||
npm run dev
|
||
```
|
||
|
||
- 前端:`http://localhost:5173`
|
||
- API 代理到:`http://localhost:8000`
|
||
|
||
### 6.2 生产构建
|
||
|
||
```bash
|
||
npm run build
|
||
```
|
||
|
||
输出目录:`dist/`
|
||
|
||
### 6.3 Docker
|
||
|
||
- 多阶段构建:Node 构建 → nginx 静态托管
|
||
- `nginx.conf` 中 `/api` 代理到后端服务(如 `http://backend:8000`)
|
||
- 环境变量需配置 `VITE_API_BASE_URL` 指向实际 API 地址
|
||
|
||
### 6.4 环境变量
|
||
|
||
`.env.example` 示例:
|
||
|
||
```
|
||
VITE_API_BASE_URL=http://localhost:8000
|
||
```
|
||
|
||
若后端挂载在 `/api`,可设置为:`VITE_API_BASE_URL=http://your-domain/api`
|
||
|
||
---
|
||
|
||
## 七、实现要点小结
|
||
|
||
| 点 | 技术 / 手段 |
|
||
|----|-------------|
|
||
| 路由守卫 | `AuthGuard` + `useAuthStore().token` + `<Navigate>` |
|
||
| JWT 持久化 | Zustand persist + localStorage |
|
||
| API 401 处理 | Axios response 拦截器 + 重定向登录 |
|
||
| 暗色模式 | class 模式 + CSS 变量 + `useTheme` |
|
||
| 开发代理 | Vite proxy `/api` → 后端 |
|
||
| 响应结构兼容 | `{ items: [] }` 与数组统一处理为 `Array.isArray` |
|
||
| 路径别名 | `@/` → `./src/` |
|
||
| 类型声明 | `vite-env.d.ts` 中引用 `vite/client` |
|
||
|
||
---
|
||
|
||
## 八、相关架构
|
||
|
||
- **SSTC 唯一事实链路**:见 [`docs/SSTC_ARCHITECTURE.md`](../docs/SSTC_ARCHITECTURE.md),定义信号→宪章→任务→执行→发布→复盘的强制绑定与版本链。
|