在线问诊与预约挂号系统设计
1. 预约挂号系统
1.1 号源管理
1.1.1 排班计划
排班计划是医院/医生在特定时间段内提供挂号服务的安排,是号源管理的基础。
排班计划表 (schedule_plan)
java
@Entity
@Table(name = "schedule_plan")
public class SchedulePlan {
@Id
@Column(name = "id", length = 32, nullable = false)
private String id;
@Column(name = "hospital_id", length = 32, nullable = false)
private String hospitalId; // 医院ID
@Column(name = "dept_id", length = 32, nullable = false)
private String deptId; // 科室ID
@Column(name = "doctor_id", length = 32, nullable = false)
private String doctorId; // 医生ID
@Column(name = "plan_date", nullable = false)
private LocalDate planDate; // 排班日期
@Column(name = "period_type", length = 16, nullable = false)
private String periodType; // 时段类型:MORNING(上午)/AFTERNOON(下午)/EVENING(晚间)
@Column(name = "start_time", nullable = false)
private LocalTime startTime; // 开始时间
@Column(name = "end_time", nullable = false)
private LocalTime endTime; // 结束时间
@Column(name = "total_slots", nullable = false)
private Integer totalSlots; // 总号源数
@Column(name = "remain_slots", nullable = false)
private Integer remainSlots; // 剩余号源数
@Column(name = "slot_duration", nullable = false)
private Integer slotDuration; // 每个号源时段时长(分钟)
@Column(name = "schedule_type", length = 16, nullable = false)
private String scheduleType; // 排班类型:NORMAL(普通)/EXPERT(专家)/VIP
@Column(name = "price", nullable = false)
private Long price; // 挂号费用(单位:分)
@Column(name = "status", length = 16, nullable = false)
private String status; // 状态:ENABLED(启用)/DISABLED(停用)/FULL(已满)/FINISHED(已结束)
@Column(name = "create_time")
private LocalDateTime createTime;
@Column(name = "update_time")
private LocalDateTime updateTime;
}1.1.2 号源池分配
号源池机制用于精细化控制不同渠道、不同人群的号源配额,防止号源被单一渠道挤占。
号源池分配策略:
| 号源池类型 | 分配比例 | 说明 |
|---|---|---|
| PUBLIC_POOL | 60% | 公共号源池,面向所有渠道开放 |
| CHANNEL_RESERVED | 20% | 渠道预留池,为特定合作渠道(如第三方平台)预留 |
| VIP_POOL | 10% | VIP/绿色通道池,优先保障重点患者 |
| FRESH_POOL | 10% | 新鲜号源池,用于放号初期动态调整 |
号源池表 (slot_pool)
java
@Entity
@Table(name = "slot_pool")
public class SlotPool {
@Id
@Column(name = "id", length = 32, nullable = false)
private String id;
@Column(name = "plan_id", length = 32, nullable = false)
private String planId; // 排班计划ID
@Column(name = "pool_type", length = 16, nullable = false)
private String poolType; // 号源池类型:PUBLIC/CHANNEL_RESERVED/VIP/FRESH
@Column(name = "total_slots", nullable = false)
private Integer totalSlots; // 总配额
@Column(name = "used_slots", nullable = false)
private Integer usedSlots; // 已使用配额
@Column(name = "frozen_slots")
private Integer frozenSlots; // 冻结配额(锁定未支付)
@Column(name = "status", length = 16)
private String status; // 状态:ACTIVE/EMPTY
@Column(name = "create_time")
private LocalDateTime createTime;
}1.1.3 放号规则
放号规则定义了号源释放的时间策略和数量策略。
| 规则维度 | 配置项 | 说明 |
|---|---|---|
| 提前天数 | advanceDays | 可提前挂号的日期范围,如7天/14天/30天 |
| 放号时间 | releaseTime | 每日放号的具体时间点,如 08:00 |
| 放号方式 | releaseMode | BATCH(批量放号)/REAL_TIME(实时放号) |
| 批量数量 | batchSize | 每次批量放号的号源数量 |
| 时间段分段 | timeSegmentInterval | 每个就诊时段间隔(分钟) |
| 限号规则 | maxPerUser | 单用户每周期最大挂号数 |
| 取消释放策略 | cancelReturnPolicy | 取消后号源回池时间:IMMEDIATE/DELAYED |
| 爽约释放策略 | noShowReleaseTime | 爽约号源释放时间,如次日或就诊时段开始后30分钟 |
1.2 挂号流程
1.2.1 完整流程图
选择科室 --> 选择医生 --> 查看排班 --> 选择时段 --> 确认订单 --> 在线支付 --> 预约成功(生成就诊凭证)
|
--> 支付超时关闭1.2.2 核心数据模型
挂号订单表 (registration_order)
java
@Entity
@Table(name = "registration_order")
public class RegistrationOrder {
@Id
@Column(name = "order_id", length = 32, nullable = false)
private String orderId; // 订单号,分布式ID生成
@Column(name = "user_id", length = 32, nullable = false)
private String userId; // 用户ID
@Column(name = "patient_id", length = 32, nullable = false)
private String patientId; // 就诊人ID(支持替他人挂号)
@Column(name = "hospital_id", length = 32, nullable = false)
private String hospitalId; // 医院ID
@Column(name = "dept_id", length = 32, nullable = false)
private String deptId; // 科室ID
@Column(name = "doctor_id", length = 32, nullable = false)
private String doctorId; // 医生ID
@Column(name = "plan_id", length = 32, nullable = false)
private String planId; // 排班计划ID
@Column(name = "slot_id", length = 32, nullable = false)
private String slotId; // 号源时段ID
@Column(name = "visit_date", nullable = false)
private LocalDate visitDate; // 就诊日期
@Column(name = "visit_start_time")
private LocalTime visitStartTime; // 就诊开始时间
@Column(name = "visit_end_time")
private LocalTime visitEndTime; // 就诊结束时间
@Column(name = "order_status", length = 16, nullable = false)
private String orderStatus; // 订单状态:PENDING_PAY/PAID/CANCELLED/COMPLETED/REFUNDING/REFUNDED/NOSHOW
@Column(name = "pay_status", length = 16)
private String payStatus; // 支付状态:UNPAID/PAID/REFUNDING/REFUNDED
@Column(name = "amount", nullable = false)
private Long amount; // 订单金额(单位:分)
@Column(name = "pay_amount")
private Long payAmount; // 实付金额(单位:分)
@Column(name = "service_fee")
private Long serviceFee; // 平台服务费(单位:分)
@Column(name = "pay_time")
private LocalDateTime payTime; // 支付时间
@Column(name = "cancel_time")
private LocalDateTime cancelTime; // 取消时间
@Column(name = "cancel_reason")
private String cancelReason; // 取消原因
@Column(name = "qr_code", length = 256)
private String qrCode; // 就诊二维码/条形码
@Column(name = "visit_status", length = 16)
private String visitStatus; // 就诊状态:WAITING(待就诊)/CHECKED_IN(已报到)/IN_CONSULTATION(就诊中)/COMPLETED(已完成)/NOSHOW(爽约)
@Column(name = "create_time")
private LocalDateTime createTime;
@Column(name = "update_time")
private LocalDateTime updateTime;
}1.2.3 挂号订单状态机
+---> CANCELLED(用户取消)
|
PENDING_PAY ---> PAID ---> COMPLETED
| | |
| | +---> NOSHOW(患者爽约)
| |
| +---> REFUNDING ---> REFUNDED(用户退号)
|
+---> CLOSED(支付超时自动关闭)| 源状态 | 目标状态 | 触发条件 | 操作 |
|---|---|---|---|
| PENDING_PAY | PAID | 支付成功回调 | 更新支付信息,锁定号源 |
| PENDING_PAY | CLOSED | 超时未支付(如30分钟) | 释放号源,关闭订单 |
| PENDING_PAY | CANCELLED | 用户主动取消 | 释放号源 |
| PAID | REFUNDING | 用户发起退号 | 进入退款流程 |
| REFUNDING | REFUNDED | 退款成功 | 释放号源 |
| PAID | COMPLETED | 就诊完成 | 标记就诊结束 |
| COMPLETED | NOSHOW | 就诊日结束未报到 | 标记爽约 |
1.3 取消预约与退号规则
1.3.1 阶梯退号策略
| 退号时间 | 退款比例 | 说明 |
|---|---|---|
| 就诊日前 >= 3天 | 100% | 全额退款 |
| 就诊日前 1-2天 | 80% | 扣除20%手续费 |
| 就诊当日,未报到 | 50% | 扣除50%手续费 |
| 就诊当日,已报到 | 不退款 | 已进入就诊流程 |
| 就诊开始后 | 不退款 | 无法退号 |
1.3.2 退号流程
用户发起退号 --> 校验退号规则(时间/次数/黑名单)
--> 扣减退号手续费
--> 发起退款(原路返回)
--> 释放号源回号源池
--> 通知医生号源释放1.4 黑名单机制
1.4.1 黑名单触发规则
| 违规类型 | 触发条件 | 惩罚时长 | 说明 |
|---|---|---|---|
| 多次取消 | 30天内取消 >= 5次 | 7天 | 限制预约挂号 |
| 频繁取消 | 单日取消 >= 3次 | 3天 | 限制预约挂号 |
| 爽约 | 单次就诊日未到 | 警告 | 首次记录 |
| 多次爽约 | 90天内爽约 >= 3次 | 30天 | 限制预约挂号 |
| 恶意抢号 | 疑似脚本/高频操作 | 永久 | 人工审核封禁 |
| 黄牛行为 | 高频挂退号,IP异常 | 永久 | 人工审核封禁 |
黑名单表 (user_blacklist)
java
@Entity
@Table(name = "user_blacklist")
public class UserBlacklist {
@Id
@Column(name = "id", length = 32, nullable = false)
private String id;
@Column(name = "user_id", length = 32, nullable = false)
private String userId;
@Column(name = "black_type", length = 16, nullable = false)
private String blackType; // 类型:CANCEL_ABUSE/NOSHOW/MALICIOUS/SCALPER
@Column(name = "punish_start", nullable = false)
private LocalDateTime punishStart; // 惩罚开始时间
@Column(name = "punish_end", nullable = false)
private LocalDateTime punishEnd; // 惩罚结束时间
@Column(name = "reason", length = 512)
private String reason; // 原因说明
@Column(name = "status", length = 16)
private String status; // 状态:ACTIVE/EXPIRED
@Column(name = "create_time")
private LocalDateTime createTime;
}违规记录表 (violation_record)
java
@Entity
@Table(name = "violation_record")
public class ViolationRecord {
@Id
@Column(name = "id", length = 32, nullable = false)
private String id;
@Column(name = "user_id", length = 32, nullable = false)
private String userId;
@Column(name = "order_id", length = 32)
private String orderId; // 关联订单
@Column(name = "violation_type", length = 16, nullable = false)
private String violationType; // 违规类型:CANCEL/NOSHOW/MALICIOUS
@Column(name = "violation_desc", length = 256)
private String violationDesc; // 违规描述
@Column(name = "create_time")
private LocalDateTime createTime;
}2. 在线问诊
2.1 问诊类型
| 问诊类型 | 交互方式 | 适用场景 | 时长限制 | 价格区间 |
|---|---|---|---|---|
| 图文咨询 | 文字+图片 | 轻症、慢病复诊、报告解读 | 48小时内 | 低 |
| 电话咨询 | 语音通话 | 急症、需要快速沟通 | 15/30分钟 | 中 |
| 视频咨询 | 视频通话 | 需要面对面查看体征 | 15/30分钟 | 高 |
| 处方问诊 | 图文+处方 | 需要开具处方 | 48小时内 | 中 |
| 复诊咨询 | 图文/视频 | 同一医生复诊 | 按类型 | 低 |
2.2 问诊流程
2.2.1 流程图
选择医生 --> 选择问诊类型 --> 填写病情描述(文字/图片/病历) --> 支付问诊费
|
+---------------------+
|
等待医生接诊 --> 医生接诊
|
+---------------+---------------+
| | |
图文交流 电话沟通 视频沟通
| | |
+-------+-------+---------------+
|
开具处方/检查单
|
问诊结束
|
评价与反馈2.2.2 核心数据模型
在线问诊表 (online_consultation)
java
@Entity
@Table(name = "online_consultation")
public class OnlineConsultation {
@Id
@Column(name = "consult_id", length = 32, nullable = false)
private String consultId; // 问诊ID
@Column(name = "user_id", length = 32, nullable = false)
private String userId; // 用户ID
@Column(name = "patient_id", length = 32, nullable = false)
private String patientId; // 就诊人ID
@Column(name = "doctor_id", length = 32, nullable = false)
private String doctorId; // 医生ID
@Column(name = "hospital_id", length = 32)
private String hospitalId; // 医院ID
@Column(name = "dept_id", length = 32)
private String deptId; // 科室ID
@Column(name = "consult_type", length = 16, nullable = false)
private String consultType; // 问诊类型:TEXT/PHONE/VIDEO/PRESCRIPTION/FOLLOWUP
@Column(name = "consult_status", length = 16, nullable = false)
private String consultStatus; // 问诊状态
@Column(name = "chief_complaint", length = 2000)
private String chiefComplaint; // 主诉/病情描述
@Column(name = "medical_history", length = 2000)
private String medicalHistory; // 既往病史
@Column(name = "image_urls", length = 2000)
private String imageUrls; // 图片附件,JSON数组
@Column(name = "amount", nullable = false)
private Long amount; // 问诊费用(单位:分)
@Column(name = "service_fee")
private Long serviceFee; // 平台服务费(单位:分)
@Column(name = "doctor_income")
private Long doctorIncome; // 医生收入(单位:分)
@Column(name = "pay_status", length = 16)
private String payStatus; // 支付状态:UNPAID/PAID/REFUNDING/REFUNDED
@Column(name = "doctor_note", length = 2000)
private String doctorNote; // 医生诊断意见
@Column(name = "start_time")
private LocalDateTime startTime; // 接诊时间
@Column(name = "end_time")
private LocalDateTime endTime; // 结束时间
@Column(name = "duration_minutes")
private Integer durationMinutes; // 问诊时长(分钟)
@Column(name = "create_time")
private LocalDateTime createTime;
@Column(name = "update_time")
private LocalDateTime updateTime;
}2.3 问诊状态机
+---> CANCELLED(用户取消,未支付)
|
PENDING_PAY --> PAID --> WAITING_ACCEPT --> IN_CONSULTATION --> COMPLETED
| | | |
| | | +---> CLOSED(正常结束)
| | |
| | +---> REFUNDING ---> REFUNDED(退款中/已退款)
| |
| +---> AUTO_CLOSED(超时未接诊,自动关闭并退款)
|
+---> CLOSED(支付超时)状态说明:
| 状态码 | 状态名称 | 说明 |
|---|---|---|
| PENDING_PAY | 待支付 | 用户已提交问诊单,等待支付 |
| PAID | 已支付 | 支付成功,进入待分配 |
| WAITING_ACCEPT | 待接诊 | 医生尚未接诊 |
| IN_CONSULTATION | 接诊中 | 医生已接诊,正在进行交流 |
| COMPLETED | 已完成 | 问诊正常结束 |
| CLOSED | 已关闭 | 问诊流程终结(正常或非正常) |
| CANCELLED | 已取消 | 用户支付前取消 |
| REFUNDING | 退款中 | 用户申请退款,审核处理中 |
| REFUNDED | 已退款 | 退款已完成 |
| AUTO_CLOSED | 超时关闭 | 医生未在规定时间内接诊,系统自动关闭 |
状态转换矩阵:
| 源状态 | 目标状态 | 触发条件 | 操作 |
|---|---|---|---|
| PENDING_PAY | PAID | 支付成功回调 | 通知医生有新问诊 |
| PENDING_PAY | CANCELLED | 用户取消 | 无 |
| PENDING_PAY | CLOSED | 超时未支付 | 自动关闭 |
| PAID | WAITING_ACCEPT | 进入医生接诊池 | 开始计时(如30分钟内需接诊) |
| WAITING_ACCEPT | IN_CONSULTATION | 医生接诊 | 锁定医患会话,通知用户 |
| WAITING_ACCEPT | AUTO_CLOSED | 超时未接诊 | 全额退款,通知用户 |
| WAITING_ACCEPT | CANCELLED | 用户付费后取消 | 进入退款流程 |
| IN_CONSULTATION | COMPLETED | 医生结束问诊 | 生成问诊总结,进入评价 |
| IN_CONSULTATION | REFUNDING | 用户申请退款 | 平台介入审核 |
| REFUNDING | REFUNDED | 退款成功 | 关闭问诊 |
| REFUNDING | IN_CONSULTATION | 退款驳回 | 继续问诊 |
| COMPLETED | CLOSED | 用户评价 | 终态 |
3. 医生端设计
3.1 医生排班管理
医生可通过医生端管理自己的排班计划:
| 功能 | 说明 |
|---|---|
| 排班设置 | 设置每周固定排班规则(如每周一上午、周三下午出诊) |
| 临时停诊 | 某天临时无法出诊,可停诊并通知已预约患者 |
| 号源调整 | 调整单日出诊号源数量(加号/限号) |
| 时段设置 | 自定义每个时段的接诊人数和间隔时长 |
| 排班日历 | 以日历形式查看和管理排班 |
医生排班模板表 (doctor_schedule_template)
java
@Entity
@Table(name = "doctor_schedule_template")
public class DoctorScheduleTemplate {
@Id
@Column(name = "id", length = 32, nullable = false)
private String id;
@Column(name = "doctor_id", length = 32, nullable = false)
private String doctorId;
@Column(name = "day_of_week", nullable = false)
private Integer dayOfWeek; // 星期几:1-7
@Column(name = "period_type", length = 16, nullable = false)
private String periodType; // 时段:MORNING/AFTERNOON/EVENING
@Column(name = "start_time", nullable = false)
private LocalTime startTime;
@Column(name = "end_time", nullable = false)
private LocalTime endTime;
@Column(name = "slot_count", nullable = false)
private Integer slotCount; // 号源数量
@Column(name = "slot_duration", nullable = false)
private Integer slotDuration; // 号源时长(分钟)
@Column(name = "status", length = 16)
private String status; // 状态:ACTIVE/INACTIVE
}3.2 接诊池与排队管理
接诊池是医生处理在线问诊请求的队列系统。
接诊池设计:
| 概念 | 说明 |
|---|---|
| 接诊池 | 医生视角下所有待接诊问诊单的集合 |
| 排队规则 | 按支付时间排序,先支付先服务,VIP用户可优先 |
| 并行接诊上限 | 医生同时接诊的最大问诊数(如图文3个,视频1个) |
| 接诊超时 | 新问诊单在池中等待超过阈值(如30分钟)未接诊,自动转分诊 |
| 分诊机制 | 医生离线或超时后,问诊单重新分配至同科室其他在线医生 |
接诊池条目表 (consultation_queue)
java
@Entity
@Table(name = "consultation_queue")
public class ConsultationQueue {
@Id
@Column(name = "id", length = 32, nullable = false)
private String id;
@Column(name = "consult_id", length = 32, nullable = false)
private String consultId; // 问诊ID
@Column(name = "doctor_id", length = 32, nullable = false)
private String doctorId; // 目标医生ID
@Column(name = "queue_status", length = 16, nullable = false)
private String queueStatus; // 队列状态:WAITING/ACCEPTED/TRANSFERRED/CLOSED
@Column(name = "priority", nullable = false)
private Integer priority; // 优先级,数值越小优先级越高
@Column(name = "entered_time", nullable = false)
private LocalDateTime enteredTime; // 入池时间
@Column(name = "expire_time")
private LocalDateTime expireTime; // 超时时间
@Column(name = "create_time")
private LocalDateTime createTime;
}3.3 电子病历书写
电子病历表 (medical_record)
java
@Entity
@Table(name = "medical_record")
public class MedicalRecord {
@Id
@Column(name = "id", length = 32, nullable = false)
private String id;
@Column(name = "consult_id", length = 32)
private String consultId; // 关联问诊ID
@Column(name = "registration_id", length = 32)
private String registrationId; // 关联挂号ID
@Column(name = "user_id", length = 32, nullable = false)
private String userId;
@Column(name = "patient_id", length = 32, nullable = false)
private String patientId;
@Column(name = "doctor_id", length = 32, nullable = false)
private String doctorId;
@Column(name = "hospital_id", length = 32)
private String hospitalId;
@Column(name = "dept_id", length = 32)
private String deptId;
@Column(name = "record_type", length = 16, nullable = false)
private String recordType; // 记录类型:FIRST_VISIT(初诊)/FOLLOW_UP(复诊)/EMERGENCY(急诊)
// ===== 主观部分 =====
@Column(name = "chief_complaint", length = 2000)
private String chiefComplaint; // 主诉
@Column(name = "present_illness", length = 4000)
private String presentIllness; // 现病史
@Column(name = "past_history", length = 2000)
private String pastHistory; // 既往史
@Column(name = "allergy_history", length = 1000)
private String allergyHistory; // 过敏史
// ===== 客观部分 =====
@Column(name = "physical_exam", length = 2000)
private String physicalExam; // 体格检查
@Column(name = "auxiliary_exam", length = 2000)
private String auxiliaryExam; // 辅助检查
// ===== 诊断与处置 =====
@Column(name = "diagnosis", length = 2000, nullable = false)
private String diagnosis; // 诊断结论
@Column(name = "treatment_plan", length = 2000)
private String treatmentPlan; // 治疗方案
@Column(name = "medical_advice", length = 2000)
private String medicalAdvice; // 医生建议
@Column(name = "sign_status", length = 16)
private String signStatus; // 签名状态:UNSIGNED/SIGNED
@Column(name = "sign_time")
private LocalDateTime signTime; // 签名时间
@Column(name = "create_time")
private LocalDateTime createTime;
@Column(name = "update_time")
private LocalDateTime updateTime;
}3.4 处方开具与签名
医生在问诊过程中可在线开具处方,并通过数字签名技术完成签章。
处方单表 (prescription)
java
@Entity
@Table(name = "prescription")
public class Prescription {
@Id
@Column(name = "prescription_id", length = 32, nullable = false)
private String prescriptionId;
@Column(name = "consult_id", length = 32)
private String consultId; // 关联问诊ID
@Column(name = "doctor_id", length = 32, nullable = false)
private String doctorId;
@Column(name = "user_id", length = 32, nullable = false)
private String userId;
@Column(name = "patient_id", length = 32, nullable = false)
private String patientId;
@Column(name = "hospital_id", length = 32)
private String hospitalId;
@Column(name = "dept_id", length = 32)
private String deptId;
@Column(name = "prescription_type", length = 16, nullable = false)
private String prescriptionType; // 处方类型:CHINESE_MEDICINE(中药)/WESTERN_MEDICINE(西药)/COMBINED(中西结合)
@Column(name = "total_amount")
private Long totalAmount; // 总金额(单位:分)
@Column(name = "status", length = 16, nullable = false)
private String status; // 状态:DRAFT/PENDING_REVIEW/PASSED/REJECTED/DISPENSING/DISPATCHED/COMPLETED
@Column(name = "review_status", length = 16)
private String reviewStatus; // 审核状态:UNREVIEWED/PASSED/REJECTED
@Column(name = "review_remark", length = 500)
private String reviewRemark; // 审核备注
@Column(name = "reviewer_id", length = 32)
private String reviewerId; // 审核药师ID
@Column(name = "review_time")
private LocalDateTime reviewTime;
@Column(name = "doctor_sign", length = 512)
private String doctorSign; // 医生数字签名
@Column(name = "pharmacist_sign", length = 512)
private String pharmacistSign; // 药师数字签名
@Column(name = "valid_days")
private Integer validDays; // 有效期(天)
@Column(name = "create_time")
private LocalDateTime createTime;
@Column(name = "update_time")
private LocalDateTime updateTime;
}处方明细表 (prescription_item)
java
@Entity
@Table(name = "prescription_item")
public class PrescriptionItem {
@Id
@Column(name = "id", length = 32, nullable = false)
private String id;
@Column(name = "prescription_id", length = 32, nullable = false)
private String prescriptionId;
@Column(name = "drug_code", length = 32, nullable = false)
private String drugCode; // 药品编码
@Column(name = "drug_name", length = 128, nullable = false)
private String drugName; // 药品名称
@Column(name = "specification", length = 64)
private String specification; // 药品规格
@Column(name = "dosage_form", length = 32)
private String dosageForm; // 剂型
@Column(name = "manufacturer", length = 128)
private String manufacturer; // 生产厂商
@Column(name = "quantity", nullable = false)
private Integer quantity; // 数量
@Column(name = "unit", length = 16)
private String unit; // 单位(盒/瓶/袋)
@Column(name = "usage_method", length = 256)
private String usageMethod; // 用法
@Column(name = "dosage", length = 64)
private String dosage; // 用量(如 每次1片)
@Column(name = "frequency", length = 64)
private String frequency; // 频次(如 每日3次)
@Column(name = "course_days")
private Integer courseDays; // 疗程天数
@Column(name = "unit_price")
private Long unitPrice; // 单价(单位:分)
@Column(name = "total_price")
private Long totalPrice; // 小计金额
}4. 处方流转
4.1 电子处方
4.1.1 处方模板
处方模板帮助医生快速生成标准格式处方,提升效率。
| 模板类型 | 说明 |
|---|---|
| 个人模板 | 医生个人常用的处方组合 |
| 科室模板 | 科室级标准治疗方案模板 |
| 医院模板 | 医院统一制定的标准化处方 |
| 药品组合模板 | 特定病症的标准用药组合 |
处方模板表 (prescription_template)
java
@Entity
@Table(name = "prescription_template")
public class PrescriptionTemplate {
@Id
@Column(name = "id", length = 32, nullable = false)
private String id;
@Column(name = "doctor_id", length = 32)
private String doctorId; // 医生ID(为空表示全院/科室模板)
@Column(name = "dept_id", length = 32)
private String deptId;
@Column(name = "hospital_id", length = 32)
private String hospitalId;
@Column(name = "template_name", length = 128, nullable = false)
private String templateName;
@Column(name = "template_type", length = 16, nullable = false)
private String templateType; // 类型:PERSONAL/DEPT/HOSPITAL
@Column(name = "diagnosis_keywords", length = 500)
private String diagnosisKeywords; // 适用诊断关键词
@Column(name = "template_content", columnDefinition = "TEXT")
private String templateContent; // 模板内容(JSON格式,包含药品明细列表)
@Column(name = "status", length = 16)
private String status; // 状态:ENABLED/DISABLED
@Column(name = "create_time")
private LocalDateTime createTime;
}4.1.2 药品合规与用量限制
| 合规维度 | 规则说明 | 校验时机 |
|---|---|---|
| 药品目录 | 仅限在药品目录内的药品可开具 | 开处方时 |
| 处方权限 | 不同职称医生可开具的药品范围不同 | 开处方时 |
| 用量限制 | 单次最大剂量、日最大剂量、疗程限制 | 开处方时 |
| 配伍禁忌 | 药品间相互作用检查 | 提交处方时 |
| 抗生素限制 | 抗生素使用级别与医生权限匹配 | 开处方时 |
| 麻/精/毒药品 | 特殊管制药品的额外审批流程 | 开处方时 |
| 儿童用药 | 按年龄/体重计算剂量的自动校验 | 开处方时 |
| 妊娠禁忌 | 孕期/哺乳期用药安全校验 | 开处方时 |
4.2 处方审核
4.2.1 审核流程
医生开具处方 --> 合规性自动校验(规则引擎)
|
+--------+--------+
| |
校验通过 校验不通过
| |
待药师审核 提示医生修改
|
+------+------+
| |
审核通过 审核驳回
| |
进入配药 通知医生修改4.2.2 规则引擎设计
规则引擎用于处方的自动合规性校验,采用可配置的规则体系。
规则表 (audit_rule)
java
@Entity
@Table(name = "audit_rule")
public class AuditRule {
@Id
@Column(name = "id", length = 32, nullable = false)
private String id;
@Column(name = "rule_code", length = 64, nullable = false, unique = true)
private String ruleCode; // 规则编码
@Column(name = "rule_name", length = 128, nullable = false)
private String ruleName; // 规则名称
@Column(name = "rule_type", length = 32, nullable = false)
private String ruleType; // 规则类型:DRUG_LIMIT/DOSAGE_LIMIT/INTERACTION/PERMISSION/AGE_CHECK
@Column(name = "rule_expression", length = 2000, nullable = false)
private String ruleExpression; // 规则表达式(可配置的规则脚本)
@Column(name = "severity", length = 16, nullable = false)
private String severity; // 严重级别:WARNING(警告)/ERROR(拦截)
@Column(name = "message_template", length = 500)
private String messageTemplate; // 提示信息模板
@Column(name = "status", length = 16)
private String status; // 状态:ENABLED/DISABLED
@Column(name = "priority")
private Integer priority; // 执行优先级
@Column(name = "create_time")
private LocalDateTime createTime;
}处方审核记录表 (prescription_audit_log)
java
@Entity
@Table(name = "prescription_audit_log")
public class PrescriptionAuditLog {
@Id
@Column(name = "id", length = 32, nullable = false)
private String id;
@Column(name = "prescription_id", length = 32, nullable = false)
private String prescriptionId;
@Column(name = "audit_type", length = 16, nullable = false)
private String auditType; // 审核类型:AUTO(自动审核)/MANUAL(人工审核)
@Column(name = "audit_result", length = 16, nullable = false)
private String auditResult; // 审核结果:PASSED/REJECTED/FLAGGED
@Column(name = "rule_code", length = 64)
private String ruleCode; // 触发规则(自动审核时)
@Column(name = "auditor_id", length = 32)
private String auditorId; // 审核人ID(人工审核时)
@Column(name = "remark", length = 500)
private String remark; // 审核备注
@Column(name = "create_time")
private LocalDateTime createTime;
}4.3 DTP 药房配送对接
DTP(Direct to Patient)药房模式,处方审核通过后直接流转至药房进行配药和配送。
| 对接环节 | 说明 |
|---|---|
| 处方推送 | 审核通过的处方推送至DTP药房系统 |
| 药品库存查询 | 实时查询药房库存,缺药时提示用户替换或转方 |
| 冷链配送 | 需冷链运输药品的特殊配送流程 |
| 配送追踪 | 物流状态实时追踪,用户端可查看 |
| 签收确认 | 患者签收后系统自动确认 |
| 药事服务 | 药师用药指导电话回访 |
配送订单表 (delivery_order)
java
@Entity
@Table(name = "delivery_order")
public class DeliveryOrder {
@Id
@Column(name = "id", length = 32, nullable = false)
private String id;
@Column(name = "prescription_id", length = 32, nullable = false)
private String prescriptionId;
@Column(name = "pharmacy_id", length = 32, nullable = false)
private String pharmacyId; // 药房ID
@Column(name = "delivery_status", length = 16, nullable = false)
private String deliveryStatus; // 配送状态:PENDING_DISPENSING/DISPENSING/DISPATCHED/IN_TRANSIT/DELIVERED/RECEIVED
@Column(name = "receiver_name", length = 32, nullable = false)
private String receiverName; // 收货人
@Column(name = "receiver_phone", length = 20, nullable = false)
private String receiverPhone; // 收货电话
@Column(name = "receiver_address", length = 256, nullable = false)
private String receiverAddress; // 收货地址
@Column(name = "delivery_company", length = 64)
private String deliveryCompany; // 物流公司
@Column(name = "tracking_no", length = 64)
private String trackingNo; // 物流单号
@Column(name = "is_cold_chain")
private Boolean isColdChain; // 是否冷链配送
@Column(name = "dispensing_time")
private LocalDateTime dispensingTime; // 配药时间
@Column(name = "dispatch_time")
private LocalDateTime dispatchTime; // 发货时间
@Column(name = "received_time")
private LocalDateTime receivedTime; // 签收时间
@Column(name = "create_time")
private LocalDateTime createTime;
}5. 问诊定价体系
5.1 定价模型
5.1.1 问诊类型定价
| 问诊类型 | 定价方式 | 价格区间 | 平台抽成比例 | 说明 |
|---|---|---|---|---|
| 图文咨询 | 医生自主定价 | 10-100元 | 15-20% | 按次收费,48小时内有效 |
| 电话咨询 | 医生自主定价 | 30-200元 | 15-20% | 按次收费,限时15/30分钟 |
| 视频咨询 | 医生自主定价 | 50-500元 | 15-25% | 按次收费,限时15/30分钟 |
| 名医问诊 | 医院统一定价 | 200-2000元 | 10-15% | 专家级医生,价格由医院制定 |
| 复诊咨询 | 医生自主定价 | 5-50元 | 10-15% | 同一医生复诊优惠价 |
| 处方问诊 | 医生自主定价 | 20-80元 | 15-20% | 含处方开具服务 |
5.1.2 医生自主定价
医生可在平台设定的价格区间内自主设定问诊价格。
| 定价因子 | 说明 |
|---|---|
| 医生职称 | 主任医师 > 副主任医师 > 主治医师 > 住院医师 |
| 医生声誉 | 好评率、患者评价、接诊量综合评分 |
| 科室热度 | 热门科室溢价(如儿科、皮肤科) |
| 时段因素 | 晚间/节假日问诊可溢价 |
| 医院等级 | 三甲医院 > 二甲医院 > 社区医院 |
5.2 平台服务费抽成
5.2.1 抽成规则
| 规则项 | 说明 |
|---|---|
| 基础抽成比例 | 按问诊费用的 15-25% 抽取 |
| 阶梯返利 | 月接诊量达到一定阈值后,抽成比例递减 |
| 优质医生激励 | 高评分医生享有更低抽成比例 |
| 平台活动补贴 | 平台营销活动期间,平台补贴部分费用 |
| 抽成上限 | 单次问诊抽成金额设上限(如不超过200元) |
平台抽成记录表 (platform_fee_record)
java
@Entity
@Table(name = "platform_fee_record")
public class PlatformFeeRecord {
@Id
@Column(name = "id", length = 32, nullable = false)
private String id;
@Column(name = "consult_id", length = 32)
private String consultId; // 问诊ID
@Column(name = "registration_id", length = 32)
private String registrationId; // 挂号ID
@Column(name = "order_type", length = 16, nullable = false)
private String orderType; // 订单类型:REGISTRATION(挂号)/CONSULTATION(问诊)
@Column(name = "order_amount", nullable = false)
private Long orderAmount; // 订单总金额(单位:分)
@Column(name = "platform_ratio", nullable = false)
private Integer platformRatio; // 平台抽成比例(如20表示20%)
@Column(name = "platform_fee", nullable = false)
private Long platformFee; // 平台抽成金额(单位:分)
@Column(name = "doctor_income", nullable = false)
private Long doctorIncome; // 医生收入(单位:分)
@Column(name = "settlement_status", length = 16)
private String settlementStatus; // 结算状态:UNSETTLED/SETTLED
@Column(name = "settlement_time")
private LocalDateTime settlementTime; // 结算时间
@Column(name = "create_time")
private LocalDateTime createTime;
}5.3 医生结算流程
问诊完成 --> 生成抽成记录 --> 进入结算周期(T+1/T+7/月结)
|
平台汇总对账
|
财务打款(自动结算)
|
通知医生收入到账| 结算周期 | 适用场景 | 说明 |
|---|---|---|
| T+1 | 优质医生、高频接诊医生 | 次日结算 |
| T+7 | 普通医生 | 每周结算一次 |
| 月结 | 低频医生 | 每月结算一次 |
| 按需提现 | 所有医生 | 达到最低提现金额后可提现 |
6. 系统架构概览
6.1 模块划分
┌─────────────────────────────────────────────────────────────────┐
│ 用户端(小程序/App/Web) │
├─────────────────────────────────────────────────────────────────┤
│ 预约挂号 │ 在线问诊 │ 处方服务 │ 健康档案 │ 支付 │
├─────────────────────────────────────────────────────────────────┤
│ 医生端(App/Web) │
├─────────────────────────────────────────────────────────────────┤
│ 排班管理 │ 接诊池 │ 电子病历 │ 处方开具 │ 收入 │
├─────────────────────────────────────────────────────────────────┤
│ 管理后台(Web) │
├─────────────────────────────────────────────────────────────────┤
│ 医院管理 │ 医生管理 │ 药品管理 │ 对账结算 │ 风控 │
├─────────────────────────────────────────────────────────────────┤
│ 基础服务层 │
├─────────────────────────────────────────────────────────────────┤
│ 用户服务 │ 订单服务 │ 支付服务 │ 消息服务 │ 文件服务 │
│ 号源服务 │ 问诊服务 │ 处方服务 │ 结算服务 │ 规则引擎 │
└─────────────────────────────────────────────────────────────────┘6.2 关键业务流程涉及的服务
| 业务流程 | 涉及服务 | 关键点 |
|---|---|---|
| 预约挂号 | 用户服务、号源服务、订单服务、支付服务 | 号源锁定与释放的原子性 |
| 在线问诊 | 问诊服务、消息服务、文件服务、支付服务 | 实时通信、超时处理 |
| 处方流转 | 处方服务、规则引擎、药品服务、配送服务 | 合规校验、签名认证 |
| 医生结算 | 结算服务、订单服务、支付服务 | 对账准确性、定时任务 |