
简介卫宁健康新一代医疗数字平台WiNEX介绍资料面向医院信息科、HIS/EMR产品经理及医疗信息化售前售后人员旨在说明当前医疗系统集成难、数据标准不一、流程冗余等痛点的应对方案。资料结合互联网、AI、物联网与大数据技术重点阐述临床业务重塑、基于SNOMED-CT与HL7 FHIR的数据标准化、“1X”开放中台架构涵盖业务中台、数据中台、技术中台等核心模块以及在线诊疗、药品配送等无边界服务场景适合希望快速理解WiNEX产品理念与数字化转型路径的读者。压缩包仅含1个PDF文件整体大小4.32MB文档结构围绕平台定位、标准模型、开放架构与场景创新展开便于按章节快速查阅整体页数适中适合快速通读。当前已有860人学习下载可作为卫宁WiNEX产品培训、方案预研或项目立项前的入门参考。1. 为什么医院信息科都在讨论 winex这不是又一套 HIS某医院信息科科长参加完产品发布会回来第一件事就是让集成平台组把排期表拿出来重排。不是他浮躁而是看完 winex 的一体化演示后他意识到手里那套刚上线一年的集成平台可能又要成为“遗产系统”。winex 不是又一套 HIS而是一个把患者主索引、主数据、接口交互、临床工作台全部重做的新一代医疗信息平台把散落在几十个子系统里的字典、接口、账号和流程收拢到统一底座上。对医院来说这意味着 C/S 客户端要换、点对点接口要拆、老患者 ID 要映射到新的 MPI。这篇文章只讲落地选型逻辑、演示环境部署、老系统并行、上线避坑。适合医院信息科、集成平台组和医疗信息化交付工程师也适合想切入医疗行业的后端开发者。2. 从单体到微服务winex 的架构设计为什么值得关注2.1 传统 HIS 的死穴为什么“功能越多”反而“越难用”老 HIS 的典型形态是一套单体内核把挂号、收费、处方、电子病历全塞进去再配一个 C/S 客户端装到每个诊室后面跟着 LIS、PACS、手麻、体检各建一套库。系统之间靠固定 IP 的 TCP 接口或中间表互通医生站在医嘱保存按钮后面可能要等四五次同步调用全部返回。结果就是改一个收费字典要同时通知五个系统患者姓名在一个系统里叫“张某”、在另一个系统里叫“张 X”主索引根本对不上。这些问题不是某一家的代码质量差而是单体架构决定了所有领域逻辑共享一个数据库和一套进程改动的副作用无法隔离。每上一个新系统就新增一张中间表时间一长接口关系就变成没人能讲清的蜘蛛网。winex 的做法是先做架构层面的切割把“人、组织、字典、消息、业务流程”从业务功能里抽出来形成独立的服务域。这也是我在评估它的时候最看重的一点它不是把菜单重新排一遍而是把数据流和事务边界重新画了一遍。层面传统单体 HISwinex 平台患者身份每个系统自建患者档案统一患者主索引MPI基础字典各系统复制粘贴维护主数据服务统一发布系统交互点对点接口 中间表API 网关 事件消息前端形态多个 C/S 客户端B/S 一体化工作台可嵌入第三方页面部署升级停业务发版风险集中容器化、按服务灰度2.2 领域拆分患者域、临床域、费用域都管什么微服务落地第一步不是写代码而是划边界。winex 的领域划分基本是沿着医院业务自然边界走的没有刻意拆得很碎患者域负责 MPI、建档、就诊记录、主索引合并临床域负责医嘱、病历、知情同意、临床路径费用域负责收费项目、计价、结算、退费药品域负责药库、药房、发药、退药公共域负责组织、人员、角色、权限、消息通知。每个域独立建库、独立发布域之间不共享表只通过 API 和事件交互。这种划分的价值在于故障隔离和发布隔离临床域半夜出了慢查询不会把收费端的结算线程拖死费用域要升级计费规则不需要让门诊医生站停服。这与老 HIS“一个库、一套进程、全局锁”的模型是本质区别。不过要泼一盆冷水领域拆完后真正难的不是服务拆分而是“跨域数据一致性”。老系统靠数据库事务一把锁保证扣费和记账同步微服务拆开后做不到跨库事务只能靠事件和补偿。所以看 winex 的架构不能只看 Kubernetes要看它对事件投递和消息消费的设计这是后面部署和排障最容易出问题的地方。2.3 事件消息让挂号、医嘱、缴费在多个服务间保持一致跨域事务的常用方案是事件驱动。以开立医嘱为例临床域保存医嘱后发布一条事件到消息中间件费用域和药品域各自消费这条事件去计价、去生成医嘱备药单据。事件体的设计一般长这样{ eventId: evt_6a3f9c2e8b1d4f7a9e0c5b3d1f2a8c70, eventType: order.created.v1, source: clinical-order-service, occurredAt: 2025-06-11T10:30:0008:00, orderId: OD20250611001, patientId: MPI00012345, payload: { orderItems: [ITEM_DIAG_001, ITEM_DRUG_005], departmentId: DEPT_INTERNAL, doctorId: DR_008 } }eventId 是全局唯一标识orderId 是业务主键这种“双 ID”设计不是冗余而是幂等的基础。消费者处理完一条消息后按 eventId 记录一次消费进度重复投递时直接跳过避免“同一条医嘱被计费两次”这种事故。实现时要注意事件发布不能先发消息再改库否则消息发出去了事务回滚后面的消费者会基于不存在的数据做操作。常见做法是本地消息表业务数据和待发事件放同一个数据库事务里写完业务后由后台任务轮询投递。这套机制在 winex 里是内置的部署时不需要自己开发但需要把消息表的清理任务配上不然跑半年后表会膨胀。2.4 统一字典与主数据为什么 winex 要先讲同一套术语医院系统的“方言”问题比想象中严重。同一个“阿莫西林胶囊”药库叫 ABXL、门诊医生站叫阿莫西林、收费处有个特殊码LIS 那边又是另一个编码。老系统靠各系统管理员手工维护映射表每次新药进院都要发通知让各科各自改一遍。winex 把字典收口到主数据服务各业务域启动时订阅不直接改库。我在看 winex 的时候特别关注字典版本机制。一个典型的同步版本表大概是这样的create table if not exists mdm.dict_sync_version ( dict_code varchar(32) not null, version_no bigint not null, publish_time timestamp not null, source_system varchar(32) not null default MDM );业务服务每次刷新缓存前先查这张表发现本地版本低于最新版本号就强制全量或增量拉取。这个机制解决了“技师更新了药库字典但医生站缓存没刷”的老大难问题。部署时我会额外关注版本号字段的时区处理统一用 UTC 存储、前端展示时转本地时间不然跨院区上线时字典发布时间会差 8 小时。2.5 前端工作台B/S 一体化的真正价值很多人以为 B/S 化就是把客户端换浏览器省了装软件。实际价值更接近“入口统一”winex 工作台把所有系统的菜单、待办、消息、最近患者集中到一个浏览器页面第三方系统通过 iframe 或前端路由嵌进来医生不用再记哪项业务在哪个客户端里点。对信息科来说最大的好处是权限模型也统一了不再一个系统一套账号离职人员账号清理变得可审计。这一层在演示时最直观但落地上要注意浏览器兼容性诊室里的老旧一体机如果系统版本过旧还是得先升级终端再推工作台。3. 用 Docker Compose 跑通 winex 演示环境最小部署与初始化3.1 先规划资源这套最小配置能跑通哪些功能演示环境不是生产环境别一上来就照着生产高可用方案堆机器。我常用的最小配置是 8 核 16G 内存加一块 200G SSD单机即可。这个规模能跑通主数据、门诊挂号、医嘱开立、消息推送这些核心链路但扛不住压测也别指望同时开十个科室的并发模拟。资源项演示环境参考最小生产参考CPU8 核32 核起内存16 G128 G 起数据盘200 G SSD按 5 年数据增量评估操作系统Linux x64与厂商支持矩阵一致建议安装 Docker 与 Docker Compose 插件后单独用一个目录存放发布包里的编排文件不要和业务代码混在一起。winex 的发布包一般会带一套面向演示的 compose 模板但如果拿到的是生产安装包里面通常是 K8s 的 Helm 模板直接 docker compose up 是起不来的。如果只有生产安装包我一般会从 demo 包开始它包含预置的租户和样例数据适合验证功能。3.2 用 docker-compose 拉起依赖中间件拿到 demo 包后先在 release 目录下看有没有 docker-compose.yml。通常基础依赖包含 PostgreSQL、Redis、RabbitMQ以及 API 网关和 Web 前端。下面是按常见 demo 包形态写的最小编排示例version: 3 services: postgres: image: registry.local/winex/pg-extension:15 environment: POSTGRES_PASSWORD: winex_demo_pwd volumes: - pgdata:/var/lib/postgresql/data redis: image: redis:7 command: [redis-server, --appendonly, yes] ports: - 6379:6379 rabbitmq: image: rabbitmq:3-management environment: RABBITMQ_DEFAULT_USER: winex_admin RABBITMQ_DEFAULT_PASS: winex_demo_pwd ports: - 15672:15672 apigateway: image: registry.local/winex/apigateway:demo ports: - 9000:9000 depends_on: - postgres - redis - rabbitmq web-ui: image: registry.local/winex/web-ui:demo ports: - 8080:8080 depends_on: - apigateway volumes: pgdata:这里的镜像地址 registry.local/winex 是示例实际部署时换成发布包内附带的离线镜像仓库地址即可。网关暴露 9000Web 页面暴露 8080Redis 和 RabbitMQ 的管理端口在内网用不建议直接映射到公网。启动顺序上中间件先起、网关次之、Web 最后depends_on 只是控制容器启动顺序不能保证“中间件已经就绪”所以脚本里需要加 sleep 或健康检查。这套编排里有几个点容易忽略Postgres 的镜像用的是厂商扩展版不是原生 postgres:15因为 winex 的表结构可能依赖额外插件Redis 开 appendonly 是为了演示环境重启后不丢缓存键但生产上要根据 RDB/AOF 策略仔细配置RabbitMQ 的管理密码不要用默认值demo 包常用的弱口令在公网环境下分分钟被扫描器爆破。3.3 初始化租户和主数据从空库到可登录容器都起来后空库是登录不进去的。winex 里“医院”是租户维度一个物理环境可以跑多家医院租户之间数据隔离。初始化命令一般长这样docker compose up -d postgres redis rabbitmq sleep 30 # 初始化租户、主数据字典、默认管理员 docker compose run --rm tooling winex-cli init --tenant DEMO --admin-account admin --admin-password Admin123 # 启动网关和前端 docker compose up -d apigateway web-uiinit 命令是发布包自带的管理 CLI具体子命令名以当前版本为准。--tenant DEMO 是租户编码--admin-account 和 --admin-password 指定默认管理员初始化过程会创建数据库 schema、写入基础字典、生成组织架构。--admin-password 这个参数在初始化完成后建议立刻改掉demo 包默认密码通常写死在文档里不改等于裸奔。初始化不是每次重跑都安全CLI 一般会做“已初始化则跳过”的保护。但如果不小心把数据库数据卷删了别指望 CLI 能恢复已产生的业务数据所以操作前先确认是在演示环境。初始化完成后浏览器访问 http://localhost:8080用刚才创建的管理员账号登录能看到工作台首页和组织架构树就算基本成功。注意生产环境不要用 init 命令带样例参数跑初始化应该使用发布包里的独立安装脚本来建库和灌主数据。3.4 第一次验证网关、登录页、健康检查服务都起来后先用简单命令验证链路docker compose ps # 检查 API 网关健康 curl -i http://localhost:9000/healthz # 检查前端页面响应 curl -I http://localhost:8080/预期结果docker compose ps 里 apigateway 和 web-ui 是 running 状态9000 端口返回 HTTP 200响应体是 JSON 格式的健康信息8080 返回 200能看到 index.html 或前端路由的响应头。如果 9000 端口超时先看 apigateway 容器日志重点找数据库连接和 RabbitMQ 连接错误。这两个是演示环境最常见的掉链子位置Postgres 密码写错、RabbitMQ 虚拟主机没创建、容器内网 DNS 解析不到服务名。还有一种情况是页面能打开但登录接口报 500这种问题多半是 Redis 连接失败因为会话信息存在 Redis 里。看 apigateway 的日志里有没有 ERR 级别的 Redisson 或 go-redis 报错有就直接连 Redis 容器docker compose exec redis redis-cli ping返回 PONG 说明 Redis 正常问题在网关配置文件的地址写错。4. 与老 HIS 并行5 个必须打通的集成点4.1 患者身份映射一院多户的“熵减”工程winex 上线后老 HIS 里的患者档案不会消失患者下次来就诊系统要能识别这是同一个人的新就诊记录。这个环节经常用一张映射表来解决insert into wmpi.patient_mapping ( source_system, source_patient_id, mpi_patient_id, merge_status ) values (HIS_V5, P202403120001, MPI00012345, ACTIVE) on conflict (source_system, source_patient_id) do update set mpi_patient_id excluded.mpi_patient_id;source_system 是来源系统编码source_patient_id 是老系统里的患者主键mpi_patient_id 是 winex 里的统一主索引。这个 SQL 的语义是“告诉 winex老系统的某个患者就是 MPI 里的这个人”遇到重复导入时直接更新映射关系。大量历史患者导入时合并主索引要先做相似度比对按身份证号、姓名、出生日期、手机号综合打分不然会出现一个 MPI 挂了两条老档案的脏数据。4.2 基础字典映射收费项目怎么对老 HIS 的收费项目和 winex 的费用域编码基本对不上集成时要建一张映射配置表。我一般把映射放在中间集成层而不是改 winex 的字典表。每条映射包含源系统编码、目标编码、有效期{ sourceSystem: HIS_V5, sourceCode: ITEM_5101, targetCode: WS_5101, category: TREATMENT, effectiveFrom: 2025-01-01, effectiveTo: null, enabled: true }effectiveTo 为 null 表示永久有效某个项目停用时再置为具体日期这样历史数据不会因为字典被删而丢了解释。映射规则要做成可配置界面不要让工程师硬编码在代码里。一个血的教训某次我把映射直接写在 Java 枚举里结果新项目上线后收费代码变了没人记得去改枚举财务对账错了一个月才查出来。4.3 医嘱与检查申请用异步消息替代直连老 HIS 和 LIS 之间的检查申请传统做法是医生站直接调用 LIS 的 WebService。winex 接入后检查申请应该从临床域发消息集成平台订阅后转成 LIS 的接口调用LIS 回传结果再发消息回来。这个环节不要直接把消息透传给 LIS要加一个转换层处理编码映射和字段裁剪。{ eventType: exam.order.created.v1, orderId: EX20250612001, patientId: MPI00012345, examItemCode: CT_CHEST_3MM, priority: NORMAL, appliedDoctorId: DR_008, departmentId: DEPT_INTERNAL }转换层拿到这条消息后按 LIS 的接口规范组装成 XML 或 JSON再调用老系统。注意给转换层加超时和重试LIS 服务不稳定时的重试要带幂等键否则同一张检查单一连发三次患者一夜之间收到三条预约短信找谁说理去。4.4 单点登录与待办从多账号到统一身份老系统各自维护自己的账号密码winex 工作台要统一入口最省事的做法是按 OAuth2 的授权码模式做winex 作为认证中心老系统接入后用户免二次登录。实现上有几个坑老系统的会话超时机制不一样有的 30 分钟无操作就踢人有的能挂一周统一后要按安全策略定一个合理的超时时间密码策略也要统一老系统如果是纯数字口令要强制用户在首次登录后改密。待办集成比登录更麻烦要把老系统的待办消息推送到 winex 的消息中心。常见做法是老系统提供一个查询待办的 APIwinex 工作台按一定频率轮询拉取。这里不要做实时推送意义不大用户能接受 1 分钟内的延迟轮询反而容易实现、好排查。4.5 财务日结与结算数据回传时间戳和状态机必须对齐门诊收费从一个系统迁到 winex 后日结数据如果两边都有财务对账就会很痛苦。最稳妥的方式是明确一个主数据源winex 上线后新发生的挂号、缴费、退费数据以 winex 为准老系统只保留历史数据。但实际切换总有一个过渡期两边都可能有当天的交易所以要做一次日终核对脚本select sett_date, count(distinct patient_id) as patients, sum(amount) as total_amount from wec_settlement.sett_detail where sett_date current_date - 1 group by sett_date;这个 SQL 跑在 winex 的费用库上拿到结果后再和财务从老系统导出的日报对比。差异通常出在退费业务上老系统是“先退费后复原状态”winex 是“先标记退款中完成后再结算”。两边操作时序不一致就会出现对账时金额差一笔。遇到这种情况不要急着改代码先确认时间戳是数据库生成还是应用生成统一成数据库时间不然时钟漂移会制造大量“跨天交易”。5. winex 上线避坑4 个我处理过的排查场景5.1 全系统登录 503网关 CPU 100%现象早上 8 点开诊高峰所有用户登录 winex 工作台都转圈几分钟后页面报 503API 网关容器 CPU 打满。原因网关默认线程池配置太保守连接池被慢请求占满。登录接口要校验密码、查用户、写 Redis 会话任何一个下游依赖响应慢都会把线程池占住后续请求全部排队。解决先看网关日志找到耗时最长的下游调用一般是 Redis 或者认证服务 GC 停顿。临时处理是把登录接口的熔断器打开下游异常时快速失败而不是无限等长期优化是把登录链路上的 Redis 操作批量合并减少一次登录 5 次网络往返。另外网关开线程池的默认参数一定要调我处理的那次是把最大线程数从 200 提到 500同时把登录接口单独配了隔离池效果立竿见影。5.2 药品能看不能开医生站提示“处方服务未就绪”现象门诊医生站能查到药品库存和价格但点“开处方”时提示处方服务未就绪药房那边又能正常发药。原因这个“玄学”现场背后是服务注册中心和数据缓存两处问题叠加。医生站从药品服务拿数据是通的但处方服务在注册中心里健康检查失败被网关摘掉了同时本地缓存的字典版本号还是上一个版本的导致处方服务拿到的药品编码和主数据不一致。解决先查注册中心里处方服务实例的 health 状态通常是内存或者磁盘指标超阈值被标记不健康重启该实例让指标归零。然后把医生站的缓存刷新接口调一下强制拉取最新字典版本。处理完再让医生重试一般就通了。关键是两个操作要一起做只刷缓存不解决服务健康检查几分钟后又会复发。5.3 检查申请单到 LIS 变成乱码现象从 winex 临床域发出的检查申请在 LIS 系统里显示一堆乱码患者姓名和检查项目全是问号。原因两个系统之间的字符集不一致。winex 内部统一用 UTF-8老 LIS 的接口还是 GBK 编码集成层做转换时只做了 URL 解码没有做字符集转换。解决在集成网关处加一层编码转换针对 LIS 的接口单独配置字符集为 GBK。同时动了检查方法类目里的特殊字符比如某些检查项目名称里有“±”GBK 下这字符有映射但转码时如果踩到非法字符就会变成“?”排查时要把样例数据和十六进制字节流一起拿出来看不能只看界面。5.4 日终结算不平退费订单“幽灵重复”现象上线第三天财务日结winex 和老系统的退费金额对不上多出一笔白天已经退掉的钱。原因退费消息被重复消费。老系统调用 winex 退费接口接口超时后重试重试前没有检查退费状态。第二次请求进来时退费事件已经发过一遍消息消费者没有做幂等把退费金额又记了一遍。解决给退费接口增加业务幂等判断用原交易号退费次数做唯一约束数据库加唯一索引重复请求直接返回上一次的结果而不是重新走一遍流程。同时检查 RabbitMQ 消费者是否按 eventId 去重把消费进度记录表补上之后这类问题基本能拦住。6. 把 winex 用出价值上线后我常做的三组巡检6.1 门诊流程耗时前后对比才是验收上线前抽一周的门诊平均耗时上线后再抽同口径一周比的是“从挂号到医生开完医嘱”的中位时长不是平均值。平均值会被抢救等长尾场景拉偏中位数更能反映大多数患者的真实感受。6.2 消息积压要每周看一次消息中间件是最容易变成黑匣子的环节docker compose exec rabbitmq rabbitmqctl list_queues name messages consumers重点关注 messages 数值持续上涨且不下降的队列说明消费者挂了或消费速度跟不上。积压不超过 1 万条还能追一旦超过 10 万条追数据本身就是风险。6.3 每周跑一遍字典一致性给自己留后悔药curl -s http://localhost:9000/mdm/dict/version | jq .data[] | select(.version_no 100)把版本号偏低的业务服务找出来确认是需要刷新还是已经废弃。我习惯每周五下午做一次这个巡检因为只要有一次版本回退没被发现后面一周的报表都会错曾经护理执行单因此多打了一整天。从那以后“对字典版本号”就写进了我的巡检清单。希望帮到你。本文还有配套的精品资源点击获取