11 Commits

Author SHA1 Message Date
seaislee1209
6d683d4e76 fix(records): lightbox/player overlay 关闭误触外层 modal — Portal + stopPropagation
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 11m2s
回归测试发现的真 bug (V1 V2 历史遗留):
点击 ReferenceList 的图片 lightbox 或音视频 player 的 overlay 关闭时,
事件冒泡 + V2 modal backdrop-filter 创建的独立 stacking context 双重作用
导致 RecordDetailModal 也被一起关掉。

根因双重:
  1. lightbox/player overlay 的 onClick 没 stopPropagation,
     React 合成事件冒泡到外层 modal overlay 触发 onClose
  2. V2 modal inner 加了 backdrop-filter: blur 创建独立 stacking context,
     lightbox 视觉上 z 10002 全屏覆盖,但实际命中区域被限制在 modal inner 内;
     点击 lightbox 视觉外的暗色区域 (modal 外) 直接命中 modal overlay → onClose

修复 (ReferenceList.tsx):
  - 用 React.createPortal 把 lightbox + audio-video player overlay 渲染到 document.body
    脱离 modal inner 的 backdrop-filter stacking context,真正全屏
  - overlay onClick 加 e.stopPropagation() 作为 React 事件链兜底
  - playerWrap 内部 stopPropagation 保留(防止点 player 内部冒泡关闭 player)

新增测试 (web/test/modal-interaction.mjs):
  专项验证 RecordDetailModal 内部交互, 7 个用例:
  1. 任务详情弹窗打开 OK
  2. 参考素材区存在 OK
  3. thumb 有 title 属性 (V2 加的 tooltip 真生效)
  4. 点击 thumb 弹出 lightbox (DOM 验证)
  4.1 关闭 lightbox 不连带关 modal (本次 fix 的关键回归)
  5. 下载按钮 stopPropagation + 触发下载
  6. modal 关闭 ✕ 按钮 OK
  7. 全程无 console.error

全套回归通过:
  - TS 编译过
  - modal-interaction 8/8 (含 lightbox 冒泡修复验证)
  - v2-smoke 25/25 (无新挂)
  - vitest 71/162 与基线一致 (无新挂)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 16:31:02 +08:00
seaislee1209
a1c16be1ea feat(records): 任务详情弹窗加视频展示 + RGB 故障字失败态
需求: 消费记录 detail modal 加多一个视频展示框
  - completed + result_url → 视频播放器
  - failed → 失败图标 (RGB 故障字风格)
  - processing/queued → spinner
  现有信息排版整体搬到右侧,布局不动。

后端 (apps/generation/views.py):
  admin_records_view + team_records_view 返回字段加 'result_url'
  (model 早就有 result_url, 只是这俩 list API 没暴露)

前端类型 (web/src/types/index.ts):
  AdminRecord 加 result_url?: string

RecordDetailModal 重构 (web/src/components/RecordDetailModal.tsx):
  - 弹窗宽 560 → 1080 (maxWidth 95vw, maxHeight 85vh)
  - body display: flex 双栏
  - 左侧 480 固定宽 + 16:9 视频框 + object-fit: contain
    (沿用 GenerationCard.resultArea 同一套 sizing 思路,
     不同长宽比视频用 contain 居中 + 黑边补足)
  - 右侧 flex 1, overflow-y auto, 现有内容整体搬过去排版不动
  - 视频用 controls + preload="metadata", 不自动播放, 跟全局音量走

MediaArea 组件分支:
  - completed + result_url: <video controls />
  - completed - result_url: 视频 icon + "视频已生成" 占位
  - failed: FailureGlitch RGB 故障字
  - processing/queued: 旋转 spinner + 文字

FailureGlitch 视觉细节:
  - 标题 "生成失败" 44px Space Grotesk weight 700
    text-shadow: -2px 0 var(--info) cyan, 2px 0 #ff00aa magenta
    + 30px 红色 glow → 模拟 CRT RGB 信号偏移
  - 副标题: 错误原因摘要 (truncate 80 char) 等宽字体
  - 背景: 红色斜纹 + 顶/底彩色条纹 (red/cyan 间隔) 仿信号丢失

