医院管理系统(HIS)核心设计:数据流转、表结构与权限实战
2026/9/2 23:29:39 网站建设 项目流程

简介:这是一套用于日常医院管理的 JavaScript 系统源码,面向医疗信息化学习者与 Web 全栈开发者。系统按角色拆分为患者、医生、管理三大模块:患者可预约挂号、查看历史预约并维护个人数据;医生能添加/删除患者、撰写处方、查看和回复预约;管理员则可统览患者、医生、预约及反馈,并增删医生账户。资源压缩包共 2000 个文件,以 JS 逻辑文件为主,同时包含大量 SVG 图标、CSS/SCSS 样式、TypeScript 类型定义、HTML 页面、PHP 接口及 SQL 数据库脚本,整体大小约 50.49MB。目录结构延续 AdminLTE 等成熟后台模板,便于按模块定位代码。目前已有 152 人学习下载。整套代码角色权限清晰,预约与处方流程完整,适合作为课程设计、毕业设计或医院管理系统的二次开发基础,也能帮助读者理解前后端交互与后台管理页面的组织方式。

1. hospital-management-esystem到底在管什么

我第一次看到这个项目名的时候,第一反应是“又一套CRUD”。但真把医院日常管理系统的需求捋下来,才发现它和普通的进销存、OA系统完全不是一个量级的东西。它管的不只是“数据”,而是整个医院的业务流转、科室协同、财务对账和医疗质量追溯。

先明确一个概念:hospital-management-esystem这类系统,在国内医院场景里通常被称为HIS(Hospital 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 Boot(Java系)或者FastAPI(Python系),前端用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风格,使用标准的状态码和错误信息结构,哪怕是内部系统之间调用也要这样。

踩过几次坑之后我的体会是,医院管理系统的难点从来不在技术,而在对医疗业务的理解。技术方案网上都能查到,但“药品为什么不能直接改库存”“退费为什么必须原路返回”“处方为什么不允许随便删改”这些问题是查不到答案的。把一个日常医院管理系统做好,本质上是在帮医院把“谁在什么时候对哪个患者做了什么”这件事变得清晰可查,这比任何花哨的技术架构都重要。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询