1. 背景与痛点:跨越"查询区间"的黑洞效应
在医疗信息化(EMR)的前端开发中,"护理记录单"受制于极度严格的病案归档和物理打印规范(A4标准分页)。
为了保证打在 A4 纸上的内容不超高,后端会实行"物理切割":当一条长记录在第 5 页底部装不下时,后端会将其"腰斩",把溢出的部分打上"虚拟行"标记,塞进第 6 页的顶部。
如果在同一个查询区间内(比如一次性查询了 1-10 页),这种切断并不可怕 ,前端完全可以把它们拼起来。但真正的灾难发生在我们 跨"查询区间边界" 的时候。
为了前端性能,通常采用步长为 5 或 10 的区间分页查询(如先查 1-5 页,再翻查 6-10 页)。此时,边界断层带来了两大灾难:
- 无头悬案(首边界断层):当护士翻到第 6-10 页区间时,第 6 页的第一条可能恰好是个被腰斩的"下半截"。因为它的"头"在第 5 页(未被请求),导致这条记录在 UI 上失去了日期、时间和签名,就像一条幽灵数据。
- 吃数据的黑洞(尾边界断层):当护士在第 5 页(1-5区间的尾部)录入了一大段病情,点击保存后,因为超长被后端切到了第 6 页。由于护士当前还在 1-5 页的视图里,超出的一半直接"凭空消失"(掉出了查询范围),引发极大的数据安全恐慌。
如何在 "保障物理 A4 分页绝对严谨" 的前提下,解决这种跨查询区间的视觉断层?我们经历了两轮核心架构的演进。
2. 演进一:突破区间思维,引入"相邻页双向边界缝合"
既然断层发生在查询区间的两端,我们就不能局限于当前获取到的数据。在表格的核心控制器中,我们实现了 "双向边界缝合算法":
算法核心
-
向上找头(突破首边界) :拦截当前查询范围(如 6-10 页)的第一条记录,一旦探测到它是个"虚拟行"且当前数据集里找不到它的主行,系统会静默发起向上一区间边界(第 5 页)的请求,把被隔断的"头"抓取过来,在前端内存中进行完整拼接。
-
向下找尾(追踪尾边界):如果当前区间(如 1-5 页)的最后一条记录未能闭合(数据溢出到了第 6 页),系统会自动向下一区间的起步页(第 6 页甚至第 7 页)发起递归追踪请求。
在此过程中,
MAX_EXTRA_PAGES = 3这道保险丝一直稳稳地插在那里。不过,它的机制非常精妙,并不是简单粗暴地"超过3页就不找了",而是采用了一种 "平滑降级(Graceful Degradation)" 策略来兼顾"消除视觉盲区"与"系统性能保护":- 第 1 ~ 3 页(正常消除盲区) :如果跨界追踪发生在 3 页以内,系统不仅会把被截断的尾巴拿过来,还会顺手把这几页里其他的正常记录也一并追加进来显示给护士看。这也就是消除由于跨查询范围导致的视觉盲区。
- 超过 3 页(触发降级熔断) :如果某个护士写了一篇"几千字的小作文",导致这条记录的残躯断臂连续蔓延了 4 页、5 页甚至 10 页。此时如果系统还一整页一整页地往内存里塞所有数据,浏览器就会因为 DOM 节点过多而卡死。一旦触发
MAX_EXTRA_PAGES = 3熔断,循环依然会继续(以保证小作文的完整性),但策略突变 :系统不再追加后面的整页数据,而是变成了一把"手术刀",精准地只从后续页面中剔出属于这条巨长记录的那个残肢(虚拟行)拼接回来,抛弃其他无关记录。
通过这套机制,既保证了在 99% 的日常跨页场景中护士享有极佳的无盲区体验,又在 1% 的极端病历数据面前守住了前端崩溃的底线,可谓 "进可攻、退可守"。
-
UX 降维打击(Auto-Jump):针对"填完消失"的黑洞效应,我们在保存拦截器中加入特征比对。一旦发现刚填写的记录溢出到了当前查询范围之外,系统直接触发跳转,提示护士"记录跨越了当前页码,已自动为您跳转至下一区间",护士的视线可以无缝跟随数据流动。
至此,无论区间怎么切,护士在屏幕上看到的始终是一幅没有盲区、严丝合缝的连续长卷。
3. 演进二:深水区危机,UI 状态与物理打印的彻底解耦
然而,当我们用跨区间缝合技术提供了完美的 UI 体验时,迎来了最致命的考验------打印。
为了消除视觉盲区,我们在前端内存里把第 5 页和第 6 页跨界切断的半截记录"缝"成了一条完美的数据(recordData)。当我们直接把这份数据喂给打印引擎时:
- 打印机会在第 5 页末尾打印了一遍这行长记录;
- 翻到第 6 页,又把这行被拼接出的记录打了一遍(造成重复)。
- 更糟的是,缝合后的数据改变了原有的物理行高,导致基于浏览器的打印引擎算错高度,挤出了毫无意义的空白尾页。
痛点结论:为了取悦人眼而消除边界的 UI 状态,变成了严格物理分页打印机的毒药。
终极解法:数据分流与绝对服从
我们对数据流控进行了彻底的重构,确立了两大架构铁律:
铁律一:UI 状态与打印状态必须解耦
在 fetchRecordContent 函数执行任何"跨区间边界缝合"动作之前,直接通过 JSON.parse(JSON.stringify(records)) 将后端原汁原味的、带着原始断层标记的物理数据拦截并克隆一份,专门赋值给 rawRecordData。
从此,屏幕展示走 recordData(被缝合的连续流),物理打印走 rawRecordData(保持原始物理切割的断层流),两者平行,互不干涉。
铁律二:前端打印引擎对后端的绝对服从
重写基于浏览器的 PrintEngine 分页算法。废弃前端"计算物理行数除以 16 强行分页"的做法。强制打印引擎扫描 rawRecordData 中由后端下发的 _pageNum 物理边界字段。
后端说这是第 5 页的数据,前端就只往第 5 页的 A4 纸容器里渲染;严禁前端自作主张做跨页溢流计算。就连页脚打印的"第 X 页",也严格取自后端的真实边界值。
4. 总结与启示
经过这两次重构,这套架构实现了真正意义上的"鱼和熊掌兼得":
- 在屏幕前,护士享受着突破查询区间的现代 Web 连续录入体验;
- 在病案室,打印机忠实、严谨地输出着符合国家病历质控标准、一字不差的 A4 物理存档。
核心启发:
前端架构设计不仅仅是"调接口、画页面"。在面对具有复杂物理世界映射逻辑(如归档、打印)的系统时,绝不能让"UI体验"越俎代庖去污染"物理边界数据"。适时地在数据总线处做分层解耦(UI View vs Physical View),绝对尊重并贯彻后端的物理切割指令,才是保障企业级重型医疗应用稳如磐石的根本之道。