ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SpringBoot+Vue3 企业打印架构:审批单、业务凭证与条码标签如何统一设计

SpringBoot+Vue3 企业打印架构:审批单、业务凭证与条码标签如何统一设计 SpringBootVue3 企业打印架构审批单、业务凭证与条码标签如何统一设计文档地址https://ruoyioffice.com 文章底部获取源码和演示地址 17156169080获取产品咨询仓库收到一批设备管理员需要打印入库凭证给每台设备贴标签还要保存一份能在下个月重新查看的电子材料。三个动作使用同一批业务数据却不能简单共用一个“打印当前页面”按钮。纸张、版式、设备、历史口径和结果确认不同决定了企业打印实际上是一套输出架构。▲ 同一份业务内容可以服务多个输出通道。统一的是数据含义和模板治理不是强行用同一种技术驱动所有设备。一、为什么打印功能容易在项目后期变成返工中心最初的需求通常很简单“把详情页打印出来。”于是前端加一个按钮调用浏览器打印。直到真实业务开始使用问题才逐渐出现左侧菜单也被打出来第二页没有表头标签尺寸不对二维码还未绘制完成旧单据重打时套用了新模板点击取消打印系统却把它记成了“已成功”。这些问题不都属于 CSS。它们来自几种不同的对象被混在一起**业务内容是什么、如何排版、交给谁输出、系统究竟确认了什么。**如果设计之初没有区分后面每个模块都会各自补丁最后形成互不兼容的打印孤岛。需求核心约束不宜直接套用的做法审批单与业务凭证主表、明细、意见、分页直接打印整个管理页面资产条码标签毫米尺寸、码制、设备校准缩小一张 A4 页面代替标签模板电子归档材料固定版式、可重现、权限把当前页面 URL 当作归档文件历史重打当时数据与当时模板永远读取当前主数据重新渲染本文采用“资产业务产生凭证与标签”作为主线同时借助流程打印代码说明跨业务数据结构。浏览器打印和资产 C-Lodop 双通道是现有工程能力统一打印任务、不可变归档快照及端到端回执是在此基础上提出的设计扩展。二、先看一笔业务怎样从屏幕走向纸面1. 从业务详情选择打印对象而不是从页面 HTML 抓字段资产卡片已经有业务身份、分类、使用组织和标识码。打印时用户实际选择的是一组业务对象而不是某个 DOM 节点。后端应按这些对象重新获取允许输出的数据形成专用打印响应。▲ 真实资产详情页面。详情用于确认打印对象打印接口仍需独立校验对象范围和字段权限不能因为按钮可见就跳过授权。这种做法能避免两类问题。第一页面为了交互可能只加载部分明细而打印需要完整内容。第二列表列配置、主题和隐藏字段会影响 DOM却不应改变凭证中的正式数据。业务响应与打印响应可以共享底层查询和转换逻辑但不要让打印模板直接访问任意数据库字段。可输出字段应有稳定标识、展示名称、类型和格式规则。后续把“使用部门”改成页面上的简称不应让模板中的字段路径全部失效。2. 模板管理的是输出规则不只是几段 HTML资产标签模板包含纸张或标签尺寸、行列布局、码制、字段配置以及打印通道。用户选择 A4 不干胶模板与标签机模板本质上是在选择不同的物理约束而不只是选择不同配色。▲ 真实模板编辑界面。模板应把字段、尺寸和输出通道放在一起治理修改模板时不需要修改业务单据本身。模板可分为身份与版本两层。模板身份表达“资产标签标准版”版本表达某次发布后的具体布局。草稿允许调整发布后要能被打印任务稳定引用。是否立即让所有新打印使用新版是业务策略历史任务怎样重现则是另一条规则。还要区分业务值和显示值。资产名称是业务数据名称过长时换行、截断或缩小字体是模板规则。金额数值与大写格式、日期值与打印日期格式同样不应混为一谈。否则同一业务内容经过不同模板后可能看起来像产生了不同事实。3. 预览应体现目标版式而不是假装设备已经成功出纸标签预览页可以展示当前模板、份数、偏移和标签内容。它让实施人员在没有真正发送打印任务前发现字段缺失、溢出和排列问题是很有价值的验收入口。▲ 真实标签预览页面。本次仅查看预览未向物理打印机发送任务界面预览正确也不等于设备已经完成出纸。在现有前端中切换模板会重新加载打印数据仅预览时不会要求累加打印次数正式点击打印时才按配置记录。这个区别值得保留因为预览通常要反复进行不能把每次调版都当成业务打印。不过“点击打印才计数”仍然不等于“设备成功才计数”。浏览器弹出打印对话框后用户可以取消标签服务接收任务后设备也可能缺纸。记录名称如果直接叫“成功打印次数”就给出了超出系统证据的承诺。三、统一架构应该统一到哪一层一个实用的边界是把系统分成业务数据提供、模板描述、输出适配和任务记录四部分。前两部分尽可能统一输出适配允许差异任务记录则必须明确各通道能提供何种证据。▲ 建议逻辑模型打印任务引用具体业务对象和模板版本输出记录描述实际通道及结果证据。统一任务与版本快照属于扩展设计。对审批单已有BpmProcessPrintServiceImpl会加载历史流程实例、实例绑定的流程定义、已完成任务和相关人员信息再组织printSchema、fieldData、tableData。这说明“打印用数据”可以成为独立协议而不是散落在 Vue 模板里的若干字符串替换。下面根据已有服务整理数据组装主线省略用户映射与具体字段构造。它展示职责分工不是可以直接替代完整服务的代码。publicBpmProcessPrintDataRespVObuildPrintData(StringinstanceId){varinstanceprocessInstanceService.getHistoricProcessInstance(instanceId);if(instancenull)throwexception(PROCESS_INSTANCE_NOT_EXISTS);vardefinitionprocessDefinitionService.getProcessDefinitionInfo(instance.getProcessDefinitionId());varformdefinition!nulldefinition.getFormId()!null?formService.getForm(definition.getFormId()):null;vartaskstaskService.getFinishedTaskListByProcessInstanceIdWithoutCancel(instanceId);// 实际实现还组装发起人、部门及审批人信息。varresultnewBpmProcessPrintDataRespVO();result.setPrintSchema(buildPrintSchema(definition,form));result.setFieldData(buildFieldData(instance,definition,form));result.setTableData(buildTableData(instance,definition,form));// 审批轨迹由实际 Convert 逻辑统一转换而非模板直接查任务表。returnresult;}这种协议的关键不是 DTO 名称而是它让模板知道哪些字段可用、哪些是多行明细、哪些是流程轨迹。模板设计器可以基于字段定义生成选择项输出适配器则基于确定的数据渲染双方都不必理解整个业务服务。同时不能忽略字段级安全。用户可以查看单据不代表可以导出所有敏感字段某个审批节点隐藏的字段也不应通过打印接口绕过限制。打印、预览、生成 PDF、下载归档文件都属于数据出口必须分别检查访问边界。四、A4、PDF 和标签机应该怎样选通道浏览器打印优先解决常规纸张与交互预览浏览器通道适合用户能确认纸张、打印机和份数的常规办公场景。页面需要独立的打印区域和打印样式隐藏导航、操作按钮等交互元素。对于长明细需要明确表头重复、行拆分、页边距和签字区的处理。现有资产标签实现没有在数据加载后立即调用打印而是等待 Vue 更新和两帧绘制。条码使用 canvas 时这个等待能减少“已经切到新数据却打印了旧图”的风险。asyncfunctionwaitForPrintReady(){awaitnextTick();awaitnewPromisevoid((resolve){requestAnimationFrame(()requestAnimationFrame(()resolve()));});}asyncfunctionhandleBrowserPrint(){if(labels.value.length0)return;printing.valuetrue;try{awaitloadPrintData(true);awaitwaitForPrintReady();document.body.classList.add(PRINT_BODY_CLASS);window.addEventListener(afterprint,removePrintMode,{once:true});window.print();}finally{printing.valuefalse;}}这是对当前前端控制流的摘录省略了空数据时的提示。对于外部字体、远程图片或异步图表两帧并不构成通用的资源完成证明还应等待对应资源真正就绪。afterprint用于恢复页面状态不应单独作为物理打印成功凭证。PDF重点是固定版式与可重现而不是文件扩展名浏览器“另存为 PDF”和服务端生成 PDF 是两种实现路径。前者依赖用户操作与客户端环境后者便于集中生成和归档但需要管理字体、分页、渲染资源、任务超时以及文件权限。不能因为浏览器具备保存 PDF 的入口就宣称系统已经具备服务端归档流水线。选择时可以先问这份材料是否需要以后按同样内容重新取得如果只是临时下载当前数据渲染可能足够如果需要证明当时输出了什么就应保存实际文件或足以重现的不可变数据和模板版本。“可重现”也有程度之分。只保存业务 ID能重新查询当前数据保存字段快照和模板版本能重建当时语义保存最终 PDF 和内容摘要才能直接比对当时文件。不同要求对应不同成本不必所有单据都采用最高等级但必须向业务方说清楚。标签机尺寸与设备指令是第一等约束资产标签实现通过printChannel区分浏览器与 C-Lodop 通道。标签机适配会把毫米尺寸、条码区域、字段位置、字体和偏移转换为打印指令特定模板还可以携带原始设备指令。因此统一模板协议应该保留通道能力差异而不是假装每个模板都能无损转换。网页 CSS、标签指令和 PDF 排版分别有自己的布局能力。设计器可显示“支持的输出通道”让用户在发布模板之前就知道限制。对于未经安装或无法检测的本地打印服务产品应给出清晰状态并保留可用的浏览器输出路径。不要在后台静默失败后仍提示打印成功也不要为了截图演示绕过设备检测。本文不假设每个客户都拥有标签机。五、一次打印任务要留下哪些可解释的记录打印任务不是一条“已打印true”。至少要分清请求已创建、内容已生成、已提交通道、设备已确认以及人工确认等不同证据等级。不是所有通道都能到达最后一种状态。▲ 建议时序先确定内容与模板再交给具体通道结果状态只能根据实际可获取的回执推进。对于用户连续点击或网络重试可以在创建任务时使用请求标识防重。但业务上的“重打”是一个新的意图不应永远被幂等键拦住。前一次请求的重试复用原任务用户明确重新打印则创建新任务并关联原任务记录原因和发起人。下面是任务创建的扩展设计伪代码。唯一约束与“同键同参数”的校验是设计前提不能仅靠先查后插防止并发重复。publicPrintJobrequestPrint(PrintCommandcommand,Subjectsubject){permission.requirePrint(subject,command.businessId());StringdigestcommandDigest.of(command);PrintJobexistingjobs.findByRequestId(subject.tenantId(),command.requestId());if(existing!null){if(!existing.payloadDigest().equals(digest)){thrownewIllegalArgumentException(同一请求标识不能携带不同参数);}returnexisting;}TemplateVersiontemplatetemplates.requirePublished(command.templateVersionId());PrintPayloadpayloaddataProvider.authorizedPayload(command,subject);PrintJobcandidatePrintJob.created(command.requestId(),subject,template,payload);candidate.setPayloadDigest(digest);// 唯一键冲突时读取胜出记录并再次核对 digest。returnjobs.insertOrGetMatching(candidate);}任务审计还应避免过度记录。包含人员信息、合同金额或内部审批意见的打印内容不宜直接写入普通应用日志。日志可以记录任务 ID、业务 ID、通道和错误类别敏感快照存放在受控区域并设置与业务相匹配的保留时间。打印任务跨越浏览器、本地服务和设备时通常不存在一个覆盖全部步骤的数据库事务。超时后也不能简单认定“没有打印”。可以把状态保留为待核实让用户检查设备和纸张再选择重试或新建重打任务。诚实的状态比虚假的成功提示更有价值。六、历史重打为什么会牵涉到业务快照假设资产的使用部门已经从研发部变成测试部用户重新打印两个月前的交接凭证。这里至少有两种合理需求打印“当时发生的交接事实”或者打印“当前资产最新情况”。两者都可能正确但必须选择其中一种不能由代码碰巧读取哪张表决定。建议在产品上使用不同名称例如“查看原凭证”和“按当前数据重新生成”。原凭证优先使用当时保存的文件重新生成则明确显示数据时间、模板版本与新生成时间。这样既能服务业务又不会把新文件伪装成原始记录。同理审批流程中的人员名称、部门名称和手写签名也可能随时间变化。引用历史流程定义解决的是定义身份并不自动冻结所有主数据。需要哪些字段快照应根据凭证用途逐项选择而不是想当然地把“使用历史实例”理解为“全部内容永远不变”。模板升级时也要考虑兼容。新模板要求一个旧单据从未保存的字段系统不应默默填空并继续盖上“完整凭证”。可以回退到旧模板、提示缺少数据或允许生成带说明的补充材料。缺失信息应被看见而不是被漂亮排版掩盖。七、实施验收把打印问题提前到交付之前软件预览只能完成一部分验收。常规 A4 至少要验证长名称、多页明细、空字段和中文字体标签至少要验证尺寸、边距、实际扫码以及更换设备后的偏移。对于没有设备的环境可以完成内容和模板检查但不能给出“实机扫码通过”的结论。验收场景应检查的行为证据要求切模板后立即打印使用新模板与新条码页面渲染就绪及输出样张用户取消浏览器打印不宣称设备出纸成功请求与结果状态分开详情更新后重新预览按明确策略刷新数据显示数据时间或快照身份历史模板已升级原凭证仍可解释模板版本与原文件可追溯连续点击与超时重试不意外重复创建同一任务请求幂等与重打关联无权访问某项数据预览和下载同样受限服务端拒绝而非仅隐藏按钮还可以准备一组固定的版式样本一页、两页、超长说明、空明细、特殊符号、不同份数。模板每次变更后用同一组数据重新渲染并比较能比人工临时找一张单据更早发现回归。如果要做视觉比对不宜把所有像素差异都判成失败。生成时间、页码和动态任务号需要单独处理真正应稳定的是字段位置、分页边界、条码内容及关键文字。验收目标应对应业务风险而不是追求没有解释的截图相似度。八、从现有双通道逐步走向统一打印服务第一阶段可以保留各模块现有打印入口先统一打印数据协议和权限校验。这样对业务页面影响小也能减少模板直接访问内部字段的问题。第二阶段集中模板身份、版本与通道能力。浏览器 A4、标签机和后续 PDF 渲染可以分别接入仍然保留各自的设备约束。统一平台不应变成限制最强通道只能使用最弱功能。第三阶段再增加任务幂等、重打关联、归档文件和留存治理。对于只需要临时标签的场景不必强制保存完整 PDF对于需要长期核对的正式凭证则应保存更强的证据。在系统中体验时可以先查看资产详情再进入标签模板与标签预览观察业务内容、模板和通道的分工流程打印服务则可作为主表、明细与审批信息统一组装的参考。本文没有新增打印服务也没有执行实机打印所有扩展方案都应按需要实施。常见问题能不能所有打印都统一用浏览器实现可以把浏览器作为常规办公默认通道但精确标签、受控设备指令、后台批量生成和长期归档可能有不同要求。统一内容和模板治理比强制统一物理输出技术更稳妥。点击打印后为什么不能直接把状态改成成功按钮点击只能证明用户发起了动作不能证明设备完成出纸。系统应按通道实际能提供的证据命名状态浏览器关闭打印界面也不能单独证明成功。有 PDF 文件是否就实现了归档还没有。需要确定文件身份、访问权限、业务关联、生成依据和保留策略。一个随当前数据重新生成的下载文件与保留当时结果的归档文件含义不同。模板变更会不会影响旧单据取决于打印时引用的是当前模板还是确定的版本以及数据是否保留了必要快照。系统必须明确选择不能把历史一致性交给默认查询行为。结语企业打印真正需要统一的是业务内容、模板身份、访问边界与结果证据。A4、PDF 和标签机可以使用不同通道但用户应该始终知道自己打印了什么、依据哪一版、系统确认到了哪一步。RuoYi Office 的流程打印数据组装与资产双通道实现为这套设计提供了实际工程起点。沿着这些边界逐步建设比每个业务页面各写一套打印逻辑更容易交付也更容易长期维护。如果这篇对你有用点个「在看」或收藏。演示地址https://ruoyioffice.com/webGitHub 源码https://github.com/yuqing2026/ruoyi-officeGitee 源码https://gitee.com/yqzy1688/ruoyi-office微信17156169080获取产品咨询打开演示地址直接查看系统。
返回列表