基于Vue+uni-app的互联网医院多端开发实战

发布时间:2026/9/15 5:26:35

基于Vue+uni-app的互联网医院多端开发实战 简介基于Vue框架与uni-app跨端方案打造的互联网医院系统前端源码面向需要开展互联网诊疗业务的医院、医疗信息化服务商及前端开发者。项目将HIS对接、远程诊疗、智慧医院、网上药房、电子处方流转等核心功能模块化呈现适合用于快速搭建同类业务或学习医疗场景下的前端架构实践。压缩包共175个文件以53个Vue组件为主力另有33个JavaScript文件支撑交互逻辑、32个PNG图片承载界面资源、20个JSON配置管理业务信息以及SCSS/CSS样式表、Markdown文档、字体与工具脚本等整体仅1.26MB结构清晰便于按模块查阅。源码采用组件化与响应式设计能够适配不同移动端运行环境既可用于直接改造上线也可作为智慧医疗项目的设计参考。目前已有369人学习或下载适合具备Vue基础、希望深入理解互联网医院业务模型的中高级前端工程师。1. 从一个App包打天下到一套源码多端运行万岳互联网医院系统的uni-app实践很多医院信息科把线上化等同于做一个App可真到上线时发现患者习惯扫微信小程序医生需要用App查房运营方还想把H5嵌进公众号和官网。三个平台、三套代码、三支维护队伍医疗项目根本养不起这种成本。万岳互联网医院系统把前端底座放在Vue uni-app上核心目的就是用一套源码编译出微信小程序、H5和Android/iOS App。这套源码的价值不在页面堆砌而在于如何让业务模块在多个平台之间复用、差异点又能被隔离。下面从源码设计角度讲目录结构、核心业务落地、多端打包和排查方法给出的命令和配置可以直接抄进项目里验证。2. 技术选型与源码架构Vue背后是业务边界的设计2.1 为什么是Vue uni-app而不是三端三套代码Vue是国内医疗IT团队最熟悉的框架之一模板语法直观生态组件丰富。uni-app则是在Vue语法上做了一次编译映射把同一套源码转换成小程序、H5和App各自的工程。这里的收益不是写起来少敲几个字而是接口层、状态层和数据层的逻辑只维护一份。医院项目往往要对接HIS、LIS、PACS等多个历史系统后端接口风格不统一如果前端再按平台拆三份联调成本会呈指数上升。代价当然也有。跨端方案最大的坑是同一段逻辑在不同平台行为不一致比如H5的跨域限制、小程序的包体积限制、App原生模块的权限声明。所以源码设计的重点不是所有代码都写在页面里而是把平台差异收敛到几个固定模块请求层、权限层、以及音视频等强原生能力层。Vue版本上老项目建议继续用Vue2新项目优选Vue3组合式API但要注意uni-app对Vue3的编译需要通过cli方式创建或者在HBuilderX里手动切到vue3版本这个选择要在项目启动时定下来中途切换成本很高。2.2 源码目录pages、store、api、components怎么分一套能长期维护的uni-app源码目录结构通常按业务域划分而不是按技术类型乱堆。以万岳这类互联网医院系统为例推荐的结构是project/ ├── pages/ │ ├── registration/ # 预约挂号 │ ├── consultation/ # 在线问诊 │ ├── report/ # 报告查询 │ └── user/ # 个人中心 ├── components/ │ ├── schedule-calendar/ # 排班日历 │ ├── patient-selector/ # 就诊人选择 │ └── empty-view/ # 空状态 ├── store/ │ ├── modules/ │ │ ├── user.js │ │ └── hospital.js ├── api/ │ ├── request.js # 统一请求 │ ├── auth.js │ ├── registration.js │ └── consultation.js ├── utils/ │ ├── auth.js │ ├── date.js │ └── location.js ├── static/ ├── App.vue ├── main.js └── manifest.json这里的核心约束是api层独立和store状态独立。页面组件只负责排版和用户交互取数逻辑全部走api层函数跨页面共享的登录态、当前医院、就诊人列表放在store里。这样做的直接好处是后端接口字段变更时页面不用动页面重构时数据层不用动。比如预约挂号页从列表流改成日历流只改页面的template和computed不需要动api。接口函数建议保持单一职责不要在函数内部拼装业务逻辑。一个典型的api文件长这样// api/registration.js import request from ./request // 获取科室列表 export const getDepartments () { return request({ url: /api/v1/hospital/departments, method: GET }) } // 获取医生排班 export const getDoctorSchedule ({ doctorId, date }) { return request({ url: /api/v1/hospital/schedule/doctors/${doctorId}, method: GET, data: { date } }) }这个文件里不出现任何业务判断也没有token拼接。调用方拿到的永远是Promise成功或失败由统一请求层处理。单元测试时可以方便地mock这个模块同时对开发人员来说看到函数名就知道它对应哪个接口。2.3 封装uni.request与登录态代码少的请求层才是好请求层uni.request在H5、小程序和App上的参数大体一致但细节有差异。统一封装请求层是所有多端项目的第一道工程。下面是一个精简但完整的request.js可以直接复制到utils/request.js使用// utils/request.js import { getToken } from ./auth const BASE_URL https://api.example.com // 从config.js读取环境地址 /** * 统一请求 * param {Object} opts { url, method, data, needAuth } */ export default function request(opts) { const token getToken() return new Promise((resolve, reject) { uni.request({ url: BASE_URL opts.url, method: opts.method || GET, data: opts.data || {}, header: { Content-Type: application/json, // 不需要登录的接口传needAuth: false不携带token Authorization: opts.needAuth false ? : token ? Bearer ${token} : }, success: (res) { if (res.statusCode 200 res.data.code 0) { resolve(res.data.data) } else { uni.showToast({ title: res.data.msg || 请求失败, icon: none }) if (res.data.code 2001) { // 登录态过期清理token并回登录页 uni.reLaunch({ url: /pages/login/index }) } reject(new Error(res.data.msg || 请求失败)) } }, fail: (err) { uni.showToast({ title: 网络异常请检查网络, icon: none }) reject(err) } }) }) }参数说明BASE_URL通过环境变量区分测试和生产可以在manifest.json的h5配置里注入也可以用条件编译needAuth用于验证码、公钥等开放接口字段code的判断依赖后端约定强约束在请求层的好处是页面永远只关心业务数据不碰状态码。要注意不要把接口返回的数据在这里二次变形比如把code0翻译成false这样会让api层语义混乱。失败就reject页面通过async/await配合try/catch处理即可不要再在页面里写一堆uni.showToast。3. 核心业务模块预约挂号与在线问诊的落地实现医疗系统页面多但大多数是标准表单加列表。真正的技术难点集中在三个方向号源这种并发敏感数据的展示与提交、视频问诊这种强实时通信、以及支付和电子处方这种需要后端签名的动作。这里拆两个代表性模块讲解一个是预约挂号一个是在线问诊。3.1 预约挂号从科室列表到号源日历的数据流预约挂号流程通常是选科室 - 选医生 - 选排班 - 选就诊人 - 提交订单。这个流程中排班日历和就诊人选择是复用频率最高的两个组件。排班日历的数据结构由后端按天返回可用号源前端需要把数据映射到日历格子并把约满的日期置灰。组件内部不建议在template里写复杂三元用computed生成日历数组是常见做法// components/schedule-calendar.vue computed: { calendarCells() { const year this.currentYear const month this.currentMonth const daysInMonth new Date(year, month, 0).getDate() const cells [] for (let day 1; day daysInMonth; day) { const dateStr ${year}-${String(month).padStart(2, 0)}-${String(day).padStart(2, 0)} const item this.scheduleMap[dateStr] || { available: 0 } cells.push({ date: dateStr, day, disabled: item.available 0, available: item.available }) } return cells } }这里的schedulerMap是把接口数组转成以日期为key的对象作用是为了避免在循环里反复用find查找数组项。computed的好处是当排班数据从接口返回后组件视图自动刷新。提交订单时前端只做按钮禁用级别的展示控制真正的号源校验必须交给后端因为用户可能在两个端同时操作。前端不要在本地判断还剩几个号那是医生端和后台管理的职责。在预约挂号页里就诊人选择器要注意每次进入页面时刷新列表因为患者可能刚在个人中心添加了卡号。这里有一个容易被忽略的细节就诊人列表的接口需要带clinicId参数不同院区的卡号体系不同如果前端缓存了上一次的就诊人数据选到另一院区时就会提交失败。3.2 在线问诊图文对话与视频通话的跨端兼容图文问诊本质是消息列表加WebSocket推送前端要处理好图片、文字、系统通知的混合展示。这里没有太多跨端障碍难点在视频问诊。视频通话必须接实时音视频SDK比如腾讯云TRTC或声网而小程序端和App端使用SDK的方式完全不同H5端又是另一套WebRTC。推进方式是用条件编译把平台差异隔离在util层页面里只调用一个createVideoCall方法// utils/call/video.js // #ifdef H5 export function createVideoCall(options) { // H5端使用WebRTC或第三方SDK的web端 const client new WebRTCClient(options) return client.start() } // #endif // #ifdef MP-WEIXIN export function createVideoCall(options) { // 小程序端使用trtc-wx-miniprogram const sdk require(trtc-wx-miniprogram) const client sdk.createClient({ mode: rtc }) return client.join(options.roomId) } // #endif // #ifdef APP-PLUS export function createVideoCall(options) { // App端使用原生插件 const module uni.requireNativePlugin(VideoCallModule) return module.start(options) } // #endif条件编译的注释在编译时会直接剔除不属于当前平台的代码因此不用担心运行时出现undefined的引用。但要注意这段注释必须原样写成// #ifdef H5不能加空格或改动标记。页面调用的代码不需要做任何平台判断这也是源码隔离差异的典型手法。在在线问诊页面还要处理摄像头和麦克风权限。微信小程序通过uni.authorize申请App端则依赖manifest中声明的权限。常见的坑是用户在iOS上第一次拒绝了摄像头权限之后再次调用uni.authorize直接返回fail没有弹窗。这时要检查uni.getSetting中的authSetting[scope.camera]如果是false需要引导用户到设置页打开权限而不是再次调用授权API。3.3 支付与电子处方经过后端签名才能信任的前端动作医疗支付不能像电商那样前端直接调起微信支付。流程是前端请求后端创建订单后端返回时间戳、nonceStr、package、signType和paySign前端再把参数传给uni.requestPayment。小程序端示例// api/payment.js export const createOrder (data) request({ url: /api/v1/order/pay, method: POST, data }) export const wxPay (orderId) { createOrder({ orderId }).then((payParams) { uni.requestPayment({ provider: wxpay, timeStamp: payParams.timeStamp, nonceStr: payParams.nonceStr, package: payParams.package, signType: payParams.signType, paySign: payParams.paySign, success: () { // 这里不要直接跳转页面等待后端通知或主动查询订单 }, fail: () { // 用户取消或支付失败 } }) }) }支付成功回调不能作为业务完成的唯一依据因为用户可能在支付过程中切后台导致小程序端的回调丢失。正确做法是在页面onShow里调用查询订单状态接口或者监听后端推送的消息。前端拿到的paySign是后端用私钥生成的前端不需要也不能去校验签名的数学正确性只需要原样传给支付SDK。电子处方和报告打印通常用PDF展示。在uni-app中不能直接用uni.previewImage看PDF需要先uni.downloadFile下载到本地临时路径再调uni.openDocument打开。这个接口在iOS上有严格的格式要求后端返回的URL必须带文件后缀否则会被识别失败。另外处方PDF往往包含患者隐私信息下载时需要在请求头带上tokenuni.downloadFile支持通过header参数传递。4. 跨端适配与打包从H5到微信小程序再到App多端项目有一半工作量花在适配和上架上。这一章的每一条都对应真实踩过的坑尤其是manifest、条件编译和权限配置。4.1 manifest配置不同端各自的门牌号manifest.json是uni-app的全局配置多端打包之前必须逐项核对这几个配置点配置项所在位置作用常见错误mp-weixin.appidmanifest - mp-weixin微信小程序唯一标识不填或填错真机预览白屏h5.router.modemanifest - h5 - routerH5路由模式history模式服务器未配置刷新404app-plus.distributemanifest - app-plusApp包名、证书、权限声明不填包名云打包失败app-plus.modulesmanifest - app-plus打包附带原生模块没勾选地图uni.getLocation报错H5路由模式我一般会写成hash。医院内网部署的nginx经常没有为history模式配置try_files一旦用户手动刷新页面就白屏。如果产品经理坚持要history需要让运维把所有路径重写到index.html这个步骤要在联调前就确认好。热词里常见的vue打包后布局异常大多数情况是publicPath没配好静态资源引用404导致样式丢失。此时检查manifest的h5.publicPath是否为/或者改为相对路径。4.2 条件编译同一段逻辑不同端走不同分支条件编译是uni-app跨端的关键语法用于编译期裁剪代码。除了音视频SDK定位、分享、埋点都会用到。以定位为例H5嵌入微信公众号时获取定位需要先注入微信JS-SDK并调用wx.getLocation小程序端直接调uni.getLocationApp端则需要原生定位模块。三种逻辑放在同一个文件里// utils/location.js export const getUserLocation () { // #ifdef H5 return new Promise((resolve, reject) { if (window.wx window.wx.getLocation) { window.wx.getLocation({ type: gcj02, success: resolve, fail: reject }) } else { uni.getLocation({ type: gcj02, success: resolve, fail: reject }) } }) // #endif // #ifdef MP-WEIXIN return uni.getLocation({ type: gcj02 }) // #endif // #ifdef APP-PLUS return uni.getLocation({ type: gcj02 }) // #endif }定位这个事前端只解决拿到坐标不要试图自己做逆地址解析或城市判断。微信H5里如果JS-SDK尚未完成config注入wx.getLocation会静默失败所以我在H5分支里处理了回退到uni.getLocation。但uni.getLocation在微信内置浏览器里也不是稳定的因为普通浏览器定位要求HTTPS且是用户主动触发才能弹窗。所以更稳妥的方案是让后端提供一个通过IP获取城市的接口定位失败时自动降级。4.3 权限与地图定位在前端只做一件事医院项目的定位通常用于查找附近医院或自动选择城市。App端要在地图上显示位置必须先在manifest的app-plus模块配置里勾选Geolocation和Maps然后云打包生成自定义基座才能真机测试。这里一个典型的坑是开发者直接在默认基座里调用uni.getLocation结果提示getLocation:fail:system permission denied这是因为默认基座没有包含定位模块的权限声明。iOS上还需要在app-plus.distribute.ios下的Info.plist里添加NSLocationWhenInUseUsageDescription写明使用目的。很多审核被拒的原因就是这段描述没写清楚谁在用、用来干嘛。不要只写我们需要你的位置要写用于自动选择附近医院帮助您预约更快这类描述通过率会高很多。4.4 打包上架云打包、本地打包与隐私弹窗微信小程序端打包最直接在HBuilderX里选发行 - 小程序-微信产物在dist/build/mp-weixin目录用微信开发者工具打开并上传代码。上传后去微信公众平台提交审核注意小程序的服务类目要包含医疗否则会被驳回。医疗类目需要提供《互联网药品信息服务资格证》或《医疗机构执业许可证》这是前置条件。App端打包有两种云打包和本地打包。云打包不需要本地安装Android Studio适合快速出包但应用市场要求的隐私弹窗、备案信息都要在manifest里预先配置。Android 10以上系统的应用市场会检查targetSdkVersionuni-app的云打包需要选择targetSdkVersion: 30或更高否则会被华为、小米等市场拒收。签名文件.keystore生成后要妥善保管所有市场的包必须用同一个签名否则用户更新App时会提示安装包未通过签名校验。热词里uniapp上架安卓应用市场的常见问题就是软著、隐私协议、备案号三者不全这属于合规事务但需要技术人员在前端把入口页面先做好。5. 性能优化与排查技巧让多端问题在源头消失5.1 长列表、分包与首屏加载先把体积减下来医院项目的首页往往要展示公告、科室入口、当日排班稍不注意就堆出几个大列表。小程序端的setData有性能瓶颈一次传一万条数据会白屏或卡顿。我常用的方案是分页加触底加载每页20条配合uni-load-more组件提示加载状态。列表页不要把所有字段都放在data里只保留渲染需要的字段后端接口也要配合做字段裁剪。微信小程序有2MB主包限制医院这种体量很难不超。需要把不常访问的页面挪到独立分包比如问诊记录、报告详情、健康档案这些二级页面。配置在pages.json里subPackages: [ { root: pages/consultation, pages: [ detail, videoCall ] } ]注意root字段对应目录名pages里写的是该分包下的页面路径跳转时要用/pages/consultation/detail的完整路径。配置错了的分包在真机上会直接白屏且不报错。首次启动的加载页也不建议放太多请求App.vue的onLaunch里只读本地缓存不要在这个时机调登录态刷新接口否则用户会明显看到白屏等待。5.2 用vConsole和真机调试替代我猜是这个问题多端项目最头疼的问题是在H5正常小程序却白屏。不要靠猜直接在代码里加真机调试日志。H5端可以引入vConsole小程序端可以使用开发者工具的真机调试面板。App端在运行到真机时选择自定义基座并且把基础库日志级别调成verbose可以看到完整的JS报错堆栈。我在项目里习惯在main.js里按环境注入vConsole// #ifdef H5 import VConsole from vconsole if (import.meta.env.MODE ! production) { new VConsole() } // #endifvConsole挂载后手机浏览器就会出现一个悬浮的绿色按钮能看到console、network和system信息。小程序端不需要这步直接用微信开发者工具的真机调试功能它可以实时查看网络请求和执行栈比云测平台好用得多。5.3 从vue2转vue3时的三个高频差异如果项目要迁到Vue3最常踩的三个坑先记下来。第一全局变量挂载方式变了Vue.prototype.$http改成app.config.globalProperties.$http在组合式API里要通过getCurrentInstance()获取。第二vuex的写法要注意mapState在script setup里不能直接用需要用useStore()。第三uni-app的组件事件从.sync改成v-model:prop比如日期选择的change逻辑要检查。热词里有uniapp轮播图安卓有黑边这个问题通常原因不是框架bug而是图片资源本身有透明通道或者比例不一致。给swiper-item加一个固定宽高比并设置object-fit: cover黑边就消失了。如果还出现检查图片加载前没有撑起高度可以在swiper-item里加一个默认背景色让加载过程不刺眼。最后修改刚进入的加载页面这点我往往会使用uni.showLaunchPage或关闭默认的loading动效换成自定义的骨架屏先渲染出页面结构占用层再异步填充数据这是感知性能提升最明显的做法。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/9/15 5:26:35

