// 确保 jQuery 全局变量 hiprintJQuery 先加载(hiprint.bundle.js 依赖它) import './jquery'; import {hiprint} from '../hooks/useHiprint'; import {getPrintTemplate} from './index.js'; import printCss from './css/print-lock.css?inline'; /** fetchAndRender 入参 */ export interface FetchAndRenderParams { code: string; params?: any; data?: any; isCustom?: boolean; /** 错误提示回调。传了用它提示(桌面传 element-plus alert);不传则 throw Error(移动端用法) */ onAlert?: (msg: string) => void; /** 自定义数据输入交互(isCustom=true 时用)。桌面传 element-plus prompt;不传则 isCustom 抛错(移动端不支持) */ onPrompt?: (message: string, defaultValue?: string | null) => Promise; } /** fetchAndRender 返回值 */ export interface FetchAndRenderResult { /** 渲染后的完整 HTML(含样式) */ html: string; /** 是否有有效数据 */ hasData: boolean; /** 模板 JSON 字符串 */ json: string; /** 模板名称 */ name?: string; /** 纸张尺寸(mm),取自模板第一个 panel 的 width/height,服务端打印用 */ pageSize?: {widthMm: number; heightMm: number}; } interface TemplateResponse { status: number; data?: { json: string; list?: any; name?: string; }; message?: string; } interface HiprintTemplate { new (options: {template: any}): any; getHtml(data: any): Array<{innerHTML: string; outerHTML: string}>; /** hiprint 面板数组,每个面板含纸张宽高(mm) */ printPanels?: Array<{width?: number; height?: number}>; } /** * 获取打印模板 + 格式化数据 + 渲染 HTML(公共方法,桌面/移动共用)。 * * 本文件为纯逻辑,不依赖任何 UI 库(element-plus / vant)。 * 错误提示通过 onAlert 注入;自定义数据输入通过 onPrompt 注入。 * * @returns {html, hasData, json, name, pageSize} 或 false(失败时) */ export async function fetchAndRender({ code, params, data, isCustom, onAlert, onPrompt, }: FetchAndRenderParams): Promise { // 错误提示:传了 onAlert 用它提示并返回 false;不传则 throw(移动端用法,由上层 catch 处理) const fail = (msg: string): false => { if (onAlert) { onAlert(msg); return false; } throw new Error(msg); }; if (!code) { return fail('请传递模板编号'); } try { // 转换参数为数组 let reqParams = params; if (!Array.isArray(reqParams)) { reqParams = reqParams ? [reqParams] : []; } // 获取打印模板(含数据源数据) const res: TemplateResponse = await getPrintTemplate(code, reqParams); if (res.status !== 200 || !res.data || !res.data.json) { return fail(res.message || '获取打印模板失败'); } const json: string = res.data.json; let list: any = res.data.list; let hasData = false; // 格式化数据源:把嵌套对象拍平为 $key[subKey],数组保留 if (Array.isArray(list) && list.length > 0) { list = list.map((item: any) => { let printData: Record = {}; let entries = Object.entries(item); entries.forEach((arr) => { if (Array.isArray(arr[1])) { hasData = arr[1].length > 0; printData[arr[0]] = arr[1]; } else { if (arr[1] !== null) { hasData = true; let itemsEntries = Object.entries(arr[1]); itemsEntries.forEach((cArr) => { printData[`$${arr[0]}[${cArr[0]}]`] = cArr[1]; }); } } }); return printData; }); } else { list = []; } // 自定义数据:通过注入的 onPrompt 交互(桌面 element-plus prompt;移动端不支持) if (isCustom) { if (!onPrompt) { return fail('当前环境不支持自定义数据输入'); } const customValue = await onPrompt( '在下面输入框中输入您给的自定义数据', localStorage.hiprintCustomValue || null ); try { hasData = true; localStorage.hiprintCustomValue = customValue; list = JSON.parse(customValue); } catch (error) { try { hasData = true; list = JSON.parse(data); } catch (error) { hasData = false; list = []; } } } else if (data) { // 本地数据覆盖远端数据 try { if (data === undefined || data === null) throw new Error(); hasData = true; list = typeof data === 'string' ? JSON.parse(data) : Array.isArray(data) ? data : [data]; } catch (error) { hasData = false; list = []; } } // 渲染 HTML const hiprintTemplate: HiprintTemplate = new (hiprint as any).PrintTemplate({ template: JSON.parse(json), }); const htmlNodes = hiprintTemplate.getHtml(list); if (!htmlNodes || !htmlNodes[0]) { return fail('打印内容渲染失败'); } // 取第一个面板的纸张宽高(mm),供服务端 webContents.print 的 pageSize 使用 const panel = hiprintTemplate.printPanels && hiprintTemplate.printPanels[0]; const pageSize = panel && typeof panel.width === 'number' && typeof panel.height === 'number' ? {widthMm: panel.width, heightMm: panel.height} : undefined; const pCss = ``; return { html: pCss + htmlNodes[0].outerHTML, hasData, json, name: res.data.name, pageSize, }; } catch (error) { console.error('fetchAndRender error:', error); return false; } }