承前过次(跨页累计)
一句话总览
读懂模板开关 → 复印模板并关掉原生合计、定下"每页 N 行" → 把数据按 N 行切页、头尾插承前行、跨页把金额累加好 → 拿复印模板 + 处理好的数据交给 hiprint,它老老实实每 N 行翻一页,合计/承前行自然落在页尾/页首。
一、行数断页(核心思想)
问题:会计账本跨好几页打印,每页末尾要写"本页合计/过次页",下一页开头写"承前页"。hiprint 本身是"按纸张高度自动分页"的——哪行排到纸底了就换页。这种方式你控制不了,而且因为字号、显示器分辨率的影响,差个一两行就会抖,合计行可能就被挤到页中间去了。
思路:我们不让 hiprint 自己决定在哪断页,而是替它规定"每页必须正好 N 行"。hiprint 有个现成功能叫 maxRows——排满 N 行就强制翻页。我们算出 N,告诉 hiprint "满 N 行你给我换页",它就听话了。
关键点:我们在数据里提前把每一页结构上排好(数据行 + 插入的承前/合计/过次行加起来正好 N 行),然后让 hiprint 按 N 行断页。两边对上了,合计行必然在页尾,承前行必然在页首。
一句话总结:与其求着 hiprint 把合计行排到页尾,不如直接命令它"每页 N 行,排满就翻页",我们自己把 N 行的内容拼好。
二、配置解析
问题:代码怎么知道"这个模板要不要承前过次?累计哪些金额?余额算不算?"
思路:模板的表格上有几个开关字段(写在 options 里),代码像读说明书一样解析它们:
-
carryForward: true→ 这个表要承前过次 -
carryForwardFields: "借方金额,贷方金额"→ 这两个字段要逐页累加 -
carryForwardBalanceFields: "余额"→ 余额只"照搬上一页末行的数",不累加(余额是滚存,加总会变成天文数字) -
carryForwardTotals: all/carryOnly/none→ 决定插哪些行(全插 / 只插承前+过次 / 都不插只分页)
几个坑点:
- 如果没显式写字段,代码会"猜":先看列上有没有设过合计,再看列名/标题里有没有"金额、借方、余额"这类字眼,自动识别。
- hiprint 存模板时,列可能是"套了娃的二维数组",代码会先把它拍平,不然认不出字段。
- 代码会记住"这个表在第几个面板、第几个元素",后面只改这一个表,不误伤同模板里的其他表。
一句话总结:代码当翻译,把模板上的人话开关读成自己能用的配置(累计啥、余额咋算、每页几行)。
三、模板副本处理(给 hiprint 定规矩,但不动原稿)
问题:原模板上 hiprint 自带的"每页合计"功能要关掉(不然会和我们的"本页合计"重复算),还要注入"每页 N 行"的规矩。但设计器里正在画的那个模板不能动。
思路:先复印一份模板(深拷贝),只在复印件上动手术:
- 删掉原生的
tableSummary合计设置(避免重复累加); - 写上
maxRows = N(就是上面说的"每页 N 行翻页")。
原件(设计器画布)纹丝不动。我们拿复印件去建打印实例。
为什么必须复印而不是改原件:模板是层层嵌套的结构,普通复制只复制第一层,里面的内容还是和原件共享的,改复印件会连原件一起改坏。所以用了 JSON.parse(JSON.stringify()) 这种"序列化再反序列化"的办法,彻底断开引用,得到一份全新独立的副本。
一句话总结:复印模板 → 只在复印件上关掉原生合计、写上"每页 N 行" → 拿复印件打印,原件不动。
四、数据切分 + 跨页累计(往数据里"插行 + 算账")
问题:原始数据是平平的一长串明细(比如 50 行),我们要把它切成"一页一页"的结构,在每页头尾插入承前/合计/过次行,还要把金额跨页连续算对。
思路:
① 算每页放几行数据
设每页总共 N 行(和上面的 maxRows 同一个数)。每页除了数据,还要占几行给"承前/合计/过次"这些特殊行,所以:
- 首页:数据 (N-2) 行 + 本页合计 + 过次页
- 中间页:承前页 + 数据 (N-3) 行 + 本页合计 + 过次页
- 末页:承前页 + 剩下的数据 + 本页合计
代码用一个 pieces 数组记录"每一页放几行数据",保证每页总数恰好 N 行。
② 逐页遍历,边插行边算账
准备两个账本:
-
总账
total:从第一页一直加到当前页(比如借方累计到 80 万),写进"过次页",下一页的"承前页"就接着这个数往下算 → 这就是"跨页连续"。 -
本页账
pageTotal:只算当前这一页的小计,写进"本页合计"。
③ 余额的特殊处理(重点)
余额不是加总,而是"照搬这一页最后一行的余额数"。所以另外用一个 carriedBalance,只记录末值,绝不累加。
④ 精度收尾
金额带小数,电脑算加法会有 20999.300000000003 这种误差,会计受不了。所以每加一笔都用 round2 收回到分位(加个极小值抵消浮点误差)。另外,数据里金额常以 "2,944.26" 这种带逗号的字符串进来,hiprint 会误判成数字算成 NaN,所以进来的第一步先把这些字符串洗成真正的数字。
一句话总结:把一长串明细按 N 行一页切开,每页头尾插好承前/合计/过次行,同时维护"总账(跨页累)"和"本页账(本页小计)",余额只搬末值不累加,金额每步收精度、先洗成数字防 NaN。
五、两个小提醒
- 换行内容不一定错位:承前过次是"按行数 N 分页",只要某页没被撑爆到触发 hiprint 的高度自然断页,行数分页就和高度分页重合,换行内容也能正常显示。"固定行高不折行"是保守前提,不是换行一定错。
-
两个函数必须成对用:
prepareTemplateForCarryForward(出模板复印件)必须先于applyCarryForward(出处理好的数据),且打印实例必须建在复印件上。漏掉任一步,原生合计会重复、断页会错位。
相关文档
- 实现规范(接入契约):
承前过次实现说明.md - 深度解析:
承前过次深度解析.md - 源码:
src/utils/print/carryForward.ts、src/utils/print/normalizeAmount.ts