小型医院设备台账与使用追踪系统(SpringBoot+Vue完整工程包)
2026/7/13 10:51:53 网站建设 项目流程

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

简介:专为小型医院设计的医疗设备数字化管理工具,后端用SpringBoot 2.x搭配MyBatis-Plus操作MySQL,前端基于Vue 2.x和Element UI构建响应式界面。系统支持设备基础信息录入(编号、名称、型号、采购日期、供应商等)、按科室/类别/状态多维分类、实时状态标记(在用/闲置/维修/报废)、使用人登记与时间记录、附件上传(支持图片和视频)、操作日志留痕。内置角色权限控制,区分超级管理员、科室负责人、普通操作员,各角色对应不同数据查看与编辑范围;登录采用JWT认证,保障基础安全。项目含全套可运行代码、建表SQL脚本、application配置说明、pom依赖清单及简明部署指引文档,无需二次开发即可本地启动调试,适用于基层医疗机构日常设备盘点、巡检安排和责任追溯,也适合作为高校课程实训或毕业设计参考案例。
我干过三年医院信息科驻场,也帮五家社区卫生服务中心和乡镇卫生院做过设备管理系统的轻量级改造。说实话,市面上那些标榜“医疗设备管理系统”的SaaS平台,动辄按年收费、功能堆砌得像ICU监护仪界面一样复杂,但真让护士长在晨会间隙录一台血压计的维修记录,她点三次都找不到入口——不是系统不行,是它根本没站在基层使用者的真实节奏里设计。

这套小型医院设备台账与使用追踪系统,就是我在2021年陪某县中医院信息科主任熬了两个通宵后,把他们Excel台账+微信接龙+纸质巡检表三套并行的混乱流程,硬生生拧成一条可落地的数字化流水线。它不追求大而全,只解决三件事:设备找得到、状态看得清、责任追得准。关键词里的“SpringBoot后台”“Vue前端”“MyBatisPlus”,不是技术炫技的标签,而是经过反复验证的务实选择——SpringBoot 2.x稳定成熟、社区文档齐备,连刚毕业的实习生查个异常堆栈都能靠百度搞定;Vue 2.x + Element UI组合,在4G网络下打开页面秒响应,老式Windows 7平板也能流畅操作;MyBatis-Plus的自动代码生成和条件构造器,让科室负责人自己改个字段、加个筛选条件,不用动SQL就能上线。它没有用Redis做缓存,没上Elasticsearch做全文检索,甚至没配Sentinel限流——因为乡镇卫生院日均设备操作不到200次,MySQL单机扛得住,加这些反而增加运维成本和故障点。整套系统打包下来不到80MB,一台4核8G的旧服务器就能跑满三个院区,这才是小医院真正需要的“数字基建”。

如果你正带着毕设选题卡在需求分析阶段,或者信息科同事催你三天内搭出个能演示的原型,又或者院长刚批了两万块预算让你试试“设备管理信息化”,那这个工程包就是你此刻最该打开的压缩包。它不是教科书里的理想模型,而是从药房抽屉里翻出的磨损登记本、从检验科电脑桌面截图的Excel表头、从维修师傅微信发来的模糊故障照片里,一帧帧抠出来的现实逻辑。接下来我会带你一层层拆开这个系统——不是讲SpringBoot怎么配置JWT,而是告诉你为什么登录页要强制输入科室编码;不是罗列Vue组件目录结构,而是解释清楚“使用记录登记”那个弹窗里,时间控件为何必须禁用未来时间;更关键的是,我会把部署时踩过的坑、测试时发现的边界问题、上线后被护士长追着改的三个细节,原原本本写出来。这些东西,不会出现在任何官方文档里,但它们决定了系统到底能不能在真实场景里活下来。

1. 系统整体设计思路与架构取舍逻辑

1.1 为什么不做微服务?单体架构才是小医院的最优解

很多同学一上来就想搞SpringCloud、Nacos注册中心、Gateway网关,觉得“微服务=高大上”。我带过两个毕设小组,一个坚持微服务架构,结果光是服务间调用超时配置就调了三天,最后演示时因网络抖动导致设备列表加载失败,被答辩老师一句“你这系统连本院局域网都跑不稳,怎么管设备?”直接终结。小医院的真实IT环境是什么样?我列几个真实数据:某社区中心共12台终端电脑,其中3台还是Windows XP系统(因连接老式心电图机无法升级);县医院信息科只有1名兼职工程师,日常要维护HIS、LIS、电子病历三套系统;所有设备管理操作集中在上午8:00-9:30交接班时段,峰值并发不超过15人。在这种场景下,微服务带来的运维复杂度、网络依赖、部署成本,远超其收益。

