1. 一套门诊管理系统先把三类人的痛说清楚我第一次接触到“vue springboot门诊电子病历处方药品进销存管理系统”这个需求是某门诊部的负责人拿着一摞单据来找我。那天下午分诊台上堆着三样东西病历本、处方笺、药房的出库单。护士要把同一张处方里的药品数量抄到手工库存账上药房的人再把处方留底最后财务对账时发现某个药的库存和实际瓶数对不上又得翻一周的单据去查。整个过程没有哪个环节是极度复杂的但每一个环节都在消耗人工、甚至消耗病人耐心。这种场景在很多小型门诊都非常典型纸质病历写了就丢处方开了无法追溯药品库存则由专人去维护Excel表格。Excel虽然灵活但并发一上来就乱更不用说价格调整、批次效期、供应商结算这类细节。做系统之前我的第一反应不是“用什么框架”而是先把业务链条理清楚。这个链条其实只有三条线患者线挂号、就诊、病历、处方、药品线采购、入库、出库、盘点、报损、钱线收费、结算、对账。这三个环节故意分开就是为了不过度耦合。但从这次实践来看完全分离也不行。门诊最核心的流程就是医生开处方处方直接触发药房出库和收费这三件事发生在同一分钟里系统必须把它们串在一个事务里完成。这就是为什么病历、处方、药品进销存要放进同一套系统而不是各做各的软件。后面所有方案都围绕这个“跨模块联动”来展开。我建议有类似需求的朋友先别急着写代码先把诊室、药房、收费处这几个岗位的日常走一圈把纸质流程里每个人做的动作记录下来再去设计模块边界。你会发现很多系统不好用的根源不是开发能力问题而是对业务流缺乏全局理解。2. 技术栈定调Vue Spring Boot这套组合为什么适合中小门诊技术选型部分我没有采用“什么人红用谁”的思路而是基于团队维护能力和部署环境做了取舍。前端用的Vue后端用Spring Boot数据库MySQL缓存Redis作为辅助。这个组合乍一看不算新潮但在门诊医疗这个场景里却是非常稳的选择。门诊系统注定是多角色、多表单、多列表的交互密集场景例如医生要快速书写病历药房要扫码核销护士要查询库存。Vue的响应式数据流非常适合这种表单和列表频繁变动的界面配合组件化的UI库开发速度明显快于传统的服务端渲染方式。Spring Boot选择的原因也很直接它天然适合做RESTful风格的接口服务把用户认证、权限控制、日志记录这些横切逻辑做成拦截器和过滤器配置清晰团队上手快。更重要的是Spring Boot生态里有成熟的数据库事务管理工具这对“开处方扣库存”这类强一致性场景至关重要。用惯了Java后端的人都能理解真正复杂的不是写CRUD而是保证跨表事务不抛出脏数据。Spring的Transactional虽然不能解决所有并发问题但它至少提供了一个可靠的边界控制基础。为了不让项目膨胀我把系统拆成几个业务模块基础数据模块患者、医生、药品字典、供应商、门诊模块挂号、病历、处方、药房模块库存、出入库、盘点、预警、系统模块用户、角色、日志。模块之间通过接口调用不搞微服务一个单体应用就能覆盖几十个终端的门诊场景。很多小型项目容易犯的一个错误是盲目上Spring Cloud那套微服务架构结果带来了不必要的运维成本。我一直觉得项目规模和架构复杂度要匹配能用单体解决的绝不拆。3. 电子病历的数据建模病历写下来容易让电脑读懂才是关键电子病历模块是整个系统的门面因为医生每天接触最多的就是这块。如果病历设计得难用再好的后台逻辑也没人愿意用了。我最初踩过一个大坑以为病历只要做一个富文本框就行医生想怎么写怎么写存一段HTML完事。这样开发速度确实快但等到要统计疾病谱、要按诊断查历史病历、要对比处方用药是否合理时自由的文本完全无法支撑结构化查询。最终的设计改为病历拆成基础信息和结构化内容两部分。基础信息包含患者主诉、现病史、既往史、诊断、医嘱等固定字段每个字段有独立的数据库字段。结构化内容部分允许医生添加自定义模板例如“感冒初诊”“高血压复查”“糖尿病随访”等模板每个模板有预定义的检查项和评估项。前端根据所选模板动态生成表单后端把提交结果以JSON格式存储。这种做法的好处是既保留了不同科室病历的灵活性又保证了主数据层面的结构化。数据库里可以建一张medical_record表保存公共字段再建一张medical_record_template_data表保存每个模板的动态内容字段包括record_id、template_key、form_data。查询的时候先查公共字段再按需加载JSON内容性能上没什么压力。处方模块的数据建模更要严谨。处方涉及财务和用药安全不能像病历一样随意。处方主表prescription保存处方号、患者ID、医生ID、开单时间、总金额、处方状态。处方明细表prescription_item保存药品ID、药品名称、单次剂量、频次、天数、数量、单价、金额。这里要注意“单次剂量”和“频次”必须由字典数据来约束否则医生手写“每日三次”和“一天3顿”会出现同义不同文的垃圾数据。药品字典独立建表是我强烈建议的做法。药品字典上有通用名、商品名、规格、剂型、生产厂家、批准文号、医保编号等属性。处方明细里不直接存药品名称字符串而是存drug_id显示名称通过关联查询带出。这样修改药品名称或价格时历史处方依然能通过ID找到准确数据而不受字典更新影响。很多初学系统开发的人会在这里偷懒直接在处方里存一个药品名字符串结果后续调整药价时历史账单跟着变了对账一团糟。4. 药品进销存全链路进、销、存、盘四个字背后的完整账务逻辑药品进销存模块是这套系统工作量最大、也是最需要抠细节的部分因为它直接关系到钱和货的账实相符。进销存的核心是“流水账”思想每一次实物变化都可以看作是一次带方向的库存变化记录。库存不是直接改一个数字就完事而是通过登记流水来体现。先说采购入库这条链路。系统先建立供应商档案每次采购生成采购单采购单里有预计入库药品、数量、采购价、金额。药品到货后库管员做验收操作根据到货实收数量更新库存并自动生成一条入库流水入库流水要记录批次号、生产日期、有效期、供应商、入库单价。为什么要单独维护批次因为药品不像普通商品有效期不管理好容易造成过期浪费尤其是疫苗、胰岛素这类对存储有要求的药品批次追踪是必须要有的。系统里药品表drug只做基础字典真正的实物账记录在drug_stock_batch表里每一批入库形成一个独立库存记录。这样做之后发药时可以按“先进先出”的原则自动选择批号避免旧批次药品长期积压。再说处方发药扣库存。这是系统里读取流量最大的接口也是容错要求最高的接口。患者缴费后药房人员点击发药系统根据处方明细逐项扣减对应药库存。扣减逻辑不能用一个简单的UPDATE drug_stock SET quantity quantity - 1嵌套循环而应该针对同一批号一次性更新并且在同一事务内完成。一个处方可能有五六个品项其中某个药品库存不足时整个发药事务都要回滚不能出现发了两盒药却有一盒失败的情况。系统在提交前先批量校验校验通过后再批量执行扣减这套预检机制能减少很多事务回滚的路径。再就是盘点、报损和库存调整。盘点不是简单地把库存数字改成实物数字就完事而是要生成盘盈盘亏记录。每次盘点生成一张盘点单盘点单里有账面数量、实盘数量、差异数量。差异如果为正说明盘盈可能是采购入库没做登记差异为负可能是发药出错了或者丢失。无论盘盈还是盘亏都要走审核流程审核通过后生成盘盈入库单或盘亏出库单这样才能保证每一笔库存变化都有据可查。报损也同理过期药品、破损药品要做报废登记报废既减少库存还要记录是质量问题还是过期问题便于后续和供应商谈退换货。库存预警和有效期提醒可以在一开始就搭好框架。库存下限预警在出库扣减后触发当某药品库存低于安全阈值时系统自动生成采购建议单推荐补货数量参考近三十天的平均日消耗量。有效期预警则以批次的效期字段为依据提前90天、30天两级提醒避免出现过期发药的事故。这些功能实现起来都不复杂麻烦的是数据口径要统一库存数量必须实时预警判断必须用实时库存去算不能依赖缓存延迟过久的数值。5. 并发放药时的库存扣减是怎么保证不超卖的门诊的高峰时段非常集中医生上午开出一批处方药房十几分钟内完成发药这种场景对库存扣减的并发控制提出了很高的要求。如果不做任何处理两个发药请求同时读到库存数量为10两个处方各需要8盒都判断“库存充足”扣减后库存变成2盒但实际上只应该成功一个。这种错误在业务量不大的时候不容易暴露一旦门诊每天处方量超过两三百张问题就会集中爆发。我采用的方案是悲观锁加事务。在业务代码中对药品批次库存记录执行SELECT ... FOR UPDATE把这一行锁住然后再判断库存是否充足执行扣减更新。为什么用悲观锁而不用乐观锁因为发药扣库存是一个高频且短事务的操作冲突概率不低悲观锁虽然会带来一些锁等待但实现简单、语义明确不容易引入重试机制。当时我们也评估了Redis缓存扣减库存再异步同步数据库的方案这种方式吞吐量更高但会让库存数据出现短暂不一致对药房这种实时性要求极高的场景不够友好。最终就锁数据库行实测下来一个批次记录上同时排队十几个事务也没问题每次扣减只在毫秒级完成。还有一个容易忽略的点是幂等设计。药房人员扫码发药时如果前端网络超时后端其实已经处理成功了用户重新点击一次提交就会导致同一条处方重复扣库。解决方法是处方发药接口设计成幂等的每次发药请求带上处方的发药流水号后端在处理前去查是否已有相同流水号的发药记录存在就直接返回上次结果不存在才执行扣减。这样既避免了用户重复操作带来的数据错误也让接口对接变得安全。处方修改的场景也要预留容错。医生开完处方后如果发现药开错了需要作废原处方并重新开新处方此时原处方状态改为“已作废”它占用的库存立即回滚释放。回滚操作同样要走库存增减流水绝不能在后台直接写一个字段。为此系统设计了一个stock_movement_log流水表记录每次变化的药品、批号、数量、类型入库、出库、报损、盘盈、盘亏、关联单据号、操作人、操作时间。有了这张表日后做财务对账和审计查账都能快速定位到每一笔变动也方便开发排查线上问题。6. 权限、审计、隐私医疗数据系统里绝对不能省的三道保险在医疗系统里权限和审计不是产品亮点而是基本底线。患者病历属于个人隐私数据处方涉及用药安全药品库存涉及的采购价又是门诊的商业数据这三类数据如果权限不分任何一名护士都能查看药品采购价任何一名医生都能修改库存数量这个系统迟早出问题。权限设计采用的是RBAC基于角色的访问控制模型系统角色划分为系统管理员、门诊医生、药房人员、收费人员、库管员、护士等。每个角色只能访问自己职责范围内的菜单和数据接口。医生角色只能查看自己接诊患者的病历不能跨医生查询这一点通过数据权限过滤器实现后端在查询病历列表时自动追加当前登录人的条件。药房人员登录后只能看到药品库存、出入库记录和待发药处方但看不到患者的完整病史只看得到就诊相关信息。库管员负责采购入库和盘点但没有发药权限。把所有角色权限理清楚后再配合Spring Security拦截器在接口层面进行逐路径校验。前端菜单只是界面屏蔽后端的权限校验才是真正的安全防线。审计日志这块一开始我把它当成简单的高频记录表来设计后来发现要真正查问题光记录“谁在什么时间改了什么东西”不够还得记录修改前后的值。病历修改必须有留痕包括修改人、修改时间、修改字段、旧值、新值。这个需求如果针对每个业务表都去做镜像会非常繁琐我采用了通用审计方案在数据库里建一张operation_log表核心业务表的变更操作通过AOP切面统一记录变更前后快照。日志表比较大没关系按月份分区查询效率可以接受。隐私保护方面我不主张把大量敏感字段明文存数据库。患者姓名、手机号、身份证号这些字段要加密存储或做脱敏处理。系统内部展示时默认显示脱敏后的值例如手机号只显示前三位和后四位需要查看完整手机号的场景再加权限控制。数据传输层统一走HTTPS防止中间人窃取。这些安全措施看起来微不足道但在真实部署中一条脱敏处理不到位的接口就可能成为整个系统合规性的败笔。7. 上线之后回头看真正决定成败的是基础数据和流程细节这个项目从开发、测试到上线前后花了四个多月。技术方案中途不算经历大改但业务侧的细节不断在调整复盘时发现最影响项目成败的不是代码架构而是几个看似边缘的基础工作。第一件事是药品基础数据清洗。市面上药品信息五花八门同一成分的药有不同厂家、不同规格、不同包装如果不做准确的药品字典后续每一个环节都会出错。我们在上线前专门花了两周时间把门诊目前常用的几百种药品逐个录入字典统一名称、规格、单位、厂家、效期。这个工作极其枯燥但没有任何捷径。将来你会发现在处方统计、采购比价、库存盘点时越是干净的基础数据越省心。第二件事是打印机和标签格式的适配。处方打印格式各家不同药袋标签需要注明药品用法用量这是容易被开发忽略的细节。我们最初只做了标准的A5处方打印后面发现不同诊室用的打印机型号不同纸张尺寸也不同导致打印内容被裁切。最终统一了纸张规范并给每类打印机单独调了一套样式才彻底解决。在这个项目里前端打印样式的工作量比想象中大一定不要小看。第三件事是对门诊人员的信息化培训。系统功能再完整如果医生不习惯打字、药房人员不习惯扫码扫描项目就发挥不出价值。我们采取了一对一跟随式培训系统上线第一周由实施人员驻场遇到流程不通畅的地方当场记录、当天改。有些看起来不合理的操作步骤实际上是系统设计时没有考虑实际工作流程。例如药房发药需要先扫描处方号但原来药房习惯按患者姓名查找我们就调整了查询方式增加按患者姓名模糊检索顺带把整个发药流程重排了一遍。最后再说一点个人体会这套系统上线以后门诊从“每天傍晚补台账”变成了“实时就知道库存余量”财务对账时间从半天缩短到半小时医生写一份病历的时间也有所降低尤其是复诊患者可以直接调出历史病历效率提升明显。但信息化这件事不是做出一个系统就结束了后续的维护、迭代、数据更新同样耗费精力。系统上线后我们还陆续加了药品与处方合理性校验、自定义统计报表、微信端预约挂号等几个功能。如果你也准备做一个类似项目我建议从一开始就把“可维护、可扩展”作为底线把精力投入到业务流程本身而不是一味追求技术上的花哨。技术永远是工具流程和数据才是最值钱的部分。