| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300 |
- import { qrPngDataUrl } from "./qrImage";
- export const CLODOP_SETUP_URL =
- (import.meta.env.BASE_URL || "/") + "lodop/CLodop_Setup_for_Win32NT.exe";
- const CLODOP_JS_URLS = [
- "http://localhost:8000/CLodopfuncs.js",
- "http://localhost:18000/CLodopfuncs.js"
- ];
- export class LodopMissingError extends Error {
- constructor(message = "未检测到 CLodop 打印服务,请先安装并启动打印脚本") {
- super(message);
- this.name = "LodopMissingError";
- }
- }
- function winLodop() {
- const win = window as any;
- try {
- if (typeof win.getCLodop === "function") {
- return win.getCLodop() || null;
- }
- } catch {
- /* 服务未就绪 */
- }
- return win.CLODOP || null;
- }
- function loadScript(src: string, timeout = 4000) {
- return new Promise<void>((resolve, reject) => {
- const existed = document.querySelector(
- `script[data-clodop="1"][src="${src}"]`
- ) as HTMLScriptElement | null;
- if (existed) {
- if (winLodop()) {
- resolve();
- return;
- }
- }
- const script = document.createElement("script");
- script.src = src;
- script.setAttribute("data-clodop", "1");
- const timer = window.setTimeout(() => {
- script.onload = null;
- script.onerror = null;
- reject(new Error("timeout:" + src));
- }, timeout);
- script.onload = () => {
- window.clearTimeout(timer);
- resolve();
- };
- script.onerror = () => {
- window.clearTimeout(timer);
- script.remove();
- reject(new Error("fail:" + src));
- };
- document.head.appendChild(script);
- });
- }
- export function isCLodopReady() {
- return !!winLodop();
- }
- export async function loadLodop(jsUrl?: string) {
- const existing = winLodop();
- if (existing) {
- return existing;
- }
- const urls = jsUrl
- ? [jsUrl, ...CLODOP_JS_URLS.filter(url => url !== jsUrl)]
- : CLODOP_JS_URLS.slice();
- for (const url of urls) {
- try {
- await loadScript(url);
- const lodop = winLodop();
- if (lodop) {
- return lodop;
- }
- } catch {
- /* 换下一个端口 */
- }
- }
- throw new LodopMissingError();
- }
- export async function probeCLodop(jsUrl?: string) {
- try {
- await loadLodop(jsUrl);
- return true;
- } catch {
- return false;
- }
- }
- export function downloadCLodop() {
- const a = document.createElement("a");
- a.href = CLODOP_SETUP_URL;
- a.download = "CLodop_Setup_for_Win32NT.exe";
- document.body.appendChild(a);
- a.click();
- a.remove();
- }
- export function tryStartCLodop() {
- window.location.href = "CLodop.protocol:setup";
- }
- export async function runLodop(lodopPack: any) {
- const LODOP = await loadLodop(lodopPack && lodopPack.js_url);
- const title = (lodopPack && lodopPack.title) || "流程单";
- const copies = Math.max(1, Number(lodopPack && lodopPack.copies) || 1);
- const page = (lodopPack && lodopPack.page) || {};
- const w = Number(page.w) || 210;
- const h = Number(page.h) || 297;
- const pages = Array.isArray(lodopPack && lodopPack.pages) ? lodopPack.pages : [];
- LODOP.PRINT_INIT(title);
- pickCapablePrinter(LODOP);
- const paperName = paperNameOf(w, h, page.paper_size);
- if (paperName) {
- LODOP.SET_PRINT_PAGESIZE(1, 0, 0, paperName);
- } else {
- LODOP.SET_PRINT_PAGESIZE(1, Math.round(w * 10), Math.round(h * 10), "");
- }
- LODOP.SET_PRINT_MODE("POS_BASEON_PAPER", 1);
- LODOP.SET_PRINT_COPIES(copies);
- applyLodopBaseTypeface(LODOP);
- if (!pages.length) {
- throw new Error("没有可套打的页面数据");
- }
- const textsPages = Array.isArray(lodopPack && lodopPack.print_texts)
- ? lodopPack.print_texts
- : pages.map((sheet: any) => sheet.print_items || sheet.items || []);
- for (let index = 0; index < pages.length; index++) {
- const sheet = pages[index];
- const items = Array.isArray(textsPages[index]) ? textsPages[index] : [];
- let added = 0;
- for (const row of items) {
- const text = String((row && row.text) || "");
- if (!text) {
- continue;
- }
- if (row.type === "qrcode") {
- await addLodopQrImage(LODOP, row, text);
- added += 1;
- continue;
- }
- LODOP.ADD_PRINT_TEXT(
- row.top || "0%",
- row.left || "0%",
- row.width || "10%",
- row.height || "4%",
- text
- );
- applyLodopTextStyle(LODOP, row);
- added += 1;
- }
- if (!added && sheet && sheet.html) {
- LODOP.ADD_PRINT_HTM(0, 0, "100%", "100%", sheet.html);
- added += 1;
- }
- if (!added) {
- LODOP.ADD_PRINT_TEXT("8%", "8%", "80%", "10%", "套打数据为空");
- applyLodopTextStyle(LODOP, { font: "微软雅黑", size: 10, bold: 0, align: 1 });
- }
- if (index < pages.length - 1) {
- LODOP.NEWPAGE();
- }
- }
- if ((lodopPack && lodopPack.print_api) === "PRINT") {
- LODOP.PRINT();
- } else {
- LODOP.PREVIEW();
- }
- }
- async function addLodopQrImage(lodop: any, row: any, text: string) {
- const top = row.top || "0mm";
- const left = row.left || "0mm";
- const width = row.width || "24mm";
- const height = row.height || "24mm";
- try {
- const png = await qrPngDataUrl(text, 640);
- lodop.ADD_PRINT_IMAGE(
- top,
- left,
- width,
- height,
- `<img border="0" src="${png}" />`
- );
- lodop.SET_PRINT_STYLEA(0, "Stretch", 1);
- } catch {
- lodop.ADD_PRINT_BARCODE(top, left, width, height, "QRCode", text);
- try {
- lodop.SET_PRINT_STYLEA(0, "QRCodeErrorLevel", "L");
- lodop.SET_PRINT_STYLEA(0, "QRCodeVersion", 4);
- lodop.SET_PRINT_STYLEA(0, "DataCharset", "UTF-8");
- } catch {
- /* 旧版 CLodop 无此样式 */
- }
- }
- }
- function applyLodopBaseTypeface(lodop: any) {
- try {
- lodop.SET_PRINT_STYLE("FontName", "微软雅黑");
- lodop.SET_PRINT_STYLE("FontSize", 10);
- lodop.SET_PRINT_STYLE("Bold", 0);
- lodop.SET_PRINT_STYLE("Italic", 0);
- } catch {
- /* 旧版 CLodop 无全局样式 */
- }
- }
- function applyLodopTextStyle(lodop: any, row: any) {
- lodop.SET_PRINT_STYLEA(0, "FontName", (row && row.font) || "微软雅黑");
- lodop.SET_PRINT_STYLEA(0, "FontSize", Number(row && row.size) || 10);
- lodop.SET_PRINT_STYLEA(0, "Bold", row && row.bold ? 1 : 0);
- lodop.SET_PRINT_STYLEA(0, "Alignment", Number(row && row.align) || 1);
- try {
- lodop.SET_PRINT_STYLEA(0, "Italic", 0);
- lodop.SET_PRINT_STYLEA(0, "Underline", 0);
- } catch {
- /* 旧版 CLodop 无斜体/下划线样式 */
- }
- }
- function paperNameOf(w: number, h: number, name?: string) {
- const n = String(name || "").toUpperCase();
- if (n === "A5" || (Math.abs(w - 148) < 1 && Math.abs(h - 210) < 1)) {
- return "A5";
- }
- if (n === "A4" || (Math.abs(w - 210) < 1 && Math.abs(h - 297) < 1)) {
- return "A4";
- }
- return "";
- }
- function pickCapablePrinter(lodop: any) {
- let count = 0;
- try {
- count = Number(lodop.GET_PRINTER_COUNT()) || 0;
- } catch {
- return;
- }
- const prefer = [
- "Microsoft Print to PDF",
- "导出为WPS PDF",
- "Microsoft XPS Document Writer",
- "WPS PDF"
- ];
- const names: string[] = [];
- for (let i = 0; i < count; i++) {
- names.push(String(lodop.GET_PRINTER_NAME(i) || ""));
- }
- const hit =
- prefer.find(name => names.includes(name)) ||
- names.find(name => /pdf|xps/i.test(name));
- if (!hit) {
- return;
- }
- try {
- lodop.SET_PRINTER_INDEXA(hit);
- } catch {
- /* 预览里仍可手选打印机 */
- }
- }
- export async function handleLodopError(err: unknown) {
- const { ElMessage, ElMessageBox } = await import("element-plus");
- const message =
- err instanceof Error ? err.message : "Lodop 预览未打开,请确认本机已启动 CLodop";
- try {
- await ElMessageBox.confirm(
- message + "。需要先在本机安装并启动 CLodop 打印服务,安装后请保持托盘图标运行并刷新本页。",
- "安装打印脚本",
- {
- confirmButtonText: "下载安装程序",
- cancelButtonText: "已安装,尝试启动",
- distinguishCancelAndClose: true,
- type: "warning"
- }
- );
- downloadCLodop();
- ElMessage.info("正在下载 CLodop_Setup_for_Win32NT.exe,请运行安装程序");
- } catch (action) {
- if (action === "cancel") {
- tryStartCLodop();
- ElMessage.info("已尝试启动本机 CLodop,请稍候再点套打");
- } else {
- ElMessage.warning(message);
- }
- }
- }
|