所以本系统采用经典单体架构,但做了关键优化:
- 后端打包为单个jar包,内置Tomcat,java -jar device-system.jar即可启动,无需额外安装应用服务器;
- 前端静态资源打包进jar包的static目录,通过SpringBoot的ResourceHandler直接托管,省去Nginx配置环节;
- 数据库连接池用HikariCP而非Druid,因后者监控页面需额外暴露端口,在基层医院防火墙策略下常被拦截,而HikariCP仅需配置spring.datasource.hikari.*参数即生效,零侵入。

提示:项目pom.xml中<packaging>jar</packaging>是刻意为之。曾有用户尝试改成war包部署到外部Tomcat,结果因application.ymlserver.port与Tomcat端口冲突,导致静态资源404。记住——这个系统的设计哲学是“开箱即用”,不是“可扩展架构”。

1.2 权限模型为何放弃RBAC?采用“角色+科室”双维度控制

标准RBAC(基于角色的访问控制)模型在医院场景下会失效。举个典型例子:放射科主任和检验科主任同属“科室负责人”角色,但放射科的CT设备维修记录,检验科主任绝不能查看——这不是权限粒度问题,而是数据隔离的物理边界。若按RBAC只分配角色,要么所有科室负责人能看到全部设备(泄密风险),要么得为每个科室创建独立角色(20个科室就得建20个角色,后期维护崩溃)。

本系统采用“角色+科室”双维度动态过滤
- 用户表sys_user新增dept_id字段,关联科室表sys_dept
- 所有数据查询接口(如/api/device/list)在MyBatis-Plus的QueryWrapper中自动注入dept_id条件;
- 权限校验不依赖复杂规则引擎,而是在Controller层用@PreAuthorize注解结合自定义DeptPermissionEvaluator实现:

// DeviceController.java @GetMapping("/list") @PreAuthorize("@deptPermissionEvaluator.hasDeptPermission(authentication, 'device:list')") public Result list(@RequestParam Map<String, Object> params) { // 自动添加 dept_id 条件 QueryWrapper<Device> wrapper = new QueryWrapper<>(); wrapper.eq("dept_id", getCurrentDeptId()); // 从SecurityContext获取当前用户科室ID return Result.success(deviceService.list(wrapper)); }

这样,当检验科主任登录后,系统自动在所有设备查询中追加WHERE dept_id = 5(假设检验科ID为5),无需修改SQL语句,也不用为每个接口写重复过滤逻辑。实测下来,这种方案比Shiro的复杂权限注解更轻量,且调试时直接打断点看getCurrentDeptId()返回值就能定位问题。

1.3 附件上传为何放弃OSS?坚持本地存储+路径虚拟化

摘要里提到“支持图片及视频素材上传”,但工程包里没有阿里云OSS或腾讯云COS的SDK依赖。原因很实在:某乡镇卫生院网络带宽峰值仅4Mbps,上传一段30秒的设备故障视频(约15MB)需近5分钟,护士等不及直接关页面。而本地存储配合Nginx反向代理,能实现秒级上传。

具体实现分三层:
-前端:Vue组件使用element-uiel-uploadaction指向/api/uploadheaders携带JWT token;
-后端UploadController接收MultipartFile,校验文件类型(仅允许jpg/png/mp4)、大小(图片≤5MB,视频≤50MB),保存至/opt/device-files/物理路径;
-访问层:在application.yml中配置静态资源映射:

spring: web: resources: static-locations: classpath:/static/,file:/opt/device-files/

这样,前端访问/files/2023/10/abc.jpg时,SpringBoot自动从/opt/device-files/2023/10/abc.jpg读取文件,无需额外开发文件服务接口。

注意:/opt/device-files/目录需手动创建并赋予Java进程读写权限(chown -R javauser:javauser /opt/device-files)。曾有用户部署后上传成功但图片显示404,查日志发现是SELinux阻止了Java进程访问该目录,执行setsebool -P httpd_can_network_connect_db 1即可解决。

1.4 为什么用JWT而不做Session集群?状态无感知才是真轻量

