From d6b1df061d1e8bbed01be0ff413a524c95140bf9 Mon Sep 17 00:00:00 2001 From: wangdl Date: Sat, 4 Jul 2026 11:29:37 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20README=20=E5=85=A8=E9=9D=A2=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=20=E2=80=94=20=E7=8E=AF=E5=A2=83=E5=8F=98=E9=87=8F=20?= =?UTF-8?q?+=20=E9=83=A8=E7=BD=B2=20+=20=E8=AE=A4=E8=AF=81=20+=20=E5=BC=80?= =?UTF-8?q?=E5=8F=91=E8=A7=84=E8=8C=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 更新项目结构(反映 18 个 types 文件、33 个 API 模块、Zustand 等) - 添加环境变量说明 - 添加认证架构(httpOnly cookie 流程) - 添加部署文档(CI/CD + 服务器架构 + 手动部署) - 添加开发规范(状态管理、错误处理、TypeScript) Co-Authored-By: Claude --- README.md | 212 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 163 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index b3b029f..29cad85 100644 --- a/README.md +++ b/README.md @@ -4,78 +4,192 @@ ## 技术栈 -- React 19 + TypeScript 6 -- Vite 8 -- Ant Design 5 + @ant-design/pro-components 2.8 -- @tanstack/react-query 5 -- ECharts 5 + echarts-for-react 3 -- dayjs -- react-router-dom v7 +| 类别 | 技术 | +|------|------| +| 框架 | React 19 + TypeScript | +| 构建 | Vite 8 | +| UI | Ant Design 5 + @ant-design/pro-components 2.8 | +| 状态管理 | @tanstack/react-query 5(服务端状态)+ Zustand(客户端偏好) | +| 路由 | react-router-dom v7 | +| 图表 | ECharts 5 + echarts-for-react 3 | +| HTTP | Axios(拦截器:cookie 认证、自动刷新、错误通知) | +| 安全 | httpOnly cookie 认证(token 不可被 JS 读取) | ## 项目结构 ``` src/ -├── components/ # 共享组件 -│ ├── AuditLogTable # 审计日志 ProTable -│ ├── ConfirmDangerModal # 高危操作确认弹窗 -│ ├── DetailDrawer # 侧滑详情抽屉 -│ ├── EChartsChartContainer # 图表容器 -│ ├── EmptyState # 空状态占位 -│ ├── MetricCard # 指标卡 -│ ├── StatusTag # 状态标签 -│ ├── AuthGuard # 登录鉴权守卫 -│ ├── PageLoading # 路由懒加载 Spin -│ └── PermissionGuard # 角色权限守卫 +├── api/ # 33 个 API 模块(纯函数,导出 API 对象 + DTO 类型) +│ └── index.ts # 统一 barrel export +├── components/ # 11 个共享组件 +│ ├── ErrorBoundary # 渲染崩溃兜底 +│ ├── AuthGuard # 登录鉴权 +│ ├── PermissionGuard # 角色权限 +│ └── ... ├── config/ -│ └── menu.tsx # 菜单树与角色过滤 +│ └── menu.tsx # 侧边栏菜单树 + 角色过滤 ├── constants/ │ └── roles.ts # 角色标签/颜色/层级 ├── contexts/ -│ └── AuthContext.tsx # 认证上下文 +│ └── AuthContext.tsx # 认证上下文(唯一 Context) ├── hooks/ -│ └── use-auth-query.ts # React Query 认证 hooks +│ └── use-auth-query.ts # 认证 TanStack Query hooks ├── layouts/ -│ └── AdminLayout.tsx # 管理后台布局(侧边栏/顶栏/面包屑) -├── pages/ -│ ├── Dashboard # 数据看板(指标卡 + 图表 + 审计日志) +│ └── AdminLayout.tsx # ProLayout 管理后台骨架 +├── lib/ +│ ├── api-client.ts # Axios 实例(withCredentials, 401 刷新, 错误通知) +│ ├── token.ts # 用户信息缓存(token 在 httpOnly cookie 中) +│ ├── antd-global.ts # 全局 message/notification 引用 +│ └── error-handler.ts # 统一错误格式化和 toast +├── pages/ # 39 个页面 + learning/ 子目录 +│ ├── Dashboard # 数据看板 │ ├── UserManagement # 管理员 CRUD -│ ├── Login # 登录页 -│ ├── Placeholder # 占位页 -│ ├── 403/404/500 # 错误页 -├── routes/ -│ └── index.tsx # 路由配置(懒加载 + 角色要求) +│ ├── ImportMonitor # 文档导入监控 +│ ├── AiGateway # AI 网关路由管理 +│ ├── Servers # 服务器运维监控 +│ ├── TaskAssistant # AI 任务助手(流式对话) +│ └── ... ├── services/ -│ ├── admin-api.ts # 类型化 API 函数 -│ ├── http-client.ts # Fetch 封装(401 自动刷新队列) -│ ├── token-store.ts # Token 本地存储 -│ └── mock-data.ts # DEV 模式 Mock 数据 -└── types/ - ├── admin.ts # AdminUser, DashboardStats, AuditLog 等 - └── api.ts # PaginatedResult, ApiError +│ ├── ai-chat.ts # SSE 流式聊天 +│ ├── http-client.ts # 向后兼容重导出 +│ └── token-store.ts # 向后兼容重导出 +├── stores/ +│ ├── index.ts # Zustand store barrel +│ └── ui-store.ts # 侧边栏偏好(persist localStorage) +├── types/ # 18 个领域类型文件,~80 个类型 +│ ├── index.ts # 统一 barrel export +│ ├── admin.ts # AdminUser, AuditLog, DashboardStats +│ ├── knowledge.ts # KnowledgeBase, ImportJob, Source +│ ├── learning.ts # ReadingEvent, Session, Progress +│ ├── server.ts # ServerInfo, ProcessInfo, Health +│ ├── ai.ts # AiRoute, AiProvider, FallbackEvent +│ ├── billing.ts # CostItem, CostSummary, BillingInfo +│ ├── ui.ts # TypedColumn, SortState, FilterState +│ └── ... +└── vite-env.d.ts # 环境变量类型声明 ``` -## 启动 +## 快速开始 ```bash +# 1. 安装依赖 npm install -npm run dev # 开发模式,默认 http://localhost:5173 -npm run build # 生产构建 + +# 2. 配置环境变量 +cp .env.example .env +# 编辑 .env,设置 VITE_API_BASE_URL(本地开发指向 http://127.0.0.1:3000) + +# 3. 启动开发服务器 +npm run dev # → http://localhost:5174 + +# 4. 生产构建 +npm run build # → dist/ ``` -## 认证流程 +## 环境变量 -1. `AuthGuard` 检查登录状态,未登录跳转 `/login` -2. `PermissionGuard` 检查角色权限,不足跳转 `/403` -3. HTTP 客户端自动处理 401 → refresh token → 重试请求 -4. refresh token 失败时强制退出到 `/login` +| 变量 | 必需 | 默认值 | 说明 | +|------|------|--------|------| +| `VITE_API_BASE_URL` | 否 | `https://api.longde.cloud` | API 后端地址(仅开发模式使用) | + +- **本地开发**:`VITE_API_BASE_URL=http://127.0.0.1:3000`(Vite dev server 代理 /admin-api/ 到本地 API) +- **生产环境**:不需要设置,Nginx 将 `/admin-api/` 反向代理到后端 +- `.env.example` 已提交到 Git,复制即可使用 +- `.env` 在 `.gitignore` 中,不会被提交 + +## 认证架构 + +``` +登录 POST /admin-api/auth/login + → 后端 Set-Cookie: admin_access_token (httpOnly, Secure, SameSite=Strict) + → 前端仅缓存 admin_user 信息到 localStorage(非敏感) + +后续请求 + → axios withCredentials: true → 浏览器自动携带 cookie + → 后端 AdminAuthGuard 从 cookie 读取 JWT + → 401 → 自动调用 /admin-api/auth/refresh(cookie 中的 refresh token) + → 刷新失败 → 清除缓存 → 跳转 /login + +登出 POST /admin-api/auth/logout + → 后端 Clear-Cookie + → 前端清除 admin_user 缓存 + TanStack Query 缓存 +``` ## 角色体系 | 角色 | 说明 | 权限范围 | |------|------|---------| -| SUPER_ADMIN | 超级管理员 | 全部权限,可管理其他管理员 | -| ADMIN | 管理员 | 用户管理、仪表盘、审计日志 | -| OPERATIONS | 运营人员 | 仪表盘、审计日志(只读) | -| DEVELOPER | 开发者 | 仪表盘(只读) | -| READONLY | 只读用户 | 仪表盘(只读) | +| `SUPER_ADMIN` | 超级管理员 | 全部权限,可管理其他管理员 | +| `ADMIN` | 管理员 | 用户管理、仪表盘、审计日志 | +| `OPERATIONS` | 运营人员 | 仪表盘、审计日志(只读) | +| `DEVELOPER` | 开发者 | 仪表盘(只读) | +| `READONLY` | 只读用户 | 仪表盘(只读) | + +## 部署 + +### CI/CD(Gitea Actions) + +推送到 `main` 分支自动触发 `.gitea/workflows/deploy.yml`: + +``` +git clone → npm install → npm run build → rsync dist/ → /opt/zhixi/admin/dist/ → nginx reload +``` + +### 生产服务器架构 + +``` +admin.longde.cloud (Nginx) + ├── / → /opt/zhixi/admin/dist/ (静态文件, SPA fallback) + ├── /admin-api/ → proxy_pass http://127.0.0.1:3000 + └── /assets/ → 静态资源缓存 (1年, gzip) +``` + +### 手动部署 + +```bash +npm run build +rsync -av --delete dist/ ubuntu@120.53.227.155:/opt/zhixi/admin/dist/ +ssh ubuntu@120.53.227.155 'sudo systemctl reload nginx' +``` + +## 开发规范 + +### 状态管理原则 + +``` +TanStack Query → 服务端数据(缓存、去重、refetch) +Zustand → 客户端全局状态(UI 偏好) +AuthContext → 认证(登录/登出/权限) +useState → 页面局部 UI(弹窗、表单、选中行) +``` + +- 不在组件内 `useEffect` + `fetch` — 一律用 `useQuery` +- 不新建 Context — 除非是真正的全局状态 +- 页面局部的 `useState` 不需要提到 Store + +### 错误处理 + +```typescript +// 异步操作中使用 toastError +try { await something() } catch (err) { toastError(err, '操作失败') } + +// 全局兜底 +// - ErrorBoundary 包裹所有路由(渲染崩溃不白屏) +// - TanStack Query mutation 默认 onError → toastError +// - Axios 响应拦截器 → 网络/业务错误自动 notification.error +``` + +### TypeScript + +- `strict: true`(`noImplicitAny` 和 `strictNullChecks` 待收紧) +- 所有 API 模块有完整类型(DTO + Response) +- Table 列使用具体记录类型,不用 `(_: any, r: any)` +- 新增类型放在 `src/types/` 对应领域文件,通过 `index.ts` 导出 + +### 新增页面 Checklist + +1. 在 `src/pages/` 创建页面组件 +2. 在 `src/types/` 补充缺失的领域类型 +3. 在 `src/api/` 添加对应 API 模块(如需要) +4. 在 `App.tsx` 添加路由(懒加载 + 角色守卫) +5. 在 `config/menu.tsx` 添加菜单项