29 KiB
Admin 前端唯一执行方案
更新时间:2026-03-19
1. 文档定位
本文是当前唯一有效的 Admin 前端执行方案,后续前端实现、拆分任务、接口联调、验收都以本文为准。
事实来源仅限以下文件:
docs/API.mdinternal/api/router/router.godocs/status/REAL_PROJECT_STATUS.mddocs/PROJECT_REVIEW_REPORT.md
约束原则:
- 只实现仓库内已经真实接线、可以联调的 API。
- PRD 与当前后端实现不一致时,以当前后端事实为准,缺口明确列为延期项或前置依赖。
- 页面、类型、认证流、API 服务层必须统一,不再允许文档内同时存在 Vue / React、Axios / Fetch、假接口 / 真接口两套口径。
2. 当前真实约束
2.1 项目现状
- 仓库中目前没有真实前端项目,Admin 前端尚未开始。
- 后端当前已经通过
go build ./...、go vet ./...、go test ./...。 - 当前项目真实状态是“后端核心链路可用,前端未开始,PRD 仍有未完成范围”。
2.2 必须接受的后端事实
- 用户管理没有
POST /api/v1/users,因此当前不支持“管理员单个创建用户”页面。 - 没有批量启用、批量禁用、批量删除接口,因此不做批量用户操作。
PUT /api/v1/users/:id/password当前只允许本人改自己的密码,不支持管理员重置他人密码。/api/v1/users/:id/avatar的处理逻辑实际上只更新当前登录用户头像,因此头像上传只放到“个人中心”,不放到用户管理页。- 仪表盘统计只提供:
- 用户总数、各状态人数
- 今日 / 本周 / 本月新增用户
- 今日成功 / 失败登录数
- 本周成功登录数
- 没有系统设置配置接口,因此不做
/settings页面。 - 没有“当前用户权限快照”接口。前端可稳定获取的是:
GET /api/v1/auth/userinfoGET /api/v1/users/:id/roles
- OAuth 回调当前由后端直接返回 JSON,不是标准 SPA redirect 完成态,因此社交登录 / 绑定不纳入当前 MVP。
- 设备接口没有“全局设备列表”,只有:
GET /api/v1/devices当前用户设备GET /api/v1/devices/users/:id指定用户设备 因此前端不做全局设备管理页面。
3. 单一技术栈
当前只接受以下一套前端技术栈:
| 关注点 | 统一方案 | 说明 |
|---|---|---|
| 框架 | React 18 + TypeScript | 统一组件模型和类型系统 |
| 构建工具 | Vite | 快速启动,适合从零搭建 |
| 路由 | React Router 6 | 足够覆盖登录、后台布局、受保护路由 |
| UI 组件 | Ant Design 5 | 后台场景成熟,减少重复造轮子 |
| 请求层 | 浏览器原生 fetch + 自建请求客户端 |
避免 Axios 二次封装分叉 |
| 状态管理 | React Context 仅管理会话态 | 不引入 Redux / Zustand / Pinia |
| 页面数据 | 页面局部状态 + 受控请求 | 首版不引入 React Query |
| 表单 | Ant Design Form | 与 UI 组件一致 |
| 样式 | CSS Modules + CSS Variables + AntD Theme Token | 不引入 styled-components |
| 图表 | MVP 不引入额外图表库 | 当前统计接口不足以支撑复杂图表 |
明确不采用:
- Vue 3
- Pinia
- Axios
- styled-components
- React Query
- “HTML + CSS + JavaScript 手写管理后台”
3.1 前端技术架构总览
前端统一采用单体 SPA 架构,不拆微前端,不做 SSR,不做多应用并行。
运行时分层固定为:
App Shell- 应用启动、主题、路由挂载、全局异常边界
Session Layer- 会话恢复、刷新令牌、登录态广播、路由准入
HTTP Client Layer- 鉴权头注入、统一解包、401 重试、下载上传
Service Layer- 按资源拆分 API 方法,不放 UI 逻辑
Page / Feature Layer- 页面编排、表格、表单、弹窗、抽屉
Shared UI Layer- 布局、通用表格状态、空态、错误态、确认弹窗
数据流固定为:
Page -> Service -> HTTP Client -> API
禁止反向依赖:
services依赖页面组件- 页面直接拼接 URL 自己发请求
- 多套 token 管理并存
- 多套类型定义并存
3.2 项目目录架构
前端项目统一新建在:
frontend/admin
目录结构固定为:
frontend/admin/
package.json
tsconfig.json
vite.config.ts
.env.example
src/
app/
App.tsx
main.tsx
router.tsx
providers/
AuthProvider.tsx
ThemeProvider.tsx
layouts/
AdminLayout/
AuthLayout/
pages/
auth/
LoginPage/
ForgotPasswordPage/
ResetPasswordPage/
admin/
DashboardPage/
UsersPage/
RolesPage/
PermissionsPage/
LoginLogsPage/
OperationLogsPage/
WebhooksPage/
ImportExportPage/
ProfilePage/
ProfileSecurityPage/
features/
auth/
users/
roles/
permissions/
logs/
webhooks/
profile/
import-export/
devices/
totp/
services/
auth.ts
users.ts
roles.ts
permissions.ts
stats.ts
logs.ts
webhooks.ts
import-export.ts
profile.ts
devices.ts
lib/
http/
client.ts
auth-session.ts
errors.ts
storage/
token-storage.ts
components/
common/
feedback/
forms/
types/
http.ts
auth.ts
user.ts
role.ts
permission.ts
device.ts
log.ts
webhook.ts
stats.ts
styles/
tokens.css
global.css
目录原则:
pages只放路由页面,不放复用业务组件features放页面内复用的业务组件与交互逻辑services只放接口调用types只放接口类型与领域类型components/common只放通用 UI,不感知业务资源
3.3 依赖白名单
首版允许引入的前端运行时依赖只保留:
reactreact-domreact-router-domantd@ant-design/iconsdayjs
首版允许引入的开发依赖只保留:
typescriptvite@vitejs/plugin-reacteslint@types/react@types/react-domvitest
依赖准入规则:
- 没有明确解决当前问题的依赖,不引入。
- 能用浏览器原生能力解决的问题,不引入包装库。
- 同类库只保留一套。
3.4 技术简化结论
这版前端技术架构刻意做了收缩,最终结论如下:
- 不做微前端
- 不做 monorepo 拆分
- 不做 SSR / SSG
- 不做 Redux / Zustand / Pinia
- 不做 React Query
- 不做 Axios
- 不做 CSS-in-JS
- 不做图表库优先接入
- 不做权限码驱动的复杂前端元编程
首版只保留四个必须的技术支点:
- React 页面和路由
- Context 会话管理
fetch请求客户端- Ant Design 后台组件
3.5 工程准则
前端开发时必须遵守以下准则:
- 一个 API 资源对应一个 service 文件。
- 一个路由页面对应一个 page 目录。
- 一个复杂弹窗 / 抽屉对应一个独立 feature 组件。
- 一个任务只解决一类问题,不混做“页面 + 所有依赖 + 所有接口”。
- 所有新代码默认 TypeScript 严格模式。
- 所有请求先写类型,再写 service,再接页面。
4. 页面与路由范围
4.1 MVP 页面
| 路由 | 访问级别 | 页面范围 | 对应 API |
|---|---|---|---|
/login |
公开 | 账号密码登录、邮箱验证码登录、短信验证码登录 | /auth/login /auth/send-email-code /auth/login/email-code /auth/send-code /auth/login/code |
/forgot-password |
公开 | 发起密码重置 | /auth/forgot-password |
/reset-password |
公开 | 校验重置 token、提交新密码 | /auth/reset-password |
/dashboard |
管理员 | 统计卡片与简表,不做假趋势图 | /admin/stats/dashboard /admin/stats/users |
/users |
管理员 | 用户列表、筛选、详情抽屉、编辑、状态切换、删除、分配角色 | /users /users/:id /users/:id /users/:id/status /users/:id/roles /users/:id |
/roles |
管理员 | 角色列表、创建、编辑、删除、启停、分配权限 | /roles /roles/:id /roles/:id/status /roles/:id/permissions |
/permissions |
管理员 | 权限列表、树、创建、编辑、删除、启停 | /permissions /permissions/tree /permissions/:id/status |
/logs/login |
管理员 | 登录日志列表 | /logs/login |
/logs/operation |
管理员 | 操作日志列表 | /logs/operation |
/webhooks |
已登录 | Webhook 列表、创建、编辑、删除、投递记录 | /webhooks /webhooks/:id/deliveries |
/import-export |
管理员 | 导入、导出、模板下载 | /admin/users/import /admin/users/export /admin/users/import/template |
/profile |
已登录 | 个人资料查看与编辑 | /auth/userinfo /users/:id |
/profile/security |
已登录 | 修改密码、TOTP、头像上传、本人设备、本人日志 | /users/:id/password /auth/2fa/* /users/:id/avatar /devices /logs/login/me /logs/operation/me |
4.2 页面能力边界
/users 当前只允许实现:
- 列表分页、关键字筛选、状态筛选、角色筛选、时间筛选、排序
- 查看用户详情
- 编辑用户资料
- 删除用户
- 修改用户状态
- 分配角色
/users 当前明确不做:
- 新建用户
- 批量操作
- 管理员代改他人密码
- 为其他用户上传头像
/dashboard 当前只允许展示真实统计字段,不做以下伪需求:
- 在线用户
- 近 7 / 30 天时序趋势图
- 地域分布图
- 最近注册用户
- 最近登录用户
4.3 延期或阻塞页面
以下页面或功能不进入当前前端实施范围:
/settings- 全局
/devices管理页 - 用户创建页
- 用户批量操作
- 管理员重置他人密码
- “记住我 / 记住设备”
- 社交登录回调页
- 社交账号绑定页
- 依赖权限码的细粒度按钮控制
5. 统一类型模型
5.1 基础响应模型
所有请求统一先经过响应解包,禁止页面直接假定不同接口的 data 结构。
export interface ApiResponse<T> {
code: number;
message: string;
data: T;
}
export interface PaginatedData<T> {
items: T[];
total: number;
page: number;
page_size: number;
}
注意:
- 分页列表真实格式是
data.items + total + page + page_size。 - 不是所有列表都是分页返回。
GET /webhooks、GET /users/:id/roles、GET /roles/:id/permissions、GET /permissions/tree等接口返回的不是PaginatedData<T>。
5.2 会话与认证类型
export interface SessionUser {
id: number;
username: string;
email: string;
phone: string;
nickname: string;
avatar: string;
status: 0 | 1 | 2 | 3;
}
export interface TokenBundle {
access_token: string;
refresh_token: string;
expires_in: number;
user: SessionUser;
}
关键约束:
POST /auth/login返回TokenBundlePOST /auth/refresh也返回TokenBundle- 不允许再定义“刷新后只返回 access_token”的前端假类型
5.3 领域类型
前端类型定义以当前后端 JSON 字段为准,至少包含以下文件:
src/types/http.tssrc/types/auth.tssrc/types/user.tssrc/types/role.tssrc/types/permission.tssrc/types/device.tssrc/types/log.tssrc/types/webhook.tssrc/types/stats.ts
必须保留的真实枚举约束:
UserStatus:0 | 1 | 2 | 3RoleStatus:0 | 1PermissionStatus:0 | 1
6. 认证与会话流
6.1 统一会话策略
采用以下单一策略:
refresh_token持久化到localStorageaccess_token保存在内存态- 应用启动时优先尝试用
refresh_token换取新的TokenBundle - 刷新成功后再加载角色信息
- 刷新失败则清空会话并回到登录页
这样做的原因:
- 当前后端刷新接口已经返回完整
TokenBundle - 可以避免前端长期持久化过期
access_token - 页面刷新后可以稳定恢复登录态
6.2 启动流程
应用启动流程固定如下:
- 读取本地
refresh_token - 若存在,则调用
POST /api/v1/auth/refresh - 刷新成功后,拿到新的
access_token、refresh_token、user - 调用
GET /api/v1/users/{user.id}/roles - 从角色列表中推导:
roleCodesisAdmin = roleCodes.includes("admin")
- 会话完成后才渲染受保护路由
补充规则:
- 不以
GET /auth/userinfo作为唯一启动入口,避免浪费一次可能会被 401 的请求 GET /auth/userinfo作为“刷新当前资料”能力保留给 Profile 页面或手动重载
6.3 登录与登出流
登录页支持三种真实入口:
- 账号密码登录
- 邮箱验证码登录
- 短信验证码登录
登录成功后统一执行:
- 写入新的
refresh_token - 将新的
access_token放入内存 - 直接使用返回体中的
user - 再请求当前用户角色
- 完成后跳转后台首页
登出统一执行:
- 调用
POST /api/v1/auth/logout - 请求体优先带上当前
access_token和refresh_token - 无论接口成功与否,都清空本地会话
- 跳回
/login
6.4 401 处理
请求客户端必须实现单次刷新机制:
- 普通业务请求收到
401 - 若当前存在
refresh_token,触发一次全局中的刷新流程 - 刷新成功后重放原请求
- 刷新失败则清会话并跳转
/login
禁止旧方案中的以下行为:
- 收到
401直接跳登录,不尝试刷新 - 刷新后只更新
access_token,不更新refresh_token
6.5 暂不纳入 MVP 的认证能力
以下能力有 API,但当前不纳入首版登录流:
- 社交登录按钮直连回调完成登录
- 社交账号绑定
- remember me
原因不是“前端不做”,而是“当前后端协议不适合 SPA 稳定落地”。
7. API 服务层统一方案
7.1 目录结构
目录结构以 3.2 项目目录架构 为准。
本节只强调 service / lib / types 三层在该目录中的职责:
lib/http- 统一请求客户端、会话刷新、错误模型
services- 资源级 API 访问层
types- 统一接口类型和领域类型
7.2 请求客户端职责
lib/http/client.ts 只做以下事情:
- 拼接基础 URL
- 注入
Authorization: Bearer <access_token> - 统一解包
ApiResponse<T> - 统一处理
401 - 统一处理
Blob下载和FormData上传 - 将后端业务错误统一转成前端可消费的
AppError
禁止:
- 页面组件内手写
fetch("/api/v1/...") - 每个页面自己处理 token 注入与刷新
- 把分页响应和普通响应混成一个类型
7.3 服务层模块边界
services/auth.ts
loginByPasswordsendEmailCodeloginByEmailCodesendSmsCodeloginBySmsCoderefreshSessionlogoutforgotPasswordvalidateResetTokenresetPasswordgetUserInfogetTwoFactorStatussetupTwoFactorenableTwoFactordisableTwoFactorverifyTwoFactor
services/users.ts
listUsersgetUserupdateUserdeleteUserupdateUserStatusgetUserRolesassignUserRoles
services/profile.ts
getMyProfileupdateMyProfilechangeMyPassworduploadMyAvatargetMyLoginLogsgetMyOperationLogs
services/roles.ts
listRolescreateRolegetRoleupdateRoledeleteRoleupdateRoleStatusgetRolePermissionsassignRolePermissions
services/permissions.ts
listPermissionsgetPermissionTreecreatePermissiongetPermissionupdatePermissiondeletePermissionupdatePermissionStatus
services/stats.ts
getDashboardStatsgetUserStats
services/logs.ts
getLoginLogsgetOperationLogs
services/webhooks.ts
listWebhookscreateWebhookupdateWebhookdeleteWebhookgetWebhookDeliveries
services/import-export.ts
downloadUserExportuploadUserImportdownloadImportTemplate
services/devices.ts
getMyDevicesgetUserDevicesgetDevicecreateDeviceupdateDevicedeleteDeviceupdateDeviceStatus
7.4 下载与上传约束
- 用户导出必须走
Blob下载 - 导入必须走
multipart/form-data - 头像上传必须走
multipart/form-data - 头像上传虽然路径是
/users/:id/avatar,但前端只允许传当前用户 ID
8. 权限与路由守卫
8.1 现阶段只做两级守卫
当前前端守卫只做:
RequireAuthRequireAdmin
判断依据:
- 会话中必须有有效
access_token - 启动后必须已成功拉到当前用户角色
role.code === "admin"视为管理员
8.2 当前不做权限码按钮系统
原因:
- 后端没有“当前用户权限快照”公开接口
- 中间件中的
permission_codes仅存在于服务端请求上下文,不会自动返回给前端
因此当前只允许:
- 管理员页面用
RequireAdmin - 用户自己的页面按“本人”场景控制
当前不允许:
- 以前端硬编码方式伪造整套按钮级
permission code控制体系
9. 实施阶段与最小任务拆解
9.1 交付顺序
前端按以下顺序交付,不允许跳步:
- 工程骨架
- 会话与请求底座
- 认证页面
- 管理后台框架
- 核心管理页
- 运营与个人安全页
- 收尾验证
9.2 任务拆解规则
最小任务定义:
- 一个任务只产出一个明确可验证的结果
- 一个任务的完成标准必须能被构建、页面行为或接口联调验证
- 一个任务不能横跨多个资源域
任务粒度控制:
- 基础设施任务:一个文件组或一个运行能力
- 服务层任务:一个资源服务文件
- 页面任务:一个路由页面
- 复杂交互任务:一个弹窗、一个抽屉、一个上传、一个下载流
9.3 M0 工程骨架
| ID | 任务 | 产出 | 完成定义 |
|---|---|---|---|
| M0-01 | 初始化 frontend/admin Vite 项目 |
基础工程目录 | 能本地启动空白 React 页面 |
| M0-02 | 建立 tsconfig 路径别名 |
@/ 别名 |
导入路径不再依赖相对路径层层回退 |
| M0-03 | 建立 .env.example |
VITE_API_BASE_URL 规范 |
请求基地址可配置 |
| M0-04 | 接入 Ant Design 5 和全局样式 | global.css / tokens.css |
页面样式正常加载 |
| M0-05 | 建立 AuthLayout 与 AdminLayout 骨架 |
两套布局组件 | 登录页和后台页布局可区分 |
| M0-06 | 建立应用路由骨架 | router.tsx |
公开页和受保护页都可访问 |
| M0-07 | 建立错误页与 404 页 | 错误反馈页面 | 未匹配路由可落到 404 |
| M0-08 | 建立全局 AppError 模型 |
统一错误结构 | 页面可接收统一错误对象 |
9.4 M1 会话与请求底座
| ID | 任务 | 产出 | 完成定义 |
|---|---|---|---|
| M1-01 | 实现 token-storage.ts |
刷新令牌读写封装 | refresh_token 可稳定存取 |
| M1-02 | 实现 auth-session.ts |
内存态 access token 管理 | 页内请求可拿到当前 access token |
| M1-03 | 实现 client.ts 基础请求能力 |
GET/POST/PUT/DELETE 封装 |
页面不再手写原生请求细节 |
| M1-04 | 实现统一响应解包 | ApiResponse<T> 解包 |
service 可直接返回业务数据 |
| M1-05 | 实现统一业务错误映射 | 后端错误转 AppError |
页面可稳定提示错误信息 |
| M1-06 | 实现 401 单次刷新机制 | 请求重试逻辑 | access token 过期后可自动刷新一次 |
| M1-07 | 实现并发刷新锁 | 单飞刷新 | 多请求 401 时只触发一次刷新 |
| M1-08 | 实现 AuthProvider |
全局会话上下文 | 页面可读取用户、角色、登录状态 |
| M1-09 | 实现应用启动会话恢复 | 启动自动 refresh | 刷新页面后能恢复登录态 |
| M1-10 | 实现 RequireAuth |
登录守卫 | 未登录不可进入受保护页面 |
| M1-11 | 实现 RequireAdmin |
管理员守卫 | 非 admin 不可进入后台管理页 |
| M1-12 | 定义 http.ts / auth.ts / user.ts 基础类型 |
通用类型文件 | 认证和用户请求不再使用 any |
9.5 M2 认证页
| ID | 任务 | 产出 | 完成定义 |
|---|---|---|---|
| M2-01 | 实现 services/auth.ts |
认证 service | 登录、刷新、登出、密码重置接口可调用 |
| M2-02 | 实现密码登录表单 | 登录页密码 Tab | 可调用 /auth/login 并进入后台 |
| M2-03 | 实现邮箱验证码发送 | 邮箱验证码发送流程 | 可调用 /auth/send-email-code |
| M2-04 | 实现邮箱验证码登录表单 | 邮箱验证码登录 Tab | 可调用 /auth/login/email-code |
| M2-05 | 实现短信验证码发送 | 短信验证码发送流程 | 可调用 /auth/send-code |
| M2-06 | 实现短信验证码登录表单 | 短信验证码登录 Tab | 可调用 /auth/login/code |
| M2-07 | 实现忘记密码页 | ForgotPasswordPage |
可调用 /auth/forgot-password |
| M2-08 | 实现重置密码页 | ResetPasswordPage |
可校验并提交重置密码 |
| M2-09 | 实现登出动作 | 退出登录入口 | 退出后会话被清空并跳转登录页 |
| M2-10 | 实现会话启动加载态 | 启动屏 / 骨架态 | 启动恢复期间不闪跳错误页面 |
9.6 M3 后台框架
| ID | 任务 | 产出 | 完成定义 |
|---|---|---|---|
| M3-01 | 实现后台菜单配置 | 路由与菜单映射 | 菜单只出现当前方案允许的页面 |
| M3-02 | 实现后台头部区域 | 顶栏组件 | 能展示当前用户和退出入口 |
| M3-03 | 实现侧边栏导航 | 菜单导航 | 页面间可跳转 |
| M3-04 | 实现面包屑和页面容器 | 页面框架组件 | 后台页面布局一致 |
| M3-05 | 实现页面级加载 / 空态 / 错误态组件 | 反馈组件 | 所有列表页使用统一反馈模式 |
9.7 M4 Dashboard
| ID | 任务 | 产出 | 完成定义 |
|---|---|---|---|
| M4-01 | 定义 stats.ts 类型 |
统计类型文件 | 用户统计和登录统计字段齐全 |
| M4-02 | 实现 services/stats.ts |
统计 service | 可请求 dashboard / users stats |
| M4-03 | 实现 Dashboard 统计卡片 | Dashboard 页面基础版 | 展示真实统计卡片 |
| M4-04 | 实现 Dashboard 简表区块 | 简单文本 / 数字区块 | 不引入假图表但信息完整 |
9.8 M5 Users
| ID | 任务 | 产出 | 完成定义 |
|---|---|---|---|
| M5-01 | 完成 user.ts 领域类型 |
用户列表 / 详情类型 | 用户页所有字段有类型约束 |
| M5-02 | 实现 services/users.ts |
用户 service | 列表、详情、编辑、状态、角色分配可调用 |
| M5-03 | 实现用户筛选表单 | UsersFilter | 支持关键字、状态、角色、时间、排序 |
| M5-04 | 实现用户列表表格 | UsersTable | 分页和列表展示正常 |
| M5-05 | 实现用户详情抽屉 | UserDetailDrawer | 可查看用户详情 |
| M5-06 | 实现编辑用户抽屉 | UserEditDrawer | 可提交 /users/:id 更新 |
| M5-07 | 实现用户状态切换动作 | 状态更新交互 | 可提交 /users/:id/status |
| M5-08 | 实现用户删除动作 | 删除确认流 | 可提交 /users/:id 删除 |
| M5-09 | 实现用户角色分配弹窗 | AssignRolesModal | 可提交 /users/:id/roles |
9.9 M6 Roles
| ID | 任务 | 产出 | 完成定义 |
|---|---|---|---|
| M6-01 | 定义 role.ts 类型 |
角色类型文件 | 列表、详情、权限关联字段齐全 |
| M6-02 | 实现 services/roles.ts |
角色 service | 增删改查、启停、权限分配可调用 |
| M6-03 | 实现角色列表页 | RolesPage | 列表、分页、状态展示正常 |
| M6-04 | 实现创建 / 编辑角色弹窗 | RoleFormModal | 可提交创建和更新 |
| M6-05 | 实现角色状态切换 | 状态操作 | 可提交 /roles/:id/status |
| M6-06 | 实现角色删除动作 | 删除确认流 | 可删除角色 |
| M6-07 | 实现角色权限分配弹窗 | RolePermissionsModal | 可读取并提交角色权限 |
9.10 M7 Permissions
| ID | 任务 | 产出 | 完成定义 |
|---|---|---|---|
| M7-01 | 定义 permission.ts 类型 |
权限类型文件 | 权限树和列表字段齐全 |
| M7-02 | 实现 services/permissions.ts |
权限 service | 列表、树、增删改查、启停可调用 |
| M7-03 | 实现权限列表页 | PermissionsPage | 列表和树切换正常 |
| M7-04 | 实现创建 / 编辑权限弹窗 | PermissionFormModal | 可提交创建和更新 |
| M7-05 | 实现权限状态切换 | 状态操作 | 可提交 /permissions/:id/status |
| M7-06 | 实现权限删除动作 | 删除确认流 | 可删除权限 |
9.11 M8 Logs
| ID | 任务 | 产出 | 完成定义 |
|---|---|---|---|
| M8-01 | 定义 log.ts 类型 |
日志类型文件 | 登录日志和操作日志字段齐全 |
| M8-02 | 实现 services/logs.ts |
日志 service | 登录日志、操作日志接口可调用 |
| M8-03 | 实现登录日志页 | LoginLogsPage | 列表、分页、筛选正常 |
| M8-04 | 实现操作日志页 | OperationLogsPage | 列表、分页、筛选正常 |
9.12 M9 Webhooks
| ID | 任务 | 产出 | 完成定义 |
|---|---|---|---|
| M9-01 | 定义 webhook.ts 类型 |
Webhook 类型文件 | 列表和投递记录字段齐全 |
| M9-02 | 实现 services/webhooks.ts |
Webhook service | 列表、增删改、投递记录可调用 |
| M9-03 | 实现 Webhook 列表页 | WebhooksPage | 列表可展示 |
| M9-04 | 实现创建 / 编辑 Webhook 弹窗 | WebhookFormModal | 可提交创建和更新 |
| M9-05 | 实现删除 Webhook 动作 | 删除确认流 | 可删除 Webhook |
| M9-06 | 实现投递记录抽屉 | DeliveriesDrawer | 可查看 /webhooks/:id/deliveries |
9.13 M10 Import / Export
| ID | 任务 | 产出 | 完成定义 |
|---|---|---|---|
| M10-01 | 实现 services/import-export.ts |
导入导出 service | 下载模板、上传导入、导出下载可调用 |
| M10-02 | 实现导出表单 | ExportPanel | 可设置格式和筛选条件 |
| M10-03 | 实现导出下载流 | Blob 下载 | CSV / XLSX 文件可正常下载 |
| M10-04 | 实现导入上传表单 | ImportPanel | 可上传 .csv / .xlsx |
| M10-05 | 实现模板下载动作 | TemplateDownload | 可下载导入模板 |
9.14 M11 Profile / Security
| ID | 任务 | 产出 | 完成定义 |
|---|---|---|---|
| M11-01 | 实现 services/profile.ts |
个人中心 service | 当前用户资料与安全接口可调用 |
| M11-02 | 实现 services/devices.ts |
设备 service | 本人设备接口可调用 |
| M11-03 | 实现个人资料页 | ProfilePage | 可查看并编辑个人资料 |
| M11-04 | 实现修改密码表单 | ChangePasswordForm | 可提交本人密码修改 |
| M11-05 | 实现 TOTP 状态与 setup 流程 | TOTPSetupPanel | 可拉取状态并展示 setup 信息 |
| M11-06 | 实现 TOTP 启用 / 关闭 / 验证 | TOTPActionPanel | 可完整跑通 2FA 管理流 |
| M11-07 | 实现头像上传 | AvatarUploadPanel | 可上传并刷新当前头像 |
| M11-08 | 实现本人设备列表 | MyDevicesPanel | 可展示和操作 /devices |
| M11-09 | 实现本人登录日志 | MyLoginLogsPanel | 可展示 /logs/login/me |
| M11-10 | 实现本人操作日志 | MyOperationLogsPanel | 可展示 /logs/operation/me |
9.15 M12 收尾与验证
| ID | 任务 | 产出 | 完成定义 |
|---|---|---|---|
| M12-01 | 统一菜单权限与路由准入复核 | 菜单守卫检查 | 管理页不会暴露给非 admin |
| M12-02 | 统一分页交互复核 | 分页行为检查 | 所有分页页都按真实结构工作 |
| M12-03 | 统一错误提示与空态复核 | 反馈体验检查 | 页面失败时不出现白屏 |
| M12-04 | 添加关键基础测试 | vitest 用例 |
至少覆盖请求客户端和会话恢复逻辑 |
| M12-05 | 执行前端构建验证 | npm run build |
生产构建通过 |
| M12-06 | 执行联调烟雾验证 | 手工联调清单 | 每个已纳入页面至少完成一次真实接口验证 |
9.16 当前不拆解的延期项
以下项在后端前置条件未补齐前,不进入任务拆解:
- 社交登录 / 绑定
- 系统设置
- 全局设备管理
- 用户创建
- 批量操作
- 细粒度权限码前端控制
- 富图表仪表盘
10. 后端补齐前置依赖
以下接口或协议补齐后,前端范围才能继续扩张:
POST /api/v1/users,用于管理员单个创建用户- 用户批量操作接口
- 当前用户角色码 / 权限码快照接口
- SPA 友好的 OAuth callback redirect 协议
- 社交账号绑定握手协议,而不是直接要求前端提交
open_id - 系统设置读写接口
- 全局设备列表与检索接口
- 时间序列统计、最近活动、地域分布等仪表盘接口
11. 验收基线
后续前端实现必须满足以下验收条件:
- 每个页面都能映射到当前真实后端 API,不出现“文档有、后端无”的按钮。
- 所有分页页都按真实结构处理
items / total / page / page_size。 - 刷新会话必须轮换
refresh_token,不能只更新access_token。 - Admin 页面必须以当前用户角色中的
admin作为准入条件。 - 个人头像上传只能从个人中心进入,不能放进用户管理页。
- Dashboard 只展示当前统计接口真实提供的数据。
- 不新增任何与本文冲突的前端栈或页面规划文档。