验证 (docs/screenshots/v2/modal/):
  completed__{dark,light}.png - 视频框 + 右侧信息
  failed__{dark,light}.png    - RGB 故障字
  TS 编译过, backend 已重启

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 14:48:23 +08:00
seaislee1209
5f30258112 test+fix(theme): V2 smoke test (25/25 pass) + 修复 AdminLayout 缺主题切换按钮
新增功能回归 smoke test 覆盖 V2 改动点:
  test/v2-smoke.mjs — 25 个端到端检查,涵盖:
    1) LoginPage + LoginModal 浅色渲染 (4 项)
    2) admin 真实登录流程 + access_token 持久化 (2 项)
    3) 主题切换端到端 — 默认 dark / 点切换 → light / localStorage 持久化 /
       刷新保持 / 来回切换 (6 项)
    4) Admin 7 个路由侧栏导航 (7 项)
    5) 团管 Sidebar + 生成页 InputBar 核心元素 (4 项 + 公告 soft-skip)
    收尾: 全程无 console.error / 无 page crash (2 项)

发现并修复 1 个真 bug:
  AdminLayout (super admin 后台) 缺主题切换按钮。
  原因:V1 只给 components/Sidebar.tsx (76px 团管侧栏) 加了 toggle 按钮,
  pages/AdminLayout.tsx (220px super admin 侧栏) 漏了。super admin 无法切主题。
  修复:在 AdminLayout sidebarFooter 加月亮/太阳 SVG 切换按钮,
  跟 components/Sidebar 一致;收起态只显示 icon,展开态 icon + 文字。
  新增 .themeToggle class 样式 (hover bg + primary color)。

验证: tsc 过 / smoke 25/25 / 无 console.error / 无 page crash
本地 commit dev 不 push

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 21:03:53 +08:00
seaislee1209
f8a39d55c7 feat(theme): 浅色主题 V2 — 玻璃质感重做 + LandingPage 浅色化 + 双语言系统
Phase A: index.css 完全重写 [data-theme="light"] block
  - 玻璃方向修正: bg-card 从 rgba(0,0,0,0.05) 黑透明 → 双 token 拆分
    --color-bg-card: #ffffff 实体白 (admin 卡)
    --color-bg-glass: rgba(255,255,255,0.65) 透明白玻璃 (sidebar/modal/banner)
  - Aurora 浅色不再 display:none, 改 pastel 紫蓝桃 0.20-0.32 alpha
  - Inset highlight 方向反转: 浅色用 rgba(255,255,255,0.50) 白高光 (玻璃顶边标志)
  - Backdrop-filter 五档标准: --bf-glass-sm/md/lg/xl (12-40px + saturate 140-180%)
  - Multi-layer shadow: --shadow-card-light (2 stops) + --shadow-glass-light (3 stops + inset)
  - 暖调 chip: --color-chip-warm-* GitBook 公告风格
  - 文字主色: #171823 微紫 → #171717 Vercel Black

Phase B: LandingPage + AuroraCanvas 浅色化
  - 移除 LandingPage 的 data-theme="dark" 强制 (V1 的回避)
  - LandingPage.module.css 21 处颜色全 var 化
  - AuroraCanvas: 订阅 useThemeStore, 新 LIGHT_ORBS 数组 pastel 紫蓝桃,
    vignette 浅色用白色, grain opacity 减半

