商品库+详情(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>
77 lines
3.0 KiB
JavaScript
77 lines
3.0 KiB
JavaScript
// 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));
|