简介:绿色医疗保健医院预约挂号的微信小程序模板源码,面向微信小程序开发者及有预约挂号功能需求的医疗相关项目,帮助快速搭建包含科室选择、医生排班、时间预约、患者信息填写等核心流程的小程序界面与逻辑。压缩包共370个文件,包含89个JS逻辑文件、85个WXML页面结构、85个WXSS样式及85个JSON配置,另有PNG/JPG图片素材,整体仅约779KB,文件类型覆盖完整,便于按模块移植与二次开发。已有87人学习下载,适合正在学习小程序开发或需要上线预约挂号类项目的读者参考。通过这份源码可以掌握微信小程序页面布局、数据绑定、API调用及表单交互等关键实现方式,同时也能借鉴其后台管理、隐私保护与扩展性设计思路,节省从零手写基础代码的时间,直接关注业务逻辑与服务流程的定制。源码前端页面与逻辑完整,可作为毕业设计、课程作业或商业项目的基础模板。
1. 挂号小程序的难点不在页面,在预约链路的完整闭环
三甲医院里最常见的场景是窗口排长队、自助机前扫码支付,但患者真正需要的只是「今天这个医生还剩哪个时段」。绿色医疗保健医院预约挂号这套微信小程序模板源码,把预约链路做成了一个可以直接二次开发的闭环:首页展示医院信息和出诊医生,预约页按日期、科室、医生筛选时段,提交后生成订单号并模拟支付确认。界面不复杂,但它把号源、医生、患者三个角色的数据流串起来了,这正是很多课设和外包项目翻车的地方——页面做完了,号源和时段对不上。
模板适合三种人:接中小型医院 HIS 项目的开发者,用它当微信小程序前端的底座;做毕业设计的学生,它比空页面多出了可复现的排班逻辑;想快速验证预约产品形态的产品经理,可以用它和真机演示走通完整的预约流程。下面直接从压缩包里的文件开始拆。
2. 源码结构与首页模块拆解:从一组jpg到可运行的小程序
2.1 压缩包内文件的职责划分
先把 zip 里的文件分层看。最上层是app.js、app.json、app.wxss这三个小程序全局文件,pages目录下分成index和reserve两个页面目录。index里放着infoImg.jpg、doctor.jpg、yy.jpg、2.jpg,是首页的医院信息图、医生头像和院区展示图;reserve里的time.jpg、1.jpg、doctor2.jpg对应预约页的时间提示、科室背景和备选医生。js 目录里实际干活的是index.js和reserve.js,一个管首页展示,一个管预约流程。
用表格把职责列一下。这个表格很重要——很多同学拿到 zip 直接往开发者工具里拖,结果图片路径乱了报错,先搞清楚每张图给谁用,能省不少排查时间。
| 文件/目录 | 归属页面 | 职责 |
|---|---|---|
| app.js / app.json / app.wxss | 全局 | 小程序生命周期、页面注册、全局样式 |
| index.js / index.wxml / index.wxss | 首页 | 医院信息与医生列表展示、跳转预约 |
| reserve.js / reserve.wxml / reserve.wxss | 预约页 | 日期选择、时段筛选、提交预约 |
| infoImg.jpg / doctor.jpg / yy.jpg / 2.jpg | 首页 | 信息横幅、医生头像、院区环境图 |
| time.jpg / 1.jpg / doctor2.jpg | 预约页 | 时间说明、备选科室背景、医生备选头像 |
2.2 首页的静态数据绑定与真实接口切换
模板里index.js的doctorList大概率是写死在代码中的静态数组,用来在开发者工具里直接出效果。这种写法和真实项目只差一个数据源:真实场景中应该由wx.request请求医院 HIS 系统的医生排班接口,把返回的列表setData到同一个字段上。页面的wxml完全不用改,只替换数据层。
首页的wxml结构围绕「信息图 + 医生卡片」展开。下面这段是模板常见的写法,注意wx:key和bindtap的><!-- pages/index/index.wxml --> <view class="page"> <image src="/pages/index/infoImg.jpg" mode="widthFix" class="banner" /> <view class="section-title">出诊医生</view> <view class="doctor-card" wx:for="{{doctorList}}" wx:key="id"> <image src="{{item.avatar}}" mode="aspectFill" class="avatar" /> <view class="doctor-info"> <text class="doctor-name">{{item.name}}</text> <text class="doctor-dept">{{item.dept}} · {{item.title}}</text> <button size="mini" bindtap="goReserve">// pages/index/index.js goReserve(e) { const doctorId = e.currentTarget.dataset.doctor; wx.navigateTo({ url: '/pages/reserve/reserve?doctorId=' + doctorId, fail: (err) => { console.error('跳转预约页失败', err); } }); }
// pages/reserve/reserve.js onLoad(options) { this.setData({ doctorId: options.doctorId }); this.buildDayList(); this.loadSchedule(); }navigateTo的 url 有长度限制,传多个参数时用&拼接,但只传 id 最稳妥。fail回调里打日志能提前发现页面路径拼错这类低级问题。这里loadSchedule是模板预留的接口方法,把wx.request放在这个方法里,后续接后端时只改函数内部实现,页面其他逻辑不受影响。
提示:如果首页和预约页放在不同分包,
wx.navigateTo无法直接跳转子包,需要改用分包预下载或在目标页面配置"independent": true,这是压缩包模板没有涉及、但真实上线一定会遇到的边界。
模板里index.js的几个方法命名比较规范,goReserve、loadSchedule、buildDayList保留原名,前后端对接时沟通成本会低很多。真实项目里医生列表往往需要按科室筛选,可以在 data 里加一个activeDept字段,点击科室 tab 时重新过滤doctorList,首页骨架不用动。
3. 预约页核心逻辑:reserve.js 的日期生成与防重提交
3.1 排班数据模型:页面凭什么知道你哪天有号
reserve.js的核心是排班数据结构。模板没有后端,所以用了一个模拟排班的数组,字段设计基本贴合真实 HIS 系统的接口返回:日期、科室、医生、时段。开发者在替换数据源时,保持这个字段名不变,页面就完全不用改。
// pages/reserve/reserve.js 模拟排班数据 const MOCK_SCHEDULE = [ { date: '2025-06-10', dept: '内科', doctorId: 'd001', slots: ['08:30', '09:00', '09:30', '10:00'] }, { date: '2025-06-10', dept: '内科', doctorId: 'd002', slots: ['14:00', '14:30', '15:00'] }, { date: '2025-06-11', dept: '外科', doctorId: 'd003', slots: ['08:30', '11:00'] } ];slots数组内的时间点是字符串而不是时间戳,方便直接渲染到按钮文本上;doctorId与首页传过来的参数完全匹配。真实接口一般还会返回每个时段剩余号数left,模板里没画这个字段,加的时候在展示层做一个「剩余 0 个自动置灰」的判断即可,数据结构层面不需要额外改动。
3.2 生成未来七天日期滑动条
预约页顶部的日期横滑条是患者操作频率最高的控件。模板里用buildDayList生成未来七天的日期,核心在于用Date对象的毫秒偏移和补零处理。
buildDayList() { const days = []; const base = new Date(); base.setHours(0, 0, 0, 0); const weekText = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']; for (let i = 0; i < 7; i++) { const d = new Date(base.getTime() + i * 86400000); const month = String(d.getMonth() + 1).padStart(2, '0'); const day = String(d.getDate()).padStart(2, '0'); days.push({ fullDate: `${d.getFullYear()}-${month}-${day}`, label: `${month}/${day} ${weekText[d.getDay()]}` }); } this.setData({ dayList: days, selectedDate: days[0].fullDate }); }这里base.setHours(0, 0, 0, 0)非常关键,它把基准时间归零,否则当天凌晨到中午这段时间打开页面,直接用i * 86400000累加会出现「第一天是今天,第二天却是后天」的跨日偏差。padStart(2, '0')用来保证日期字符串是2025-06-08而不是2025-6-8,这直接决定了它能不能和后端接口的日期字段做相等比较,后端返回的日期如果有T00:00:00后缀,前端要先做一次split('T')[0]裁剪。
3.3 选择日期后联动可约时段
日期切换后,reserve.js里的loadSchedule会根据selectedDate和doctorId从MOCK_SCHEDULE里过滤出可约时段,并同步更新页面上的时段按钮列表。
loadSchedule() { const { selectedDate, doctorId } = this.data; const matched = MOCK_SCHEDULE.filter( item => item.date === selectedDate && item.doctorId === doctorId ); const slots = matched.length ? matched[0].slots : []; this.setData({ slotList: slots, selectedSlot: '' }); }filter匹配用的是全等比较,所以日期字符串格式必须一致。selectedSlot: ''这行是重置上次选择——如果患者先看了周二的号再切回周一,不清空的话会把周二的时段带到周一的订单上,这是排班类小程序最常见的脏数据来源。模板里科室的切换依据是doctorId,如果改成按科室统一放号,那过滤条件要换成dept === selectedDept && !item.isFull,逻辑一样,只是维度不同。
3.4 提交预约:订单号生成与防连点
提交的代码体现预约链路的收口。模板在这块需要注意三个点:未选时段时的toast提示、提交中的按钮禁用、以及前端生成的订单号。
submitReserve() { const { selectedDate, selectedSlot, patient, doctorId } = this.data; if (!selectedDate || !selectedSlot) { wx.showToast({ title: '请选择完整时段', icon: 'none' }); return; } if (this.data.submitting) return; this.setData({ submitting: true }); const orderNo = 'GH' + Date.now() + Math.floor(1000 + Math.random() * 9000); wx.request({ url: 'https://his.example.com/api/reserve', method: 'POST', data: { orderNo, doctorId, date: selectedDate, time: selectedSlot, patientName: patient.name, idCard: patient.idCard, phone: patient.phone }, success: (res) => { if (res.data && res.data.code === 0) { wx.showToast({ title: '预约成功', icon: 'success' }); } else { wx.showToast({ title: res.data.msg || '预约失败', icon: 'none' }); } }, complete: () => { this.setData({ submitting: false }); } }); }if (this.data.submitting) return;是防重复提交的第一道闸,配合按钮的disabled="{{submitting}}"双保险。orderNo用时间戳加随机数生成,只用于前端追踪,真正对外业务单号仍以后端返回为准。patient对象在真实项目中来自上一页填写的表单,模板里是提前写在data中的静态对象,接后端时把patient换成从全局用户信息中读取即可。https://his.example.com是占位域名,实际对接时替换成医院 HIS 系统的真实地址,并把urlCheck在开发阶段关掉。
注意:身份证号、手机号这类敏感字段,不要通过 URL 参数传递,也不要
setData后长期留在 page data 里。模板只演示了提交动作,正式上线前必须对请求体做 HTTPS 加密传输,并在显示层做脱敏。
4. 用户登录、支付确认与后台接口:把模板变成真系统
4.1 wx.login 换取 openid 的正确姿势
摘要里强调用户认证,很多新手会误以为wx.login返回的 code 可以直接当身份凭证用。实际上 code 五分钟内有效且只能使用一次,需要把它发给后端,由后端调用微信的code2Session接口换取openid和session_key,再返回一个自定义token给小程序端。
wx.login({ success: (res) => { if (!res.code) { wx.showToast({ title: '登录失败', icon: 'none' }); return; } wx.request({ url: 'https://his.example.com/api/login', method: 'POST', data: { code: res.code }, success: (r) => { const token = r.data && r.data.token; if (token) { wx.setStorageSync('token', token); } } }); } });wx.login不弹授权框,这是它和getUserProfile最大的区别。openid是用户在你们医院体系里的唯一标识,前端拿到它没有意义,反而增加泄露风险,所以正确做法是前端只存后端签发的token。token过期时请求返回 401,需要在封装wx.request时的响应拦截器里重新调wx.login,这是模板没有但真实系统必须有的逻辑。模板里没有封装request,建议在utils/request.js里统一处理,所有接口调用走同一套 token 注入和错误码拦截。
4.2 患者信息的加密、脱敏与存储
医院小程序里的患者信息字段,按敏感程度可以拆成三类。模板目前的表单是全量收集,真正上线时要做的是分级处理:姓名和手机号在页面上脱敏展示,身份证号提交后在后端加密存储,微信用户信息则只保留昵称和头像用于界面展示。
| 字段 | 存储位置 | 提交前处理 | 展示脱敏 |
|---|---|---|---|
| 姓名 | 小程序本地缓存 + 后端数据库 | HTTPS 传输 | 刘** |
| 手机号 | 后端数据库 | 服务端加密 | 138****1234 |
| 身份证号 | 仅后端 | 服务端 RSA/国密加密 | 不展示 |
| 用户昵称/头像 | 小程序本地 | 直接使用 | 不需脱敏 |
小程序端的加密能力有限,密钥放前端等于没有加密,所以敏感信息的正确路径是「前端最小化收集、传输只走 HTTPS、存储加密全在后端」。模板里的 reserve 表单收集了身份证号,可以作为参考,但不要照搬到生产环境。脱敏在展示层做,wxml里用wx:if判断用户是否授权过,授权过才显示完整身份证号。
4.3 支付确认与改期退号的接口预留
预约挂号涉及支付时,微信小程序的wx.requestPayment参数(timeStamp、nonceStr、package、signType、paySign)必须全部由后端生成,前端只负责调起收银台和监听回调。模板里的支付确认用的是模拟弹窗,真实上线时这里要替换成:
wx.requestPayment({ timeStamp: res.data.timeStamp, nonceStr: res.data.nonceStr, package: res.data.package, signType: 'RSA', paySign: res.data.paySign, success: () => { this.setData({ payStatus: 'paid' }); }, fail: (err) => { if (err.errMsg.includes('cancel')) { wx.showToast({ title: '已取消支付', icon: 'none' }); } } });后端在生成预支付订单前,需要先校验这个时段的号源是否还有余量,防止「前端提交成功、后端号源已满」的竞态。改期和退号的语义在后端是「取消原单 + 创建新单」,前端不要自己维护复杂的订单状态机,把这两个操作分别映射到退号接口和挂号接口即可。模板没有任何订单状态字段,加的时候建议只保留pending、paid、cancelled三个状态,超过三个前端页面就要开始维护状态流转了。
4.4 后台管理端需要同步约定的接口契约
医院后台要实时更新排班、空闲时段和科室状态,前端模板假设了接口返回结构,那么后台界面至少要能维护三张表:医生排班表、号源余量表、预约订单表。先把接口契约定下来,前后端并行开发时模板的reserve.js就能无缝切换。下面这张表可以直接贴给后端同事。
| 接口 | 方法 | 入参 | 出参 |
|---|---|---|---|
| /api/login | POST | code | token |
| /api/schedule | GET | date、dept | 医生+时段+余号 |
| /api/reserve | POST | orderNo、doctorId、date、time、patient | 订单号、支付参数 |
| /api/reserve/cancel | POST | orderNo | 退号结果 |
接口字段名尽量与模板里MOCK_SCHEDULE的命名保持一致,后端返回code: 0表示成功,非 0 时msg字段携带错误原因。这样前端的loadSchedule、submitReserve两个函数体内部只需要把写死的数据换成wx.request返回值,其他逻辑完全复用。
5. 部署与真机调试:三个最容易卡壳的配置点
5.1 appid 与 project.config.json 的替换
拿到 zip 解压后,先不要急着把整个目录拖进微信开发者工具。模板里的project.config.json写的可能是别人的 appid,直接预览会报 invalid appid。正确做法是在project.config.json里把appid改成你自己的测试号,或者在导入时选择「测试号」并让工具自动覆盖。改完这一项,编译报错会少一半。
{ "appid": "wx你的测试号或正式appid", "projectname": "green-hospital-reserve", "setting": { "urlCheck": false, "es6": true, "postcss": true } }urlCheck改成false只用于开发阶段,让wx.request可以请求未配置的域名;上线前必须去 mp 后台把 https 接口域名加入 request 合法域名列表,否则真机上所有请求全部 fail,且不会在开发者工具里给出明确报错。
5.2 导航栏高度与安全区适配
搜索「微信小程序顶部导航栏高度」出现的讨论,大多卡在胶囊按钮和自定义导航的适配。模板用的是默认导航栏,不会踩这个坑;如果你后续想换自定义导航,要用wx.getMenuButtonBoundingClientRect拿胶囊位置,把页面头部padding-top撑到状态栏以下。更稳的写法是先用wx.getSystemInfoSync取statusBarHeight,再结合胶囊坐标计算导航栏总高度。
5.3 页面跳转层级与登录态的检查
预约流程里从首页跳到预约页,再跳到支付页,三层以内没压力;但如果你加了在线咨询、电子病历等扩展页,wx.navigateTo会把页面栈堆到十层,超过后跳转会静默失败。这时候把支付页改成wx.redirectTo关闭预约页,或把咨询页改为半屏组件,能立刻缓解问题。最后在真机预览里验证一个完整场景:登录拿 token、选日期、选时段、提交预约、支付回调确认。走到第五步时看一眼开发者工具的 Network 面板,确认 reserve 请求的返回码是0而不是-1,再检查一下 storage 里的 token 是否被setStorageSync写入,这两处没问题,模板的预约链路就能拿去接真实后端了。
本文还有配套的精品资源,点击获取