Files
bj_power/shots_capture.py
T

177 lines
7.8 KiB
Python
Raw Normal View History

# -*- 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()