医院管理系统(HIS)核心设计:数据流转、表结构与权限实战 简介这是一套用于日常医院管理的 JavaScript 系统源码面向医疗信息化学习者与 Web 全栈开发者。系统按角色拆分为患者、医生、管理三大模块患者可预约挂号、查看历史预约并维护个人数据医生能添加/删除患者、撰写处方、查看和回复预约管理员则可统览患者、医生、预约及反馈并增删医生账户。资源压缩包共 2000 个文件以 JS 逻辑文件为主同时包含大量 SVG 图标、CSS/SCSS 样式、TypeScript 类型定义、HTML 页面、PHP 接口及 SQL 数据库脚本整体大小约 50.49MB。目录结构延续 AdminLTE 等成熟后台模板便于按模块定位代码。目前已有 152 人学习下载。整套代码角色权限清晰预约与处方流程完整适合作为课程设计、毕业设计或医院管理系统的二次开发基础也能帮助读者理解前后端交互与后台管理页面的组织方式。1. hospital-management-esystem到底在管什么我第一次看到这个项目名的时候第一反应是“又一套CRUD”。但真把医院日常管理系统的需求捋下来才发现它和普通的进销存、OA系统完全不是一个量级的东西。它管的不只是“数据”而是整个医院的业务流转、科室协同、财务对账和医疗质量追溯。先明确一个概念hospital-management-esystem这类系统在国内医院场景里通常被称为HISHospital Information System的轻量级版本或专科版。它覆盖的范围大致包括门诊挂号、医生工作站、收费退费、药房药库、住院登记、护理记录、检验检查申请、报表统计、系统权限管理等模块。简单说只要医院前台、病区、药房、收费处、检验科之间需要传递信息就都在这个系统的工作范围内。这套系统能解决什么问题最直接的一点是消灭“手写处方人工传递”的低效链路。一个患者从挂号到拿到药中间要经过分诊台、诊室、收费窗口、药房四个节点如果靠纸质单据任何一个环节排队、丢失、写错都会造成患者投诉和科室扯皮。系统上线之后每个节点的操作都在系统里留痕门诊流程从“人跑”变成“数据跑”这才是医院管理数字化最核心的价值。适合谁来参考这套系统如果你是做医疗卫生信息化开发的工程师、医院信息科的运维人员、或者准备做智慧医疗创业的产品经理这个项目都值得拆开看一遍。它的业务复杂度恰到好处——没有医保接口、电子病历评级、互联网医院那么复杂但又比普通的后台管理系统多出了科室规则、计价逻辑、库存联动这些很“医疗”的细节。1.1 为什么医院系统不能用普通企业软件思路做很多刚从企业级后台转过来做医院系统的团队第一个月基本都在交学费。企业软件的思路是“流程驱动”审批流、工单、状态机逻辑上偏重控制而医院系统的核心是“时间敏感责任追溯”每个操作都对应着真实的诊疗行为错了不是重新提交一遍的问题。举个例子药品库存。普通电商系统的库存扣减失败最多是订单超卖赔个券就完了。但在医院药房如果门诊医生开的处方在收费后药房显示库存不足患者已经交了钱这单就变成了“欠药单”要退费重开、药房补货、科室重新确认涉及三个部门的协调。所以在hospital-management-esystem里药品库存必须做“可用库存”和“物理库存”的双层设计医生开方时实时校验可用量而不是等到发药环节才发现缺货。再一个差异点是权限模型。医院里的角色非常细院长要看全院运营数据科主任只能看本科室医生只能开自己权限内的药品和检查护士只能执行不能修改医嘱收费员只能操作费用不能改价格。这种基于“角色数据范围功能权限”的三维管控比企业里简单的RBAC要复杂得多而且每个角色的数据可见范围还和科室、病区、时间挂钩。所以这篇博文我不会只贴代码而是把这套系统的业务设计、数据流转、表结构、典型接口和踩坑经验一起拆开讲让你不仅能复现一个demo更能理解为什么这么做。2. 核心模块划分与数据流转2.1 模块清单与职责边界一套能承担“日常管理”的医院系统模块划分必须清晰不然就是大泥球。我这里列一个经过实际项目验证的模块清单这套划分也在hospital-management-esystem的名字下做过落地实现模块核心职责关键操作挂号/分诊创建就诊记录分配号源窗口挂号、预约签到、分诊排队医生工作站书写病历开具处方/检查/检验病历录入、处方开立、医嘱下达收费/退费费用确认、发票生成门诊收费、住院预交金、退费审批药房/药库药品库存管理、发药退药入库、出库、盘点、近效期预警住院管理病区床位、入出转院住院登记、床位分配、医嘱执行检验检查申请单派发、结果回传检验标本登记、报告查询系统管理用户、角色、菜单、字典权限配置、日志审计、参数设置每个模块之间要有明确的边界比如“医生工作站”只能产生申请和医嘱不能直接改库存“收费处”只认费用项目编码不管药品规格。职责划清楚了后面做接口、做权限、做统计报表才不会被业务方带偏。2.2 最容易被忽略的主数据问题第一次设计医院系统很容易把所有精力放在业务流程上忽略了“主数据”这个地基。但实际跑起来你会发现医院里最乱的就是基础档案。科室主数据就是第一个坑。医院科室有行政科室、临床科室、医技科室、护理单元几种分类一个科室可能有多个名称“心血管内科”和“心内科”是同一个科还可能同时挂靠在住院部和门诊。如果系统里科室表只存一个名称一个编码后面做工作量统计、绩效核算的时候报表数据根本对不上。我的做法是给科室表加上“类型”和“上级科室”两个字段并且统一维护一套标准编码历史曾用名放到扩展表里。药品和诊疗项目主数据更复杂。同一个药品可能有多个厂家、多个规格同一个诊疗项目在不同院区价格可能不同。所以收费项目必须独立建表通过“项目编码”和药品字典、检查项目字典关联而不是直接在业务表里存名称。这个设计决定了后续计价、退费、医保对账能不能跑得顺。2.3 数据流转设计一次门诊就诊全链路理解hospital-management-esystem最好的方式是跟着一条最典型的业务流走一遍。我拿“患者门诊就诊”这条链路举例。第一步患者在挂号窗口建档。如果之前没有档案系统在patients表里创建一条记录分配一个全局唯一的患者ID这个ID后面所有业务表都引用它。第二步挂号员选择科室和号别在appointments表创建一条挂号记录状态为“已挂号”同时把费用明细写入charge_items表并生成应收记录。此时诊室排队大屏根据科室号别自动更新。第三步患者进入诊室医生在doctor_workstation页面接诊挂号记录状态变为“就诊中”。医生书写电子病历开立处方。处方不是直接生成收费单而是先写入prescriptions表状态“待提交”费用明细同时生成但标记为“未确认”。这样设计是为了让医生在系统里检查一下有没有开错药再确认提交。第四步患者到收费窗口收费员调出该患者当前待支付的费用明细点击收费。此时charge_items里对应记录状态变为“已支付”同时调用药房库存接口锁定药品批次。第五步药房窗口看到处方已交费进行发药操作库存可用量减少处方状态变为“已发药”。整个链路下来核心不是某一个模块做得多炫而是数据在各部门之间的流转准确且可追溯。每个步骤都有状态字段支撑每个环节都记录操作人出了问题能回溯到具体节点。3. 技术架构与核心表设计3.1 技术栈选型与分层思路hospital-management-esystem落地时我建议按照最常见的分层架构来做别整花活。后端可以用Spring BootJava系或者FastAPIPython系前端用Vue或React都行数据库选MySQL或PostgreSQL。选型的核心在于团队熟悉度而不是技术先进性。我自己实测下来Spring Boot Vue MySQL这套组合在医院信息系统里最稳原因有三个一是Java生态对医疗行业的支撑库和案例最多接各类硬件读卡器、扫码枪、打印机的驱动基本都是Java的二是Spring Security做细粒度权限控制比较成熟三是MySQL运维人才好找医院信息科的人多少都懂一些。前端模块按业务拆分成管理后台和医生工作站两个入口。管理后台给挂号收费药房等窗口用强调键盘操作效率和表单展示的清晰度医生工作站独立出来是因为它的页面交互密度大病历编辑器、处方笺、检查申请单在一个页面里要协同处理。分层设计上建议严格按四层拆Controller负责参数校验和路由Service负责业务逻辑和事务Mapper/Repository负责数据访问Domain层放核心实体和枚举。特别是“计价”“退费”“库存锁定”这种涉及多表更新的操作必须放在同一个事务里由Service层统一编排不能散落在Controller里。3.2 核心表结构设计理解了整体架构我们来看看最核心的几张表设计。我这里直接贴我在实际项目中打磨过的精简版本并说明每个关键字段的考虑。第一张表患者信息表CREATE TABLE patients ( id BIGINT PRIMARY KEY AUTO_INCREMENT, patient_no VARCHAR(32) NOT NULL COMMENT 患者编号全局唯一, name VARCHAR(64) NOT NULL COMMENT 姓名, gender TINYINT NOT NULL COMMENT 1男 2女 0未知, birth_date DATE COMMENT 出生日期, phone VARCHAR(20), id_card VARCHAR(32) COMMENT 证件号码做加密存储, address VARCHAR(255), status TINYINT DEFAULT 1 COMMENT 1有效 0冻结, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uk_patient_no (patient_no) ) COMMENT 患者基本信息表;注意这里patient_no是全局唯一业务编号不能用数据库自增ID直接暴露出去因为后续挂号、缴费、病历等场景都要引用这个编号业务编号是给人看的自增ID是给系统关联用的。第二张表挂号记录表CREATE TABLE appointments ( id BIGINT PRIMARY KEY AUTO_INCREMENT, appointment_no VARCHAR(32) NOT NULL COMMENT 挂号单号, patient_id BIGINT NOT NULL COMMENT 关联患者ID, dept_id BIGINT NOT NULL COMMENT 科室ID, doctor_id BIGINT COMMENT 医生ID, visit_type TINYINT NOT NULL COMMENT 1门诊 2急诊, visit_date DATE NOT NULL COMMENT 就诊日期, time_slot VARCHAR(16) COMMENT 号别时间段, status TINYINT NOT NULL DEFAULT 1 COMMENT 1待就诊 2就诊中 3已完成 4已退号, fee_amount DECIMAL(10,2) NOT NULL DEFAULT 0 COMMENT 挂号费, created_by BIGINT COMMENT 创建人, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_appointment_no (appointment_no), KEY idx_patient_date (patient_id, visit_date), KEY idx_dept_date (dept_id, visit_date) ) COMMENT 挂号记录表;这张表是门诊流程的枢纽所以索引要按最常见的查询场景来建按患者查历史就诊记录、按科室查某天的号源情况。状态字段的设计要覆盖完整生命周期后续退号、转诊都在这个字段上做流转。第三张表处方和处方明细CREATE TABLE prescriptions ( id BIGINT PRIMARY KEY AUTO_INCREMENT, rx_no VARCHAR(32) NOT NULL COMMENT 处方号, appointment_id BIGINT NOT NULL COMMENT 关联挂号记录, patient_id BIGINT NOT NULL, doctor_id BIGINT NOT NULL, rx_type TINYINT NOT NULL COMMENT 1西药 2中成药 3中草药, status TINYINT NOT NULL DEFAULT 0 COMMENT 0待提交 1已提交 2已收费 3已发药 4已退费, total_amount DECIMAL(10,2) NOT NULL DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_rx_no (rx_no) ) COMMENT 处方主表; CREATE TABLE prescription_items ( id BIGINT PRIMARY KEY AUTO_INCREMENT, prescription_id BIGINT NOT NULL, drug_id BIGINT NOT NULL COMMENT 药品ID, drug_name VARCHAR(128) NOT NULL COMMENT 冗余药品名称防止字典修改后追溯丢失, spec VARCHAR(64) COMMENT 规格, dosage VARCHAR(64) COMMENT 用法用量, quantity INT NOT NULL COMMENT 数量, unit_price DECIMAL(10,2) NOT NULL, amount DECIMAL(10,2) NOT NULL, KEY idx_prescription_id (prescription_id) ) COMMENT 处方明细表;处方明细表里的drug_name和spec字段是冗余存储这在数据建模时是故意的。因为处方是医疗凭证今天开的药名必须和当时打印出来的一致如果后续药品字典改了名称历史处方不能跟着变。这一点务必记住医疗系统的历史记录是不可变的靠join去取最新字典会导致追溯错误。3.3 关键接口设计思路核心接口的设计我挑两个最有代表性的来说。第一个是“创建处方并计价”的接口第二个是“收费完成扣库存”的接口。创建处方接口必须在事务中同时写处方主表、处方明细表和收费明细表。三次写入必须同生共死否则就会出现“医生开了药但收费处看不到”的数据不一致问题。Spring Boot里用Transactional注解直接包住Service方法即可但要注意事务边界不能跨网络调用比如调用药房库存接口就不能放在这个事务里面要等事务提交后通过事件或消息队列处理。收费完成扣库存的接口核心逻辑是“先校验再更新”。校验包括处方状态是否为“已提交”、是否已超过有效期、药品批次库存是否充足。校验全部通过后在同一个事务里完成三件事更新处方状态为“已收费”更新收费明细状态为“已支付”扣减指定批次库存。这里我的做法是使用乐观锁UPDATE drug_batch_stock SET available_qty available_qty - #{quantity} WHERE drug_id #{drugId} AND batch_no #{batchNo} AND available_qty #{quantity};这个SQL通过available_qty quantity条件实现数据库层面的并发控制防止两个窗口同时卖出最后一个库存。如果更新影响行数为0说明库存不足或批次冲突接口直接抛异常让收费员换批次或者通知药房补货。4. 实施落地中的常见问题与排查4.1 挂号并发冲突医院系统里面最典型的并发场景就是上午八点的挂号高峰。多个窗口同时挂同一个专家号如果没有做好并发控制很容易把同一个号源分配给两个患者。我踩过这个坑之后现在的方案是给号源表加一个version字段更新号源时带上version条件。具体步骤是读取号源记录拿到当前剩余号数和version执行扣减时UPDATE号源表 SET remain remain - 1, version version 1 WHERE id ? AND remain 0 AND version ?如果更新失败说明有人抢了本次挂号失败提示患者该号源已满。这个方案既不需要数据库锁也不需要引入Redis在日均几千号源的规模下实测足够稳定。4.2 权限控件的边界模糊医院系统里的权限问题最怕的不是功能权限配错而是数据权限越界。比如“医生离职后账号为什么还能看到过往患者信息”这种问题本质上是权限模型里没有把“数据归属”和“账号状态”联动起来。我现在的做法是在所有业务查询的Service层强制注入一个数据范围过滤器。登录用户如果没有“全院查看”的权限SQL自动追加AND doctor_id 当前登录用户 或者 AND dept_id IN (当前用户所属科室及子科室)。这个过滤器是全局AOP实现的所有敏感数据的查询接口都必须经过它避免开发者在某个新接口里忘了加WHERE条件把全院的处方都暴露出去。4.3 业务流程与财务对账误差运营一两个月后财务那边经常会对不上账。不是系统算错了而是退费流程没闭环。比如患者交了费但药房没发药第二天来退费这时候库存已经在收费时扣掉了。如果退费操作只退了钱没有把库存加回来月底盘点就会盘亏。这个问题的根源在于“收费扣库存”的设计在退费场景下没有做反向操作。我的建议是退费必须走“原路返回”的接口不允许直接改数据库。退费接口里校验原收费记录存在、当前状态允许退费然后在一个事务里同时做费用记录状态改为“已退费”、生成负向费用流水、回补库存占用或物理库存。负向流水很重要财务对账时报表只需要汇总正向和负向流水就能得出净收入。4.4 系统上线的运维注意事项医院系统上线和普通企业系统不一样最大的区别是“不能停”。门诊在上班时间不能接受系统维护所以要预留“夜间维护窗口”。我一般在凌晨12点到4点做数据库备份和版本发布。数据备份策略上核心业务库每天全量备份一次binlog实时备份确保最多丢失5分钟内的数据。备份文件要加密存储且异地保留不能和数据库在同一台机器上。这个不是我吓唬人真实发生过机房断电导致服务器磁盘损坏如果没有异地备份几年的就诊记录全部没了的惨例。登录安全方面医生工作站要支持账号密码U盾或手机扫码的双因素登录因为医护人员账号的权限很高一旦泄露可以直接开药、改病历。建议所有敏感操作都记录审计日志包括时间、操作人、操作内容、IP地址。审计日志不能只存业务库要单独存一份并且做只读权限控制防止开发人员自己删日志。最后分享几个实践中的小技巧根据我个人做这个项目的经验给准备动手的朋友三个建议。第一个建议先画业务流程图再写代码。不要一上来就建表、写接口。我做过好几个类似的项目凡是推进顺畅的都是前期把“挂号-收费-发药-退药”这些链路和科室负责人逐一确认过的。流程图不用画得多专业重点是让医生、护士、收费员看一眼就能指出“我这里不对”。逼着自己把流程画清楚后面开发能少走一半弯路。第二个建议把字典表当一等公民设计。诊断字典、药品字典、检查项目字典、科室字典所有带中文名称的业务字段统一从字典表取值业务表里只存编码。这样后面做电子病历评级或者区域医疗平台对接时数据能直接转成行业标准编码。第三个建议留存充足的开发接口文档。医院信息化建设是一个长期过程今天做his明天可能就做lis、pacs、体检系统。接口不预留好后续每次对接都要改别人的代码极其痛苦。最简单的做法是所有对外接口统一走RESTful风格使用标准的状态码和错误信息结构哪怕是内部系统之间调用也要这样。踩过几次坑之后我的体会是医院管理系统的难点从来不在技术而在对医疗业务的理解。技术方案网上都能查到但“药品为什么不能直接改库存”“退费为什么必须原路返回”“处方为什么不允许随便删改”这些问题是查不到答案的。把一个日常医院管理系统做好本质上是在帮医院把“谁在什么时候对哪个患者做了什么”这件事变得清晰可查这比任何花哨的技术架构都重要。本文还有配套的精品资源点击获取