百度地图商圈边界数据本地化:CityList与多边形绘制优化

简介:面向 JavaScript 开发者的城市行政区域与商圈数据获取工具类,基于百度地图 API 1.5,主要为房地产、本地服务、交通规划等需要精确地理信息的应用场景提供行政区边界与商圈几何数据支持。主入口类为 CityList,开发者通过实例化…

2026/9/15 5:26:35

Shopify撤离React Native真相:从跨端回迁原生的真实成本

去年 Shopify 官宣把移动端主 App 从 React Native 逐步撤回 Swift/Kotlin 的时候,圈子里讨论声很大。有人把这解读成“跨端已死”,也有人觉得这是“大厂终于认清了现实”。但真正从头到尾跟过这类迁移的人,大概率不会说得这么简单——因为从…

2026/9/15 5:41:35

WorkBuddy零基础实战:7个可落地AI工作流搭建指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 5:41:35

SpringBoot记账本源码实战:从项目骨架到SQL性能优化

简介:这是一份基于SpringBoot实现的记账本系统完整源码包,面向Java方向毕业设计、课程实训以及SSM技术栈学习者。项目围绕日常收支管理场景,内置账单增删改查、分类管理、用户登录与数据表格展示等模块,Controller、实体类、业务辅…

2026/9/15 5:41:35