Phase C: 13 个玻璃面升级 (3 sub-agent 并行)
  - Modal 类 (Login/ForceChange/VideoDetail.infoPanel/RecordDetail/AssetLibrary/
    Announcement/Confirm/TeamsPage.detailModal): 接入 bg-modal-glass +
    bf-glass-lg/xl + shadow-glass-light (含 inset highlight)
  - Bar/Dropdown/Toast (AnnouncementBanner/Toast/Dropdown/Select/DatePicker):
    bg-glass-strong + bf-glass-md + inset-highlight
  - Sidebar + 生成页 (Sidebar/PromptInput/GenerationCard): glass + 顶边白高光
  - AnnouncementBanner 写双套独立 [data-theme] 规则 (CSS gradient 内不能 var alpha)

Phase D: admin 实体卡 multi-layer shadow (13 处, 1 sub-agent)
  - DashboardPage / TeamsPage / UsersPage / RecordsPage / AdminAssetsPage /
    LoginRecordsPage / AuditLogsPage / ProfilePage / SettingsPage
    的 .statCard / .tableWrapper / .chartWrapper / .accordionItem 等
    加 var(--shadow-card-light) 双层柔阴影

AdminLayout 修复 (V1 漏的):
  - .layout 改 transparent, 让 AmbientBackground pastel aurora 在主区透出
  - .sidebar 加 bf-glass-md + inset highlight + 立体阴影

LoginModal / ForceChangePassword 残留 mint 清理:
  - submitBtn bg/border/color 用 mint-accent var, 字重 500→600 + 字距 0.04em
  - input:focus border 用 var(--color-mint-accent)
  - 加 bf-glass-sm + inset highlight

验证:
  - TS 编译过
  - vitest 71 fail / 162 pass 与 V1 基线完全一致, 无新增回归
  - 24 张 V2 截图位于 docs/screenshots/v2/ (本地, .gitignore 排除 png)

完成报告: docs/todo/亮色主题切换V2-完成报告.md
V2 plan: docs/todo/亮色主题切换V2.md
视觉对齐稿: docs/todo/showcase.html

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 19:46:55 +08:00
seaislee1209
f0f47e8368 feat(theme): 亮色主题切换完整实现 — dark/light 双套 var + Sidebar 切换 + 浅色色板
Stage 1 (var 化, 350 处): 425 处硬编码颜色 → CSS var, 涉及 49 个 tsx/css module 文件,
   按 hot files (DashboardPage/TeamDashboardPage/RecordDetailModal/ReferenceList) →
   Modal/Asset/Profile/Login → 生成页家族/管理后台/公共 UI 三波 8 个 sub-agent 并行处理。
   index.css :root 加 ~70 个新 var (modal/text 层级/状态色 bg 变体/chart/mention pill 等)。
