当前位置: 首页 > news >正文

医院预约管理系统

医院预约管理系统 — 设计思路与实现笔记

本文档记录从需求分析 → 架构设计 → 分层实现 → 边界处理的完整思路。


一、需求分析与建模

1.1 业务背景

某社区医院需要一个预约管理系统,管理科室、医生、患者及预约挂号。核心痛点:

  • 科室与医生:多对一关系,医生排班信息需直观呈现
  • 患者管理:身份证唯一标识,联系方式一对一独立存储
  • 预约挂号:需防止超额预约和重复预约
  • 数据统计:管理者需快速了解每日运营概况

1.2 实体关系分析

科室 (departments) 1 ── N 医生 (doctors) 医生 (doctors) 1 ── N 预约 (appointments) 患者 (patients) 1 ── N 预约 (appointments) 患者 (patients) 1 ── 1 联系方式 (patient_contacts)

1.3 关键设计决策

Q: 联系方式为何独立成表而非放在 patients 表中?

A: 遵循数据库范式,联系方式字段(手机、微信、邮箱、地址、紧急联系人)是可选信息且与患者核心标识(姓名、身份证)职责不同。独立存储便于:

  • 按需加载(列表页不需要联系方式,减少数据传输)
  • 独立维护(联系方式更新不影响患者主体)

Q: 为何使用 Tortoise ORM 而非 SQLAlchemy?

A: Tortoise ORM 是 Python 异步生态的原生选择,与 FastAPI 的 async/await 无缝配合,无需额外线程池处理数据库操作。


二、架构设计

2.1 分层思想

采用经典的8 层架构,自上而下单向依赖:

┌──────────────────────────────────────────────┐ │ ⑦ api/ 路由层 HTTP 入口/出口 │ ← 薄控制器,不做业务判断 │ ⑥ services/ 业务逻辑层 规则编排 │ ← 核心,所有 if/else 在这里 │ ⑤ repositories/ 数据访问层 ORM 查询封装 │ ← 屏蔽数据库细节 │ ③ models/ ORM模型层 表映射 │ ← 纯声明 ├──────────────────────────────────────────────┤ │ ④ schemas/ Pydantic层 数据校验 │ ← 与路由层配合 │ ② core/ 基础设施层 DB/JWT/异常/依赖 │ ← 横向支撑 │ ① config/ 配置层 .env → Settings │ ← 环境隔离 │ ⑧ utils/ 工具层 响应封装 │ ← 无状态纯函数 └──────────────────────────────────────────────┘

2.2 为什么需要 Repository + Service 两层?

模式问题
路由直接写 ORM路由层承担太多职责:参数校验 + 业务判断 + 查询构建 + 响应组装,难以测试和复用
路由 → Service → ORMService 既要处理业务规则又要写 SQL,Service 变臃肿
路由 → Service → Repository → ORM每层职责单一:Service 只管"能不能做",Repository 只管"怎么查"

具体收益

  • 切换数据库时只改 Repository 层
  • Service 可以 mock Repository 做单元测试
  • 复杂查询(如预约 5 维筛选)封装在 Repository 中,Service 只需传参

2.3 统一响应格式设计

{"code":200,"message":"操作成功","data":null}

设计考量

  • code用于前端判断成功/失败(不依赖 HTTP 状态码,因为部分代理可能改写)
  • message可直接展示给用户(Toast/提示框)
  • data承载实际业务数据,失败时为null

三、各层实现要点

3.1 配置层 (config/settings.py)

.env 文件 → python-dotenv 加载 → os.getenv() 读取 → Settings 类属性 ↓ DB_URL 属性动态拼接连接串

为什么用.env而非硬编码?

  • 开发/测试/生产环境分离,.env.dev/.env.prod各自维护
  • 敏感信息(密码)不入 Git

3.2 基础设施层 (core/)

