- web/: React + Vite + TypeScript 前端 - backend/: Django + DRF + SimpleJWT 后端 - prototype/: HTML 设计原型 - docs/: PRD 和设计评审文档 - test: 单元测试 + E2E 极限测试
1612 lines
73 KiB
Markdown
1612 lines
73 KiB
Markdown
# 产品需求文档 (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 核心变更摘要
|
||
|
||
1. **计量单位变更**: 所有「调用次数」改为「生成秒数」,用户每次生成视频消耗的是秒数(= 视频时长),不是次数
|
||
2. **后台管理系统重做**: 从单页面改为多页面 + 左侧 Sidebar 导航(仪表盘/用户管理/消费记录/系统设置)
|
||
3. **新增用户个人中心** `/profile`: 消费概览 + 消费记录 + 趋势迷你图
|
||
4. **图表库引入**: 使用 ECharts(echarts + echarts-for-react)展示趋势图、排行榜、环形进度条
|
||
5. **设计升级**: 管理后台深色主题(Linear/Vercel 风格)、骨架屏加载、页面过渡动画
|
||
|
||
## 2. 功能需求
|
||
|
||
### 2.1 核心功能(P0)
|
||
|
||
#### 已有前端功能
|
||
|
||
- [x] **深色主题全屏页面** — 背景色 `#0a0a0f`,页面无滚动,输入栏固定在底部居中,最大宽度 ~900px
|
||
- [x] **InputBar 容器** — 背景 `#16161e`,边框 `1px solid #2a2a38`,圆角 `20px`,内部分为上半区(上传+输入)和下半区(工具栏)
|
||
- [x] **提示词多行文本输入框** — 自适应高度(min 1行,max ~6行),支持换行输入,placeholder 根据当前模式动态切换
|
||
- [x] **全能参考模式(默认模式)** — 左侧 [+ 参考内容] 上传按钮,支持上传 1-5 张图片/视频文件;上传后显示缩略图网格,每张标注「图片1」「图片2」等序号,每个缩略图右上角有 × 关闭按钮;上传区与文本输入框左右排列
|
||
- [x] **首尾帧模式** — 上传区变为 [首帧缩略图] ↔ [+ 尾帧] 双框布局,中间双向箭头图标连接;首帧和尾帧各上传一张图片
|
||
- [x] **模式切换下拉** — 工具栏中「全能参考/首尾帧」下拉菜单,点击切换模式,切换时联动:上传区 UI、比例选项、时长默认值
|
||
- [x] **工具栏按钮行** — 一行横排按钮,透明背景,灰色文字 `#8a8a9a`,hover 时微亮背景
|
||
- [x] **发送按钮** — 圆形按钮,内含上箭头图标;无内容时灰色不可点击,有内容(文字或上传文件)时变为蓝色 `#00b8e6` 可点击
|
||
|
||
#### [Phase 2] 用户认证系统
|
||
|
||
- [x] **用户注册页面** — 前端注册页 `/register`,包含用户名、邮箱、密码、确认密码字段,提交后调用后端注册 API
|
||
- [x] **用户登录页面** — 前端登录页 `/login`,包含用户名/邮箱、密码字段,登录成功后获取 JWT Token 并存储到 localStorage
|
||
- [x] **JWT 认证机制** — 后端签发 Access Token(有效期 2 小时)+ Refresh Token(有效期 7 天),前端请求自动附加 Authorization Bearer Token
|
||
- [x] **登录状态保持** — 前端全局 Auth 状态管理(Zustand),未登录用户自动跳转到登录页,已登录用户显示用户信息和退出按钮
|
||
- [x] **Token 自动刷新** — Access Token 过期时自动使用 Refresh Token 刷新,刷新失败则跳转到登录页
|
||
|
||
#### [Phase 2] Django 后端服务
|
||
|
||
- [x] **Django 项目初始化** — 在 `backend/` 子目录创建 Django 项目,连接 MySQL 云数据库
|
||
- [x] **RESTful API** — 使用 Django REST Framework (DRF) 提供用户认证、视频生成记录等 API
|
||
- [x] **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)
|
||
|
||
#### 已有前端功能
|
||
|
||
- [x] **视频生成下拉按钮** — 蓝色文字 `#00b8e6` + 视频图标 + 下拉箭头,点击展开下拉菜单(菜单项仅 UI 展示,如"视频生成"/"图片生成"等)
|
||
- [x] **模型选择按钮** — 显示「Seedance 2.0」+ 钻石图标,点击展开模型选择下拉(仅 UI 展示,如 Seedance 2.0 / Seedance 2.0 Fast)
|
||
- [x] **比例选择按钮** — 全能参考模式下显示屏幕图标 + 当前比例值,点击弹出选项:`16:9` / `9:16` / `1:1` / `21:9` / `4:3` / `3:4`,默认 `21:9`;首尾帧模式下显示「自动匹配」不可选择
|
||
- [x] **时长选择按钮** — 时钟图标 + 当前时长值,点击弹出选项:`5s` / `10s` / `15s`;全能参考模式默认 `15s`,首尾帧模式默认 `5s`
|
||
- [x] **@ 按钮** — 仅在全能参考模式下显示,点击插入 `@` 符号到文本输入框光标位置
|
||
- [x] **文件上传交互** — 点击上传区触发文件选择器,accept 为 `image/*,video/*`;上传后生成本地预览缩略图;支持拖拽上传
|
||
- [x] **上传数量限制** — 全能参考模式最多 5 张,超出时 toast 提示;首尾帧模式首帧/尾帧各 1 张
|
||
|
||
#### [Phase 2] 后台管理与生成接入
|
||
|
||
- [x] **Django Admin 集成** — 启用 Django Admin 面板(`/admin/`),管理员可查看和管理所有用户、视频生成记录
|
||
- [x] **发送按钮接入后端** — 点击发送按钮时,调用后端 `/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)
|
||
|
||
- [x] **下拉菜单动画** — 下拉展开/收起有 fade + slide 动画过渡
|
||
- [x] **文本输入框自动聚焦** — 页面加载后自动 focus 到文本输入框
|
||
- [x] **键盘快捷键** — `Ctrl/Cmd + Enter` 触发发送(等同点击发送按钮)
|
||
- [ ] **上传进度条** — 文件上传时缩略图上显示加载进度
|
||
- [ ] **拖拽排序** — 全能参考模式下已上传的缩略图支持拖拽调整顺序
|
||
- [x] **响应式适配** — 移动端窄屏下工具栏按钮文字隐藏只显示图标,输入栏宽度自适应
|
||
- [ ] **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 数据库连接配置(不变)
|
||
|
||
```python
|
||
# 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 类型(保留)
|
||
|
||
```typescript
|
||
// 创作模式
|
||
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 已有下拉菜单配置(保留)
|
||
|
||
```typescript
|
||
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 修改配额字段)
|
||
|
||
```typescript
|
||
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] 前端新增类型
|
||
|
||
```typescript
|
||
// 管理后台统计数据
|
||
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 修改] 用户模型
|
||
|
||
```python
|
||
# 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 修改] 生成记录模型
|
||
|
||
```python
|
||
# 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 修改] 配额配置模型
|
||
|
||
```python
|
||
# 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(已全部通过)
|
||
1. 页面打开后显示深色全屏背景 `#0a0a0f`,底部居中显示 InputBar
|
||
2. InputBar 样式与参考截图视觉一致:背景 `#16161e`、边框 `#2a2a38`、圆角 `20px`
|
||
3. 默认处于「全能参考」模式,显示 [+ 参考内容] 上传按钮 + 提示词输入框
|
||
4. 点击 [+ 参考内容] 可选择图片/视频文件,上传后显示带序号的缩略图
|
||
5. 上传 1-5 张文件后缩略图正确显示,每个有 × 关闭按钮可删除
|
||
6. 切换到「首尾帧」模式后,上传区变为首帧 ↔ 尾帧双框布局
|
||
7. 工具栏所有按钮正确显示,布局与参考截图一致
|
||
8. 发送按钮状态正确:无内容时灰色,有内容时蓝色 `#00b8e6`
|
||
|
||
#### P1(已全部通过)
|
||
9. 「视频生成」下拉、「模型选择」下拉、「模式切换」下拉均可正常展开和选择
|
||
10. 比例选择按钮点击弹出 6 个选项,选中后按钮文字更新
|
||
11. 时长选择按钮点击弹出 3 个选项,选中后按钮文字更新
|
||
12. 切换模式时联动正确:全能参考→首尾帧时比例变为「自动匹配」、时长变为 5s、隐藏 @ 按钮
|
||
13. 文件上传支持拖拽
|
||
|
||
#### P2(已全部通过)
|
||
14. 下拉菜单有动画过渡效果
|
||
15. `Ctrl/Cmd + Enter` 可触发发送
|
||
16. 页面加载后文本输入框自动聚焦
|
||
17. 移动端下工具栏按钮自适应
|
||
|
||
### Phase 2 验收标准(已通过)
|
||
|
||
#### P0(已全部通过)
|
||
18. 未登录用户访问 `/` 自动跳转到 `/login`
|
||
19. 注册页表单验证正确,注册成功后自动登录跳转到首页
|
||
20. 登录页输入正确凭据后成功登录,获取 JWT Token
|
||
21. 后端 Django 服务正常启动,能连接 MySQL 数据库
|
||
22. 发送按钮点击后调用后端 API,后端记录调用并返回剩余配额
|
||
|
||
#### P1(已全部通过)
|
||
23. 管理员登录后可访问管理后台,普通用户无法访问
|
||
24. 管理后台正确显示用户总数、调用统计等指标
|
||
25. 管理员可修改用户的每日/每月调用限额
|
||
26. 超出限额时前端显示友好提示,后端返回 429 状态码
|
||
27. Django Admin 后台(`/admin/`)可管理用户和生成记录
|
||
|
||
### Phase 3 验收标准(当前迭代)
|
||
|
||
#### P0(必须全部通过)
|
||
28. 所有「调用次数」展示改为「生成秒数」—— UserInfoBar 显示「剩余 Ns/Ns(日)」而非「剩余 N 次」
|
||
29. 后端 User 模型字段 `daily_limit`/`monthly_limit` 迁移为 `daily_seconds_limit`/`monthly_seconds_limit`
|
||
30. GenerationRecord 模型新增 `seconds_consumed` 字段,生成 API 返回 `seconds_consumed` 和 `remaining_seconds_today`
|
||
31. 管理后台使用左侧 Sidebar + 右侧内容区布局,Sidebar 包含 4 个导航项(仪表盘/用户管理/消费记录/系统设置)
|
||
32. `/admin/dashboard` 仪表盘页面显示 4 个统计卡片(总用户、今日新增、今日消费秒数、本月消费秒数)+ ECharts 消费趋势折线图 + 用户消费排行柱状图
|
||
33. `/admin/users` 用户管理页面支持分页列表、搜索筛选、编辑配额、启用/禁用用户
|
||
34. `/profile` 用户个人中心显示消费概览(环形进度条)+ 消费记录列表
|
||
|
||
#### P1
|
||
35. `/admin/records` 消费记录页面显示所有用户消费明细,支持时间范围筛选和导出 CSV
|
||
36. `/admin/settings` 系统设置页面支持修改全局默认配额和管理系统公告
|
||
37. 用户个人中心显示消费趋势 Sparkline 迷你图(近 7天/30天 切换)
|
||
38. 仪表盘统计卡片显示环比变化百分比 + 趋势箭头
|
||
39. 用户管理页面点击用户名展开详情抽屉,显示用户详情 + 近期消费记录
|
||
40. 管理后台深色主题与 Linear/Vercel Dashboard 风格一致
|
||
41. 数据加载使用骨架屏(Skeleton)
|
||
|
||
#### P2
|
||
42. 管理后台 Sidebar 支持折叠为图标模式
|
||
43. 页面切换有 fade/slide 过渡动画
|
||
44. 当日额度消费超过 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 端点 |
|