SayClaw Admin 前端重构计划
决策:弃用 Soybean Admin (Vue) 模板,基于设计稿从零构建 React 应用。
1. 为什么重构
| 问题 | 说明 |
|---|---|
| 模板臃肿 | Soybean Admin 自带大量我们不用的功能,打包体积大 |
| 定制成本高 | 改模板样式 = 和 UnoCSS + 模板约定打架 |
| 设计稿已就绪 | admin-full-design.html 包含全部 12 个页面的完整 UI |
| 技术栈统一 | 文档站 (Docusaurus) 已是 React,统一降低心智负担 |
2. 技术选型
| 层 | 选择 | 理由 |
|---|---|---|
| 框架 | React 18 + TypeScript | 生态最大,AI 辅助编码支持最好 |
| 构建 | Vite 6 | 快,和之前一致 |
| 路由 | React Router v7 | 成熟稳定 |
| 状态 | Zustand | 轻量,比 Redux 少 90% 模板代码 |
| HTTP | ky (或 axios) | 轻量 fetch wrapper |
| 样式 | CSS Modules + CSS 变量 | 零运行时,直接复用设计稿的 CSS 变量和类名 |
| 图表 | Recharts | React 原生,Dashboard 图表用 |
| 表格 | @tanstack/react-table | 排序、分页、筛选 |
| 表单 | React Hook Form | 轻量表单验证 |
| 包管理 | pnpm | 与现有项目一致 |
| 代码质量 | ESLint + Prettier + Biome | — |
3. 项目结构
sayclaw-admin-v2/
├── public/
│ └── favicon.svg
├── src/
│ ├── main.tsx # 入口
│ ├── App.tsx # 路由定义
│ │
│ ├── assets/
│ │ ├── icons/ # SVG 图标(从设计稿提取)
│ │ └── styles/
│ │ ├── variables.css # 设计稿 CSS 变量(绿色主题)
│ │ ├── global.css # 全局重置 + 基础样式
│ │ └── components.css # 共用组件样式
│ │
│ ├── components/ # 通用 UI 组件
│ │ ├── Layout/
│ │ │ ├── Sidebar.tsx # 侧栏导航
│ │ │ ├── MainLayout.tsx # 主布局(侧栏 + 内容区)
│ │ │ └── PageBanner.tsx # 页面顶部绿色 Banner
│ │ ├── Table/
│ │ │ ├── DataTable.tsx # 通用数据表格
│ │ │ └── Pagination.tsx # 分页
│ │ ├── Form/
│ │ │ ├── Input.tsx
│ │ │ ├── Select.tsx
│ │ │ ├── Switch.tsx
│ │ │ └── DateRangePicker.tsx
│ │ ├── Modal.tsx # 通用弹窗
│ │ ├── Tag.tsx # 状态标签 (green/blue/yellow/red/gray)
│ │ ├── Button.tsx # 按钮
│ │ ├── Card.tsx # 卡片容器
│ │ ├── TabBar.tsx # Tab 切换栏
│ │ └── SearchBox.tsx # 搜索框
│ │
│ ├── pages/ # 12 个页面
│ │ ├── Dashboard/ # 数据总览
│ │ │ └── index.tsx
│ │ ├── AdminUsers/ # 后台账号
│ │ │ └── index.tsx
│ │ ├── ApiKeys/ # API 密钥(3 Tab)
│ │ │ ├── index.tsx
│ │ │ ├── MasterKeys.tsx
│ │ │ ├── SubKeys.tsx
│ │ │ └── AiModels.tsx
│ │ ├── PortalUsers/ # 员工账号
│ │ │ └── index.tsx
│ │ ├── Usage/ # 使用记录
│ │ │ └── index.tsx
│ │ ├── Servers/ # 服务器管理
│ │ │ └── index.tsx
│ │ ├── Instances/ # OC 实例
│ │ │ └── index.tsx
│ │ ├── Scheduler/ # 调度管理(2 Tab)
│ │ │ ├── index.tsx
│ │ │ ├── CronJobs.tsx
│ │ │ └── TaskQueue.tsx
│ │ ├── AuditLog/ # 审计日志(2 Tab)
│ │ │ ├── index.tsx
│ │ │ ├── LlmRequestLog.tsx
│ │ │ └── OpsLog.tsx
│ │ └── Shrimp/ # 捕虾场(3 子页面)
│ │ ├── Professions.tsx # 职能虾管理
│ │ ├── Pool.tsx # 虾池管理
│ │ ├── Claims.tsx # 捕获记录
│ │ └── ProfessionModal.tsx # 新增/编辑弹窗
│ │
│ ├── services/ # API 层
│ │ ├── request.ts # HTTP client (ky/axios 封装)
│ │ ├── auth.ts # 登录、OAuth、JWT
│ │ ├── dashboard.ts # 统计数据
│ │ ├── admin-users.ts # 后台账号 CRUD
│ │ ├── api-keys.ts # 主Key/子Key/模型
│ │ ├── portal-users.ts # Portal 用户
│ │ ├── instances.ts # OC 实例
│ │ ├── servers.ts # 服务器
│ │ ├── scheduler.ts # Cron + 任务队列
│ │ ├── audit.ts # 审计日志 + LLM日志
│ │ └── shrimp.ts # 捕虾场全部 API
│ │
│ ├── stores/ # Zustand stores
│ │ ├── useAuthStore.ts # 登录态、JWT、用户信息
│ │ └── useGlobalStore.ts # 侧栏折叠、主题等
│ │
│ ├── hooks/ # 自定义 hooks
│ │ ├── useAuth.ts # 鉴权守卫
│ │ └── useTimezone.ts # 时区检测 + 格式化
│ │
│ └── utils/
│ ├── format.ts # 日期/金额/token 格式化
│ └── constants.ts # 路由路径、枚举值
│
├── index.html
├── vite.config.ts
├── tsconfig.json
├── package.json
└── .env # VITE_API_BASE_URL=https://api.sayclaw.ai/api/v1
4. 路由设计
// App.tsx
<Routes>
<Route path="/login" element={<Login />} />
<Route element={<AuthGuard><MainLayout /></AuthGuard>}>
<Route path="/" element={<Navigate to="/dashboard" />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/admin-users" element={<AdminUsers />} />
<Route path="/api-keys" element={<ApiKeys />} />
<Route path="/portal-users" element={<PortalUsers />} />
<Route path="/usage" element={<Usage />} />
<Route path="/servers" element={<Servers />} />
<Route path="/instances" element={<Instances />} />
<Route path="/scheduler" element={<Scheduler />} />
<Route path="/audit" element={<AuditLog />} />
<Route path="/shrimp/professions" element={<Professions />} />
<Route path="/shrimp/pool" element={<Pool />} />
<Route path="/shrimp/claims" element={<Claims />} />
</Route>
</Routes>
5. 设计系统(直接复用设计稿)
CSS 变量(从 admin-full-design.html 提取)
:root {
--primary: #43b581;
--primary-light: #5ec49a;
--primary-dark: #369e6e;
--primary-bg: #eafaf1;
--gradient: linear-gradient(135deg, #43b581, #2d8f63);
--success: #43b581; --success-bg: #eafaf1;
--warning: #f0a020; --warning-bg: #fef8eb;
--danger: #e85d5d; --danger-bg: #fdf0f0;
--info: #5b8def; --info-bg: #edf3fe;
--gray-50 ~ --gray-900 (10 级灰)
--radius: 12px;
--radius-sm: 8px;
--shadow / --shadow-md / --shadow-lg
}
组件 → 设计稿对照
| 组件 | 设计稿 class | 复用方式 |
|---|---|---|
<PageBanner> | .banner | 直接搬 CSS |
<Tag color="green"> | .tag .tag-green | Props 控制颜色 |
<DataTable> | table th td | 同样式 |
<Button variant="primary"> | .btn .btn-primary | Props 控制变体 |
<Modal> | .modal-overlay .modal | 搬原样式 |
<Card> | .card | 搬原样式 |
<ShrimpCard> | .shrimp-card | 捕虾场专用 |
<IconBox color="emerald"> | .si .si-emerald | SVG 渐变图标盒 |
<SkillPicker> | .skill-picker .skill-chip | 多选 chip |
<MdEditor> | .md-split | 左右分栏编辑器 |
6. 分期交付
Phase 1:骨架 + 核心页面(3 天)
| 任务 | 交付物 |
|---|---|
| 项目初始化 | Vite + React + TS + pnpm |
| 设计系统 | CSS 变量 + 全局样式 + 图标 SVG |
| 布局组件 | Sidebar + MainLayout + PageBanner |
| 通用组件 | Button, Tag, Card, Modal, Table, Pagination, TabBar |
| 登录页 | Google OAuth + 密码登录 |
| 数据总览 | 统计卡片 + 图表 + 告警表 + 服务器状态 |
| API 层 | request.ts + auth.ts + dashboard.ts |
交付标准: 能登录、看到 Dashboard、侧栏可点击。
Phase 2:管理页面(3 天)
| 任务 | 交付物 |
|---|---|
| 后台账号 | CRUD 表格 + 新增/编辑弹窗 |
| API 密钥 | 3 Tab(主Key/子Key/模型)+ CRUD |
| 员工账号 | 表格 + 分配实例 |
| 使用记录 | 日期筛选 + 请求日志表格 |
交付标准: 4 个管理页面可正常 CRUD。
Phase 3:基础设施(2 天)
| 任务 | 交付物 |
|---|---|
| 服务器管理 | 服务器卡片 + 资源监控条 |
| OC 实例 | 实例表格 + 健康状态 + 操作按钮 |
| 调度管理 | 2 Tab: Cron Jobs + 任务队列 |
| 审计日志 | 2 Tab: LLM 请求日志 + 管理操作日志 |
交付标准: 所有基础设施页面对接真实 API。
Phase 4:捕虾场(2 天)
| 任务 | 交付物 |
|---|---|
| 职能虾管理 | 卡片网格 + 新增弹窗(技能多选 + MD 编辑器) |
| 虾池管理 | 状态 Tab + 表格 + 回收/维护操作 |
| 捕获记录 | 只读表格 + 筛选 + CSV 导出 |
交付标准: 捕虾场 3 页完整可用。
Phase 5:打磨 + 部署(1-2 天)
| 任务 | 交付物 |
|---|---|
| 响应式 | 适配 ≥1024px(不做移动端,后续再说) |
| 错误处理 | 全局错误边界 + API 错误 toast |
| 权限 | super_admin vs admin 菜单/按钮权限 |
| CI/CD | GitLab Pipeline: lint → build → scp 部署 |
| Nginx | 更新 /var/www/sayclaw-admin 指向新构建产物 |
总计:11-12 天
7. API 对接清单
现有后端 API(admin-api port 8081):
| 模块 | 端点数 | 状态 |
|---|---|---|
| 认证 (auth) | 4 | ✅ 已有 |
| 管理员账号 | 4 | ✅ 已有 |
| Portal 用户 | 5 | ✅ 已有 |
| OC 实例 | 11 | ✅ 已有 |
| 服务器 | 6 | ✅ 已有 |
| LLM 主Key | 4 | ✅ 已有 |
| LLM 子Key | 5 | ✅ 已有 |
| LLM 日志 | 4 | ✅ 已有 |
| Cron/任务队列 | 6 | ✅ 已有 |
| 捕虾场 | 10+ | ⚠️ 部分在 MR 中 |
| 审计日志 | 2 | ❌ 需新增 |
8. 部署架构
开发: localhost:5173 (Vite dev server) → proxy → localhost:8081
生产: admin.sayclaw.ai → nginx → /var/www/sayclaw-admin/dist/
↘ /api/v1/* → 127.0.0.1:8081
9. 开发约定
- 一个页面一个目录,index.tsx 为入口
- 服务层:所有 API 调用在
services/中,页面不直接调 fetch - 时间格式:统一
YYYY-MM-DD HH:MM:SS,前端根据浏览器时区显示 - Git 分支:
feature/admin-v2-phase-N,每个 Phase 一个 MR - 代码仓库:
sayclaw-app(或新建sayclaw-admin-v2)
10. 风险 & 决策点
| 风险 | 缓解 |
|---|---|
| 审计日志 API 未实现 | Phase 3 时后端补上 2 个端点 |
| 捕虾场 API 在未合并的 MR 中 | Phase 4 前合并 backend #5, #6, #7 |
| 设计稿主色 (#43b581) 与旧前端 (#5B4FE8) 不同 | 按设计稿绿色走,弃用旧紫色 |
| 移动端 | V2 先不做 H5,后续单独迭代 |