Stage 2 (双套 var): :root 保留 DARK 默认值, [data-theme="light"] 覆盖 ~95 个 token。
   浅色色板按 Vercel Geist (#fafafa / #171717 / shadow-border) + Linear Light surface 分层规范,
   主色 #6c63ff → #5048cc 加深 18% 满足 WCAG AA。aurora 极光在 light 下 display:none。
Stage 3 (切换机制): 新建 store/theme.ts (Zustand + localStorage 持久化),
   Sidebar 加月亮/太阳 SVG 切换按钮 (位于头像上方),
   DashboardPage/TeamDashboardPage/ProfilePage 的 ECharts 配 key={theme} 强制重渲染。
Stage 4 (微调): LandingPage 强制 data-theme="dark" 保持品牌识别 (登录流程一直深色),
   sidebar bg / card bg / border 在浅色下加深 0.02 提升轮廓辨识度。
Stage 5 (验证): Playwright 头无浏览器自动登录 admin + screenshot_user, 截深/浅各 12 个页面 = 24 张
   到 docs/screenshots/ (本地档, .gitignore 排除 png 不入库)。
   vitest 71fail/162pass 与改造前基线完全一致, 无新增回归。

完成报告: docs/todo/亮色主题切换-完成报告.md

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 11:10:35 +08:00
seaislee1209
27bfa689ce test: 加测试服 E2E — 1080P 分辨率支持线上验证 (8/8 通过)
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 4m29s
针对 airflow-studio.test.airlabs.art 使用团管账号 tudou 真实验证:
- Sidebar「今日剩余次数」文案 + 无钻石图标
- Toolbar 默认 720P
- AirDrama 可切 1080P
- 1080P 下 Fast Dropdown 置灰(UI 不可达 Fast+1080P)
- Fast 下 1080P Dropdown 置灰(反向)
- ProfilePage 预警文案无「今日额度」老称谓
- API 拒绝 Fast+1080P 组合(400 invalid_resolution)
- API 拒绝 adaptive ratio(400)

已跑通,附带 resolution-1080p.spec.ts (本地版,admin 账号,5/5 通过)
和 backend tests (23 unit + 5 integration 全过)。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 19:14:28 +08:00
seaislee1209
39667ff19c feat: v0.19.0 1080P 分辨率支持 — 完整前后端 + 严格计费准确性 + 47 测试
火山 Seedance 2.0 于 2026-04-16 上线 1080P 支持。本次实现前端 UI、
后端校验/计费、数据库迁移,并严格遵守三原则:
1. 禁止兜底/静默降级 — Fast+1080P 组合在 UI/store/serializer/view/计价
   五层防御,任一层穿透都 fail loud,不悄悄按 720P 扣费
2. 钱的计算绝对准确 — 前端预估公式与后端 estimate_tokens 完全一致
   `(输入时长+输出时长) × 宽 × 高 × fps / 1024`;实际扣费按火山返回
   total_tokens × 官方单价;预估端不维护最低 token 修正表
3. 不隐藏 bug — 无 `or '720p'` / `|| '720p'` 兜底;类型严格;异常暴露

## 后端(7 处 + 1 次迁移)

- models.py: QuotaConfig 加 base_token_price_1080p(51)/base_token_price_1080p_video(31);
  GenerationRecord.resolution 加 RESOLUTION_CHOICES 约束 + default='720p'
- migrations/0020: 含 RunPython data migration 回填历史 resolution='' → '720p'
- utils/billing.py:
  * RESOLUTION_MAP 加 1080P 六种宽高比(21:9 是 2206×946,不是 seedance 1.0 值)
  * get_resolution 去掉 tier 默认值,非法组合 raise KeyError 不静默降级
  * estimate_tokens 纯官方公式,加 input_video_duration 参数(公式完整)
- utils/airdrama_client.py: create_task 加 resolution 必填参数(无默认值)
- apps/generation/serializers.py:
  * VideoGenerateSerializer 加 resolution ChoiceField
  * aspect_ratio 改 ChoiceField 显式拒绝 adaptive
  * SystemSettingsSerializer 加 2 个 1080P 单价
- apps/generation/views.py:
  * _get_token_price 加 resolution 必填参数,Fast+1080P raise ValueError
  * _sum_video_duration 累加视频参考时长
  * video_generate_view 读 resolution、400 拒绝 Fast+1080P 组合、
    传给 get_resolution/estimate_tokens/_get_token_price/create_task/
    GenerationRecord.resolution(移除 L450 硬编码 '720p')
  * _settle_payment 按 record.resolution 取单价(1080P 结算按 1080P 价)
  * _serialize_task + 5 处手工序列化加 resolution 字段(无 `or '720p'`)
- apps/accounts/views.py: team 接口返回 token_price_1080p/_video

## 前端(10 处)

- types/index.ts: Resolution 类型;GenerationTask/BackendTask/Team/
  QuotaConfig/AssetVideo 加字段(全部必填,无 optional)
- store/inputBar.ts: resolution state;setModel/setResolution 双向拦截
  Fast+1080P 组合,toast 提示引导,不静默降级
- store/generation.ts: addTask/backendToFrontend/reEdit/regenerate 全链路
  携带 resolution;mapErrorMessage 改 '今日生成次数或团队余额不足'
- components/Toolbar.tsx:
  * 加分辨率选择器 Dropdown(位置:比例和时长之间)
  * modelItems/resolutionItems 双向 disabled(Fast 下 1080P 灰 / 1080P 下 Fast 灰)
  * estimatedTokens 对齐后端公式(含输入视频时长 + assetMentions 视频时长)
  * estimatedCost 按 resolution 选单价(Fast→fast_*、1080p→1080p_*、其他→基础)
  * tooltip 明示"实际费用以火山 API 返回的 token 数为准"
- components/Dropdown.tsx: 加 disabled 属性支持
- components/VideoDetailModal.tsx: 重新编辑恢复 resolution
- components/GenerationCard.tsx: 动态显示 task.resolution.toUpperCase()
- pages/SettingsPage.tsx: 加 2 个 1080P 单价输入框(独立分组)
- pages/AdminAssetsPage.tsx / TeamAssetsPage.tsx: 去 || '720p' 兜底
- lib/api.ts: videoApi.generate 参数 resolution 必填

## 测试(47 个用例)

### 后端(28 个)
- tests/test_1080p_billing.py(23): RESOLUTION_MAP 像素、estimate_tokens
  公式(含/不含输入视频、不做最低 token 修正)、_get_token_price 六种
  组合、Fast+1080P 抛异常、calculate_cost 对齐官方示例 4.97 / 12.39 元
- tests/test_1080p_api.py(5): video_generate_view 拒绝 Fast+1080P (400)
  + 拒绝 adaptive + 拒绝非法 resolution + 默认值兼容 + 合法组合通过

### 前端(19 个)
- test/unit/resolution1080p.test.ts(14): store 状态、双向拦截
  (1080P 下切 Fast 被阻止 model 不变、反向同样)、官方像素契约测试、
  价格示例对齐(720P 4.97 / 1080P 12.39)
- test/e2e/resolution-1080p.spec.ts(5): 真实浏览器验证默认 720P、
  Dropdown 双向置灰、tooltip 明示以火山为准

## 与官方文档对齐

- 参数:resolution (480p/720p/1080p 小写)、ratio、duration、generate_audio
- 像素:来自 docs/API文档/创建视频生成任务API.md Seedance 2.0 & 2.0 fast 列
- 单价:来自 docs/API文档/seedance模型价格.md (46/28/51/31/37/22)
- Fast 不支持 1080P:来自 docs/API文档/Seedance 2.0 1080P.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 19:06:45 +08:00
seaislee1209
dafdc8983f fix: v0.18.3 版权报错友好提示 + 图片删除即梦式连续重命名
Bug 1: 版权限制错误友好提示
- ERROR_MESSAGES 加 OutputVideoSensitiveContentDetected.PolicyViolation 映射
- 漫威等知名 IP 触发的版权拦截不再显示英文 raw error

Bug 2: 图片删除后同类型引用连续重命名(即梦逻辑)
- inputBar.ts::removeReference 重写:删除后同类型剩余引用按顺序 1/2/3 连续编号
- 用 DOMParser 同步更新 editorHtml 里对应 data-ref-id 的 @mention span textContent
- 缩略图区和提示词栏同步刷新,避免"两个图片2"命名冲突

验证
- 11 个 Vitest 单元测试覆盖图片/视频/音频删除、空 editorHtml、无 @mention、
  连续快速删除等边界场景
- 3 个 Playwright E2E 真实浏览器验证:上传 3 张图 → 删中间 → 再上传 → 编号不冲突

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 18:03:36 +08:00
seaislee1209
ba33c35dd8 add test
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 4m13s
2026-04-04 19:38:36 +08:00
zyc
566c3a476f add 存储桶
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m17s
2026-03-13 15:38:08 +08:00
zyc
ffe92f7b15 Initial commit: 即梦视频生成平台
- web/: React + Vite + TypeScript 前端
- backend/: Django + DRF + SimpleJWT 后端
- prototype/: HTML 设计原型
- docs/: PRD 和设计评审文档
- test: 单元测试 + E2E 极限测试
2026-03-13 09:59:33 +08:00