- web/: React + Vite + TypeScript 前端 - backend/: Django + DRF + SimpleJWT 后端 - prototype/: HTML 设计原型 - docs/: PRD 和设计评审文档 - test: 单元测试 + E2E 极限测试
73 KiB
73 KiB
产品需求文档 (PRD)
1. 项目概述
- 项目名称: Jimeng Clone — AI 视频生成平台
- 一句话描述: 1:1 还原即梦平台 (jimeng.jianying.com) 的 AI 视频生成页面,包含完整的用户认证体系、视频生成输入界面、后台管理系统和用户个人中心
- 目标用户: 前端开发学习者、AI 视频产品原型验证团队、平台管理员
- 项目范围: 视频生成输入栏(InputBar)及其交互逻辑 + Django 后端 API + 用户登录注册 + 后台管理(生成秒数统计与限制) + 用户个人中心(消费概览与记录)
开发阶段划分
| 阶段 | 范围 | 状态 |
|---|---|---|
| Phase 1 | 纯前端视频生成输入界面(InputBar、工具栏、上传、模式切换) | ✅ 已完成 |
| Phase 2 | Django 后端 + 用户认证 + 前端路由 + 管理后台(基于调用次数) | ✅ 已完成 |
| Phase 3 | 计量单位变更(次数→秒数)+ 管理后台重做(多页面 Sidebar)+ 用户个人中心 | 🔲 待开发 |
当前迭代范围: Phase 3。Phase 1 和 Phase 2 功能已完成。Phase 3 在 Phase 2 基础上进行重大重构和新增功能。文档中
[Phase 3]标记用于区分本次迭代的新增/修改内容。
Phase 3 核心变更摘要
- 计量单位变更: 所有「调用次数」改为「生成秒数」,用户每次生成视频消耗的是秒数(= 视频时长),不是次数
- 后台管理系统重做: 从单页面改为多页面 + 左侧 Sidebar 导航(仪表盘/用户管理/消费记录/系统设置)
- 新增用户个人中心
/profile: 消费概览 + 消费记录 + 趋势迷你图 - 图表库引入: 使用 ECharts(echarts + echarts-for-react)展示趋势图、排行榜、环形进度条
- 设计升级: 管理后台深色主题(Linear/Vercel 风格)、骨架屏加载、页面过渡动画
2. 功能需求
2.1 核心功能(P0)
已有前端功能
- 深色主题全屏页面 — 背景色
#0a0a0f,页面无滚动,输入栏固定在底部居中,最大宽度 ~900px - InputBar 容器 — 背景
#16161e,边框1px solid #2a2a38,圆角20px,内部分为上半区(上传+输入)和下半区(工具栏) - 提示词多行文本输入框 — 自适应高度(min 1行,max ~6行),支持换行输入,placeholder 根据当前模式动态切换
- 全能参考模式(默认模式) — 左侧 [+ 参考内容] 上传按钮,支持上传 1-5 张图片/视频文件;上传后显示缩略图网格,每张标注「图片1」「图片2」等序号,每个缩略图右上角有 × 关闭按钮;上传区与文本输入框左右排列
- 首尾帧模式 — 上传区变为 [首帧缩略图] ↔ [+ 尾帧] 双框布局,中间双向箭头图标连接;首帧和尾帧各上传一张图片
- 模式切换下拉 — 工具栏中「全能参考/首尾帧」下拉菜单,点击切换模式,切换时联动:上传区 UI、比例选项、时长默认值
- 工具栏按钮行 — 一行横排按钮,透明背景,灰色文字
#8a8a9a,hover 时微亮背景 - 发送按钮 — 圆形按钮,内含上箭头图标;无内容时灰色不可点击,有内容(文字或上传文件)时变为蓝色
#00b8e6可点击
[Phase 2] 用户认证系统
- 用户注册页面 — 前端注册页
/register,包含用户名、邮箱、密码、确认密码字段,提交后调用后端注册 API - 用户登录页面 — 前端登录页
/login,包含用户名/邮箱、密码字段,登录成功后获取 JWT Token 并存储到 localStorage - JWT 认证机制 — 后端签发 Access Token(有效期 2 小时)+ Refresh Token(有效期 7 天),前端请求自动附加 Authorization Bearer Token
- 登录状态保持 — 前端全局 Auth 状态管理(Zustand),未登录用户自动跳转到登录页,已登录用户显示用户信息和退出按钮
- Token 自动刷新 — Access Token 过期时自动使用 Refresh Token 刷新,刷新失败则跳转到登录页
[Phase 2] Django 后端服务
- Django 项目初始化 — 在
backend/子目录创建 Django 项目,连接 MySQL 云数据库 - RESTful API — 使用 Django REST Framework (DRF) 提供用户认证、视频生成记录等 API
- CORS 配置 — 允许前端开发服务器(localhost:5173)跨域访问后端 API
[Phase 3] 计量单位变更(次数 → 秒数)
- 用户配额字段变更 — User 模型的
daily_limit/monthly_limit(次数)改为daily_seconds_limit/monthly_seconds_limit(秒数),默认值分别为 600秒/日、6000秒/月 - 消费记录增加秒数字段 — GenerationRecord 模型新增
seconds_consumed字段(FloatField),记录每次生成消耗的秒数(= 视频时长 duration) - 配额检查逻辑变更 — 后端配额检查从「今日调用次数 < daily_limit」改为「今日消费秒数 < daily_seconds_limit」
- 前端展示变更 — 所有显示「剩余次数」的地方改为「剩余秒数」,UserInfoBar 组件配额显示改为秒数
[Phase 3] 后台管理系统重做
- 管理后台布局 — 采用左侧 Sidebar + 右侧内容区的经典管理后台布局,Sidebar 固定宽度 240px,支持折叠
- Sidebar 导航菜单 — 包含 4 个导航项:仪表盘、用户管理、消费记录、系统设置,当前项高亮,使用 react-router 嵌套路由
- 管理后台路由 —
/admin为管理后台根路由(重定向到/admin/dashboard),子路由:/admin/dashboard、/admin/users、/admin/records、/admin/settings
[Phase 3] 用户个人中心
- 个人中心页面 — 新增
/profile路由,已登录用户可访问,展示个人消费概览和历史记录 - 消费概览卡片 — 显示已用秒数/总额度(环形进度条,使用 ECharts gauge)、今日已用/日限额、本月已用/月限额
2.2 重要功能(P1)
已有前端功能
- 视频生成下拉按钮 — 蓝色文字
#00b8e6+ 视频图标 + 下拉箭头,点击展开下拉菜单(菜单项仅 UI 展示,如"视频生成"/"图片生成"等) - 模型选择按钮 — 显示「Seedance 2.0」+ 钻石图标,点击展开模型选择下拉(仅 UI 展示,如 Seedance 2.0 / Seedance 2.0 Fast)
- 比例选择按钮 — 全能参考模式下显示屏幕图标 + 当前比例值,点击弹出选项:
16:9/9:16/1:1/21:9/4:3/3:4,默认21:9;首尾帧模式下显示「自动匹配」不可选择 - 时长选择按钮 — 时钟图标 + 当前时长值,点击弹出选项:
5s/10s/15s;全能参考模式默认15s,首尾帧模式默认5s - @ 按钮 — 仅在全能参考模式下显示,点击插入
@符号到文本输入框光标位置 - 文件上传交互 — 点击上传区触发文件选择器,accept 为
image/*,video/*;上传后生成本地预览缩略图;支持拖拽上传 - 上传数量限制 — 全能参考模式最多 5 张,超出时 toast 提示;首尾帧模式首帧/尾帧各 1 张
[Phase 2] 后台管理与生成接入
- Django Admin 集成 — 启用 Django Admin 面板(
/admin/),管理员可查看和管理所有用户、视频生成记录 - 发送按钮接入后端 — 点击发送按钮时,调用后端
/api/v1/video/generate接口(需登录),后端记录调用并检查配额
[Phase 3] 仪表盘页面(/admin/dashboard)
- 核心指标卡片 — 4 个统计卡片:总用户数、今日新增用户、今日消费秒数、本月消费秒数。每个卡片显示数值 + 环比变化百分比 + 趋势箭头(↑绿色/↓红色)
- 消费趋势折线图 — 使用 ECharts 折线图展示近 30 天每日消费秒数趋势,支持 tooltip 悬浮显示具体数值,X轴为日期,Y轴为秒数
- 用户消费排行柱状图 — 使用 ECharts 水平柱状图展示消费 Top 10 用户(按本月消费秒数降序),柱状图标签显示用户名和秒数
- 时间范围选择器 — 支持「今日 / 近7天 / 近30天 / 自定义时间范围」切换,图表数据联动更新
- 图表 Mock 数据 — 开发阶段使用 30 天的真实结构 Mock 数据(随机波动、周末低谷),确保图表有真实感
[Phase 3] 用户管理页面(/admin/users)
- 用户列表表格 — 分页展示所有用户(每页 20 条),列:头像、用户名、邮箱、注册时间、状态(启用/禁用)、日限额(秒)、月限额(秒)、今日消费(秒)、本月消费(秒)、操作
- 搜索和筛选 — 支持按用户名/邮箱关键字搜索 + 按状态筛选(全部/启用/禁用)
- 配额编辑 — 每个用户行的操作列有「编辑配额」按钮,点击弹出模态框,可修改日限额秒数和月限额秒数
- 用户状态管理 — 操作列有「启用/禁用」开关按钮,点击后调用 API 切换用户
is_active状态 - 用户详情抽屉 — 点击用户名展开右侧抽屉面板,显示用户详情 + 该用户近期消费记录列表
[Phase 3] 消费记录页面(/admin/records)
- 消费明细表格 — 分页展示所有用户的消费记录,列:时间、用户名、消费秒数、视频描述(prompt 截断)、生成模式、状态
- 时间范围筛选 — 日期选择器,支持选择起止日期筛选记录
- 用户筛选 — 支持按用户名搜索筛选特定用户的消费记录
- 导出功能 — 「导出 CSV」按钮,将当前筛选条件下的消费记录导出为 CSV 文件
[Phase 3] 系统设置页面(/admin/settings)
- 全局默认配额设置 — 表单修改全局默认日限额秒数和月限额秒数(新注册用户自动获得此配额)
- 系统公告管理 — 公告文本编辑框 + 启用/禁用开关,启用后公告内容展示在用户端页面顶部
[Phase 3] 用户个人中心详细功能
- 消费记录列表 — 分页展示当前用户的消费记录,每条记录显示:时间、消费秒数、生成的视频描述(prompt)、生成模式、状态
- 消费趋势迷你图 — 使用 ECharts Sparkline 样式展示近 7 天 / 近 30 天每日消费秒数趋势,可切换时间范围
- 配额提示 — 当日额度消费超过 80% 时显示黄色警告提示,超过 100% 时显示红色禁用提示
2.3 锦上添花(P2)
- 下拉菜单动画 — 下拉展开/收起有 fade + slide 动画过渡
- 文本输入框自动聚焦 — 页面加载后自动 focus 到文本输入框
- 键盘快捷键 —
Ctrl/Cmd + Enter触发发送(等同点击发送按钮) - 上传进度条 — 文件上传时缩略图上显示加载进度
- 拖拽排序 — 全能参考模式下已上传的缩略图支持拖拽调整顺序
- 响应式适配 — 移动端窄屏下工具栏按钮文字隐藏只显示图标,输入栏宽度自适应
- Tooltip 提示 — 工具栏按钮 hover 显示功能说明 tooltip
- [Phase 2] 忘记密码 — 邮箱验证码找回密码流程
- [Phase 2] 用户个人资料编辑 — 查看和修改个人信息(头像、昵称)
- [Phase 3] 页面切换过渡动画 — 路由切换时使用 fade/slide 过渡动画,提升体验流畅度
- [Phase 3] 数据加载骨架屏 — 管理后台和个人中心的数据加载使用骨架屏(Skeleton)替代 loading spinner
- [Phase 3] Sidebar 折叠模式 — 管理后台 Sidebar 支持折叠为图标模式,增大内容区宽度
3. 技术栈建议
3.1 现有技术栈(保留)
| 层级 | 技术选型 | 说明 |
|---|---|---|
| 前端框架 | React 18 + TypeScript | 函数组件 + Hooks |
| 构建工具 | Vite 5 | 极速 HMR,原生 ESM |
| UI 组件库 | @arco-design/web-react | 字节跳动设计系统,即梦同款 |
| 状态管理 | Zustand | 轻量、TypeScript 友好 |
| 样式方案 | CSS Modules + Arco Design Token | 深色主题定制 |
| 图标 | @arco-design/web-react/icon + 自定义 SVG | 工具栏图标 |
| 文件处理 | 浏览器原生 File API | 本地预览、缩略图生成 |
3.2 [Phase 2] 已有前端依赖(保留)
| 依赖 | 说明 |
|---|---|
| react-router-dom v7 | 前端路由(登录页、注册页、管理页) |
| axios | HTTP 请求库,支持拦截器实现 Token 自动附加和刷新 |
3.3 [Phase 3] 新增前端依赖
| 依赖 | 说明 |
|---|---|
| echarts | 图表库核心,用于折线图、柱状图、环形图等数据可视化 |
| echarts-for-react | ECharts 的 React 封装组件,声明式使用图表 |
组件优先级: 如果 Arco Design 内置了对应组件(如 Table、Modal、Skeleton、DatePicker),优先使用 Arco 组件,ECharts 仅用于复杂图表。
3.4 [Phase 2] 后端技术栈(保留)
| 层级 | 技术选型 | 说明 |
|---|---|---|
| 后端框架 | Django 4.2+ (LTS) | Python Web 框架 |
| API 框架 | Django REST Framework (DRF) | RESTful API 开发 |
| 认证方案 | djangorestframework-simplejwt | JWT Token 签发与验证 |
| 数据库 | MySQL 8.0(阿里云 RDS) | 云数据库,已提供连接信息 |
| 数据库驱动 | mysqlclient | Django 官方推荐的 MySQL 驱动 |
| CORS | django-cors-headers | 跨域请求支持 |
| 后端管理 | Django Admin | 内置管理后台 |
| 部署 | Gunicorn + Nginx | 生产环境部署方案 |
后端代码目录: 所有后端代码放在项目根目录下的
backend/子目录中。
3.5 数据库连接配置(不变)
# backend/config/settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'video_auto',
'USER': 'ai_video',
'PASSWORD': 'JogNQdtrd3WY8CBCAiYfYEGx',
'HOST': 'rm-7xv1uaw910558p1788o.mysql.rds.aliyuncs.com',
'PORT': '3306',
'OPTIONS': {
'charset': 'utf8mb4',
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
},
}
}
4. 页面列表
4.1 [已有] 视频生成页 (/)
整体布局:
┌─────────────────────────────────────────────┐
│ [Phase 3 修改] 顶部用户信息: │
│ 用户名 | 剩余: 345s/600s(日) | [个人中心] [退出]│
│ │
│ 深色背景空白区域 │
│ #0a0a0f │
│ │
│ ┌─────────────────────────────────────┐ │
│ │ InputBar (底部固定) │ │
│ │ max-width: 900px, 居中 │ │
│ │ 背景: #16161e │ │
│ │ 边框: #2a2a38, 圆角: 20px │ │
│ │ │ │
│ │ ┌──────┐ ┌──────────────────────┐ │ │
│ │ │上传区 │ │ 提示词文本输入框 │ │ │
│ │ │ │ │ │ │ │
│ │ └──────┘ └──────────────────────┘ │ │
│ │ │ │
│ │ ─────────── 工具栏按钮行 ────────── │ │
│ │ [视频生成▼][模型][模式▼][比例][时长] │ │
│ │ [@] flex空白 [发送⬆] │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
- [Phase 3 修改] 顶部用户信息区的配额显示从「剩余 N 次」改为「剩余 N 秒」,增加「个人中心」链接
- [Phase 2] 需要登录才能访问,未登录重定向到
/login
全能参考模式 — 上传区细节:
┌──────────┐
│ + │ ← 初始状态: [+ 参考内容] 按钮
│ 参考内容 │ 虚线边框,点击触发上传
└──────────┘
┌───┐┌───┐┌──────┐
│图1││图2││ + │ ← 已上传状态: 缩略图网格 + 添加按钮
│ × ││ × ││ │ 每张有序号标签和关闭按钮
└───┘└───┘└──────┘
首尾帧模式 — 上传区细节:
┌──────┐ ┌──────┐
│ 首帧 │ ↔ │+ 尾帧 │ ← 两个独立上传框
│ │ │ │ 中间双向箭头
└──────┘ └──────┘
工具栏按钮排布:
全能参考模式:
[🎬 视频生成 ▼] [💎 Seedance 2.0] [✨ 全能参考 ▼] [🖥 21:9] [🕐 15s] [@] ——flex空白—— [⬆ 发送]
首尾帧模式:
[🎬 视频生成 ▼] [💎 Seedance 2.0] [🔀 首尾帧 ▼] [自动匹配] [🕐 5s] ——flex空白—— [⬆ 发送]
4.2 [已有] 登录页 (/login)
┌─────────────────────────────────────────────┐
│ │
│ 深色背景 #0a0a0f │
│ │
│ ┌──────────────────────┐ │
│ │ Jimeng Clone │ │
│ │ │ │
│ │ 用户名/邮箱: [____] │ │
│ │ 密码: [____] │ │
│ │ │ │
│ │ [ 登录 ] │ │
│ │ │ │
│ │ 没有账号?去注册 → │ │
│ └──────────────────────┘ │
│ │
└─────────────────────────────────────────────┘
- 表单验证:用户名/邮箱必填,密码最少 6 位
- 登录成功后跳转到
/(视频生成页) - 风格与主应用一致:深色主题,卡片式表单
4.3 [已有] 注册页 (/register)
┌─────────────────────────────────────────────┐
│ │
│ 深色背景 #0a0a0f │
│ │
│ ┌──────────────────────┐ │
│ │ 创建账号 │ │
│ │ │ │
│ │ 用户名: [____] │ │
│ │ 邮箱: [____] │ │
│ │ 密码: [____] │ │
│ │ 确认密码: [____] │ │
│ │ │ │
│ │ [ 注册 ] │ │
│ │ │ │
│ │ 已有账号?去登录 → │ │
│ └──────────────────────┘ │
│ │
└─────────────────────────────────────────────┘
- 表单验证:用户名 3-20 位、邮箱格式校验、密码最少 6 位、两次密码一致
- 注册成功后自动登录并跳转到
/
4.4 [Phase 3] 管理后台布局(/admin/*)
┌──────────────────────────────────────────────────────────────┐
│ Jimeng Admin [管理员名] [退出] │
├────────────┬─────────────────────────────────────────────────┤
│ │ │
│ SIDEBAR │ CONTENT AREA │
│ 240px │ (根据子路由渲染不同页面) │
│ │ │
│ ┌──────┐ │ │
│ │ 📊 │ │ │
│ │仪表盘 │ │ │
│ ├──────┤ │ │
│ │ 👥 │ │ │
│ │用户 │ │ │
│ │管理 │ │ │
│ ├──────┤ │ │
│ │ 📋 │ │ │
│ │消费 │ │ │
│ │记录 │ │ │
│ ├──────┤ │ │
│ │ ⚙️ │ │ │
│ │系统 │ │ │
│ │设置 │ │ │
│ └──────┘ │ │
│ │ │
│ ─────── │ │
│ [返回首页] │ │
│ │ │
├────────────┴─────────────────────────────────────────────────┤
│ Jimeng Clone Admin v3.0 │
└──────────────────────────────────────────────────────────────┘
设计规范(管理后台专用):
- 整体风格参考 Linear / Vercel Dashboard,深色主题
- 背景色
#0a0a0f,Sidebar 背景#111118,内容区背景#0a0a0f - Sidebar 当前项背景
rgba(255, 255, 255, 0.08),文字#ffffff - 非当前项文字
#8a8a9a,hover 背景rgba(255, 255, 255, 0.04) - 卡片背景
#16161e,边框1px solid #2a2a38,圆角12px - 数据加载时显示 Arco Skeleton 骨架屏
4.5 [Phase 3] 仪表盘页面(/admin/dashboard)
┌─────────────────────────────────────────────────────────────┐
│ │
│ 仪表盘 [今日] [近7天] [近30天] [自定义]│
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 总用户数 │ │今日新增 │ │今日消费 │ │本月消费 │ │
│ │ 1,234 │ │ +23 │ │ 4,560s │ │ 89,010s │ │
│ │ ↑12% │ │ ↑15% │ │ ↓5% │ │ ↑8% │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 消费趋势 (ECharts 折线图) │ │
│ │ │ │
│ │ Y轴: 秒数 ___/\___ │ │
│ │ / \___/\ │ │
│ │ ___/\___/ \___ │ │
│ │ │ │
│ │ X轴: 日期 (3/1 3/5 3/10 3/15 3/20 3/25 3/30) │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 用户消费排行 Top 10 (ECharts 水平柱状图) │ │
│ │ │ │
│ │ user_a ████████████████████████ 2,340s │ │
│ │ user_b ██████████████████ 1,890s │ │
│ │ user_c ████████████████ 1,560s │ │
│ │ ... │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
- 仅
is_staff=True的用户可访问 - 统计卡片使用 Arco Card 组件 + 自定义样式
- 折线图使用 ECharts
line类型,开启tooltip、dataZoom交互 - 柱状图使用 ECharts
bar类型,水平方向,标签显示用户名和秒数 - 时间范围选择器使用 Arco DatePicker.RangePicker
- 数据来源:
GET /api/v1/admin/stats
4.6 [Phase 3] 用户管理页面(/admin/users)
┌─────────────────────────────────────────────────────────────┐
│ │
│ 用户管理 │
│ │
│ [🔍 搜索用户名/邮箱___________] [状态: 全部 ▼] [刷新] │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 用户名 │ 邮箱 │ 注册时间 │ 状态 │ 日限额│ │
│ │ │ │ │ │ (秒) │ │
│ │ 月限额 │ 今日消费(秒) │ 本月消费(秒)│ 操作 │ │
│ ├──────────┼──────────────┼──────────┼──────┼──────┤ │
│ │ user_a │ a@test.com │ 3/1 │ ✅ │ 600 │ │
│ │ 6000 │ 123 │ 2345 │[编辑][禁用] │ │
│ ├──────────┼──────────────┼──────────┼──────┼──────┤ │
│ │ user_b │ b@test.com │ 3/5 │ ❌ │ 300 │ │
│ │ 3000 │ 0 │ 0 │[编辑][启用] │ │
│ └──────────┴──────────────┴──────────┴──────┴──────┘ │
│ │
│ 共 56 条 [< 1 2 3 >] │
│ │
└─────────────────────────────────────────────────────────────┘
- 使用 Arco Table 组件(分页、排序)
- 搜索使用 Arco Input.Search
- 状态筛选使用 Arco Select
- 编辑配额使用 Arco Modal 弹窗
- 用户详情使用 Arco Drawer 右侧抽屉
- 数据来源:
GET /api/v1/admin/users
4.7 [Phase 3] 消费记录页面(/admin/records)
┌─────────────────────────────────────────────────────────────┐
│ │
│ 消费记录 [导出 CSV] │
│ │
│ [用户名搜索____] [时间: 2026-03-01 ~ 2026-03-12] [查询] │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 时间 │ 用户名 │ 消费秒数│ 视频描述 │ │
│ │ │ │ │ (prompt截断) │ │
│ │ 模式 │ 状态 │ │
│ ├───────────────────┼────────┼────────┼─────────────┤ │
│ │ 3/12 14:30:00 │ user_a │ 15s │ 一只猫在... │ │
│ │ 全能参考 │ 已完成 │ │
│ ├───────────────────┼────────┼────────┼─────────────┤ │
│ │ 3/12 14:25:00 │ user_b │ 5s │ 日落海边... │ │
│ │ 首尾帧 │ 生成中 │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ 共 1,234 条 [< 1 2 3 ... 62 >] │
│ │
└─────────────────────────────────────────────────────────────┘
- 使用 Arco Table 组件(分页)
- 时间范围筛选使用 Arco DatePicker.RangePicker
- 导出 CSV:前端调用 API 获取全部数据并生成 CSV 文件下载
- 数据来源:
GET /api/v1/admin/records
4.8 [Phase 3] 系统设置页面(/admin/settings)
┌─────────────────────────────────────────────────────────────┐
│ │
│ 系统设置 │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 全局默认配额 │ │
│ │ │ │
│ │ 默认每日限额 (秒): [____600____] │ │
│ │ 默认每月限额 (秒): [____6000___] │ │
│ │ │ │
│ │ [保存配额设置] │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 系统公告 [启用公告: ON] │ │
│ │ │ │
│ │ ┌──────────────────────────────────────────────┐ │ │
│ │ │ │ │ │
│ │ │ 公告内容 (支持纯文本) │ │ │
│ │ │ │ │ │
│ │ └──────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ [保存公告] │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
- 使用 Arco Form、InputNumber、Switch、Input.TextArea 组件
- 保存后 showToast 提示「设置已保存」
- 数据来源:
GET/PUT /api/v1/admin/settings
4.9 [Phase 3] 用户个人中心(/profile)
┌─────────────────────────────────────────────────────────────┐
│ │
│ [← 返回首页] 个人中心 [用户名] [退出] │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 消费概览 │ │
│ │ │ │
│ │ ┌────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ (环形图)│ │ 今日额度 │ │ 本月额度 │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ 已用 │ │ 已用: 123s │ │ 已用: 2345s │ │ │
│ │ │ 345s │ │ 限额: 600s │ │ 限额: 6000s │ │ │
│ │ │ /600s │ │ ████████░░░ │ │ ████░░░░░░░ │ │ │
│ │ │ │ │ 20.5% │ │ 39.1% │ │ │
│ │ └────────┘ └──────────────┘ └──────────────┘ │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 消费趋势 [近7天] [近30天] │ │
│ │ ___/\___/\___ (Sparkline 迷你折线图) │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 消费记录 │ │
│ │ │ │
│ │ 3/12 14:30 │ 15s │ 一只猫在花园... │ 全能参考 │ 完成│ │
│ │ 3/12 14:25 │ 5s │ 日落海边散步... │ 首尾帧 │ 完成│ │
│ │ 3/12 13:00 │ 10s │ 城市夜景延时... │ 全能参考 │ 失败│ │
│ │ ... │ │
│ │ │ │
│ │ [加载更多] │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
- 环形进度条使用 ECharts
gauge类型(半环或全环) - 进度条使用 Arco Progress 组件
- 消费记录列表使用 Arco List 或 Table 组件,支持「加载更多」分页
- Sparkline 迷你图使用 ECharts
line类型(无坐标轴,仅曲线) - 数据来源:
GET /api/v1/profile/overview+GET /api/v1/profile/records - 深色主题风格与主应用一致
5. API 设计
5.1 [已有] 视频生成(Phase 3 修改配额返回字段)
POST /api/v1/video/generate
Content-Type: multipart/form-data
Authorization: Bearer <access_token>
Request:
{
"prompt": string,
"mode": "universal" | "keyframe",
"model": "seedance_2.0" | "seedance_2.0_fast",
"aspect_ratio": "16:9" | "9:16" | "1:1" | "21:9" | "4:3" | "3:4" | "auto",
"duration": 5 | 10 | 15,
"references": File[],
"first_frame": File | null,
"last_frame": File | null
}
Response: 202 Accepted
{
"task_id": "uuid",
"status": "queued",
"estimated_time": 120,
"seconds_consumed": 15, ← [Phase 3] 本次消耗秒数
"remaining_seconds_today": 345 ← [Phase 3] 今日剩余秒数
}
Error Response: 429 Too Many Requests
{
"error": "quota_exceeded",
"message": "您今日的生成额度已用完", ← [Phase 3] 改为秒数描述
"daily_seconds_limit": 600,
"daily_seconds_used": 600,
"reset_at": "2026-03-13T00:00:00+08:00"
}
5.2 [已有] 文件上传(不变)
POST /api/v1/upload
Content-Type: multipart/form-data
Authorization: Bearer <access_token>
Request:
{
"file": File,
"type": "image" | "video"
}
Response: 200 OK
{
"file_id": "uuid",
"url": "https://cdn.example.com/...",
"thumbnail_url": "https://cdn.example.com/.../thumb.jpg",
"width": 1920,
"height": 1080,
"duration": 10.5
}
5.3 [已有] 用户注册(不变)
POST /api/v1/auth/register
Content-Type: application/json
Request:
{
"username": "string (3-20字符)",
"email": "string (合法邮箱)",
"password": "string (最少6位)"
}
Response: 201 Created
{
"user": {
"id": 1,
"username": "johndoe",
"email": "john@example.com"
},
"tokens": {
"access": "eyJ...",
"refresh": "eyJ..."
}
}
Error Response: 400 Bad Request
{
"username": ["该用户名已被注册"],
"email": ["该邮箱已被注册"]
}
5.4 [已有] 用户登录(不变)
POST /api/v1/auth/login
Content-Type: application/json
Request:
{
"username": "string (用户名或邮箱)",
"password": "string"
}
Response: 200 OK
{
"user": {
"id": 1,
"username": "johndoe",
"email": "john@example.com",
"is_staff": false
},
"tokens": {
"access": "eyJ...",
"refresh": "eyJ..."
}
}
Error Response: 401 Unauthorized
{
"error": "invalid_credentials",
"message": "用户名或密码错误"
}
5.5 [已有] Token 刷新(不变)
POST /api/v1/auth/token/refresh
Content-Type: application/json
Request:
{
"refresh": "eyJ..."
}
Response: 200 OK
{
"access": "eyJ..."
}
5.6 [已有] 获取当前用户信息(Phase 3 修改配额字段)
GET /api/v1/auth/me
Authorization: Bearer <access_token>
Response: 200 OK
{
"id": 1,
"username": "johndoe",
"email": "john@example.com",
"is_staff": false,
"quota": {
"daily_seconds_limit": 600, ← [Phase 3] 改为秒数
"daily_seconds_used": 123,
"monthly_seconds_limit": 6000,
"monthly_seconds_used": 2345
}
}
5.7 [Phase 3] 管理后台 — 仪表盘统计
GET /api/v1/admin/stats?period=30d
Authorization: Bearer <access_token>
(requires is_staff=True)
Query Parameters:
period: "today" | "7d" | "30d" | "custom"
start_date: "2026-03-01" (当 period=custom 时必填)
end_date: "2026-03-12" (当 period=custom 时必填)
Response: 200 OK
{
"total_users": 1234,
"new_users_today": 23,
"seconds_consumed_today": 4560,
"seconds_consumed_this_month": 89010,
"today_change_percent": -5.0,
"month_change_percent": 8.0,
"daily_trend": [
{"date": "2026-02-11", "seconds": 3200},
{"date": "2026-02-12", "seconds": 4100},
...
],
"top_users": [
{
"user_id": 1,
"username": "user_a",
"seconds_consumed": 2340
},
...
]
}
5.8 [Phase 3] 管理后台 — 用户列表
GET /api/v1/admin/users?page=1&page_size=20&search=&status=&sort_by=created_at&order=desc
Authorization: Bearer <access_token>
(requires is_staff=True)
Query Parameters:
page: int (默认 1)
page_size: int (默认 20,最大 100)
search: string (按用户名或邮箱模糊搜索)
status: "active" | "disabled" | "" (空表示全部)
sort_by: "created_at" | "seconds_today" | "seconds_month" (排序字段)
order: "asc" | "desc"
Response: 200 OK
{
"total": 56,
"page": 1,
"page_size": 20,
"results": [
{
"id": 1,
"username": "user_a",
"email": "a@test.com",
"is_active": true,
"date_joined": "2026-03-01T10:00:00+08:00",
"daily_seconds_limit": 600,
"monthly_seconds_limit": 6000,
"seconds_today": 123,
"seconds_this_month": 2345
},
...
]
}
5.9 [Phase 3] 管理后台 — 用户详情 + 消费记录
GET /api/v1/admin/users/:id
Authorization: Bearer <access_token>
(requires is_staff=True)
Response: 200 OK
{
"id": 1,
"username": "user_a",
"email": "a@test.com",
"is_active": true,
"is_staff": false,
"date_joined": "2026-03-01T10:00:00+08:00",
"daily_seconds_limit": 600,
"monthly_seconds_limit": 6000,
"seconds_today": 123,
"seconds_this_month": 2345,
"seconds_total": 5678,
"recent_records": [
{
"id": 101,
"created_at": "2026-03-12T14:30:00+08:00",
"seconds_consumed": 15,
"prompt": "一只猫在花园里追蝴蝶",
"mode": "universal",
"model": "seedance_2.0",
"status": "completed"
},
...
]
}
5.10 [Phase 3] 管理后台 — 修改用户配额
PUT /api/v1/admin/users/:id/quota
Authorization: Bearer <access_token>
(requires is_staff=True)
Content-Type: application/json
Request:
{
"daily_seconds_limit": 900,
"monthly_seconds_limit": 9000
}
Response: 200 OK
{
"user_id": 1,
"username": "user_a",
"daily_seconds_limit": 900,
"monthly_seconds_limit": 9000,
"updated_at": "2026-03-12T14:30:00+08:00"
}
5.11 [Phase 3] 管理后台 — 启用/禁用用户
PATCH /api/v1/admin/users/:id/status
Authorization: Bearer <access_token>
(requires is_staff=True)
Content-Type: application/json
Request:
{
"is_active": false
}
Response: 200 OK
{
"user_id": 1,
"username": "user_a",
"is_active": false,
"updated_at": "2026-03-12T14:30:00+08:00"
}
5.12 [Phase 3] 管理后台 — 消费记录列表
GET /api/v1/admin/records?page=1&page_size=20&search=&start_date=&end_date=
Authorization: Bearer <access_token>
(requires is_staff=True)
Query Parameters:
page: int (默认 1)
page_size: int (默认 20,最大 100)
search: string (按用户名搜索)
start_date: "2026-03-01" (起始日期)
end_date: "2026-03-12" (结束日期)
Response: 200 OK
{
"total": 1234,
"page": 1,
"page_size": 20,
"results": [
{
"id": 101,
"created_at": "2026-03-12T14:30:00+08:00",
"user_id": 1,
"username": "user_a",
"seconds_consumed": 15,
"prompt": "一只猫在花园里追蝴蝶",
"mode": "universal",
"model": "seedance_2.0",
"aspect_ratio": "16:9",
"status": "completed"
},
...
]
}
5.13 [Phase 3] 管理后台 — 系统设置
GET /api/v1/admin/settings
Authorization: Bearer <access_token>
(requires is_staff=True)
Response: 200 OK
{
"default_daily_seconds_limit": 600,
"default_monthly_seconds_limit": 6000,
"announcement": "系统将于今晚 22:00 进行维护",
"announcement_enabled": true
}
PUT /api/v1/admin/settings
Authorization: Bearer <access_token>
(requires is_staff=True)
Content-Type: application/json
Request:
{
"default_daily_seconds_limit": 600,
"default_monthly_seconds_limit": 6000,
"announcement": "系统将于今晚 22:00 进行维护",
"announcement_enabled": true
}
Response: 200 OK
{
"default_daily_seconds_limit": 600,
"default_monthly_seconds_limit": 6000,
"announcement": "系统将于今晚 22:00 进行维护",
"announcement_enabled": true,
"updated_at": "2026-03-12T14:30:00+08:00"
}
5.14 [Phase 3] 用户个人中心 — 消费概览
GET /api/v1/profile/overview?period=7d
Authorization: Bearer <access_token>
Query Parameters:
period: "7d" | "30d" (趋势数据的时间范围)
Response: 200 OK
{
"daily_seconds_limit": 600,
"daily_seconds_used": 123,
"monthly_seconds_limit": 6000,
"monthly_seconds_used": 2345,
"total_seconds_used": 5678,
"daily_trend": [
{"date": "2026-03-06", "seconds": 45},
{"date": "2026-03-07", "seconds": 120},
{"date": "2026-03-08", "seconds": 0},
{"date": "2026-03-09", "seconds": 88},
{"date": "2026-03-10", "seconds": 200},
{"date": "2026-03-11", "seconds": 156},
{"date": "2026-03-12", "seconds": 123}
]
}
5.15 [Phase 3] 用户个人中心 — 消费记录
GET /api/v1/profile/records?page=1&page_size=20
Authorization: Bearer <access_token>
Query Parameters:
page: int (默认 1)
page_size: int (默认 20)
Response: 200 OK
{
"total": 45,
"page": 1,
"page_size": 20,
"results": [
{
"id": 101,
"created_at": "2026-03-12T14:30:00+08:00",
"seconds_consumed": 15,
"prompt": "一只猫在花园里追蝴蝶",
"mode": "universal",
"model": "seedance_2.0",
"aspect_ratio": "16:9",
"status": "completed"
},
...
]
}
6. 数据模型
6.1 已有前端 Store 类型(保留)
// 创作模式
type CreationMode = 'universal' | 'keyframe';
// 模型选项
type ModelOption = 'seedance_2.0' | 'seedance_2.0_fast';
// 宽高比
type AspectRatio = '16:9' | '9:16' | '1:1' | '21:9' | '4:3' | '3:4';
// 时长
type Duration = 5 | 10 | 15;
// 上传文件
interface UploadedFile {
id: string;
file: File;
type: 'image' | 'video';
previewUrl: string;
label: string;
}
// 输入栏状态 Store
interface InputBarStore {
mode: CreationMode;
setMode: (mode: CreationMode) => void;
model: ModelOption;
setModel: (model: ModelOption) => void;
aspectRatio: AspectRatio;
setAspectRatio: (ratio: AspectRatio) => void;
duration: Duration;
setDuration: (duration: Duration) => void;
prompt: string;
setPrompt: (prompt: string) => void;
references: UploadedFile[];
addReference: (file: File) => void;
removeReference: (id: string) => void;
clearReferences: () => void;
firstFrame: UploadedFile | null;
lastFrame: UploadedFile | null;
setFirstFrame: (file: File | null) => void;
setLastFrame: (file: File | null) => void;
canSubmit: () => boolean;
switchMode: (mode: CreationMode) => void;
submit: () => void;
reset: () => void;
}
6.2 已有下拉菜单配置(保留)
interface DropdownOption {
label: string;
value: string;
icon?: string;
disabled?: boolean;
}
const generationTypes: DropdownOption[] = [
{ label: '视频生成', value: 'video', icon: 'video' },
{ label: '图片生成', value: 'image', icon: 'image' },
];
const modelOptions: DropdownOption[] = [
{ label: 'Seedance 2.0', value: 'seedance_2.0', icon: 'diamond' },
{ label: 'Seedance 2.0 Fast', value: 'seedance_2.0_fast', icon: 'diamond' },
];
const modeOptions: DropdownOption[] = [
{ label: '全能参考', value: 'universal', icon: 'sparkle' },
{ label: '首尾帧', value: 'keyframe', icon: 'swap' },
];
const aspectRatioOptions: DropdownOption[] = [
{ label: '16:9', value: '16:9' },
{ label: '9:16', value: '9:16' },
{ label: '1:1', value: '1:1' },
{ label: '21:9', value: '21:9' },
{ label: '4:3', value: '4:3' },
{ label: '3:4', value: '3:4' },
];
const durationOptions: DropdownOption[] = [
{ label: '5s', value: '5' },
{ label: '10s', value: '10' },
{ label: '15s', value: '15' },
];
6.3 [Phase 2] 前端 Auth Store 类型(Phase 3 修改配额字段)
interface User {
id: number;
username: string;
email: string;
is_staff: boolean;
}
// [Phase 3] 配额字段改为秒数
interface Quota {
daily_seconds_limit: number; // 原 daily_limit
daily_seconds_used: number; // 原 daily_used
monthly_seconds_limit: number; // 原 monthly_limit
monthly_seconds_used: number; // 原 monthly_used
}
interface AuthStore {
// 状态
user: User | null;
accessToken: string | null;
refreshToken: string | null;
isAuthenticated: boolean;
isLoading: boolean;
// 操作
login: (username: string, password: string) => Promise<void>;
register: (username: string, email: string, password: string) => Promise<void>;
logout: () => void;
refreshAccessToken: () => Promise<void>;
fetchUserInfo: () => Promise<void>;
// 配额
quota: Quota | null;
fetchQuota: () => Promise<void>;
}
6.4 [Phase 3] 前端新增类型
// 管理后台统计数据
interface AdminStats {
total_users: number;
new_users_today: number;
seconds_consumed_today: number; // 原 calls_today
seconds_consumed_this_month: number; // 原 calls_this_month
today_change_percent: number;
month_change_percent: number;
daily_trend: { date: string; seconds: number }[];
top_users: { user_id: number; username: string; seconds_consumed: number }[];
}
// 管理后台用户列表项
interface AdminUser {
id: number;
username: string;
email: string;
is_active: boolean;
date_joined: string;
daily_seconds_limit: number;
monthly_seconds_limit: number;
seconds_today: number;
seconds_this_month: number;
}
// 管理后台消费记录
interface AdminRecord {
id: number;
created_at: string;
user_id: number;
username: string;
seconds_consumed: number;
prompt: string;
mode: CreationMode;
model: ModelOption;
aspect_ratio: string;
status: 'queued' | 'processing' | 'completed' | 'failed';
}
// 系统设置
interface SystemSettings {
default_daily_seconds_limit: number;
default_monthly_seconds_limit: number;
announcement: string;
announcement_enabled: boolean;
}
// 用户个人中心概览
interface ProfileOverview {
daily_seconds_limit: number;
daily_seconds_used: number;
monthly_seconds_limit: number;
monthly_seconds_used: number;
total_seconds_used: number;
daily_trend: { date: string; seconds: number }[];
}
// 用户消费记录
interface ProfileRecord {
id: number;
created_at: string;
seconds_consumed: number;
prompt: string;
mode: CreationMode;
model: ModelOption;
aspect_ratio: string;
status: 'queued' | 'processing' | 'completed' | 'failed';
}
// 分页响应
interface PaginatedResponse<T> {
total: number;
page: number;
page_size: number;
results: T[];
}
6.5 后端数据模型(Django Models)
[Phase 2 → Phase 3 修改] 用户模型
# backend/apps/accounts/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
"""扩展用户模型 — Phase 3: 配额单位改为秒数"""
email = models.EmailField(unique=True, verbose_name='邮箱')
# [Phase 3] 改为秒数限制
daily_seconds_limit = models.IntegerField(default=600, verbose_name='每日秒数上限')
monthly_seconds_limit = models.IntegerField(default=6000, verbose_name='每月秒数上限')
created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
verbose_name = '用户'
verbose_name_plural = '用户'
迁移说明: 需要创建 Django migration 将
daily_limit→daily_seconds_limit,monthly_limit→monthly_seconds_limit,并将现有数据按「原次数 × 15」换算为秒数(假设平均每次生成 15 秒)。
[Phase 2 → Phase 3 修改] 生成记录模型
# backend/apps/generation/models.py
import uuid
from django.db import models
from django.conf import settings
class GenerationRecord(models.Model):
"""视频生成记录 — Phase 3: 新增消费秒数字段"""
MODE_CHOICES = [
('universal', '全能参考'),
('keyframe', '首尾帧'),
]
MODEL_CHOICES = [
('seedance_2.0', 'Seedance 2.0'),
('seedance_2.0_fast', 'Seedance 2.0 Fast'),
]
STATUS_CHOICES = [
('queued', '排队中'),
('processing', '生成中'),
('completed', '已完成'),
('failed', '失败'),
]
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='generation_records',
verbose_name='用户'
)
task_id = models.UUIDField(default=uuid.uuid4, unique=True, verbose_name='任务ID')
prompt = models.TextField(blank=True, verbose_name='提示词')
mode = models.CharField(max_length=20, choices=MODE_CHOICES, verbose_name='创作模式')
model = models.CharField(max_length=30, choices=MODEL_CHOICES, verbose_name='模型')
aspect_ratio = models.CharField(max_length=10, verbose_name='宽高比')
duration = models.IntegerField(verbose_name='视频时长(秒)')
seconds_consumed = models.FloatField(default=0, verbose_name='消费秒数') # [Phase 3] 新增
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='queued', verbose_name='状态')
created_at = models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='创建时间')
class Meta:
verbose_name = '生成记录'
verbose_name_plural = '生成记录'
ordering = ['-created_at']
indexes = [
models.Index(fields=['user', 'created_at']),
]
消费秒数逻辑:
seconds_consumed= 视频duration(5/10/15秒),在调用生成 API 时自动设置。
[Phase 2 → Phase 3 修改] 配额配置模型
# backend/apps/generation/models.py (续)
class QuotaConfig(models.Model):
"""全局配额配置 — Phase 3: 改为秒数"""
default_daily_seconds_limit = models.IntegerField(default=600, verbose_name='默认每日秒数上限')
default_monthly_seconds_limit = models.IntegerField(default=6000, verbose_name='默认每月秒数上限')
announcement = models.TextField(blank=True, default='', verbose_name='系统公告') # [Phase 3] 新增
announcement_enabled = models.BooleanField(default=False, verbose_name='启用公告') # [Phase 3] 新增
updated_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = '系统配置'
verbose_name_plural = '系统配置'
def save(self, *args, **kwargs):
# 单例模式,确保只有一条记录
self.pk = 1
super().save(*args, **kwargs)
7. 非功能需求
性能要求
- 首屏加载 < 2s(Vite 构建,代码分割)
- 文件上传后缩略图预览 < 200ms(使用 URL.createObjectURL 本地生成)
- 下拉菜单展开/收起动画 < 150ms
- 文本输入无感知延迟(非受控组件或 debounce)
- [Phase 2] 后端 API 响应时间 < 500ms(除文件上传外)
- [Phase 2] JWT Token 验证 < 50ms
- [Phase 3] ECharts 图表渲染 < 300ms(含数据加载)
- [Phase 3] 管理后台页面切换 < 200ms(路由级代码分割)
- [Phase 3] 分页列表请求 < 300ms
安全要求
- 文件上传仅限 image/* 和 video/* MIME 类型
- 文件大小限制:图片 < 20MB,视频 < 100MB
- 使用 URL.createObjectURL 生成预览,组件卸载时调用 URL.revokeObjectURL 释放内存
- [Phase 2] 密码使用 Django 默认的 PBKDF2 算法加密存储
- [Phase 2] JWT Access Token 有效期 2 小时,Refresh Token 有效期 7 天
- [Phase 2] 数据库密码等敏感配置通过环境变量管理(生产环境),开发环境可硬编码在 settings 中
- [Phase 2] API 接口对未认证请求返回 401,对权限不足返回 403
- [Phase 2] 管理接口仅
is_staff=True用户可访问 - [Phase 3] 管理后台操作(修改配额、禁用用户)需记录操作日志
- [Phase 3] CSV 导出需要防止 CSV 注入攻击(prompt 字段可能包含特殊字符)
响应式设计要求
- 桌面端(≥1024px):InputBar 最大宽度 900px 居中;管理后台 Sidebar 240px + 内容区自适应
- 平板端(768px-1023px):InputBar 宽度 90% 居中;管理后台 Sidebar 折叠为图标模式
- 移动端(<768px):InputBar 宽度 95%,工具栏按钮文字隐藏仅显示图标;管理后台 Sidebar 隐藏,使用汉堡菜单
浏览器兼容
- Chrome 90+、Firefox 90+、Safari 15+、Edge 90+
8. 验收标准
重要: Phase 1 和 Phase 2 功能已完成。当前验收范围为 Phase 3 全部功能。Phase 1/2 功能保持不变,不重复验收。
Phase 1 验收标准(已通过)
P0(已全部通过)
- 页面打开后显示深色全屏背景
#0a0a0f,底部居中显示 InputBar - InputBar 样式与参考截图视觉一致:背景
#16161e、边框#2a2a38、圆角20px - 默认处于「全能参考」模式,显示 [+ 参考内容] 上传按钮 + 提示词输入框
- 点击 [+ 参考内容] 可选择图片/视频文件,上传后显示带序号的缩略图
- 上传 1-5 张文件后缩略图正确显示,每个有 × 关闭按钮可删除
- 切换到「首尾帧」模式后,上传区变为首帧 ↔ 尾帧双框布局
- 工具栏所有按钮正确显示,布局与参考截图一致
- 发送按钮状态正确:无内容时灰色,有内容时蓝色
#00b8e6
P1(已全部通过)
- 「视频生成」下拉、「模型选择」下拉、「模式切换」下拉均可正常展开和选择
- 比例选择按钮点击弹出 6 个选项,选中后按钮文字更新
- 时长选择按钮点击弹出 3 个选项,选中后按钮文字更新
- 切换模式时联动正确:全能参考→首尾帧时比例变为「自动匹配」、时长变为 5s、隐藏 @ 按钮
- 文件上传支持拖拽
P2(已全部通过)
- 下拉菜单有动画过渡效果
Ctrl/Cmd + Enter可触发发送- 页面加载后文本输入框自动聚焦
- 移动端下工具栏按钮自适应
Phase 2 验收标准(已通过)
P0(已全部通过)
- 未登录用户访问
/自动跳转到/login - 注册页表单验证正确,注册成功后自动登录跳转到首页
- 登录页输入正确凭据后成功登录,获取 JWT Token
- 后端 Django 服务正常启动,能连接 MySQL 数据库
- 发送按钮点击后调用后端 API,后端记录调用并返回剩余配额
P1(已全部通过)
- 管理员登录后可访问管理后台,普通用户无法访问
- 管理后台正确显示用户总数、调用统计等指标
- 管理员可修改用户的每日/每月调用限额
- 超出限额时前端显示友好提示,后端返回 429 状态码
- Django Admin 后台(
/admin/)可管理用户和生成记录
Phase 3 验收标准(当前迭代)
P0(必须全部通过)
- 所有「调用次数」展示改为「生成秒数」—— UserInfoBar 显示「剩余 Ns/Ns(日)」而非「剩余 N 次」
- 后端 User 模型字段
daily_limit/monthly_limit迁移为daily_seconds_limit/monthly_seconds_limit - GenerationRecord 模型新增
seconds_consumed字段,生成 API 返回seconds_consumed和remaining_seconds_today - 管理后台使用左侧 Sidebar + 右侧内容区布局,Sidebar 包含 4 个导航项(仪表盘/用户管理/消费记录/系统设置)
/admin/dashboard仪表盘页面显示 4 个统计卡片(总用户、今日新增、今日消费秒数、本月消费秒数)+ ECharts 消费趋势折线图 + 用户消费排行柱状图/admin/users用户管理页面支持分页列表、搜索筛选、编辑配额、启用/禁用用户/profile用户个人中心显示消费概览(环形进度条)+ 消费记录列表
P1
/admin/records消费记录页面显示所有用户消费明细,支持时间范围筛选和导出 CSV/admin/settings系统设置页面支持修改全局默认配额和管理系统公告- 用户个人中心显示消费趋势 Sparkline 迷你图(近 7天/30天 切换)
- 仪表盘统计卡片显示环比变化百分比 + 趋势箭头
- 用户管理页面点击用户名展开详情抽屉,显示用户详情 + 近期消费记录
- 管理后台深色主题与 Linear/Vercel Dashboard 风格一致
- 数据加载使用骨架屏(Skeleton)
P2
- 管理后台 Sidebar 支持折叠为图标模式
- 页面切换有 fade/slide 过渡动画
- 当日额度消费超过 80% 时用户端显示黄色警告提示
9. 模式切换联动逻辑
| 切换动作 | 上传区 | 比例 | 时长 | @ 按钮 | Placeholder |
|---|---|---|---|---|---|
| → 全能参考 | [+ 参考内容] 多文件上传 | 恢复用户之前选择(默认 21:9) | 恢复用户之前选择(默认 15s) | 显示 | "上传1-5张参考图或视频,输入文字,自由组合图、文、音、视频多元素,定义精彩互动。" |
| → 首尾帧 | [首帧] ↔ [+ 尾帧] | 自动匹配(灰色不可选) | 5s(可切换) | 隐藏 | "输入描述,定义首帧到尾帧的运动过程" |
注意: 切换模式时不清空已输入的提示词文本,但上传的文件会被清空(因为两种模式的上传逻辑不同)。
10. 设计规范(Design Token)
颜色
| Token | 值 | 用途 |
|---|---|---|
--color-bg-page |
#0a0a0f |
页面背景 |
--color-bg-input-bar |
#16161e |
InputBar 背景 |
--color-border-input-bar |
#2a2a38 |
InputBar 边框 |
--color-primary |
#00b8e6 |
主强调色(发送按钮、视频生成文字) |
--color-text-primary |
#ffffff |
主文字 |
--color-text-secondary |
#8a8a9a |
次文字(工具栏按钮、placeholder) |
--color-text-disabled |
#4a4a5a |
禁用文字 |
--color-bg-hover |
rgba(255, 255, 255, 0.06) |
按钮 hover 背景 |
--color-bg-dropdown |
#1e1e2a |
下拉菜单背景 |
--color-bg-upload |
rgba(255, 255, 255, 0.04) |
上传区背景 |
--color-border-upload |
#2a2a38 |
上传区虚线边框 |
--color-btn-send-disabled |
#3a3a4a |
发送按钮禁用状态 |
--color-btn-send-active |
#00b8e6 |
发送按钮激活状态 |
[Phase 3] 管理后台专用颜色
| Token | 值 | 用途 |
|---|---|---|
--color-bg-sidebar |
#111118 |
Sidebar 背景 |
--color-sidebar-active |
rgba(255, 255, 255, 0.08) |
Sidebar 当前项背景 |
--color-sidebar-hover |
rgba(255, 255, 255, 0.04) |
Sidebar hover 背景 |
--color-bg-card |
#16161e |
卡片/面板背景 |
--color-border-card |
#2a2a38 |
卡片边框 |
--color-success |
#00b894 |
正向指标(↑绿色) |
--color-danger |
#e74c3c |
负向指标(↓红色) / 禁用状态 |
--color-warning |
#f39c12 |
警告提示(额度 80%+) |
圆角
| Token | 值 | 用途 |
|---|---|---|
--radius-input-bar |
20px |
InputBar 容器 |
--radius-btn |
8px |
工具栏按钮 |
--radius-send-btn |
50% |
发送按钮(圆形) |
--radius-thumbnail |
8px |
缩略图 |
--radius-dropdown |
12px |
下拉菜单 |
--radius-card |
12px |
[Phase 3] 管理后台卡片 |
尺寸
| Token | 值 | 用途 |
|---|---|---|
--input-bar-max-width |
900px |
InputBar 最大宽度 |
--send-btn-size |
36px |
发送按钮直径 |
--thumbnail-size |
80px |
上传缩略图尺寸 |
--toolbar-height |
44px |
工具栏行高 |
--toolbar-btn-height |
32px |
工具栏按钮高度 |
--sidebar-width |
240px |
[Phase 3] Sidebar 宽度 |
--sidebar-collapsed-width |
64px |
[Phase 3] Sidebar 折叠宽度 |
11. 组件树结构
App
├── AuthProvider // [Phase 2] 认证上下文
├── Router // [Phase 2] 路由
│ ├── /login → LoginPage // [Phase 2] 登录页
│ ├── /register → RegisterPage // [Phase 2] 注册页
│ ├── / → ProtectedRoute // [Phase 2] 需要登录
│ │ └── VideoGenerationPage
│ │ ├── UserInfoBar // [Phase 2] 顶部用户信息 + [Phase 3] 秒数配额 + 个人中心链接
│ │ ├── PageBackground
│ │ └── InputBar
│ │ ├── InputArea
│ │ │ ├── UploadSection
│ │ │ │ ├── UniversalUpload
│ │ │ │ │ ├── UploadButton
│ │ │ │ │ └── ThumbnailGrid
│ │ │ │ │ └── ThumbnailItem
│ │ │ │ └── KeyframeUpload
│ │ │ │ ├── FrameUpload
│ │ │ │ ├── ArrowIcon
│ │ │ │ └── FrameUpload
│ │ │ └── PromptInput
│ │ └── Toolbar
│ │ ├── GenerationTypeDropdown
│ │ ├── ModelSelector
│ │ ├── ModeDropdown
│ │ ├── AspectRatioSelector
│ │ ├── DurationSelector
│ │ ├── AtButton
│ │ ├── FlexSpacer
│ │ └── SendButton
│ ├── /profile → ProtectedRoute // [Phase 3] 用户个人中心
│ │ └── ProfilePage
│ │ ├── ProfileHeader // 返回首页 + 用户信息
│ │ ├── ConsumptionOverview // 消费概览卡片
│ │ │ ├── EChartsGauge // 环形进度条
│ │ │ ├── DailyQuotaCard // 今日额度进度条
│ │ │ └── MonthlyQuotaCard // 本月额度进度条
│ │ ├── ConsumptionTrend // Sparkline 迷你趋势图
│ │ └── ConsumptionRecordList // 消费记录列表
│ ├── /admin → ProtectedRoute (requireAdmin) // [Phase 3] 管理后台
│ │ └── AdminLayout // Sidebar + Content 布局
│ │ ├── AdminSidebar // 左侧导航栏
│ │ │ ├── SidebarLogo // Logo
│ │ │ ├── SidebarNav // 导航菜单
│ │ │ │ ├── NavItem (仪表盘)
│ │ │ │ ├── NavItem (用户管理)
│ │ │ │ ├── NavItem (消费记录)
│ │ │ │ └── NavItem (系统设置)
│ │ │ └── SidebarFooter // 返回首页链接
│ │ └── AdminContent // 右侧内容区 (Outlet)
│ │ ├── /admin/dashboard → DashboardPage
│ │ │ ├── StatsCards // 4 个指标卡片
│ │ │ ├── TrendLineChart // ECharts 折线图
│ │ │ └── TopUsersBarChart // ECharts 柱状图
│ │ ├── /admin/users → UsersPage
│ │ │ ├── UserSearchBar // 搜索 + 筛选
│ │ │ ├── UserTable // Arco Table
│ │ │ ├── QuotaEditModal // 配额编辑弹窗
│ │ │ └── UserDetailDrawer // 用户详情抽屉
│ │ ├── /admin/records → RecordsPage
│ │ │ ├── RecordFilters // 筛选条件
│ │ │ ├── RecordTable // Arco Table
│ │ │ └── ExportButton // 导出 CSV
│ │ └── /admin/settings → SettingsPage
│ │ ├── QuotaSettingsCard // 全局配额表单
│ │ └── AnnouncementCard // 公告管理
│ └── * → Navigate to /
12. 后端项目结构
backend/
├── manage.py
├── requirements.txt
├── config/ # Django 项目配置
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ ├── wsgi.py
│ └── asgi.py
├── apps/
│ ├── accounts/ # 用户认证模块
│ │ ├── __init__.py
│ │ ├── models.py # User 扩展模型 (Phase 3: 秒数字段)
│ │ ├── serializers.py # 注册/登录序列化器
│ │ ├── views.py # 注册/登录/Token刷新 API
│ │ ├── urls.py
│ │ └── admin.py # 用户管理 Admin
│ └── generation/ # 视频生成模块
│ ├── __init__.py
│ ├── models.py # GenerationRecord (Phase 3: +seconds_consumed) + QuotaConfig (Phase 3: +announcement)
│ ├── serializers.py # [Phase 3] 新增管理后台 + 个人中心序列化器
│ ├── views.py # [Phase 3] 新增管理后台 API (stats/users/records/settings) + 个人中心 API (overview/records)
│ ├── urls.py # [Phase 3] 新增路由
│ ├── admin.py # 生成记录 Admin
│ └── middleware.py # 配额检查中间件 (Phase 3: 改为秒数检查)
13. 参考截图说明
参考截图存放于 /Users/maidong/Desktop/zyc/研究openclaw/视频生成平台/ 目录:
| 文件 | 内容描述 |
|---|---|
20260311-154443.jpeg |
空状态全貌 — 完整展示了 InputBar 在无输入时的样式 |
20260311-154432.jpeg |
已上传状态 — 展示了上传 1 张图片后的 InputBar |
20260311-154407.jpeg |
有内容状态 — 展示了输入完整提示词 + 多张图片引用后的 InputBar |
14. 修订历史
| 日期 | 版本 | 变更内容 |
|---|---|---|
| 2026-03-11 | v1.0 | 初始版本 — 纯前端视频生成输入界面 |
| 2026-03-12 | v2.0 | 增量迭代 — 新增 Django 后端、用户认证系统、后台管理系统 |
| 2026-03-12 | v2.1 | 需求修订(BUG-002) — 引入开发阶段划分(Phase 1 / Phase 2),验收标准按阶段分组 |
| 2026-03-12 | v2.2 | 需求修订(BUG-002 后续) — Phase 2 功能已完成开发,更新阶段状态和验收范围 |
| 2026-03-12 | v3.0 | 重大迭代 — Phase 3 — 计量单位从「调用次数」改为「生成秒数」;管理后台从单页面重做为多页面 Sidebar 布局(仪表盘/用户管理/消费记录/系统设置);新增用户个人中心(/profile)含消费概览、环形进度条、消费趋势 Sparkline、消费记录列表;引入 ECharts 图表库;管理后台深色主题升级(参考 Linear/Vercel 风格);新增骨架屏加载和页面过渡动画;新增 8 个 API 端点、修改 3 个已有 API 端点 |