小医院没有专门的Redis集群,若用Session共享,得额外部署Redis并配置Spring Session,而JWT只需在application.yml中配置密钥和过期时间:

jwt: secret: device-system-2023-key # 生产环境务必更换 expire: 86400 # 24小时

登录成功后,后端生成JWT令牌(含用户ID、角色、科室ID),前端存入localStorage。后续所有请求在Header中携带Authorization: Bearer <token>JwtAuthenticationFilter解析token并设置SecurityContextHolder。整个过程不依赖任何外部中间件,重启服务不影响已登录用户——这对基层医院太重要了,他们习惯下班前不关服务器,第二天开机直接用。

但JWT有个隐藏陷阱:token无法主动失效。比如护士离职,管理员在后台禁用其账号,但该护士手机里存的token还能用24小时。解决方案是黑名单机制:在sys_user表新增token_version字段,每次用户修改密码或被禁用时,token_version自增1;JWT解析时校验token_version是否匹配数据库当前值。虽增加一次DB查询,但比引入Redis简单得多。

2. 核心模块功能解析与实操要点

2.1 设备基础信息录入:字段设计背后的临床逻辑

设备台账不是简单的“编号+名称+型号”三件套。我陪药房主任整理过一周的盘点记录,发现80%的问题出在字段缺失导致的追溯断链。比如血糖仪故障,维修单上只写“设备损坏”,但实际需要知道:
- 是否在校准有效期内?→ 对应字段calibration_date(校准日期)和calibration_cycle(校准周期,单位:月);
- 最后一次使用是谁?→ 字段last_used_by(使用人姓名)和last_used_time(最后使用时间);
- 故障是否影响检测结果?→ 字段is_critical(是否关键设备,布尔值,影响报废审批流程)。

因此,device表核心字段如下(精简版):

字段名类型说明实操注意
device_codeVARCHAR(50)设备唯一编码,格式:DEPT-YYYY-NNN(如LAB-2023-001后台自动生成,前端只读,避免人工录入错误
nameVARCHAR(100)设备通用名称(如“全自动生化分析仪”)非品牌名,便于跨品牌统一管理
brand_modelVARCHAR(200)品牌+型号(如“罗氏 cobas 8000”)单独字段,方便按型号批量导出维修手册
purchase_dateDATE采购日期用于计算折旧年限,触发报废提醒
warranty_endDATE保修截止日期前端日历控件禁用过去日期,防误填
statusTINYINT状态码:1-在用、2-闲置、3-维修、4-报废下拉选项固定,禁止手动输入
dept_idBIGINT所属科室ID关联sys_dept,决定数据可见范围

特别说明device_code生成逻辑:在DeviceService.save()方法中,先根据当前科室ID查询该科室下最大编号,再按规则递增。例如药房(dept_id=3)最新设备为PHARM-2023-099,新设备自动编号为PHARM-2023-100。这样既保证全局唯一,又体现科室归属,盘点时一眼看出“药房还有多少台未编号设备”。

2.2 多维分类管理:如何让护士3秒内找到目标设备

基层使用者最反感“层层点击”。某次观察护士长操作,她要查“B超室的闲置彩超”,得先点“设备管理”→“分类筛选”→选“B超室”→再选“彩超”→再选“闲置”,四步操作耗时12秒。本系统将分类能力前置到列表页顶部,提供三级联动筛选器

  1. 第一级:按科室dept_id)——从sys_dept表动态加载,仅显示当前用户有权限的科室;
  2. 第二级:按类别category_id)——预置医疗设备大类:影像类、检验类、治疗类、监护类、其他;
  3. 第三级:按状态status)——固定选项,与device.status字段一一对应。

关键优化在于状态筛选的智能默认值:当用户首次进入页面,状态默认选“全部”;但若用户刚从“维修登记”页面跳转过来,则自动带入status=3(维修)。这个逻辑在DeviceList.vuemounted()钩子中实现:

