Files
zyt/app/scripts/render_client_design.py
2026-10-29 16:14:55 +08:00

144 lines
5.6 KiB
Python
Raw Permalink 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.
"""Render the real native client with synthetic data for UI design review."""
from __future__ import annotations
import argparse
import html
import json
import os
from pathlib import Path
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
os.environ.setdefault("DOCTOR_MOTION", "off")
from PySide6.QtCore import QSettings, QThreadPool
from PySide6.QtGui import QImage
from PySide6.QtTest import QTest
from PySide6.QtWidgets import QApplication
from doctor_workstation.services import DemoDoctorRepository
from doctor_workstation.ui import ShellWindow, apply_theme
from doctor_workstation.ui.login import LoginWindow
ROUTES = {
"appointments": "挂号列表",
"consultations": "问诊列表",
"patients": "我的患者",
"prescription_library": "我的处方库",
"prescriptions": "已开处方",
"reception": "接诊台",
}
def settle(app: QApplication) -> None:
for _ in range(4):
QThreadPool.globalInstance().waitForDone(3000)
app.processEvents()
QTest.qWait(75)
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--output", type=Path, default=Path("artifacts/client-design"))
args = parser.parse_args()
output = args.output.resolve()
output.mkdir(parents=True, exist_ok=True)
app = QApplication.instance() or QApplication([])
apply_theme(app)
repo = DemoDoctorRepository()
records = []
def capture(window, name: str, title: str) -> None:
settle(app)
filename = f"{name}.png"
if not window.grab().save(str(output / filename)):
raise RuntimeError(f"Could not save {filename}")
records.append({
"title": title, "file": filename,
"width": window.width(), "height": window.height(),
})
# Isolate preview settings from the user's saved account and credentials.
settings = QSettings(str(output / "preview-login.ini"), QSettings.Format.IniFormat)
settings.clear()
login = LoginWindow(repo, settings=settings)
login.show()
for width, height in ((1280, 800), (860, 640)):
login.resize(width, height)
capture(login, f"login-{width}", "登录工作站")
login.close()
session = repo.login(repo.DEMO_ACCOUNT, repo.DEMO_PASSWORD)
shell = ShellWindow(
repo, {"session": session, "demo_mode": True}, permissions=session.permissions,
)
shell.show()
try:
for width, height in ((1440, 900), (1024, 640)):
shell.resize(width, height)
for route, title in ROUTES.items():
shell.navigate(route)
capture(shell, f"{route}-{width}", title)
finally:
settle(app)
shell.close()
# Include independently rendered dialog/media fixtures when available.
supplementary = [
("patient_orders_1366x768.png", "患者业务订单"),
("patient_progress_1366x768.png", "患者进度"),
("clinical-after/appointment_drawer_1440x900.png", "预约编辑"),
("clinical-after/diagnosis_edit_1440x900.png", "诊单编辑"),
("clinical-after/diagnosis_edit_1024x640.png", "诊单编辑 · 紧凑窗口"),
("clinical-after/diagnosis_index_1440x900.png", "诊单列表"),
("assistant-1440.png", "AI 问诊"),
("assistant-1080.png", "AI 问诊 · 紧凑窗口"),
("../subwindow_exact/prescription_editor_860x900.png", "处方编辑"),
("../subwindow_exact/prescription_ai_report_920x760.png", "处方报告"),
("video-call-1120x760.png", "视频面诊"),
("video-call-440x300.png", "视频面诊 · 小窗"),
("video-chat-440x300.png", "视频聊天 · 小窗"),
("video-preview-1120x760.png", "视频截图确认"),
]
for filename, title in supplementary:
preview = QImage(str(output / filename))
if not preview.isNull():
records.append({
"title": title, "file": filename,
"width": preview.width(), "height": preview.height(),
})
(output / "gallery.json").write_text(
json.dumps(records, ensure_ascii=False, indent=2), encoding="utf-8",
)
cards = []
for record in records:
filename = html.escape(record["file"])
title = html.escape(record["title"])
cards.append(
f'<section><h2>{title} <small>{record["width"]} × {record["height"]}</small>'
f'</h2><a href="{filename}"><img src="{filename}" alt="{title}" loading="lazy">'
'</a></section>'
)
(output / "index.html").write_text(
'<!doctype html><html lang="zh-CN"><meta charset="utf-8">'
'<meta name="viewport" content="width=device-width, initial-scale=1">'
'<title>医生工作站 · 客户端设计验收</title><style>'
'body{margin:0;padding:32px;background:#F5F7FA;color:#223047;'
'font-family:"Microsoft YaHei",sans-serif}main{max-width:1440px;margin:auto}'
'h1{font-size:28px}p,small{color:#647287}small{font-weight:400;font-size:14px}'
'section{margin:32px 0 48px}h2{font-size:20px;display:flex;gap:20px;align-items:baseline}'
'img{width:100%;display:block;border:1px solid #E6EAF0;border-radius:16px}'
'a:focus-visible{outline:3px solid #6D8CCB}footer{padding:24px 0}'
'</style><main><h1>医生工作站 · 客户端设计验收</h1>'
'<p>使用演示数据渲染的真实客户端。点击图片查看原始尺寸。</p>'
+ "".join(cards)
+ '<footer>主窗口与紧凑窗口均按实际控件排版生成。</footer></main></html>',
encoding="utf-8",
)
print(output / "index.html")
if __name__ == "__main__":
main()