166 lines
7.5 KiB
JavaScript
166 lines
7.5 KiB
JavaScript
#!/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);
|
||
});
|