简介:微医互联网医院平台详细介绍是一份面向医疗信息化从业者、互联网医院产品经理及开发人员的PPTX演示文档,系统梳理了互联网医院的整体产品架构与核心业务流程。内容从平台云端架构切入,重点拆解医师端与患者端两大入口:医师端覆盖在线复诊、远程门诊、远程会诊、双向转诊、检查检验、远程培训、视频会议、面诊处方等场景;患者端则包括患者主页、在线复诊、预约挂号、智能导诊与个人中心,完整呈现了线上线下融合的医疗服务闭环。资源包内为1个PPTX文件,压缩包约25MB,页面结构清晰、目录层级完整,适合直接用于产品方案设计、竞品分析或项目汇报参考。已有317人学习浏览,可作为快速理解微医互联网医院产品形态和功能模块的实用资料。
1. 微医互联网医院平台的定位:连接三端,但技术难点集中在状态一致
刚接触微医互联网医院平台的人,很容易先把它当成一个复杂一点的在线预约挂号系统:患者打开手机挂号,到医院凭号就诊,线下结束。真正接入过这类平台之后会发现,这个判断只摸到了最外面一层。平台实际由医疗业务、药事履约、交易结算、基础服务四条链路叠成,患者看到的是问诊对话,背后跑的是号源库存、电子处方流转、药品出库、支付对账这些独立子系统。
这几条链路的技术要求并不一致。预约挂号拼的是高并发下的库存扣减,电子处方拼的是状态机和多系统回执的一致性,支付环节拼的是对账审计的完备性。对 IT 从业者来说,研究这个平台的价值不在于它的界面长什么样,而在于业务规则如何拆成数据模型、接口如何对接、故障怎么兜底。下文按我实际切入一个互联网医院项目的思路,从模块拆解、HIS 对接、高峰排障到数据治理逐层展开。
2. 微医互联网医院平台的模块拆解:预约挂号、电子处方与履约的状态设计
2.1 把平台业务拆成四个域,比按功能拆更容易落地
不管微医侧的系统代码具体怎么组织,从外部接入一个互联网医院平台时,我一般先按业务域而不是按页面画图。按域拆,一方面是职责边界清晰,另一方面是排障时能快速定位问题属于哪个子系统的协作故障,而不是在一个大表里翻来翻去。
| 业务域 | 代表能力 | 一次就诊里的角色 | 最容易出问题的点 |
|---|---|---|---|
| 医疗业务域 | 在线问诊、电子病历、处方开具 | 给患者看病,产出诊疗数据 | 处方状态漂移,病历归属错乱 |
| 药事履约域 | 药品目录、审方、库存、配送 | 把处方变成实体药品 | 药品无货、配送回执丢失 |
| 交易结算域 | 订单、支付、医保、退款 | 管钱怎么收、怎么退、怎么对账 | 回调丢失、重复退款 |
| 基础服务域 | 账号、认证、消息推送、日志 | 管理身份、通信与审计 | 医生排班变更未通知到问诊会话 |
微医互联网医院平台的这四个域不是前后串联,而是围绕同一条就诊主键协同。患者挂号成功后,医疗域开始记录问诊内容,处方审核通过后药事履约域才接单,交易结算域始终监听处方和履约事件来更新账单。页面迭代往往只碰一个域,而真正让运维头疼的,是跨域状态出现不一致。
2.2 放号时段的高并发扣减:Redis 执行 Lua 再回源 DB 校验
预约挂号是互联网医院平台流量最集中的入口,号源本质上是一个库存。常见错误是只用SETNX当分布式锁,锁超时后被其他线程覆盖,最终还是超卖;或者直接更新数据库update slots set left = left - 1 where schedule_id = ?,在万级并发下主库行锁会拖垮整个库。我一般用 Redis 的 Lua 脚本先做原子扣减,再用数据库唯一约束兜底订单。
import redis r = redis.Redis(host="10.x.x.20", port=6379, db=2, decode_responses=True) lua_acquire = """ local left = tonumber(redis.call('GET', KEYS[1])) if left == nil then return -2 -- 排班缓存不存在,需要回源加载 end if left < 1 then return -1 -- 号源已放完 end redis.call('DECR', KEYS[1]) return left - 1 -- 返回扣减后的剩余数 """ def acquire_slot(schedule_id, patient_id): key = f"schedule:slot:{schedule_id}" left = r.eval(lua_acquire, 1, key) if left == -2: # 缓存键缺失,从DB加载排班总数后初始化,只重试一次 total = load_total_from_mysql(schedule_id) if total is None: raise ScheduleNotFound(schedule_id) r.set(key, total, ex=1800) left = r.eval(lua_acquire, 1, key) if left == -1: raise SlotSoldOut(schedule_id) # 异步写占用流水,失败只报警不阻断挂号主流程 append_slot_record(schedule_id, patient_id) return lefteval调用可以在 Redis 内部原子完成检查和扣减动作,中间不会被其他命令插入,这是它能在高并发下成立的根本原因。-2用于标记排班缓存不存在,回源加载后只重试一次,防止缓存击穿把 DB 打爆。Redis 扣减成功不等于订单成立,所以append_slot_record做成异步,抢号峰值时同步写流水会立刻放大数据库压力,丢几条流水可以通过日志重建。真正的订单防重,靠的是订单表里schedule_id + patient_id + visit_date的唯一索引。
2.3 处方和履约拆成两个状态机,防止一张表锁死两个流程
电子处方不是订单表里的一个 JSON 字段,它本身有完整的生命周期。开方、审方、通过、拒方、配药、出库、发货、签收,每一步都可能中止。如果把处方状态和配送状态混在一张表里,修改物流状态时会锁住处方行,而医生端的开方审核还等着同一条记录,业务阻塞就发生了。
CREATE TABLE rx_order ( rx_id varchar(32) primary key, visit_no varchar(64) not null, order_id varchar(64) not null, doctor_id varchar(32) not null, patient_id varchar(32) not null, drug_json json not null, -- 药品明细,含用法用量 rx_status tinyint not null default 0, -- 0待审核 1通过 2拒方 3作废 fulfill_status tinyint not null default 0, -- 0未履约 1配药中 2已发货 3已签收 audit_opinion varchar(512) default null, -- 审方意见 created_at datetime not null, updated_at datetime not null, key idx_order (order_id), key idx_patient (patient_id, created_at) );rx_status和fulfill_status拆成两个独立字段,业务上允许它们不同步推进。比如处方已经审核通过但药房暂时无货,fulfill_status停在配药中,问诊记录和医嘱继续保留;反过来物流链路需要回退时,也不会影响处方的有效状态。两个状态字段的值域完全独立,就不会出现“处方又要发药又要退款”互相覆盖的脏判断。
3. 医院HIS接入微医互联网医院平台的接口协议与降级补偿方案
3.1 先谈协议:接口认证、签名、幂等三件事一次对齐
医院 HIS 接入时,真正耗时间的不是接口数量,而是三方对同一事件的表示方式不一致。通常的做法是先在一张协议表上把通信规则钉死,再开始联调。
| 约定项 | 推荐做法 | 说明 |
|---|---|---|
| 通讯链路 | 正式环境走 HTTPS,外网不裸传 | 通过反向代理或 API 网关统一管理证书 |
| 服务认证 | 每家医院分配一个医院编码和 Secret | 不透传医院内部账号密码 |
| 请求签名 | 业务参数按 key 排序后做 HMAC-SHA256 | 防止参数被中间人篡改 |
| 幂等控制 | 医院侧对rx_id、order_id建唯一索引 | 重复回调时返回成功但不重复处理 |
| 超时限制 | 同步接口控制在 3 秒内 | 超过就转异步补偿队列 |
| 时间格式 | 业务时区本地时间加毫秒时间戳 | 避免跨时区把预约日期推错 |
签名算法我习惯这样定:把请求体里所有业务参数去掉空值字段,按 key 字典序拼接成k1=v1&k2=v2,末尾拼上医院 Secret 做 HMAC-SHA256,结果放在请求头的X-Sign字段。同时请求头带上X-Hospital-Code和X-Timestamp,接收方先校验时间戳偏差是否小于 300 秒,再重算签名,这样能同时挡住重放和篡改两种攻击。
3.2 必通的九个核心接口及容易忽略的返回字段
多数医院接入互联网医院平台时不会一次性开通全部能力,而是先预约挂号,再问诊,最后打通处方和支付。按这个顺序,我整理了一份最小接口清单:
| 接口场景 | 接口名称 | 方向 | 关键字段 | 失败影响 |
|---|---|---|---|---|
| 基础档案 | 患者建档 | 平台→HIS | patient_id、证件号、手机号 | 无档案,后续无法挂号 |
| 号源同步 | 排班查询/同步 | HIS→平台 | schedule_id、医生、时间段、总号量 | 平台号源与线下不一致 |
| 号源锁定 | 预约锁号 | 平台→HIS | patient_id、schedule_id | 平台有号但下单失败 |
| 改约退约 | 取消预约 | 平台→HIS | appointment_id | 线下号源被占用 |
| 问诊会话 | 会话创建 | 平台→HIS | visit_no、doctor_id、patient_id | 医生无法接诊 |
| 病历回传 | 就诊记录同步 | HIS→平台 | 诊断、病历、医嘱 | 患者端看不到报告 |
| 处方下发 | 电子处方同步 | 平台→HIS | rx_id、drug_json、审方状态 | 药房无法出库 |
| 检验检查 | 报告查询 | HIS→平台 | report_id、报告内容 | 复诊无法追溯 |
| 支付结算 | 费用状态回传 | 双向 | order_id、pay_status、refund_amount | 对账不平 |
这里最容易踩的坑是“预约锁号”和“订单创建”两件事没有合并成一个动作。平台先锁号再创订单,可以用本地锁加 HIS 锁双重保护;如果先创单后锁号,锁号失败时还要回滚订单,回滚又触发一次 HIS 调用,链路翻倍,故障概率也就翻倍。
3.3 HIS 接口抖动时:先做异步补偿再做人工介入
接口联调完不代表稳定下来,HIS 老系统经常在夜间批处理或月末结算时明显变慢。遇到这种情况,不建议把同步请求的超时时间拉长,那只会让业务线程全部挂起。我更偏向“同步尝试 3 秒,失败立刻进补偿队列”的模式。
// 将HIS同步调用改为“同步尝试+异步补偿”的入口逻辑 async function syncPrescriptionToHis(rx) { const ok = await callHisWithTimeout(rx, 3000) if (ok) return const entry = { rx_id: rx.rx_id, payload: rx, retry_count: 0, next_retry_at: Date.now() + 5000, last_error: 'timeout', } await mqProducer.send('his.compensate', entry) logger.error('[HIS补偿入队] 同步超时,rx_id=%s', rx.rx_id) }callHisWithTimeout在 3000 毫秒内得不到响应就主动返回失败,不继续占用线程。失败请求进入补偿队列后,由消费端按指数退避重试,退避间隔从 5 秒递增到 5 分钟,重试 5 次仍然失败就写入死信表并发送告警,转成人工介入流程。这个方案把 HIS 抖动对主流程的影响控制在单个调用内,不会因为一次网络闪断导致用户的挂号或问诊被卡住。
4. 微医互联网医院平台高峰期排障:抢号并发、消息积压与订单回写
4.1 抢号时 Redis 热 key 怎么拆
抢号时段,同一个医生排班的号源对应同一个 Redis key。如果只用一个 key,几万人同时DECR它,这个 key 所在的分片会成为热点节点,Redis 实例 CPU 先被打满,整个集群的读写请求都会变慢。常见的做法是把一个排班拆成多个子分片,每个分片承载一部分号量:
SEGMENTS = 10 def slot_key(schedule_id, segment_idx): return f"schedule:slot:{schedule_id}:{segment_idx}" def acquire_from_segments(schedule_id, patient_id): # 随机顺序遍历分片,避免每次都从第一个分片开始抢 segs = random.sample(range(SEGMENTS), SEGMENTS) for seg in segs: left = acquire_once(slot_key(schedule_id, seg), patient_id) if left >= 0: return left # 扣减成功 return -1 # 所有分片都已无号请求按随机顺序访问 10 个分片,单 key 热点压力下降一个数量级。代价是号源统计变得分散,所以每个分片扣减成功后要异步上报一段占用流水,由聚合任务把已占号池和未占号池汇总到管理后台。分段扣减还必须配合数据库的唯一约束兜底,否则分段逻辑漏掉一个位置也会超卖。
4.2 消息积压的判定标准与处理顺序
互联网医院平台链路里的消息队列不少:处方回执、支付回调、配送状态、短信通知都走 MQ。积压不可怕,可怕的是不分优先级,把短信队列和支付回调排在同一个消费组里,结果患者支付状态几十秒不同步。
| 队列 | 业务流向 | 建议积压阈值 | 超限动作 |
|---|---|---|---|
| his.rx.callback | HIS 回写处方状态到平台 | lag 大于 5000 | 先扩消费者,再检查 HIS 接口响应码 |
| pay.notify.callback | 支付渠道回调 | lag 大于 1000 | 暂停非必要的风控过滤逻辑,优先收单 |
| drug.ship.status | 药房出库与配送状态 | lag 大于 2000 | 检查药房 WMS 接口,防止轮询拖垮 |
| sms.send | 通知短信与推送 | lag 大于 10000 | 压缩营销类通知,保留诊疗状态类 |
先处理支付回调积压,因为它直接影响用户的支付结果感知和资金对账;短信通知排在最后,即便延迟十分钟用户也能接受。当处方队列积压时,优先看 HIS 返回值是不是集中在同一个业务错误码,比如数据库繁忙,这时不应该加消费线程,加得多反而把 HIS 打得越来越慢。合理做法是开启退避重试并降低消费速率,等 HIS 恢复后再自动追平。
4.3 订单状态回写不一致,以状态日志为准排查
支付回调、HIS 回执、物流回执三路都可能修改同一个订单,谁先到谁后到无法保证。我处理这类问题的原则很简单:一个字段只允许一个域去写,其他域通过事件订阅感知变化。线上排查时先看订单状态时间线,而不是直接看当前状态:
select order_id, status, event_type, operator, created_at from order_status_log where order_id = 'MZ20250218001' order by created_at, id;正常的时间线应该是CREATED -> LOCKED -> PAID -> RX_SYNCED -> DISPENSED -> SHIPPED。如果中间出现PAID之后再收到患者侧的CANCELED,不能直接改状态,因为订单可能已经在药房出库了,这时要去判断当前履约节点:未发货可以取消并退款,已发货则要走退药退款流程。状态日志表把所有变更来源记清楚,排查时能直接在日志里对出是哪个域写错了,省去翻业务代码的功夫。
5. 微医互联网医院平台的数据安全治理:脱敏、授权与对账审计
5.1 患者身份字段按场景做动态脱敏
平台上涉及患者姓名、证件号、手机号、住址和疾病诊断,这些字段会出现在接口回执、日志、消息队列和前端页面上。一个字段在不同场景里要求不一样,我会在统一序列化层做动态脱敏,而不是在每段业务代码里手工处理。
| 场景 | 脱敏粒度 | 示例效果 |
|---|---|---|
| 患者端列表展示 | 保留姓氏和末四位 | 张****1234 |
| 数据分析与科研 | 去掉身份字段匿名化 | 患者匿名ID + 诊断 |
| 调用医院 HIS 接口 | 完整传输,不落日志 | 原文走加密通道 |
| MQ 消息体 | 只带患者 ID | 不传输身份细节 |
def mask_identity(value, field, scene): if scene == "list": # 列表页只保留首字符和末四位 return value[0] + "*" * (len(value) - 4) + value[-4:] if scene == "his_api": # 医院侧调用需要真实值,但每次调用要登记审计日志 audit_log( operator=current_user(), target=value, action="patient_detail_view", scene=scene, ) return value_full if scene == "mq": # 消息队列里只保留平台内部患者ID,不出现身份明文 return patient_id raise MaskPolicyNotFound(field, scene)his_api场景返回完整值,但每条调用都会产生审计记录,做到可追溯。mq场景只传内部患者 ID,下游消费者需要详细资料时再走带签名的查询接口,而不是把身份信息直接塞进消息体。
5.2 日终对账脚本:找出平台有记录但渠道没有的回单
医疗平台的支付清算建议做成“日终文件对账 + 实时流水核对”两层。实时流水核对监控每一笔退款是否在约定时间内完成,日终对账则在凌晨拉取渠道结算文件与本地订单比对。
-- 日终对账:找出平台已标记支付成功,但渠道结算文件里不存在的订单 select o.order_id, o.pay_amount from pay_order o left join channel_checkfile c on o.channel_trade_no = c.channel_trade_no and c.biz_date = '2025-02-18' where o.pay_date = '2025-02-18' and o.status = 'PAID' and c.id is null;这条 SQL 查出的是“平台认为已支付,渠道对账单里没有”的差异数据,属于高优处理对象,可能涉及支付状态被错误更新或渠道文件延迟。反向差集同样要查:渠道文件里有记录但平台没有订单,这类情况多半是测试单或渠道异常单,需要转入人工核查列表,不能直接自动入账。对账脚本本身要保证幂等,重复执行不能产生重复的差异记录。
6. 微医互联网医院平台落地后的 AI 预分诊与慢病数据增值
6.1 AI 预分诊:把它放在问诊入口,而不是放在病历之后
平台上线稳定后,最值得投入的智能改造是预分诊。让患者在主诉输入前先做结构化自述,再用模型输出建议科室和医生等级。关键不是把模型做得多么复杂,而是把输出格式固定成标准 JSON,下游系统只需要解析三个字段就能路由。
{ "chief_complaint": "咳嗽3天", "structured_triage": { "symptom": "咳嗽", "duration_days": 3, "fever": "38.1", "chronic_disease": ["高血压"], "medication": [] }, "recommended_department": "呼吸内科", "referred_doctor_level": 2 }recommended_department直接映射到号的科室编码,referred_doctor_level用来决定推送普通门诊还是专病门诊。这套接口的好处是路由逻辑和模型完全解耦,模型升级替换不影响现有流程。
6.2 慢病随访数据回灌:把服药提醒变成下一次就诊的参考依据
处方履约完成后患者还会持续产生数据:血压血糖上传、用药依从度、复查提醒点是否点击。这些数据建议按时序数据库保存,以patient_id + metric + day为分区,查询时按患者聚合,不按设备聚合。
一个可靠的落地方式是把随访记录合并到下一次问诊会话里。医生打开复诊会话时,平台自动把近 30 天的血压曲线和漏服记录推到医生工作台,医生在开方前就能看到连续性趋势,而不需要再问患者“最近控制得怎么样”。这块对数据质量的要求是先保证字段字典一致,比如血压单位到底是 mmHg 还是 kPa,必须在接入时定死,否则模型和图表都会算出错误结果。
本文还有配套的精品资源,点击获取