资讯动态

Django+Vue3医院医疗设备维修管理系统实战指南

发布时间:2026/10/15 16:23:38 来源:尧图企业网站定制
医院设备科的报修群每天从早响到晚。呼吸机的光耦烧了、心电监护仪的导联线断了、CT机房的温度报警又触发了……报修信息零散地堆在微信里维修工程师背着工具包满楼跑事后的记录要么写在纸质本子上要么压根没写。等到年底盘点设备完好率统计报表只能靠人工翻聊天记录拼凑。我最早接触“python-django医院医疗设备维修管理系统vue3”这个项目就是在这样的背景下——设备科需要一个能替代微信群报修、把工单流转、设备台账、维修历史、统计报表全部线上化的系统后端用Django提供稳定的API服务前端用Vue3搭建操作界面。这篇博文会把整个项目的需求拆解、技术选型、数据库设计、实际开发步骤和踩坑经验完整讲一遍适合正在做医疗信息化、设备管理系统或者打算用DjangoVue3做业务管理系统的人参考。1. 项目整体设计与技术选型拆解1.1 标题背后的真实需求是什么只看“医院医疗设备维修管理系统”这几个字很容易做成一个普通的“报修工单系统”。但真正在一家综合医院里跑过设备管理的人会告诉你核心痛点远不止“报修、派单、完单”这么简单。医院设备大致分三类大型影像设备CT、MRI、DR、生命支持设备呼吸机、麻醉机、监护仪、通用后勤设备消毒机、血压计、输液泵。每一类设备的生命周期管理要求完全不同比如呼吸机这类急救设备维修响应时间按分钟算验收记录要能追溯到具体维修人员CT这类大型设备除了维修单还需要关联巡检计划、保养记录、原厂服务合同。系统如果只做“报修单”这一个对象后续十有八九要返工。我把标题拆开看真正的需求应该包含四块一是设备台账数字化给每台设备一个独立ID沉淀购置信息、科室归属、使用状态二是维修工单全流程流转从报修、派单、接单、维修、验收、归档每一步有记录、有人负责三是维修历史与费用统计能够查询某台设备修过几次、换过什么配件、花了多少钱四是直观的数据看板设备完好率、科室报修排行、维修及时率这些指标管理员打开系统就能看到。这套逻辑放在Django项目里对应的是设备管理、工单管理、备件管理、统计报表、用户权限五大模块。我建议第一版就按这个边界划分app而不是把所有表都塞进一个app里后面扩展时你会感谢这个决定。1.2 为什么是Django Vue3而不是其他方案技术选型这块我在做方案评审时反复比过。后端如果图省事可以直接用Django的模板系统加Admin十天就能出一个能用的内部系统。但考虑到医院信息科未来大概率要对接HIS、LIS或者物资系统接口必须标准化前后端分离是更稳的选择。Django作为后端框架在医疗信息类项目里有几个天然优势。ORM足够成熟不用手写SQL就能做多表联查自带Admin后台开发阶段给设备科做基础数据维护界面几乎零成本Django REST FrameworkDRF把序列化、分页、认证、权限这些API开发必备的东西全封装好了开发者能集中精力写业务逻辑。另外Python生态里有大量医疗数据处理相关的库哪怕以后要做设备数据采集分析后端语言保持不变也能平滑扩展。前端选Vue3一方面是因为Element Plus提供了一整套中后台管理组件表格、表单、弹窗、日期选择器开箱即用很适合设备管理这类功能密集的管理系统另一方面Vue3的Composition API在维护复杂页面状态时比Vue2的Options API更顺手一个维修工单详情页要同时展示设备信息、维修步骤时间线、配件清单、操作按钮这种多状态联动的场景非常适合用Composition API组织逻辑。另一点容易被忽略的是团队招聘成本。国内做医疗信息化的技术团队大部分人熟悉Python和Vue招人比找Rails或者Angular的人容易得多。技术选型不是越新越好而是要考虑团队能长期维护。这一点在医疗项目里尤为重要系统交付后往往要维护五六年。1.3 系统架构与核心模块设计整个系统采用前后端分离的单体架构Django提供REST APIVue3打包成静态文件后由Nginx托管两边的数据交互走JSON。医院内网环境下单体架构比微服务更容易部署和排查问题一台内网服务器就能跑起来。业务模块划分如下设备管理设备台账、设备分类、设备档案详情、设备保养计划工单管理报修单创建、待派单列表、维修记录填报、验收/关闭工单备件管理备件出入库、备件与维修工单关联统计报表设备完好率、科室报修排行、工程师工作量、维修费用统计系统管理用户管理、角色权限、数据字典、操作日志工单是贯穿这套系统的核心对象。一台设备从报修到归档数据链条是这样的报修人从设备台账里选择故障设备创建报修单设备科管理员在待派单列表里指派工程师工程师接单后填写故障原因、维修措施、更换配件最后报修人或者管理员验收并关闭工单。每一步状态变化系统都要写一条操作记录。这套设计对医院场景有一个很关键的好处任何一台设备出事都能查清楚“谁报修的、谁修的、换了什么、修了多久、花了多少钱”。一旦出现医疗设备相关的事故纠纷这套审计链条是设备科最有力的说明依据。2. 核心细节解析与关键模型设计2.1 设备台账模型主数据是一切的基础设备台账是这套系统里最不能糊弄的部分因为所有工单、报表都挂在设备ID下面。如果设备编码混乱、科室归属不清后续的统计全都会失真。我在设计Device模型时核心字段分了四类。身份标识类包含设备编码、设备名称、出厂编号、资产编号分类属性类包含设备分类外键、型号、生产厂家、供应商位置与状态类包含所属科室、安装位置、设备状态、启用日期合同与财务类包含购置日期、购入金额、保修截止日期、折旧状态。设备分类我单独建了一张自关联的DeviceCategory表支持二级分类比如“生命支持设备-呼吸机-有创呼吸机”这样后续统计可以按大类或者小类分别聚合。字段类型上有几个细节值得展开说。设备编码设置uniqueTrue同时用Django的db_indexTrue建索引因为设备编码会高频出现在查询条件和报表分组里。生产厂家和供应商这类字段看起来像是字符串但建议单独建表存避免出现“某公司”和“某公司 ”带空格这种脏数据。设备的扩展属性比如CT的球管使用次数、核磁共振的液氦剩余量不同设备差别很大用JSONField存灵活性最高不必为每种设备单独建字段。注意设备编码规则要在开发前跟设备科确认好。我见过一个项目设备科报上来的编码规则和资产科的系统对不上导致系统上线前要重刷几千条数据。最稳妥的做法是把设备编码设计成“科室缩写设备类型流水号”并且保证全系统唯一。关键要理解为什么台账要独立成模块而不是塞在维修工单里。工单系统关注的是“某一次维修过程”而台账关注的是“这台设备的全生命周期”。把两者分开设备每次维修后台账里的设备状态正常/维修中/待报废由工单完成事件驱动更新这样数据职责清晰不会出现多个人改同一个字段引起的数据不一致。2.2 维修工单的状态机与历史追踪维修工单是整个系统的核心流程载体。我见过不少初版设计把状态放在一个简单的CharField里然后视图函数里自由赋值结果线上跑一段时间后一个工单出现了“已验收”和“维修中”同时存在的混乱。原因就是没有在模型层约束状态流转。我的做法是在模型里定义状态常量同时写一个transition方法做状态流转校验。RepairOrder模型的核心字段包括工单号唯一、设备外键、报修人外键、故障描述、紧急程度、当前状态、派单时间、指派工程师、预计完成时间、实际完成时间、验收意见、故障分类。状态被严格定义为五个当前状态允许的操作目标状态操作角色pending待派单指派工程师processing维修中设备科管理员processing维修中填写维修记录accepting待验收维修工程师accepting待验收验收通过done已完成报修人/管理员accepting待验收验收驳回processing维修中报修人/管理员done已完成关闭归档closed已关闭设备科管理员在transition方法里每次状态变更都会写入一条OperationLog记录包含操作人、操作时间、旧状态、新状态、备注。这么做以后设备科领导追问“上个月CT机维修为什么拖了三天”只需要查询这台设备的工单流转记录就能还原整个过程而不是听维修工程师口头解释。除了主工单表我还设计了RepairLog维修日志子表。工程师在维修过程中可能多次进场每次进场换过什么配件、做过什么测试、耗了多少工时都作为独立记录追加到工单下。这样工单表本身保持精简只存流程状态而维修日志完整记录业务细节。查询历史时OrderLog负责“状态怎么变的”RepairLog负责“维修时做了什么”两条线互不干扰。2.3 角色权限与操作边界设计医院场景下的角色划分比较固定我按用户身份分成了四类科室报修人、设备科管理员、维修工程师、院方领导只读统计。不在这套系统里做超级复杂的RBAC矩阵因为一复杂现场维护人员就搞混了。具体权限用Django的Group加自建角色字段实现。报修人可以创建设备报修单查看自己发起的工单工程师可以查看被指派给自己的工单填写维修日志管理员拥有设备台账、工单派单、人员管理、报表查看的全部权限领导角色的代码里直接强制只读写操作一律拒绝。一个容易踩坑的地方是对象级权限。只有查询接口做了“用户只能看到自己的报修单”还不够如果维修接口没做同样的过滤工程师把工单号改成别人的单号就能越权操作。我后来统一在ViewSet的get_queryset里根据当前用户角色过滤数据源同时写了一个IsOwnerOrAdmin权限类放在写操作的permission_classes里双重校验。另外医院里有时候会有一个维修工程师处理多个科室设备的情况所以角色和科室之间做了多对多关联。一个工程师可以绑定“内科片区”和“外科片区”派单时系统会优先匹配同时满足设备类型和科室归属的工程师这个逻辑在后端接口里用一次内存筛选完成不需要引入复杂的调度引擎。2.4 数据库设计的避坑指南第一版设计最容易出现的四类问题我提前列出来供参考。第一忽略外键的级联策略。设备被删除时如果直接级联删除关联的维修工单历史数据会全部丢失。维修工单是医院设备管理的凭证性数据绝对不能物理删除。所以设备表和工单表统一用软删除加is_deleted字段查询时默认过滤掉已删除记录但原始数据永远留在库里。第二日期字段时区混乱。Django开启USE_TZTrue后数据库中存的是UTC时间前端拿到的JSON是带时区的ISO格式。如果前端组件不做处理直接显示会出现报修时间比本地时间早8小时的问题。我在所有日期字段进入序列化器时统一转成Asia/Shanghai时区格式的字符串前端拿到的永远是本地化时间不用再做时区换算。第三备注和文本字段滥用TextField。故障描述、维修措施这类字段确实是TextField但“设备状态”“紧急程度”这类有固定枚举值的字段一定不要用TextField随便填。我见过有人把设备状态存成“正常”、“正常运行”、“好的”三种说法一个意思统计时却会被分到三个组里。所有枚举字段统一用IntegerField加choices映射输出时由序列化器翻译成中文标签。第四查询性能的隐性问题。工单列表页默认会带出设备名称、报修人姓名、工程师姓名三层关联如果不做select_related每展示一行工单就多出几次SQL查询列表70条数据可能要触发两百多次数据库查询。我所有list接口都会用select_related把设备、报修人、维修人的外键关系预加载出来这个优化在数据量上来后效果极其明显。3. 实操过程——完整搭建一套可运行的维修管理系统3.1 开发环境准备与项目初始化先说环境版本。一套相对稳妥的组合是Python 3.10、Django 4.2、Django REST Framework 3.14、Vue 3.3、Vite 5数据库开发环境用SQLite零配置跑通生产环境切换MySQL。这套组合的API完全兼容不用改业务代码。创建后端项目mkdir med-device-manager cd med-device-manager python -m venv venv source venv/bin/activate # Windows环境改执行venv/Scripts/activate pip install django djangorestframework django-cors-headers djangorestframework-simplejwt django-filter django-admin startproject config . python manage.py startapp devices python manage.py startapp workorders python manage.py startapp users python manage.py startapp commonINSTALLED_APPS里需要重点说明的是rest_framework、corsheaders、rest_framework_simplejwt这三个一定要放在新增业务app之前注册顺序错了中间件和认证配置不会生效。3.2 核心配置文件解读settings.py里有两个容易出错的地方。一个是数据库配置生产环境用MySQL时由于医院内网服务器通常没有外网额外安装mysqlclient需要提前准备离线包。另一个是DRF全局配置我建议这样写REST_FRAMEWORK { DEFAULT_AUTHENTICATION_CLASSES: ( rest_framework_simplejwt.authentication.JWTAuthentication, ), DEFAULT_PERMISSION_CLASSES: ( rest_framework.permissions.IsAuthenticated, ), DEFAULT_FILTER_BACKENDS: ( django_filters.rest_framework.DjangoFilterBackend, rest_framework.filters.SearchFilter, rest_framework.filters.OrderingFilter, ), DEFAULT_PAGINATION_CLASS: rest_framework.pagination.PageNumberPagination, PAGE_SIZE: 20, DATETIME_FORMAT: %Y-%m-%d %H:%M:%S, }这里把全局默认权限设为IsAuthenticated意味着所有未登录请求都会返回401避免哪个视图漏写权限装饰器导致接口裸奔。JWT的过期时间我设置为8小时医院内网系统里这个时间足够一个白班使用也避免了频繁重新登录的麻烦。CORS配置用django-cors-headers解决。前后端分离后本地开发时Vite端口是5173Django端口是8000不配CORS前端调接口会直接被浏览器拦截。配置时需要注意在DEBUG模式外生产环境不要轻易用CORS_ALLOW_ALL_ORIGINSTrue而是指定具体的内网域名这是从安全角度考虑的底线。3.3 设备与工单的模型代码实现设备模型的核心代码class Device(models.Model): code models.CharField(设备编码, max_length64, uniqueTrue, db_indexTrue) name models.CharField(设备名称, max_length128) category models.ForeignKey(DeviceCategory, on_deletemodels.PROTECT, verbose_name设备分类) model_name models.CharField(型号, max_length128, blankTrue) manufacturer models.CharField(生产厂家, max_length128) asset_no models.CharField(资产编号, max_length64, blankTrue) serial_no models.CharField(出厂编号, max_length64, blankTrue) department models.ForeignKey(Department, on_deletemodels.PROTECT, verbose_name所属科室) location models.CharField(安装位置, max_length255, blankTrue) status models.CharField(设备状态, max_length16, choicesDEVICE_STATUS, defaultnormal) purchase_date models.DateField(购置日期, nullTrue, blankTrue) purchase_price models.DecimalField(购置金额, max_digits12, decimal_places2, nullTrue, blankTrue) warranty_date models.DateField(保修截止日期, nullTrue, blankTrue) is_deleted models.BooleanField(已删除, defaultFalse) created_at models.DateTimeField(创建时间, auto_now_addTrue) updated_at models.DateTimeField(更新时间, auto_nowTrue) class Meta: db_table device ordering [-created_at]几个设计细节的解释。分类外键用on_deletemodels.PROTECT而不是CASCADE因为设备分类下面挂着设备分类一旦被引用就不允许删除能防止用户误删分类导致整组设备失效。设备状态是CharField枚举值不直接用IntegerField原因是直接读库时字符串更直观排查问题时省一步转换。维修工单模型的关键实现class RepairOrder(models.Model): STATUS_CHOICES [ (pending, 待派单), (processing, 维修中), (accepting, 待验收), (done, 已完成), (closed, 已关闭), ] order_no models.CharField(工单号, max_length32, uniqueTrue) device models.ForeignKey(Device, on_deletemodels.PROTECT, verbose_name设备) reporter models.ForeignKey(User, on_deletemodels.PROTECT, related_namereported_orders, verbose_name报修人) assignee models.ForeignKey(User, on_deletemodels.PROTECT, related_nameassigned_orders, nullTrue, blankTrue, verbose_name维修工程师) description models.TextField(故障描述) fault_type models.CharField(故障分类, max_length32, choicesFAULT_TYPE_CHOICES, defaultother) priority models.CharField(紧急程度, max_length16, choicesPRIORITY_CHOICES, defaultnormal) status models.CharField(当前状态, max_length16, choicesSTATUS_CHOICES, defaultpending) complete_time models.DateTimeField(完成时间, nullTrue, blankTrue) created_at models.DateTimeField(报修时间, auto_now_addTrue) updated_at models.DateTimeField(更新时间, auto_nowTrue)工单号生成不能依赖数据库自增主键直接拼接因为多进程下会重复。我封装了一个函数用“日期当日流水号”生成流水号通过Redis自增计数或者Django的get_or_create锁保证唯一。没有Redis的环境用数据库表级别的一个Sequence记录也可以但要注意并发下的事务隔离。状态流转方法示例def assign(self, engineer): if self.status ! pending: raise ValidationError(只有待派单状态才能指派工程师) self.assignee engineer self.status processing self.save()每次状态变更前做合法性检查非法跳转会抛出ValidationError。API层再配合Permission校验前端几乎不可能把系统状态弄乱。3.4 序列化器与视图的实现要点写Serializer时我把输出字段分成两层基础字段直接用ModelSerializer自动生成额外的展示字段一对一手动声明。设备外的维修工单列表通常需要在表格里直接看到设备名称和科室而不是等用户点进详情才看到。所以Serializer上要加两个只读字段class RepairOrderListSerializer(serializers.ModelSerializer): device_name serializers.CharField(sourcedevice.name, read_onlyTrue) device_code serializers.CharField(sourcedevice.code, read_onlyTrue) department_name serializers.CharField(sourcedevice.department.name, read_onlyTrue) reporter_name serializers.CharField(sourcereporter.username, read_onlyTrue) assignee_name serializers.CharField(sourceassignee.username, read_onlyTrue, defaultNone) status_display serializers.CharField(sourceget_status_display, read_onlyTrue) class Meta: model RepairOrder fields (id, order_no, device_name, device_code, department_name, reporter_name, assignee_name, priority, status, status_display, created_at, complete_time)这里有个细节source里连续跨了两层关联比如sourcedevice.department.nameDRF会自动帮你完成链式取值。但前提是列表查询时已经用select_related(device__department, reporter, assignee)预加载了否则这条链式取值会导致多查询数据库。写source的时候记得检查对应的ViewSet是否预加载了全部需要的关联。ViewSet选择ModelViewSet能少写很多重复代码但create和update方法需要覆盖因为创建工单时要自动生成order_no更新工单时要校验状态流转。代码大致如下class RepairOrderViewSet(viewsets.ModelViewSet): queryset RepairOrder.objects.select_related(device__department, reporter, assignee).all() def perform_create(self, serializer): serializer.save( reporterself.request.user, order_nogenerate_order_no() )细心的读者会发现create时把reporter直接取当前登录用户防止用户在请求体里伪造报修人身份。这种赋值逻辑放在perform_create里而不是从request.data里读取安全性和数据一致性都会好很多。3.5 Vue3前端工程搭建与接口对接前端Vue3项目我使用Vite构建组件库用Element Plus状态管理用Pinia路由用Vue Router 4。具体搭建过程不重复直接说核心文件。创建项目后安装依赖npm create vitelatest frontend -- --template vue cd frontend npm install element-plus element-plus/icons-vue npm install vue-router4 pinia axiosaxios封装是前后端对接最关键的环节。我给出一个可直接使用的封装import axios from axios import { ElMessage } from element-plus const service axios.create({ baseURL: /api, timeout: 15000 }) service.interceptors.request.use(config { const token localStorage.getItem(access_token) if (token) { config.headers.Authorization Bearer token } return config }) service.interceptors.response.use( response response.data, error { if (error.response error.response.status 401) { localStorage.removeItem(access_token) window.location.href /login } else { ElMessage.error(error.response?.data?.detail || 请求失败) } return Promise.reject(error) } ) export default serviceVite的代理配置注意这样写server: { proxy: { /api: { target: http://127.0.0.1:8000, changeOrigin: true } } }这样开发环境里前端请求/api/device会被代理转发到Django的8000端口生产环境则由Nginx负责同样的转发规则前后端联调时不需要改任何业务代码。前端路由分成两块登录页面单独一个layout登录后的首页、设备管理、工单管理、统计报表放在主layout下。路由守卫里检查本地token是否存在不存在就跳登录页。注意路由守卫只是体验优化真正的权限校验必须依赖后端接口判断不能把前端隐藏按钮当成安全手段。工单管理页面的核心交互是工单列表和详情抽屉。列表用el-table绑定工单数据状态列用el-tag按颜色区分详情用el-drawer展示工单完整信息包含维修日志timeline。Vue3的Composition API在这个页面尤其好用工单列表、筛选条件、分页参数、详情数据各自用ref管理互不干扰import { ref, onMounted } from vue import { getRepairOrders } from /api/workorder const orders ref([]) const total ref(0) const queryParams ref({ page: 1, page_size: 20, status: , keyword: }) const fetchOrders async () { const res await getRepairOrders(queryParams.value) orders.value res.results total.value res.count } onMounted(fetchOrders)3.6 一个完整工单的端到端流转演练整个系统做好后我用一个模拟场景验证全流程。设备“某医院内科ICU-002号呼吸机”出现故障报警值班护士登录系统进入设备台账找到这台呼吸机点击“报修”按钮填写故障描述“开机自检失败氧浓度模块报警”紧急程度选择“高”提交工单。设备科管理员在系统首页看到待派单列表多了一条工单点开后能看到设备全信息和故障描述指派给负责ICU片区的维修工程师。工程师手机端收到提醒点击接单在维修日志里填写第一次进场记录检查发现氧浓度传感器老化更换备件后重新自检通过然后提交待验收。护士确认设备恢复正常点验收通过工单状态变为已完成台账里这台设备的“最近维修”字段自动更新。整个过程没有电话、没有纸质单据、没有微信语音。医院设备科要看的报表数据比如本月呼吸机维修次数、平均维修时长、备件消耗排名全部自动生成。这就是这类系统的核心价值——把隐性的维修工作变成可管理、可追溯、可统计的数字资产。4. 常见问题与排查技巧实录4.1 接口跨域和CORS配置踩坑前后端分离项目开发环境最常见的报错就是浏览器控制台出现“CORS policy: No Access-Control-Allow-Origin”。配置django-cors-headers后大部分情况能解决但有一个隐蔽问题当接口需要携带Cookie或自定义Header时前端axios必须配置withCredentials同时后端CORS配置不能使用通配符*。通配符与Credentials组合是不允许的必须显式指定允许的来源否则浏览器依然会拦截响应。我还遇到过一种情况接口能通但前端发起OPTIONS预检请求时Django直接返回404。原因是URL路由里没有匹配到OPTIONS请求对应的视图。django-cors-headers中间件会处理OPTIONS预检前提是它被正确加入MIDDLEWARE并且放在CommonMiddleware之前。4.2 文件上传与静态文件服务问题维修记录常需要上传设备故障照片。开发环境Django默认能处理本地文件上传但如果没配置MEDIA_URL和MEDIA_ROOT上传后的文件无法通过URL访问。我在settings里的配置MEDIA_URL /media/ MEDIA_ROOT BASE_DIR / media同时在config/urls.py里DEV模式加一条from django.conf.urls.static import static urlpatterns static(settings.MEDIA_URL, document_rootsettings.MEDIA_ROOT)生产环境务必把/media/路径交给Nginx或者单独的对象存储服务不要让Django进程处理文件读写否则高并发上传时会拖垮API服务。上传文件大小默认限制为2.5MB医院现场拍照照片动辄四五MB。我调大了两个参数DATA_UPLOAD_MAX_MEMORY_SIZE设为10MB前端组件同时限制文件数量为3张。超过10MB的照片提示压缩后再传避免数据库和存储被大文件拖垮。4.3 工单查询性能优化的进阶操作设备数量超过两千台、工单超过五万条后列表接口会明显变慢。排查时先看数据库慢查询日志通常问题集中在两类。一类是列表页的排序字段没用索引。RepairOrder表按created_at排序需要在字段上建索引。另一类是搜索关键词的模糊查询。设备名称包含搜索在数据量大的时候会全表扫描我用了Django的SearchFilter配合MySQL的全文索引或者退而求其次限制搜关键字最短长度避免用户输入一个“a”就触发全表扫描。工单列表带出关联字段前面提到用select_related。如果工程师绑定科室的多对多字段也要展示还需要prefetch_related。这两者的区别是select_related用于外键单值关联生成SQL JOINprefetch_related用于多对多或反向关联执行额外查询后内存拼接。用错了会导致N1查询问题这是DRF列表接口性能杀手。4.4 权限校验的隐性漏洞普通的越权测试很好防比如工单详情接口如果直接传别人的工单ID就能看到数据那是queryset过滤没做好。但有一个隐蔽场景容易被忽略工程师A被派单后如果他把自己负责工单里的“维修日志”删除系统是否允许我的方案是对维修日志的删除操作做权限控制只允许创建设备科管理员或者维修工单结束前由管理员操作工程师自己只能新增日志不能删除已有日志。这个细节如果不处理一旦发生纠纷维修记录被工程师自行删除审计链条就断掉了。后来在操作日志表里增加了“删除原因”字段任何删除都要求填写原因虽然增加了使用成本但在医疗场景下这是必要的约束。JWT安全也是重点。我把JWT的过期时间设为8小时但存在一个隐患token被截获后8小时内都能调用接口。为了解决这个问题我在每次变更敏感状态删除设备、修改权限、关闭工单时检查用户的token签发时间如果用户密码已修改则旧token立即失效。代码逻辑虽简单但现场实测下来安全性和用户体验能达到平衡。4.5 数据时区与日期筛选的兼容处理医院业务特征是跨天工作。比如工单要求按“报修日期”筛选前端选的是“2025-03-10”后端用DateTimeField直接精确等于是查不到数据的。我在Serializer里输出日期字段时全部格式化为“YYYY-MM-DD HH:mm:ss”但查询接口接收的是“YYYY-MM-DD”字符串所以需要做一次日期范围转换把单日查询自动扩展为当天00:00:00到23:59:59。还有时区问题。如果Django配置USE_TZTrue库里存的是UTC查询“2025-03-10”时先转换成UTC再比较就会丢掉8小时。我常用的处理方式是重写filter后端或者干脆在项目里全局使用本地时区时间。内部管理系统对国际时间一致性没有要求统一用Asia/Shanghai反而更简洁也能避免前端显示时间落后8小时这种尴尬。5. 实操总结与我的几点体会这个项目做完之后有几点体会对我后面的工作影响很大。第一这类系统的价值不取决于技术复杂度而取决于对设备科业务流程的还原程度。把工单状态定清楚、把设备台账弄干净比把页面做得炫花哨重要得多。第二权限控制一定要在起步阶段就设计好等上线后再补几乎所有操作日志和数据审计都需要返工。第三医院内网环境里部署经常遇到网络隔离、离线依赖的问题开发阶段就要准备好依赖包的本地缓存避免现场装到一半发现缺包。最后一个小技巧给工单详情页加一个“打印维修单”按钮输出为A4格式的PDF。医院设备科在设备报废申请、科室对账、审计检查时都需要纸质单据这个功能看着不起眼但现场使用频率很高也让我在几个关键节点上少挨了不少催。后续这套系统还能继续扩展比如接入HIS系统获取科室床位占用数据从而判断设备使用压力或者增加设备巡检计划模块把定期保养也纳入工单管理体系无论朝哪个方向走现有的设备台账和工单数据底座都不会白做。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