模块核心实现设计要点
database.pyTortoise.init()+generate_schemas()开发自动建表,生产用 Aerich 迁移
security.pypython-josejwt.encode/decodeexp字段控制过期,HS256 对称加密
exceptions.py3 个异常处理器注册到 appIntegrityError转为用户友好中文提示
dependencies.pyHeader(authorization)提取 →verify_token()支持Bearer xxx和纯 token 两种格式

3.3 ORM 模型层 (models/hospital.py)

classDoctor(models.Model):department=fields.ForeignKeyField("models.Department",related_name="doctors")

设计要点

  • related_name让反向查询更语义化:dept.doctors而非dept.doctor_set
  • auto_now_add=True创建时自动填时间,auto_now=True更新时自动刷新
  • null=True允许字段为空,与 MySQLDEFAULT NULL对应

3.4 数据访问层 (repositories/)

基类设计

classBaseRepository:model:Type[Model]# 子类覆写asyncdefpaginate(self,query,page,page_size,order_by):"""通用分页,返回 (items, total)"""

所有 Repository 继承此基类,获得get_by_id/create/update/delete/paginate五件套。

批量加载避免 N+1

# ❌ 坏做法:循环中逐条查(N+1 问题)fordoctorindoctors:dept=awaitDepartment.get(id=doctor.department_id)# 每轮 1 次 SQL# ✅ 好做法:先收集 ID,再批量查dept_ids=list({d.department_idfordindoctors})departments=awaitDepartment.filter(id__in=dept_ids).all()dept_map={d.id:d.namefordindepartments}

3.5 业务逻辑层 (services/)

核心模式:三元组返回

asyncdefcreate_appointment(self,data:dict)->tuple[bool,str,dict|None]:""" 返回 (是否成功, 提示消息, 数据或None) 四个校验按序执行,任一失败立即返回: ① 患者存在? → 否则 "患者不存在" ② 医生在岗? → 否则 "该医生当前不在岗" ③ 当天已预约? → 否则 "该患者当天已预约过该医生" ④ 号满? → 否则 "该时段号已满" ⑤ 全部通过 → 创建 """

为什么用 fail-fast 而非收集所有错误?

社区医院场景,用户一次只操作一条预约,即时反馈比批量错误提示体验更好。

3.6 路由层 (api/v1/)

路由层只做三件事:

  1. 接收 HTTP 参数(Query/Path/Body)
  2. 调用 Service 方法
  3. 根据返回值组装 JSON 响应
@router.post("/appointments")asyncdefcreate_appointment(data:AppointmentCreate,...):ok,msg,result=awaitappointment_service.create_appointment(data.model_dump())ifnotok:returnerror(msg)# 业务失败 → 400returnsuccess(data=result,message=msg)# 成功 → 200

四、边界情况处理清单

边界场景处理方式层级
科室名称重复新增/编辑时查重,编辑时排除自身Service
删除有医生的科室先查Doctor表,有则返回错误Service
删除有待就诊的医生Appointment(status=待就诊)Service
身份证重复新增/编辑时查重,编辑排除自身Service
同一患者同天重复预约同一医生组合条件查重Service
预约数超过日限额先统计同时段数,≥限额则拒绝Service
医生不在岗时预约查医生 status != “在岗”Service
取消/完成非待就诊预约查 status,不符则拒绝Service
联系方式不存在时查询返回空结构(id=0),前端据此显示"创建"按钮Service
联系方式已存在时再次创建查唯一约束,提示"请使用编辑"Service
编辑联系方式时不存在容错处理:自动创建Service
搜索无结果返回空数组 + total=0Repository
分页超出范围Tortoise ORM 自动返回空数组Repository
Token 过期/伪造verify_token()返回 None → 401Security
数据库唯一键冲突全局异常处理器 → 400 + 友好提示Exception
请求参数格式错误Pydantic 校验 → 422 + 字段级错误Exception

五、代码风格约定

注释规范

# ── 区块分隔注释(用 ── 区分不同逻辑块) ──# ① 有编号的步骤说明# → 缩进表示结果/后果# ✅ 成功路径 ❌ 失败路径