CPO技术:AI算力时代的光互连革命

1. 为什么我们需要重新思考算力互连架构?当我在数据中心现场第一次看到那些密密麻麻的光纤布线时,整个人都愣住了。机架间缠绕的光纤像蜘蛛网一样复杂,而工程师们告诉我,这还只是传统可插拔光模块方案下的常规场景。随着AI算力需求…

2026/9/15 5:41:35

光储并网系统Simulink仿真与MPPT控制实践

1. 光储并网系统与Simulink仿真概述在新能源发电领域,光伏直流微电网系统正成为分布式能源的重要解决方案。这类系统通常由光伏阵列、MPPT控制器、储能单元和并网逆变器构成核心架构。Simulink作为MATLAB中的动态系统仿真平台,因其模块化建模方式和丰富的…

2026/9/15 5:41:35

基于PLC与组态王的四层电梯控制系统优化设计

1. 项目背景与需求分析四层电梯控制系统是工业自动化领域中一个经典的控制案例,也是PLC编程初学者的"毕业设计"。这个项目基于组态王6.53(Kingview)与三菱FX系列PLC搭建,主要解决传统电梯控制系统中外呼信号响应不及时、…

2026/9/15 5:36:35

密码学课程设计实战:从BigInt到RSA与ElGamal的C++实现

