App.tsx: thread saveProfile/changePassword/uploadAvatar/generateImages handlers + assets prop to pages. - settings.tsx: profile save / password modal / avatar upload wired; notification/theme prefs -> localStorage - library.tsx + product-detail: asset thumbnails + grids render real TOS preview_url - ai-tools ImageWorkbenchPage: 生成图片 wired to /api/ai/generate-image, renders returned assets - pipeline.tsx stage2-5: base_assets/storyboard/video_segments(adopted_asset)/timeline(clips/subtitles/bgm) rendered from real project data; graceful empty states - types.ts: +VideoSegment.adopted_asset, +Timeline.subtitle_tracks/bgm_tracks verified: tsc --noEmit clean; screenshots confirm pipeline stages 2-5 + product-detail render real data+images (demo asset object_keys re-pointed to image objects so thumbnails resolve) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
40 lines
2.0 KiB
JavaScript
40 lines
2.0 KiB
JavaScript
// 抓图:pipeline 五阶段真数据 + 商品详情 + ai-tools(用 demo 项目/商品)
|
|
import { chromium } from "playwright";
|
|
import { mkdirSync } from "node:fs";
|
|
const BASE = "http://127.0.0.1:5180";
|
|
const API = "http://127.0.0.1:8010";
|
|
const OUT = process.argv[2] || "shots-pipeline";
|
|
mkdirSync(OUT, { recursive: true });
|
|
const tok = (await (await fetch(`${API}/api/auth/login/`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ username: "airshelf", password: "Restraint2026" }) })).json()).token;
|
|
const projs = (await (await fetch(`${API}/api/projects/`, { headers: { Authorization: `Token ${tok}` } })).json()).results;
|
|
const demo = projs.find((p) => p.name.startsWith("演示")) || projs[0];
|
|
const prods = (await (await fetch(`${API}/api/products/`, { headers: { Authorization: `Token ${tok}` } })).json()).results;
|
|
const prod = prods.find((p) => p.title.includes("补水")) || prods[0];
|
|
console.log("demo project", demo?.id, "| product", prod?.id);
|
|
|
|
const shots = [
|
|
["pipeline-stage2", `/pipeline/${demo.id}?st=2#stage-2`],
|
|
["pipeline-stage3", `/pipeline/${demo.id}?st=3#stage-3`],
|
|
["pipeline-stage4", `/pipeline/${demo.id}?st=4#stage-4`],
|
|
["pipeline-stage5", `/pipeline/${demo.id}?st=5#stage-5`],
|
|
["product-detail", `/products/${prod.id}`],
|
|
["image-optimize", `/image-optimize`]
|
|
];
|
|
const browser = await chromium.launch();
|
|
const ctx = await browser.newContext({ viewport: { width: 1440, height: 900 }, deviceScaleFactor: 1 });
|
|
await ctx.addInitScript((t) => localStorage.setItem("airshelf_token", t), tok);
|
|
const page = await ctx.newPage();
|
|
page.on("pageerror", (e) => console.error(" pageerror:", e.message));
|
|
for (const [name, route] of shots) {
|
|
try {
|
|
await page.goto(BASE + route, { waitUntil: "networkidle", timeout: 30000 });
|
|
await page.waitForTimeout(1600);
|
|
await page.screenshot({ path: `${OUT}/${name}.png`, fullPage: true });
|
|
console.log("shot", name);
|
|
} catch (e) {
|
|
console.error("FAIL", name, e.message);
|
|
}
|
|
}
|
|
await browser.close();
|
|
console.log("DONE ->", OUT);
|