// 独立预览入口:打印请假单页(LeavePrint.vue)的视觉/交互验收。 // // 与 main-list.ts 同一套思路:业务 dev 端口受 CAS 保护,自动化浏览器截不到真实页面, // 这里用 mock-api 的页内 fetch 拦截独立渲染(无需登录、无需 mock-server)。 // // 用法: // npx vite --config preview.vite.config.ts --port 8099 // 打开 http://localhost:8099/preview-print.html → 屏幕预览(A4 纸张样式) // 加 ?probe=1 跑断言并把结果写入 document.title // // 说明:window.print() 会弹浏览器打印对话框,自动化环境不可控,探针只断言 // 「打印 CSS 已注入 + html.leave-print-mode 已挂载」,纸张效果以屏幕截图核对。 import { createApp, h } from "vue"; import { createRouter, createMemoryHistory, RouterView } from "vue-router"; import { createPinia } from "pinia"; import ViewUIPlus from "view-ui-plus"; import "view-ui-plus/dist/styles/viewuiplus.css"; import "@/assets/styles/main.scss"; import "@/assets/styles/layout.css"; import "@/assets/styles/icons.css"; import "virtual:uno.css"; import "virtual:svg-icons-register"; import utils from "@/utils"; import config from "@/assets/config/host.config"; import { installApiStub } from "./mock-api"; import LeavePrint from "@/views/leave/LeavePrint.vue"; installApiStub(); const RUNTIME_ERRORS: string[] = []; window.addEventListener("error", (e) => RUNTIME_ERRORS.push(String(e.message || e))); window.addEventListener("unhandledrejection", (e) => RUNTIME_ERRORS.push(`reject:${e.reason}`)); const router = createRouter({ history: createMemoryHistory(), routes: [{ path: "/print", component: LeavePrint }], }); const app = createApp({ render: () => h(RouterView) }); app.use(createPinia()); app.use(router); app.use(ViewUIPlus); app.config.globalProperties.$conf = config; app.config.globalProperties.$utils = utils; // 先 install 再跳转:install 前的 push 在部分 vue-router 4 小版本上会丢初始导航 router.push("/print?leaveId=4"); router.isReady().then(() => app.mount("#app")); if (new URLSearchParams(location.search).has("probe")) { setTimeout(() => { const out: string[] = []; let bad = 0; const say = (ok: boolean, msg: string) => { if (!ok) bad++; out.push(`${msg}${ok ? "=ok" : "=FAIL"}`); }; // 挂载期间应给 html 打上打印模式类(print CSS 作用域开关) say(document.documentElement.classList.contains("leave-print-mode"), "modeClass"); // 全局打印规则已注入(非 scoped 块存在 @media print + .header-container 隐藏) let printRule = false; for (const sheet of Array.from(document.styleSheets)) { try { for (const rule of Array.from(sheet.cssRules || [])) { const r = rule as CSSMediaRule; if (r.type === CSSRule.MEDIA_RULE && /print/.test(r.conditionText || "")) { if (/header-container/.test(r.cssText)) printRule = true; } } } catch { /* 跨域样式表忽略 */ } } say(printRule, "printRule"); // 单据渲染:标题 / 信息表 / 审批记录 / 签字栏 say(!!document.querySelector(".print-sheet"), "sheet"); const title = document.querySelector(".sheet-title"); say(!!title && title.textContent!.includes("教职工请假单"), `title(${title?.textContent})`); say(document.querySelectorAll(".sheet-table").length >= 3, `tables(${document.querySelectorAll(".sheet-table").length})`); say(document.querySelectorAll(".flow-table tbody tr").length === 3, `steps(${document.querySelectorAll(".flow-table tbody tr").length})`); say(!!document.querySelector(".status-stamp"), "stamp"); // 数据正确性:产假 80 小时 + 状态「已通过」 const bodyText = document.querySelector(".print-sheet")?.textContent || ""; say(bodyText.includes("产假"), "typeName"); say(bodyText.includes("80 小时"), "hours"); say(bodyText.includes("已通过"), "statusName"); say(bodyText.includes("2026-10-09 19:28"), "applyTime"); // 工具栏存在(打印/返回按钮) say(document.querySelectorAll(".print-toolbar .ivu-btn").length === 2, "toolbar"); say(RUNTIME_ERRORS.length === 0, `errs(${RUNTIME_ERRORS.length})`); document.title = `PRINT|bad=${bad}|` + out.join("|") + (RUNTIME_ERRORS.length ? "|" + RUNTIME_ERRORS.slice(0, 2).join("~") : ""); }, 2200); }