Files
bj_power/shots_capture.py
T
SunYF 92f0439d89 feat: 新增产线看板功能并优化多端系统体验
1. 新增SSE看板广播机制,业务操作后主动推送刷新事件
2. 新增产线工序横道图与工位状态展示面板
3. 移除dashboard无用的three.js依赖
4. 重构WMS客户端布局与WMS前端资源哈希
5. 新增工位终端时钟图标与大屏自适应布局
6. 新增系统截图脚本与说明书生成工具
7. 修复多处代码细节与空值处理逻辑
2026-09-04 17:31:18 +08:00

177 lines
7.8 KiB
Python
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.
# -*- 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 渲染(大屏用轮询/SSEnetworkidle 不可达)
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()