Files
users/scripts/screenshot-pages.mjs

166 lines
7.5 KiB
JavaScript
Raw 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.

#!/usr/bin/env node
/**
* 神射手前端全站截图脚本
* 使用中文文件名:{序号}-{页面中文名}-视口.png / {序号}-{页面中文名}-长图.png
* 使用前请先启动pnpm dev端口 3117
* 运行node scripts/screenshot-pages.mjs 或 pnpm exec node scripts/screenshot-pages.mjs
*/
import { chromium } from "playwright";
import { existsSync, mkdirSync } from "fs";
import { join, dirname } from "path";
import { fileURLToPath } from "url";
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = join(__dirname, "..");
const BASE_URL = process.env.BASE_URL || "http://localhost:3117";
const OUT_DIR = process.env.OUT_DIR || join(ROOT, "开发文档", "4、前端", "截图");
const VIEWPORT = { width: 1280, height: 800 };
const WAIT_MS = 2500;
const NAV_TIMEOUT = 15000;
// 路由与中文名称(序号从 06 起01-05 已存在)
const ROUTES = [
{ path: "/", name: "首页" },
{ path: "/ai-analysis", name: "AI分析" },
{ path: "/data-market", name: "数据市场" },
{ path: "/tag-portrait", name: "标签画像" },
{ path: "/value-model", name: "估值模型" },
{ path: "/settings", name: "设置" },
{ path: "/documentation", name: "文档" },
{ path: "/login", name: "登录" },
{ path: "/traffic-pool", name: "流量池" },
{ path: "/user-portrait", name: "用户画像" },
{ path: "/user-portrait/tags", name: "用户画像-标签" },
{ path: "/user-portrait/1", name: "用户画像详情" },
{ path: "/tag-portrait/tags", name: "标签画像-标签" },
{ path: "/tag-portrait/portrait", name: "标签画像-画像" },
{ path: "/tag-portrait/crowd", name: "标签画像-人群" },
{ path: "/data-asset", name: "数据资产" },
{ path: "/data-asset/packages", name: "数据资产-包" },
{ path: "/data-asset/api-market", name: "数据资产-API市场" },
{ path: "/data-market/packages", name: "数据市场-包" },
{ path: "/data-market/api", name: "数据市场-API" },
{ path: "/data-market/open-api", name: "数据市场-开放API" },
{ path: "/value-model/models", name: "模型列表" },
{ path: "/value-model/assessment", name: "价值评估" },
{ path: "/value-model/reports", name: "估值报表" },
{ path: "/value-assessment", name: "价值评估页" },
{ path: "/user-valuation", name: "用户估值" },
{ path: "/user-value", name: "用户价值" },
{ path: "/data-integration", name: "数据集成" },
{ path: "/data-ingestion", name: "数据接入" },
{ path: "/data-ingestion/sources", name: "数据接入-数据源" },
{ path: "/data-ingestion/tasks", name: "数据接入-任务" },
{ path: "/data-ingestion/lineage", name: "数据接入-血缘" },
{ path: "/data-ingestion/cleaning", name: "数据接入-清洗" },
{ path: "/data-ingestion/ai-engine", name: "数据接入-AI引擎" },
{ path: "/data-governance", name: "数据治理" },
{ path: "/data-governance/tasks", name: "数据治理-任务" },
{ path: "/data-governance/quality", name: "数据治理-质量" },
{ path: "/data-governance/sources", name: "数据治理-数据源" },
{ path: "/data-governance/cleaning", name: "数据治理-清洗" },
{ path: "/platform/dashboard", name: "平台-仪表盘" },
{ path: "/platform/data-management", name: "平台-数据管理" },
{ path: "/platform/user-portrait", name: "平台-用户画像" },
{ path: "/platform/value-assessment", name: "平台-价值评估" },
{ path: "/platform/ai-assistant", name: "平台-AI助手" },
{ path: "/workspace/auto-group", name: "工作台-自动分组" },
{ path: "/workspace/moments-sync", name: "工作台-朋友圈同步" },
{ path: "/workspace/moments-sync/new", name: "工作台-朋友圈同步-新建" },
{ path: "/workspace/pricing", name: "工作台-定价" },
{ path: "/workspace/pricing/new", name: "工作台-定价-新建" },
{ path: "/content", name: "内容" },
{ path: "/content/new", name: "内容-新建" },
{ path: "/scenarios", name: "场景" },
{ path: "/scenarios/phone", name: "场景-手机" },
{ path: "/scenarios/api", name: "场景-API" },
{ path: "/system/health", name: "系统-健康" },
{ path: "/system/metrics", name: "系统-指标" },
{ path: "/system/alerts", name: "系统-告警" },
{ path: "/system/logs", name: "系统-日志" },
{ path: "/monitoring", name: "监控" },
{ path: "/monitoring/health", name: "监控-健康" },
{ path: "/monitoring/business", name: "监控-业务" },
{ path: "/monitoring/alerts", name: "监控-告警" },
{ path: "/ai-assistant", name: "AI助手" },
{ path: "/ai-agent", name: "AI智能体" },
{ path: "/ai-agent/chat", name: "AI智能体-对话" },
{ path: "/ai-agent/smart-tag", name: "AI智能体-智能打标" },
{ path: "/ai-agent/nlq", name: "AI智能体-NLQ" },
{ path: "/ai-agent/report", name: "AI智能体-报告" },
{ path: "/ai-insight", name: "AI洞察" },
{ path: "/wechat-accounts", name: "企微账号" },
{ path: "/data-output/subscription", name: "数据输出-订阅" },
{ path: "/data-output/packages", name: "数据输出-包" },
{ path: "/data-output/api-market", name: "数据输出-API市场" },
{ path: "/overview/dashboard", name: "概览-仪表盘" },
{ path: "/overview/search", name: "概览-搜索" },
{ path: "/overview/monitoring", name: "概览-监控" },
{ path: "/intelligent-search", name: "智能搜索" },
{ path: "/database-structure", name: "数据库结构" },
{ path: "/data-dictionary", name: "数据字典" },
{ path: "/data-platform", name: "数据平台" },
{ path: "/data-middle-platform", name: "数据中台" },
{ path: "/api-interface", name: "API接口" },
{ path: "/user-discovery", name: "用户发现" },
{ path: "/user-profile", name: "用户资料" },
{ path: "/rfm", name: "RFM" },
{ path: "/group-sync", name: "群同步" },
{ path: "/conversion", name: "转化" },
{ path: "/devices", name: "设备" },
];
function safeFilename(name) {
return name.replace(/[/\\?*:|"]/g, "-").trim();
}
async function main() {
if (!existsSync(OUT_DIR)) mkdirSync(OUT_DIR, { recursive: true });
console.log("输出目录:", OUT_DIR);
console.log("基础URL:", BASE_URL);
console.log("共", ROUTES.length, "个页面\n");
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
viewport: VIEWPORT,
ignoreHTTPSErrors: true,
});
const page = await context.newPage();
page.setDefaultNavigationTimeout(NAV_TIMEOUT);
let ok = 0;
let fail = 0;
for (let i = 0; i < ROUTES.length; i++) {
const { path, name } = ROUTES[i];
const num = String(i + 1).padStart(2, "0");
const safeName = safeFilename(name);
const url = BASE_URL + path;
const viewportPath = join(OUT_DIR, `${num}-${safeName}-视口.png`);
const fullPath = join(OUT_DIR, `${num}-${safeName}-长图.png`);
try {
await page.goto(url, { waitUntil: "domcontentloaded", timeout: NAV_TIMEOUT });
await page.waitForTimeout(WAIT_MS);
await page.screenshot({ path: viewportPath, type: "png" });
await page.screenshot({ path: fullPath, type: "png", fullPage: true });
console.log(`[${num}] ${name} 视口+长图 OK`);
ok++;
} catch (e) {
console.error(`[${num}] ${name} 失败:`, e.message);
try {
await page.screenshot({ path: fullPath, type: "png", fullPage: true }).catch(() => {});
console.log(`[${num}] ${name} 已保存长图`);
} catch (_) {}
fail++;
}
}
await browser.close();
console.log("\n完成. 成功:", ok, "失败:", fail);
}
main().catch((e) => {
console.error(e);
process.exit(1);
});