feat(core): Wave 3 batch3 — 商品库视图切换/多选/素材三态 + 项目进度条/批量 + 工作台真实KPI

商品库+详情(sub-agent):网格/列表视图切换、分类筛选改多选(Set+计数徽标)、素材卡三态pill
  (接真实 review_status 循环切换)、采用版本联动素材卡状态+prepend、素材区视图/状态筛选/重置
项目列表(sub-agent):网格卡补 .prog 5段进度条+N/5、失败 pill 修返回 err(原 fail 无定义退化无色)、
  批量栏+card-check多选+批量删、镜数/时长用真实字段(缺则降级不造假)、去重复删除入口
工作台(sub-agent):KPI delta 接真实本月新建数(全量未加载则不显)、删无真实源的假delta、
  余额用真实冻结/总资金占比、日期改 mono、最近项目镜数用真实 video_segment_count

验证: tsc 0 · build 0 · 走查 视图切换/列表态/分类chip/进度条/批量勾选/KPI 全过 · 0 console error

⚠️ 真实数据缺(未造假,降级处理):非person素材无review_status初值;dashboard无月度预算/上月对比字段。移交监督。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
seaislee1209
2026-06-19 05:19:32 +08:00
co-authored by Claude Opus 4.8
parent 38f56cb037
commit da8c6a70a7
6 changed files with 410 additions and 45 deletions
+76
View File
@@ -0,0 +1,76 @@
// Wave 3 batch3 walkthrough (scratch): products 视图切换/多选 + projects 进度条/批量 + dashboard.
import { chromium } from "playwright";
import fs from "node:fs";
import path from "node:path";
const BASE = process.env.BASE || "http://localhost:5173";
const TOKEN = process.env.TOKEN || "";
const OUT = path.resolve("../../../_qa_shots/wave3-batch3");
fs.mkdirSync(OUT, { recursive: true });
const browser = await chromium.launch({ headless: true });
const ctx = await browser.newContext({ viewport: { width: 1440, height: 900 }, colorScheme: "light" });
const seed = await ctx.newPage();
await seed.goto(BASE + "/", { waitUntil: "domcontentloaded" });
await seed.evaluate((t) => localStorage.setItem("airshelf_token", t), TOKEN);
await seed.close();
const r = { products: {}, projects: {}, dashboard: {}, consoleErrors: [] };
async function page(route, tag) {
const p = await ctx.newPage();
p.on("console", (m) => { if (m.type() === "error") r.consoleErrors.push(`${tag}:` + m.text()); });
p.on("pageerror", (e) => r.consoleErrors.push(`${tag}:PAGEERR:` + e.message));
await p.goto(BASE + route, { waitUntil: "load" });
await p.waitForTimeout(1800);
return p;
}
// products
{
const p = await page("/products", "products");
r.products.viewTog = await p.locator(".view-tog").count();
r.products.productCards = await p.locator(".product-card").count();
await p.screenshot({ path: path.join(OUT, "products-grid.png") });
// 切列表视图
const listBtn = p.locator(".view-tog button").last();
if (await listBtn.count()) {
await listBtn.click();
await p.waitForTimeout(400);
r.products.listViewApplied = await p.locator(".product-grid.list-view").count();
await p.screenshot({ path: path.join(OUT, "products-list.png") });
}
// 分类多选 chip
r.products.catChip = await p.locator(".chip-wrap").count();
await p.close();
}
// projects
{
const p = await page("/projects", "projects");
r.projects.progBars = await p.locator(".proj-card .prog, .prog").count();
r.projects.projCards = await p.locator(".proj-card").count();
await p.screenshot({ path: path.join(OUT, "projects-grid.png") });
// 进编辑态(找含「编辑」/「批量」的按钮)
const editBtn = p.locator("button:has-text('编辑'), button:has-text('批量'), .btn-edit-toggle").first();
if (await editBtn.count()) {
await editBtn.click();
await p.waitForTimeout(400);
r.projects.cardChecks = await p.locator(".card-check, .row-check").count();
await p.screenshot({ path: path.join(OUT, "projects-edit.png") });
}
await p.close();
}
// dashboard
{
const p = await page("/dashboard", "dashboard");
r.dashboard.kpiStats = await p.locator(".stat, .stats .stat").count();
r.dashboard.recentRows = await p.locator(".recent-row").count();
await p.screenshot({ path: path.join(OUT, "dashboard.png") });
await p.close();
}
await browser.close();
console.log(JSON.stringify(r, null, 2));
fs.writeFileSync(path.join(OUT, "summary.json"), JSON.stringify(r, null, 2));