Files
WenwuMap/e2e/demo.config.mjs
selfrelease 2d847e154f chore: 初始化仓库
中华文明全图鉴——文物全图系统(PC Web 地图 + NestJS API + 管理后台)。
含三大 IP(文物南迁北归 / 国宝海外回归 / 博物馆手艺人)、AI 文物对话、
文物地图与详情、以及 demo-video-kit 演示视频生成工具。
2026-06-13 20:55:44 +08:00

222 lines
8.6 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// WenwuMap 演示视频配置(使用 tools/demo-video-kit
// 运行:node tools/demo-video-kit/src/cli.mjs e2e/demo.config.mjs --out e2e/videos-kit
import { NARRATION } from "./narration.mjs";
const N = (k) => NARRATION[k] || k;
export default {
baseUrl: "http://localhost:3000/map",
viewport: { width: 1440, height: 900 },
brand: "中华文明全图鉴 · 功能演示",
outDir: "e2e/videos-kit",
voice: { name: "Cherry", model: "qwen-tts", apiKeyEnv: "AI_API_KEY", fallbackVoice: "Tingting" },
intro: { narration: N("__intro"), sub: "中华文明全图鉴 · Cultural Heritage Atlas" },
outro: { narration: N("__outro") },
steps: [
{
label: "搜索",
narration: N("搜索“青铜”"),
run: async ({ page, pause }) => {
const input = page.getByPlaceholder("搜索文物、机构、城市…");
await input.click();
await input.pressSequentially("青铜", { delay: 120 });
await pause(1500);
await input.fill("");
await pause(500);
},
},
{
label: "城市分布翻页",
narration: N("城市分布翻页"),
run: async ({ page, pause }) => {
const next = page.locator("aside").first().getByRole("button", { name: "下一页" });
for (let i = 0; i < 2; i++) {
await next.click({ timeout: 4000 });
await pause(900);
}
},
},
{
label: "门类筛选:青铜器",
narration: N("门类筛选:青铜器"),
run: async ({ page, pause }) => {
const b = page.getByRole("button", { name: "青铜器" }).first();
await b.click({ timeout: 5000 });
await pause(1500);
await b.click({ timeout: 5000 });
await pause(600);
},
},
{
label: "年代筛选:唐代",
narration: N("年代筛选:唐代"),
run: async ({ page, pause }) => {
const b = page.getByRole("button", { name: "唐代", exact: true }).first();
await b.click({ timeout: 5000 });
await pause(1500);
await b.click({ timeout: 5000 });
await pause(600);
},
},
{
label: "左栏收起/展开",
narration: N("左栏收起/展开"),
run: async ({ page, pause }) => {
const t = page.getByTitle(/收起左栏|展开左栏/);
await t.click({ timeout: 5000 });
await pause(1100);
await t.click({ timeout: 5000 });
await pause(800);
},
},
{
label: "右栏收起/展开",
narration: N("右栏收起/展开"),
run: async ({ page, pause }) => {
const t = page.getByTitle(/收起右栏|展开右栏/);
await t.click({ timeout: 5000 });
await pause(1100);
await t.click({ timeout: 5000 });
await pause(800);
},
},
{
label: "点击地图标记 · 查看馆藏",
narration: N("点击地图标记 · 查看馆藏"),
run: async ({ page, pause }) => {
const markers = page.locator("div.cursor-pointer.flex-col");
await markers.first().waitFor({ state: "attached", timeout: 25000 });
await pause(1200);
const aside = page.locator("aside").last();
const total = Math.min(await markers.count(), 8);
for (let i = 0; i < total; i++) {
const box = await markers.nth(i).boundingBox();
if (!box) continue;
await page.mouse.click(box.x + box.width / 2, box.y + box.height - 3);
await pause(1300);
if (
(await aside.getByText("机构藏品").count()) > 0 ||
(await page.getByRole("button", { name: /文物信息/ }).count()) > 0
)
break;
}
},
},
{
label: "进入文物详情",
narration: N("进入文物详情"),
run: async ({ page, pause }) => {
const aside = page.locator("aside").last();
if ((await aside.getByText("机构藏品").count()) > 0) {
await aside.locator("button:has(div.truncate)").first().click({ timeout: 4000 });
await pause(1600);
}
await page.getByRole("button", { name: /文物信息/ }).waitFor({ timeout: 8000 });
},
},
{
label: "展开同一机构列表",
narration: N("展开同一机构列表"),
run: async ({ page, pause }) => {
await page.getByText(/还有 \d+ 件/).first().click({ timeout: 4000 });
await pause(1500);
},
},
{
label: "文物信息折叠/展开",
narration: N("文物信息折叠/展开"),
run: async ({ page, pause }) => {
const btn = page.getByRole("button", { name: /文物信息/ });
await btn.click({ timeout: 4000 });
await pause(1000);
await btn.click({ timeout: 4000 });
await pause(800);
},
},
{
label: "AI 文物对话 · 流式回答与追问建议",
narration: N("AI 文物对话 · 流式回答与追问建议"),
run: async ({ page, pause }) => {
const aside = page.locator("aside").last();
await page.getByRole("button", { name: "讲解员" }).first().click({ timeout: 4000 });
await pause(800);
await page.getByText("它为什么珍贵?").first().click({ timeout: 4000 });
await page.locator("div.md-chat").first().waitFor({ timeout: 30000 });
await pause(3500);
await aside.getByText("下一步 · 你可以问").waitFor({ timeout: 20000 });
await aside.locator('button:has-text("")').first().click({ timeout: 4000 });
await page.locator("div.md-chat").nth(1).waitFor({ timeout: 30000 });
await pause(3500);
},
},
{
label: "图片放大与无极缩放(马踏飞燕)",
narration: N("图片放大与无极缩放(马踏飞燕)"),
run: async ({ page, pause }) => {
const input = page.getByPlaceholder("搜索文物、机构、城市…");
await input.fill("马踏飞燕");
await page
.waitForFunction(() => document.querySelectorAll("div.cursor-pointer.flex-col").length <= 2, null, {
timeout: 8000,
})
.catch(() => {});
await pause(900);
const markers = page.locator("div.cursor-pointer.flex-col");
await markers.first().waitFor({ state: "attached", timeout: 15000 });
const box = await markers.first().boundingBox();
await page.mouse.click(box.x + box.width / 2, box.y + box.height - 3);
await pause(1700);
const aside = page.locator("aside").last();
if ((await aside.getByText("机构藏品").count()) > 0) {
await aside.locator("button:has(div.truncate)").first().click({ timeout: 4000 });
await pause(1500);
}
const cover = page.locator("img.cursor-zoom-in").first();
await cover.waitFor({ state: "visible", timeout: 6000 });
const cb = await cover.boundingBox();
await page.mouse.click(cb.x + cb.width / 2, cb.y + cb.height / 2);
await pause(1400);
await page.mouse.move(720, 450);
for (let i = 0; i < 6; i++) {
await page.mouse.wheel(0, -320);
await pause(420);
}
await pause(1200);
await page.keyboard.press("Escape");
await pause(900);
},
},
{
label: "文物南迁北归 · 重走万里守护之路",
narration: N("文物南迁北归 · 重走万里守护之路"),
run: async ({ page, pause }) => {
await page.getByPlaceholder("搜索文物、机构、城市…").fill("");
await pause(700);
await page.getByRole("button", { name: "文物南迁北归之路" }).click({ timeout: 6000 });
await pause(2600);
await page.getByRole("button", { name: "播放" }).click({ timeout: 6000 });
await pause(12000);
await page.getByRole("button", { name: "退出路线" }).click({ timeout: 6000 });
await pause(1000);
},
},
{
label: "国宝海外回归 · 选择文物,重走回家之路",
narration: N("国宝海外回归 · 选择文物,重走回家之路"),
run: async ({ page, pause }) => {
await page.getByRole("button", { name: "国宝海外回归" }).click({ timeout: 6000 });
await page.getByText("国宝海外回归 · 选择文物").first().waitFor({ timeout: 6000 });
await pause(1600);
await page.locator('button:has-text("现藏")').first().click({ timeout: 6000 });
await pause(2600);
await page.getByRole("button", { name: "播放" }).click({ timeout: 6000 });
await pause(7000);
await page.getByRole("button", { name: "退出路线" }).click({ timeout: 6000 });
await pause(1000);
},
},
],
};