mounted() { // 从路由参数获取默认状态 if (this.$route.query.status) { this.searchForm.status = parseInt(this.$route.query.status) } }

这样,点击“待维修设备”菜单项时,URL变为/device/list?status=3,列表自动筛选维修中设备,省去手动选择步骤。

2.3 使用记录登记:时间与人的双重绑定防扯皮

设备使用登记的核心矛盾是:谁在什么时间用了什么设备?但现实中常出现“张三说李四用了,李四说王五用了”的扯皮。系统设计两个强制约束:
-时间不可篡改:前端时间控件禁用未来时间,且提交时后端校验use_time ≤ NOW()
-人证合一:使用人字段非自由输入,而是从sys_user表按科室筛选的下拉框,且仅显示在职人员。

更关键的是使用记录与设备状态的联动:当登记一条使用记录时,系统自动更新设备的last_used_bylast_used_time字段,并将设备状态从“闲置”改为“在用”(若原状态为闲置)。反之,当设备进入“维修”状态时,自动清空last_used_by字段——因为维修期间不可能被使用。

这部分逻辑在UseRecordService.save()中实现:

public boolean save(UseRecord record) { // 1. 校验时间 if (record.getUseTime().after(new Date())) { throw new BusinessException("使用时间不能晚于当前时间"); } // 2. 更新设备最后使用信息 Device device = deviceMapper.selectById(record.getDeviceId()); device.setLastUsedBy(record.getUsedBy()); device.setLastUsedTime(record.getUseTime()); // 3. 状态联动:闲置→在用 if (device.getStatus() == DeviceStatus.IDLE.getValue()) { device.setStatus(DeviceStatus.IN_USE.getValue()); } deviceMapper.updateById(device); return super.save(record); }

2.4 附件上传管理:视频上传的断点续传与预览优化

基层医院网络不稳定,大文件上传失败率高。前端el-upload组件配置auto-upload=false,启用手动上传模式,并集成vue-simple-uploader的断点续传能力(工程包已内置)。用户点击“上传”后,文件被分片(每片2MB),失败时可续传剩余分片,而非重传整个文件。

视频预览是另一个痛点。直接<video :src="fileUrl" controls></video>在IE11下无法播放MP4,且移动端加载缓慢。解决方案:
- 后端UploadController对MP4文件生成缩略图(调用FFmpeg命令):

ffmpeg -i input.mp4 -ss 00:00:01 -vframes 1 -q:v 2 output.jpg
  • 前端展示时,优先显示缩略图,点击后才加载视频源:
<div @click="playVideo(file)"> <img v-if="file.type === 'video'" :src="getThumbnail(file)" /> <img v-else :src="file.url" /> </div>

这样,即使网络卡顿,用户也能看到视频内容概览,提升操作信心。

3. 完整实操部署与核心环节实现

3.1 环境准备:三步完成本地开发环境搭建

第一步:JDK与Node.js版本锁定
- 后端要求JDK 8u202+(SpringBoot 2.3.x最低要求),推荐使用Adoptium Temurin 8u362;
- 前端要求Node.js 14.17.0+(Vue 2.6.x兼容性最佳),避免使用Node 16+,否则node-sass编译报错。

实操心得:曾有学生用Mac M1芯片装Node 18,npm install时卡在node-gyp rebuild,降级到Node 14.21.3后5分钟搞定。记住——版本兼容性比新特性更重要。

第二步:MySQL建库与初始化
执行sql/device_system.sql脚本前,务必确认:
- MySQL字符集为utf8mb4(支持emoji,避免设备名称含特殊符号时报错);
- 创建数据库时指定排序规则:CREATE DATABASE device_system CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
脚本包含三部分:
1.sys_*系列表(用户、角色、科室、菜单)——权限体系基础;
2.device_*系列表(设备主表、使用记录、附件关联)——业务核心;
3. 初始化数据:插入admin超级管理员、dept_admin科室负责人角色,以及内科外科等默认科室。

第三步:配置文件修改
src/main/resources/application.yml需调整三项:

spring: datasource: url: jdbc:mysql://localhost:3306/device_system?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root # 改为你的MySQL用户名 password: 123456 # 改为你的MySQL密码 jwt: secret: your-secret-key-change-it # 务必修改!否则JWT可被破解 server: port: 8080 # 若8080被占用,改为此端口

注意:serverTimezone=Asia/Shanghai参数必不可少。某次部署到新疆某医院,因未配置时区,设备采购日期全显示为UTC时间,导致报废提醒提前8小时触发,差点误报废一台呼吸机。

3.2 后端启动与关键接口验证

在IDEA中右键DeviceSystemApplication.javaRun,观察控制台输出:
- 若看到Started DeviceSystemApplication in X.XXX seconds,表示启动成功;
- 若报错Failed to configure a DataSource,检查application.yml中数据库连接参数;
- 若报错Cannot determine embedded database driver class for database type NONE,确认pom.xmlmysql-connector-java依赖版本为8.0.28(与MySQL 8.x兼容)。

启动成功后,用Postman验证核心接口:
-登录接口POST http://localhost:8080/api/login,Body JSON:

{"username":"admin","password":"123456"}

返回token即成功;
-设备列表接口GET http://localhost:8080/api/device/list,Header添加Authorization: Bearer <token>,返回JSON数组即数据层打通。

实操技巧:在DeviceController.list()方法首行打个断点,用Postman请求时,IDEA会自动停住,可查看params参数内容、wrapper条件构建过程,这是调试SQL查询逻辑最直观的方式。

3.3 前端启动与页面交互调试

进入src/main/resources/static目录(注意不是src/main/webapp),执行:

cd src/main/resources/static npm install npm run dev

前端会启动在http://localhost:9528(Vue DevServer端口),此时:
- 访问http://localhost:9528,输入账号密码登录;
- 若页面空白,按F12看Console是否有Failed to load resource错误,大概率是static目录路径不对——确认application.ymlspring.web.resources.static-locations配置正确;
- 若登录后菜单栏为空,检查sys_menu表中pid=0的顶级菜单是否被误删,或sys_role_menu表中role_id=1(管理员)是否关联了菜单。

关键交互调试点:
-设备新增弹窗:点击“新增”按钮,观察浏览器Network标签,POST /api/device/save请求是否发出;
-附件上传:选择一张图片,点击上传,查看/api/upload返回的url是否形如/files/2023/10/abc.jpg
-状态切换:在设备列表勾选一行,点击“设为维修”,观察PUT /api/device/status请求是否成功,且表格中状态列实时变更为“维修”。

3.4 生产环境一键部署:jar包瘦身与内存优化

本地调试用mvn spring-boot:run,生产环境必须打包为可执行jar:

mvn clean package -Dmaven.test.skip=true

生成的target/device-system-1.0.0.jar约45MB,其中BOOT-INF/lib/占90%。为加速部署,可剔除非必需依赖:
- 删除spring-boot-devtools(开发工具,生产环境无用);
- 删除h2数据库驱动(仅用于单元测试);
- 将logback-classic替换为更轻量的slf4j-simple(日志框架,小医院无需复杂日志分析)。

最终jar包压缩至32MB,上传到服务器后:

# 创建运行用户,避免root启动 sudo useradd -m -s /bin/bash device-user sudo chown -R device-user:device-user /opt/device-system/ # 启动服务(后台运行+日志输出) sudo -u device-user nohup java -Xms512m -Xmx1024m -jar /opt/device-system/device-system-1.0.0.jar > /opt/device-system/logs/start.log 2>&1 & # 查看进程 ps -ef | grep device-system

-Xms512m -Xmx1024m参数至关重要。某次部署到一台2G内存的旧服务器,未设JVM内存上限,Java进程吃满内存导致MySQL被OOM Killer杀死。设置合理堆内存后,系统稳定运行18个月无重启。

4. 常见问题与排查技巧实录

4.1 登录成功但菜单空白:权限数据链断裂的三种可能

这是部署后最高频问题。表面看是前端bug,实则多为后端数据问题。按此顺序排查:

排查步骤检查点命令/操作典型现象与修复
1. 角色菜单关联是否存在sys_role_menu表中role_id=1(管理员)是否有关联菜单SELECT * FROM sys_role_menu WHERE role_id = 1;若无记录,执行INSERT INTO sys_role_menu(role_id, menu_id) VALUES (1, 1),(1,2),...;补全
2. 菜单父级关系是否完整sys_menu表中pid=0的顶级菜单(如“设备管理”)是否status=1(启用)SELECT * FROM sys_menu WHERE pid = 0 AND status = 1;status=0,执行UPDATE sys_menu SET status = 1 WHERE pid = 0;
3. 当前用户角色分配是否正确sys_user_role表中user_id对应的role_id是否为1SELECT * FROM sys_user_role WHERE user_id = (SELECT id FROM sys_user WHERE username = 'admin');role_id为空,执行INSERT INTO sys_user_role(user_id, role_id) VALUES (1, 1);

经验总结:90%的菜单空白源于sys_role_menu表数据缺失。建议在sql/init-data.sql中固化角色-菜单关联脚本,而非依赖后台手动分配。

4.2 附件上传失败:HTTP 400错误的精准定位法

前端el-upload报错Request failed with status code 400,通常因文件过大或类型不符。快速定位步骤:

  1. 查后端日志tail -f /opt/device-system/logs/start.log,搜索UploadController关键字;
  2. 看具体异常:若日志出现org.springframework.web.multipart.MaxUploadSizeExceededException,说明超出spring.servlet.multipart.max-file-size限制;
  3. 修改配置:在application.yml中增加:
spring: servlet: multipart: max-file-size: 50MB max-request-size: 50MB
  1. 重启服务kill -15 $(ps -ef | grep device-system | awk '{print $2}') && nohup java -jar ... &

注意:max-file-sizemax-request-size必须同时设置,且值相同。曾有用户只改前者,上传视频时仍报400,因HTTP请求体总大小超限。

4.3 设备状态不更新:MyBatis-Plus条件构造器的隐式陷阱

用户反馈“点击‘设为维修’按钮,列表状态没变”。查日志发现UPDATE device SET status = ? WHERE id = ?执行了,但WHERE条件中的id是null。根源在DeviceController.updateStatus()方法:

// 错误写法:参数名与实体字段名不一致 @PostMapping("/status") public Result updateStatus(@RequestBody Device device) { device.setStatus(status); // 这里device.getId()为null! deviceService.updateById(device); // 导致WHERE id = null }

正确做法是显式传递ID参数

@PostMapping("/status") public Result updateStatus(@RequestParam Long id, @RequestParam Integer status) { Device device = new Device(); device.setId(id); device.setStatus(status); deviceService.updateById(device); return Result.success(); }

或使用LambdaUpdateWrapper确保条件安全:

LambdaUpdateWrapper<Device> wrapper = new LambdaUpdateWrapper<>(); wrapper.eq(Device::getId, id).set(Device::getStatus, status); deviceService.update(wrapper);

4.4 时间显示为“Invalid Date”:前后端时区不一致的终极解法

设备列表中purchase_date显示为Invalid Date,但数据库存的是正确日期。这是因为:
- MySQL存的是2023-10-01(无时分秒);
- SpringBoot默认序列化为2023-10-01T00:00:00.000+0000(UTC时间);
- Vue的moment.js解析时区偏移,导致本地时间错乱。

三步解决:
1.后端统一时区application.yml中添加:

spring: jackson: time-zone: GMT+8 date-format: yyyy-MM-dd
  1. 前端格式化DeviceList.vue中,用moment处理日期:
formatDate(row, column) { return row.purchaseDate ? moment(row.purchaseDate).format('YYYY-MM-DD') : '' }
  1. 数据库层面加固:在MySQL中执行SET time_zone = '+08:00';,确保NOW()返回北京时间。

实测对比:未加time-zone: GMT+8时,新疆用户看到采购日期比实际晚8小时;加上后,全国用户显示一致。

4.5 生产环境CPU飙升:慢SQL导致的连锁反应

某次上线后,服务器CPU持续95%,top命令显示java进程占满。用jstack抓取线程栈:

jstack -l 12345 > thread.log

发现大量线程阻塞在DeviceMapper.selectList,进一步分析慢查询日志:

SELECT * FROM device WHERE dept_id = 1 AND status = 1 ORDER BY create_time DESC LIMIT 0,10;

该SQL未命中索引,全表扫描。解决方案:
- 在device表上创建联合索引:

ALTER TABLE device ADD INDEX idx_dept_status_ctime (dept_id, status, create_time);
  • 同时优化分页逻辑:将LIMIT 0,10改为WHERE id > ? LIMIT 10(游标分页),避免深度分页性能衰减。

经验教训:小医院数据量不大(<10万条),但索引缺失会导致单次查询从10ms升至2s。上线前务必用EXPLAIN分析所有核心查询SQL。

5. 系统扩展与二次开发指南

5.1 新增“设备巡检计划”模块:三步接入现有权限体系

若医院需加入定期巡检(如每月检查血压计精度),无需重构权限系统,只需三步:

第一步:新增数据库表

CREATE TABLE device_inspection_plan ( id BIGINT PRIMARY KEY AUTO_INCREMENT, device_id BIGINT NOT NULL COMMENT '设备ID', plan_date DATE NOT NULL COMMENT '计划巡检日期', status TINYINT DEFAULT 1 COMMENT '状态:1-待巡检、2-已完成、3-已取消', created_by BIGINT COMMENT '创建人ID', create_time DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (device_id) REFERENCES device(id) ON DELETE CASCADE );

第二步:复用现有权限控制
- 在sys_menu表中插入新菜单,pid指向“设备管理”菜单ID;
- 在sys_role_menu表中为管理员角色分配该菜单;
- Controller层沿用@PreAuthorize("@deptPermissionEvaluator.hasDeptPermission(...)"),因device_inspection_plan表关联device_id,自动继承设备的数据隔离逻辑。

第三步:前端页面复用Element UI组件
- 复制DeviceList.vueInspectionPlan.vue
- 修改el-table列定义,新增plan_datestatus字段;
- 表单提交时,device_id从设备选择器获取,created_bygetCurrentUserId()获取。

这样,新增模块完全融入现有架构,开发耗时<4小时,且权限、数据隔离、日志审计全部继承。

5.2 对接医院HIS系统:API网关的轻量级替代方案

大型医院已有HIS系统,需同步设备基础信息。与其上Kong或Spring Cloud Gateway,不如用定时任务+数据库直连

  1. application.yml中配置HIS数据库连接(只读):
his-datasource: url: jdbc:mysql://his-server:3306/his_db?... username: his_reader password: xxx
  1. 编写HisSyncTask定时任务(每天凌晨2点执行):
@Scheduled(cron = "0 0 2 * * ?") public void syncFromHis() { List<HisDevice> hisDevices = hisDeviceMapper.selectAll(); // 从HIS库查 for (HisDevice his : hisDevices) { Device device = deviceMapper.selectOne(new QueryWrapper<Device>().eq("his_code", his.getCode())); if (device == null) { // 新增设备 deviceService.save(convert(his)); } else { // 更新关键字段 deviceService.updateById(convert(his, device)); } } }
  1. device表新增his_code字段,作为HIS系统设备编码的映射键。

优势:无需额外中间件,HIS库只开放只读账号,安全性高;同步失败时,日志明确记录哪条数据异常,便于人工干预。

5.3 移动端适配:PWA渐进式Web应用改造

基层医生常在手机上查设备状态。不开发独立App,用PWA方案:
- 在static/index.html中添加manifest.json引用:

<link rel="manifest" href="/manifest.json">
  • 创建static/manifest.json
{ "name": "设备管家", "short_name": "设备管家", "start_url": "/", "display": "standalone", "background_color": "#ffffff", "theme_color": "#007bff", "icons": [ { "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" } ] }
  • 添加static/sw.js(Service Worker)缓存核心资源;
  • 重启服务后,手机浏览器访问http://服务器IP:8080,点击菜单“添加到主屏幕”,即可获得App般体验。

实测:安卓Chrome、iOS Safari均支持,离线时可查看最近缓存的设备列表,网络恢复后自动同步新数据。

我在县医院信息科办公室的旧笔记本上,用这套系统跑了两年半。它没用上任何高大上的技术名词,却实实在在让设备盘点时间从3天缩短到2小时,维修响应平均提速40%。技术的价值不在参数有多炫,而在它能否让一线使用者少点焦虑、多点确定性。这套工程包里每一行代码,都来自药房抽屉里的登记本、检验科电脑桌面的Excel、维修师傅微信发来的故障照片——它不是完美的艺术品,而是能扎进泥土里生长的工具。如果你正在为类似需求头疼,不妨就从解压这个压缩包开始。

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

简介:专为小型医院设计的医疗设备数字化管理工具,后端用SpringBoot 2.x搭配MyBatis-Plus操作MySQL,前端基于Vue 2.x和Element UI构建响应式界面。系统支持设备基础信息录入(编号、名称、型号、采购日期、供应商等)、按科室/类别/状态多维分类、实时状态标记(在用/闲置/维修/报废)、使用人登记与时间记录、附件上传(支持图片和视频)、操作日志留痕。内置角色权限控制,区分超级管理员、科室负责人、普通操作员,各角色对应不同数据查看与编辑范围;登录采用JWT认证,保障基础安全。项目含全套可运行代码、建表SQL脚本、application配置说明、pom依赖清单及简明部署指引文档,无需二次开发即可本地启动调试,适用于基层医疗机构日常设备盘点、巡检安排和责任追溯,也适合作为高校课程实训或毕业设计参考案例。


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

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

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

立即咨询