7.8 KiB
7.8 KiB
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 | 浏览器固定请求同源 /api;开发由 Vite proxy 转发,生产由 nginx /api 反代 |
| 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: 1refetchOnWindowFocus: falsemutations.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)
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 本地开发
cd frontend
npm install
npm run dev
- 前端:
http://localhost:5173 - API 代理到:
http://localhost:8000
6.2 生产构建
npm run build
输出目录:dist/
6.3 Docker
- 多阶段构建:Node 构建 → nginx 静态托管
nginx.conf中/api代理到后端服务(如http://backend:8000)- 浏览器侧不再配置后端绝对地址,避免本机地址、公网地址和生产地址分叉
6.4 环境变量
.env.example 示例:
VITE_DEV_API_PROXY_TARGET=http://127.0.0.1:8001
VITE_DEV_API_PROXY_TARGET 只给 Vite dev server 使用;浏览器请求始终是同源 /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,定义信号→宪章→任务→执行→发布→复盘的强制绑定与版本链。