PMFlow/frontend/PMFLOW_IMPLEMENTATION.md

7.7 KiB
Raw Blame History

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)

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)
  • 环境变量需配置 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,定义信号→宪章→任务→执行→发布→复盘的强制绑定与版本链。