简介:一份面向密码学课程设计的C/C源码与工程文件集合,围绕五个典型编程题目展开,涵盖凯撒与替换密码、对称加密、非对称加密、哈希函数与消息认证、数字签名等核心知识点,适合高校学生完成课程实验、撰写设计报告或复习备考。压缩…

2026/9/15 4:54:30

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/15 0:01:16

AI英语单词APP开发:自适应学习算法与移动端优化实践

1. 项目概述 作为一名在移动应用开发领域摸爬滚打多年的老手,我最近完成了一个AI英语单词APP的开发项目。这个项目将传统单词记忆方法与现代AI技术相结合,打造了一款能够智能适应不同用户学习习惯的英语学习工具。 市面上大多数单词APP都存在一个通病&a…

2026/9/15 0:01:16

Flutter与OpenHarmony结合开发手语学习APP实战

1. 项目背景与核心价值作为一名同时接触过Flutter和OpenHarmony的开发者,最近我完成了一个基于Flutter for OpenHarmony的手语学习APP实战项目。这个项目最大的特点在于实现了跨平台框架与国产操作系统深度结合的创新实践——用Flutter开发的应用能完美运行在OpenHa…

2026/9/15 0:01:16

六个月成为机器人工程师:从ROS2到SLAM的实战路径

1. 六个月的紧迫感从哪来:先搞清楚你要成为哪种机器人工程师说实话,六个月的期限并不是一个宽松的时间线。市面上任何一本正经的机器人学教材都超过五百页,ROS2的官方文档可以翻到你怀疑人生,再加上ABB、KUKA这些工业机器人厂家动…

2026/9/14 11:59:31

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/14 13:53:59

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/14 11:22:57

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码