命名约定

  • Repository 类{Entity}Repo,如DoctorRepo
  • Service 类{Entity}Service,如DoctorService
  • Schema 类{Entity}{Action},如DoctorCreate/DoctorUpdate
  • 路由文件:实体名复数,如doctors.py
  • 路由函数{action}_{entity},如list_doctors/create_doctor

文件组织

每层一个模块目录,每个实体一个文件:

  • 简单的实体(如科室)把相关逻辑集中在一个文件
  • 复杂的实体(如患者 + 联系方式)在 Repository 中合并为patient_repo.py,类之间用空行分隔

六、可扩展性预留

扩展点当前实现扩展方向
多角色认证固定 admin 账号core/security.py增加角色字段,dependencies.py增加require_role()
数据库迁移generate_schemas()改用 Aerich:aerich initaerich migrateaerich upgrade
日志系统utils/增加logger.pycore/middleware.py增加请求日志中间件
缓存repositories/base.py增加 Redis 缓存层
API 版本化api/v1/新增api/v2/,路由注册时指定 prefix
单元测试tests/目录,pytest + httpx 异步测试客户端
定时任务增加 APScheduler,定时将过期预约状态改为「已过期」

七、总结

本项目采用8 层分层架构,核心思想是关注点分离

  1. 路由层只管 HTTP 协议(请求解析、响应序列化)
  2. 业务逻辑层只管业务规则(能不能做、什么条件)
  3. 数据访问层只管数据查询(怎么查、查什么)
  4. 模型层只管表结构(字段类型、关系映射)

每层只做一件事,每行代码都有注释,降低了认知负担和维护成本。所有边界情况在 Service 层显式处理,不依赖数据库异常作为业务逻辑控制流。

http://www.cnnetsun.cn/news/3573439.html

相关文章:

  • C++动态链接库(DLL)运行时加载:Boost.DLL实战与插件系统开发
  • Kafka集群搭建与Golang客户端开发实战指南
  • Superset自动化报表分发:Schedule Email功能详解
  • 近期量化工具重点,会随着学习阶段一起变化
  • 抖音合集批量下载终极指南:快速搞定mix_id解析与自动化下载
  • Python3 注释编写完全指南:从基础规范到高效实践
  • L3级智能座舱技术解析:从架构到量产挑战
  • Claude Code生态中的MCP协议与Agent Skills开发指南
  • WaveTools开源工具:解锁鸣潮帧率限制与画质优化的终极解决方案
  • Faiss相似性搜索库在NLP中的应用与实践
  • AI Agent自动化MCU外设配置系统解析
  • RocketMQ原生API实战:消息生产与消费深度解析
  • 多租户RAG从零搭建:5步实现严格权限隔离,企业级安全实战攻略
  • 终极指南:快速解决Cursor试用限制的完整教程
  • 影刀RPA 网页分页采集的通用模式:下一页判断与循环控制
  • AI语音转文字采访稿质量崩塌真相(行业首份1272小时录音压力测试报告)
  • 深入解析eQEP模块寄存器:捕获、比较与中断配置实战
  • SpringBoot整合Spring Security实现认证授权实战
  • 深入解析MFC静态链接库mfcs80u.lib:原理、配置与实战排错
  • LLM多服务商路由状态连续性:ContinuityBench基准与故障切换实践
  • Hermes Agent 入门:别再把 AI 当聊天框,30 分钟搭好会成长的行动助手
  • AI中的Token:原理、优化与应用实践
  • TapTap PC版与MuMu模拟器技术解析与优化
  • 企业级生成式AI安全实战:基于127次事故的7层隔离架构设计
  • 分布式动作捕捉框架EgoExoMoCap:低成本实现多视角人体运动追踪
  • Apache Druid 0.15.0安装与配置指南
  • SATA AHCI控制器DMA驱动开发实战:从寄存器配置到数据传输
  • 【Springboot毕设全套源码+文档】基于springboot冷链运输生鲜销售系统的设计与实现(丰富项目+远程调试+讲解+定制)
  • 国家中小学智慧教育平台电子课本下载工具:三步搞定PDF教材下载
  • React+Node.js全栈留言板开发实战