# -*- coding: utf-8 -*- """逐页截图 4 个前端系统,输出 PNG + manifest.json 供生成 PDF。""" import os, json, sys from playwright.sync_api import sync_playwright SHOTS = "D:/hardman/bj_power/shots" os.makedirs(SHOTS, exist_ok=True) WMS = "http://127.0.0.1:8891" MES = "http://127.0.0.1:8888" DASH = "http://127.0.0.1:5173" WS = "http://127.0.0.1:8892" W = 1920 H = 1080 # (route, 标题, 说明用的key) —— 标题用于 PDF WMS_PAGES = [ ("/", "工作台", "dashboard"), ("/inbound", "入库管理", "inbound"), ("/outbound", "出库管理", "outbound"), ("/inventory", "库存查询", "inventory"), ("/inspection", "质量检验", "inspection"), ("/stocktake", "库存盘点", "stocktake"), ("/semi", "半成品管理", "semi"), ("/ledger", "工单备料台账", "ledger"), ("/agv", "AGV配送", "agv"), ("/zone", "区域维护", "zone"), ("/material", "物料档案", "material"), ("/users", "账号管理", "users"), ("/roles", "角色管理", "roles"), ("/event-log", "操作日志", "eventlog"), ("/change-password", "修改密码", "changepwd"), ("/display", "库存动态大屏", "display"), ] MES_PAGES = [ ("/work-order", "工单管理", "workorder"), ("/daily-plan", "日排产", "dailyplan"), ("/bom", "物料清单", "bom"), ("/material-request","备料单", "materialrequest"), ("/plc-send", "工位组合下发", "plcsend"), ("/torque", "拧紧查询", "torque"), ("/process-flow", "工艺流程", "processflow"), ("/station", "关联工位", "station"), ("/performance", "绩效报表", "performance"), ("/inspect", "巡检终端", "inspect"), ("/scan", "手动报工", "scan"), ("/trace", "工件追溯", "trace"), ("/product-type", "产品类型", "producttype"), ("/account", "账号管理", "account"), ("/role", "角色管理", "role"), ("/event-log", "操作日志", "eventlog"), ("/change-password", "修改密码", "changepwd"), ] manifest = {"wms": [], "mes": [], "dash": [], "ws": []} def log(msg): sys.stdout.write(msg + "\n"); sys.stdout.flush() def do_login(page, base, user, pwd): page.goto(base + "/login", wait_until="networkidle") page.wait_for_timeout(600) filled = False for sel in ['input[placeholder*="用户名"]', 'input[placeholder*="账号"]', 'input[name="username"]', 'input[type="text"]']: try: page.fill(sel, user, timeout=3000); filled = True; break except Exception: continue if not filled: raise RuntimeError("找不到用户名输入框") page.fill('input[type="password"]', pwd, timeout=5000) page.click('button.el-button--primary', timeout=5000) page.wait_for_timeout(1500) return "login" not in page.url def shot(page, url, path, wait=1500, full=False): page.goto(url, wait_until="networkidle") page.wait_for_timeout(wait) page.screenshot(path=path, full_page=full) return os.path.getsize(path) def main(): with sync_playwright() as p: browser = p.chromium.launch(channel="msedge", args=["--no-sandbox", "--disable-gpu"]) ctx = browser.new_context(viewport={"width": W, "height": H}, device_scale_factor=1) page = ctx.new_page() page.set_default_timeout(15000) # ---------- WMS 库房客户端 ---------- log("===== WMS 库房客户端 (8891) =====") ok = do_login(page, WMS, "admin", "123456") log(" login=%s" % ok) for route, title, key in WMS_PAGES: d = "wms" if route != "/display" else "wms" out = os.path.join(SHOTS, d, "%02d_%s.png" % (len(manifest["wms"])+1, key)) try: if route == "/display": # 免登录大屏,单独开上下文避免 token 干扰 page2 = ctx.new_page() sz = shot(page2, WMS + "/display", out, wait=3500) page2.close() else: sz = shot(page, WMS + route, out, wait=1600) manifest["wms"].append({"route": route, "title": title, "file": out, "size": sz}) log(" [OK ] %-14s %s (%dKB)" % (title, route, sz//1024)) except Exception as e: log(" [ERR] %-14s %s -> %s" % (title, route, e)) # ---------- MES 产线控制 ---------- log("===== MES 产线控制 (8888) =====") ok = do_login(page, MES, "admin", "123456") log(" login=%s" % ok) for route, title, key in MES_PAGES: out = os.path.join(SHOTS, "mes", "%02d_%s.png" % (len(manifest["mes"])+1, key)) try: sz = shot(page, MES + route, out, wait=1600) manifest["mes"].append({"route": route, "title": title, "file": out, "size": sz}) log(" [OK ] %-14s %s (%dKB)" % (title, route, sz//1024)) except Exception as e: log(" [ERR] %-14s %s -> %s" % (title, route, e)) # ---------- 大屏 (5173) ---------- log("===== 数据大屏 (5173) =====") # 整页(含生产/仓储/3D产线三板) dctx = browser.new_context(viewport={"width": W, "height": 1440}, device_scale_factor=1) dpage = dctx.new_page() try: dpage.goto(DASH + "/", wait_until="load") # 等数据加载 + 3D 渲染(大屏用轮询/SSE,networkidle 不可达) dpage.wait_for_timeout(7000) out = os.path.join(SHOTS, "dash", "01_dashboard.png") dpage.screenshot(path=out, full_page=True) manifest["dash"].append({"route": "/", "title": "生产·仓储·产线三维总览", "file": out, "size": os.path.getsize(out)}) log(" [OK ] 大屏总览 (%dKB)" % (os.path.getsize(out)//1024)) except Exception as e: log(" [ERR] 大屏 -> %s" % e) dpage.close(); dctx.close() # ---------- 工位终端 (8892) ---------- log("===== 工位终端 (8892) =====") wctx = browser.new_context(viewport={"width": W, "height": H}, device_scale_factor=1) wpage = wctx.new_page() try: wpage.goto(WS + "/#/login", wait_until="networkidle") wpage.wait_for_timeout(1200) out = os.path.join(SHOTS, "ws", "01_login.png") wpage.screenshot(path=out) manifest["ws"].append({"route": "/#/login", "title": "工位终端登录", "file": out, "size": os.path.getsize(out)}) log(" [OK ] 工位登录页") # 登录 wpage.fill('input[placeholder*="账号"]', "syf", timeout=5000) wpage.fill('input[type="password"]', "123456", timeout=5000) wpage.click('button.el-button--primary', timeout=5000) wpage.wait_for_url("**/#/main", timeout=8000) wpage.wait_for_timeout(2500) out = os.path.join(SHOTS, "ws", "02_main.png") wpage.screenshot(path=out) manifest["ws"].append({"route": "/#/main", "title": "工位终端主界面", "file": out, "size": os.path.getsize(out)}) log(" [OK ] 工位主界面") except Exception as e: log(" [ERR] 工位终端 -> %s" % e) wpage.close(); wctx.close() browser.close() with open(os.path.join(SHOTS, "manifest.json"), "w", encoding="utf-8") as f: json.dump(manifest, f, ensure_ascii=False, indent=2) log("===== DONE =====") log("WMS=%d MES=%d DASH=%d WS=%d" % ( len(manifest["wms"]), len(manifest["mes"]), len(manifest["dash"]), len(manifest["ws"]))) if __name__ == "__main__": main()