diff --git a/jeecgboot-vue3/src/views/print/template/components/NativeTemplateListPreviewModal.vue b/jeecgboot-vue3/src/views/print/template/components/NativeTemplateListPreviewModal.vue
index 4e42c93f..74023dfb 100644
--- a/jeecgboot-vue3/src/views/print/template/components/NativeTemplateListPreviewModal.vue
+++ b/jeecgboot-vue3/src/views/print/template/components/NativeTemplateListPreviewModal.vue
@@ -95,6 +95,17 @@
打印
+
+
+ PrintDot
+
+
@@ -152,6 +163,7 @@
import { generateNativeMockDataObject } from '../native/core/nativeMockData';
import { normalizeImportedNativeSchema } from '../native/core/nativeSchemaNormalize';
import type { NativeTemplateSchema } from '../native/core/types';
+ import { printNativeSchemaViaPrintDot } from '../utils/printNativeViaPrintDot';
const props = defineProps<{
open: boolean;
@@ -171,6 +183,7 @@
});
const loading = ref(false);
+ const printDotLoading = ref(false);
const errorText = ref('');
const schema = ref
(null);
const canvasJsonText = ref('{}');
@@ -372,6 +385,26 @@
window.setTimeout(() => updateContentMeasure(), 400);
}
+ async function handlePrintDotPrint() {
+ if (!schema.value) {
+ createMessage.warning('模板未加载');
+ return;
+ }
+ printDotLoading.value = true;
+ try {
+ await printNativeSchemaViaPrintDot({
+ schema: schema.value,
+ data: previewData.value,
+ jobName: props.templateId ? `tpl-${props.templateId}` : 'native-preview',
+ });
+ createMessage.success('已通过 PrintDot 提交打印');
+ } catch (e: any) {
+ createMessage.error(e?.message || 'PrintDot 打印失败');
+ } finally {
+ printDotLoading.value = false;
+ }
+ }
+
/** 调用浏览器打印预览 iframe 内文档(与当前预览 HTML 一致) */
function handleBrowserPrint() {
const win = previewIframeRef.value?.contentWindow;
diff --git a/jeecgboot-vue3/src/views/print/template/index.vue b/jeecgboot-vue3/src/views/print/template/index.vue
index f3b365fd..d4c534bb 100644
--- a/jeecgboot-vue3/src/views/print/template/index.vue
+++ b/jeecgboot-vue3/src/views/print/template/index.vue
@@ -20,6 +20,20 @@
/>
添加打印机
刷新打印机
+ PrintDot 桥接
+
+
新增原生模板
快速打印
@@ -50,8 +64,13 @@
按模板样式打印(推荐)
Lodop实验(模板样式)
前端转PDF后端打印
+ PrintDot 本地桥接(PDF)
服务端直打(纯文本)
+
+ 需本机运行 PrintDot 客户端(默认 WebSocket ws://127.0.0.1:1122/ws)。勾选「PrintDot
+ 桥接」并刷新打印机后,可选择桥接器上报的打印机;支持原生模板与 hiprint 模板(均在前端转 PDF 后送出)。
+
('templateStyle');
+ const quickPrintMode = ref<'templateStyle' | 'lodopTemplate' | 'pdfServer' | 'printDotBridge' | 'serverText'>(
+ 'templateStyle',
+ );
+ const LS_PRINT_DOT_ENABLED = 'qhmes_print_dot_enabled';
+ const printDotEnabled = ref(localStorage.getItem(LS_PRINT_DOT_ENABLED) === '1');
+ const printDotCfg = getPrintDotBridgeConfig();
+ const printDotWsUrl = ref(printDotCfg.wsUrl);
+ const printDotKey = ref(printDotCfg.key);
+
+ function persistPrintDotConfig() {
+ setPrintDotBridgeConfig(printDotWsUrl.value, printDotKey.value);
+ }
+
+ function onPrintDotEnabledChange() {
+ localStorage.setItem(LS_PRINT_DOT_ENABLED, printDotEnabled.value ? '1' : '0');
+ void refreshPrinterOptions(false);
+ }
/** 技能转换打印:示例数据(与快速打印占位说明一致) */
const SKILL_DATA_JSON_EXAMPLE = `{
"docNo": "MO-001",
@@ -311,10 +359,31 @@
});
}
printerOptions.value = Array.from(optionMap.values());
+ if (printDotEnabled.value) {
+ try {
+ const dotList = await fetchPrintDotPrinters();
+ dotList.forEach((p) => {
+ const name = String(p.name || '').trim();
+ if (!name) {
+ return;
+ }
+ if (!optionMap.has(name)) {
+ optionMap.set(name, { label: `[PrintDot] ${name}`, value: name });
+ }
+ });
+ if (showMessage && dotList.length) {
+ createMessage.success(`PrintDot 已连接,识别 ${dotList.length} 台打印机`);
+ }
+ } catch (e: any) {
+ if (showMessage) {
+ createMessage.warning(`PrintDot:${e?.message || '无法连接本地桥接器'}`);
+ }
+ }
+ }
if (showMessage) {
if (names.length) {
createMessage.success(`已从服务端识别到 ${names.length} 台打印机`);
- } else {
+ } else if (!printDotEnabled.value) {
const reason = String(payload?.capability?.localReason || '').trim();
createMessage.warning(`服务端未返回可用打印机。${reason || '请在后端配置网络打印机后重试。'}`);
}
@@ -510,7 +579,7 @@
const panel = Array.isArray(templateJson?.panels) && templateJson.panels.length ? templateJson.panels[0] : {};
const widthMm = Number(panel?.width || 210);
const heightMm = Number(panel?.height || 297);
- const pdfBase64 = await buildPdfBase64FromTemplate(html, widthMm, heightMm);
+ const pdfBase64 = await buildPdfBase64FromHtmlFragment(html, widthMm, heightMm);
const printer = String(params.printerName || '').trim();
await directPrintPdf({
templateCode,
@@ -1249,54 +1318,6 @@