基于微信小程序的预约挂号系统设计与实现
2026/9/18 15:08:16 网站建设 项目流程

简介:一份原创学士学位毕业论文《基于微信小程序的预约挂号系统的设计与实现》面向计算机科学与技术、软件工程等专业的本科/专科毕业生,也适合对小程序开发感兴趣的初学者。论文以预约挂号场景为依托,系统阐述微信小程序概述、需求分析、系统设计、开发实现与测试等关键技术:需求分析覆盖功能与非功能需求,系统设计涉及MVC架构、数据库表结构和用户界面,开发实现则聚焦于微信开发者工具、WXML/WXSS/JS前端交互及后端接口对接,并提及项目开发中的迭代优化与测试方法。既有理论分析又有实践案例,内容详实且提供代码示例,未入库可过查重,可直接用于毕业设计、学术研究或项目开发。压缩包内仅含1个docx文档(约28KB),为完整论文正文,目录结构清晰,从摘要、前言到总结与展望依次呈现,便于对照学习。已有302人学习下载,适合作为同类毕业设计写作与小程序开发入门的参考。

1. 为什么是微信小程序:预约挂号的真实痛点与选型逻辑

下午三点,想挂周三上午的心内科专家号。打开医院公众号,发现号源列表是静态的,只剩几个普通号;想换个时间,得挨个科室翻;好不容易看到一位副主任医师有号,点进去又提示"排班已调整,请重新选择"。这不是个例,而是传统预约挂号流程里最常见的三个问题:号源信息不透明、排班变更无法及时触达患者、号源状态与医生实际出诊计划脱节。

基于微信小程序的预约挂号系统,核心就是把"号"这件事做成一个实时流转的数据闭环。患者端负责查号、约号、取消号;医生端负责维护排班、查看当日挂号情况;管理员端负责审核医院和医生信息、统计各科室预约量。整个系统围绕"用户、医生、管理员"三个角色展开,技术上走的是微信小程序前端 + 后端接口 + 关系型数据库的经典路线。对于正在做毕设的计算机相关专业学生,或者想给中小型诊所做信息化改造的开发者,这套系统是一个足够完整、能讲清楚全流程的参考实现。

2. 需求边界与模块划分:三大角色如何倒推功能清单

2.1 功能需求:从业务用例到功能清单

预约挂号系统的功能需求,本质上来自三个角色的日常操作。用户端的核心诉求是"快速找到能看病的医生并约上时间",医生端的核心诉求是"我的排班可控、号源可见",管理员端的核心诉求是"所有数据可查、可统计"。这三个诉求叠加,就构成了系统的功能边界。

用户端功能包括:微信授权注册登录、个人信息维护、按医院和科室浏览医生列表、查看医生排班并选择时段预约、在个人中心查看预约记录并取消预约。医生端功能包括:维护个人简介和擅长领域、设置每周出诊排班、查看某个日期段内的挂号患者列表。管理员端功能包括:维护医院和科室信息、审核和管理医生账号、按时间维度统计各科室和各医生的预约挂号数据。

三个模块之间不是孤立的,而是通过"排班"和"预约记录"这两类数据串联。医生的排班决定了用户可预约的时段;用户的预约记录又反过来约束医生的排班容量。设计时先把这些用例画清楚,再落到具体页面和接口,后面写代码就不会反复改结构。

2.2 非功能需求:性能、安全与可维护性对选型的影响

非功能需求决定了系统的技术选型和代码组织方式。性能方面,用户加载医院列表和医生排班数据的接口响应时间应控制在 2 秒以内,预约提交接口需要具备一定的并发处理能力,避免多人同时抢最后一个号源时出现超卖。可靠性方面,预约提交必须保证数据一致性,不能出现"前端提示成功、数据库没有记录"或"数据库扣减了号源、用户却没收到预约确认"的情况。

安全性方面,用户身份要使用微信的 openid 体系做绑定,不能只依赖前端传来的用户 ID 就放行接口;医生的排班修改和管理员的统计接口要分别做角色权限校验,防止普通用户越权调用。可维护性方面,前端页面要拆成组件,后端接口要按模块划分路由,数据库表结构要预留扩展字段,比如后续新增体检预约或疫苗预约时可以复用现有模式。

这些约束直接决定了架构设计:前端用微信小程序原生框架,后端用 Node.js 或 Java Spring Boot 提供 RESTful API,数据库用 MySQL 存储业务数据。小程序端通过 wx.request 调用后端接口,登录态用 Token 维护。整个架构走 MVC 模式,视图层是小程序的 WXML/WXSS 页面,控制器层是后端路由和接口逻辑,模型层是数据库表结构和数据访问层。

提示:如果后端选择微信云开发,可以省去自己维护服务器的成本,云函数 + 云数据库已经覆盖了大部分中小型预约系统的数据量和并发需求。但如果你需要做复杂的排班冲突检测或跨天统计,自建后端在 SQL 灵活性和调试可见性上更有优势。

3. 数据库设计与权限模型:预约系统的地基

3.1 实体关系:从业务对象到关系模型

先梳理系统涉及的实体:用户、医生、科室、医院、排班、预约记录。这六个实体之间的关系是:医院下有多个科室,科室下有多名医生,医生每天有排班时段,用户针对某个排班时段发起预约,预约成功后生成一条预约记录。

用户和医生可以理解为两个独立的角色表,也可以合并成一张用户表用 role 字段区分。但实际开发中,医生需要额外维护职称、擅长领域、所属科室等字段,和普通用户信息差异较大,分开建表更清晰,查询时互不干扰。

3.2 核心表结构与字段说明

以下是一套可以直接落地的核心表结构设计。表名和字段都按业务语义命名,类型和索引也做了基本规划。

CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, openid VARCHAR(64) NOT NULL UNIQUE, nickname VARCHAR(64) DEFAULT '', phone VARCHAR(20) DEFAULT '', avatar_url VARCHAR(255) DEFAULT '', role TINYINT DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE doctor ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL, hospital_id INT NOT NULL, department_id INT NOT NULL, name VARCHAR(32) NOT NULL, title VARCHAR(32) DEFAULT '', specialty TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES user(id) ); CREATE TABLE schedule ( id INT PRIMARY KEY AUTO_INCREMENT, doctor_id INT NOT NULL, work_date DATE NOT NULL, time_slot VARCHAR(16) NOT NULL, total_slots INT DEFAULT 10, booked_slots INT DEFAULT 0, status TINYINT DEFAULT 1, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_doctor_date_slot (doctor_id, work_date, time_slot) ); CREATE TABLE appointment ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL, doctor_id INT NOT NULL, schedule_id INT NOT NULL, appointment_date DATE NOT NULL, time_slot VARCHAR(16) NOT NULL, status TINYINT DEFAULT 0, cancel_reason VARCHAR(255) DEFAULT '', created_at DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_user_id (user_id), KEY idx_schedule_id (schedule_id) );

核心设计逻辑集中在 schedule 表。total_slots 是某一时段的最大号源数,booked_slots 是已预约数,预约时先 UPDATE booked_slots = booked_slots + 1 WHERE booked_slots < total_slots,通过数据库行锁保证不会超卖。appointment 表中的 status 用 0、1、2 分别表示已预约、已完成、已取消,取消预约时需要回滚 schedule 表的 booked_slots 字段,保证号源数据始终一致。

3.3 预约状态流转与时间窗口控制

预约记录的状态不能随意跳变。已预约可以变为已完成或已取消,但已完成不能回退到已预约;已取消的预约不能重新激活,只能重新发起新的预约。这些规则在后端接口里要做统一校验,而不是散落在各个页面里。

时间窗口的控制也是一个容易遗漏的细节。患者发起预约时,后端需要判断排班日期是否在今天之后,以及当前时间是否已经超过了可取消的最晚时间。比如规则可以定义为"就诊当天 0 点前可取消",过了这个时间,取消接口直接拒绝,避免医生出诊当天号源突然出现空缺。

3.4 微信登录与用户身份映射

用户身份体系是整个系统的安全基础。小程序端调用wx.login()拿到临时 code,传给后端后,由后端通过微信的code2Session接口换取 openid 和 session_key。openid 是用户在当前小程序下的唯一标识,后端用 openid 去 user 表里匹配:如果不存在则自动注册,存在则直接登录并返回自定义 Token。

这里需要注意的是,openid 只能由后端持有,小程序端不能存储 openid,所有涉及身份识别的接口都要走 Token 校验。Token 过期时间建议设置为 2 到 7 天,既保证用户不需要频繁重新登录,又避免长期有效导致的安全风险。用户更换手机号或注销时,只需要在服务端将 openid 映射关系解除即可。

4. 小程序端实现关键细节:登录态、排班日历与预约表单

4.1 微信登录与 Token 会话管理

小程序端登录的完整流程是:页面加载时先检查本地 storage 是否有 Token;如果没有,调用wx.login获取 code,再请求后端登录接口换取 Token;拿到 Token 后存入 storage,并在之后所有 wx.request 请求的 header 中携带。

// 小程序端登录代码片段 wx.login({ success: async (res) => { if (res.code) { const loginRes = await wx.request({ url: 'https://your-api.example.com/api/auth/login', method: 'POST', data: { code: res.code }, }); const { token, userInfo } = loginRes.data; wx.setStorageSync('token', token); wx.setStorageSync('userInfo', userInfo); } else { console.error('登录失败', res.errMsg); } }, });

后端拿到 code 后调用jscode2session接口获取 openid,查询或创建用户记录,然后生成一个带有效期的 Token(建议用 JWT)返回给前端。前端后续请求在 header 里带上Authorization: Bearer <token>,后端通过中间件解析 Token 并注入用户信息,才能访问受保护的接口。这样设计的好处是:Token 无状态,后端不需要单独维护 session 存储,分布式部署时也方便扩展。

4.2 排班日期与剩余号源渲染

排班展示是预约系统里交互最复杂的页面,核心是实现"日期 + 时段 + 剩余号源"的三级联动。用户先选日期,再选时段,每个时段后面显示剩余号数,号数为 0 的时段置灰不可点击。这个数据完全由 schedule 表驱动,前端不需要自己维护任何排班逻辑。

日期选择适合用 swiper 加自定义 tab 实现,例如固定展示未来 7 天的日期条。时段选择建议按上午、下午分组,每组列出具体时间段和剩余号数。每个时段的唯一标识就是 schedule 表的主键 ID,用户在时段上点击后,把 scheduleId 和 showDate 暂存到页面 data 中,提交预约时一并传给后端。

// 渲染某个日期的排班时段 async loadSchedule(doctorId, date) { const res = await wx.request({ url: `https://your-api.example.com/api/schedule/list`, data: { doctorId, date }, }); const scheduleList = res.data.map((item) => ({ scheduleId: item.id, timeSlot: item.time_slot, remaining: item.total_slots - item.booked_slots, disabled: item.total_slots - item.booked_slots <= 0, })); this.setData({ scheduleList }); }

remaining 字段直接由后端计算并返回,前端只做展示判断。这里不建议前端根据 totalSlots 和 bookedSlots 自己算剩余号数,因为多个渠道并发预约时,前端缓存的数据可能已经过期,用户看到有号但提交时后端可能已经扣完,体验很差。合理的做法是每次进入时段列表时实时请求,并在提交预约的接口返回值中再次校验。

4.3 预约表单校验与提交确认

预约表单本身字段不多,核心是患者姓名、手机号和就诊人备注。但即便如此,提交前的双重校验仍然必不可少:前端校验保证用户填写完整、手机号格式合法;后端校验保证当前用户没有在同一时段重复预约、目标医生的该时段还有剩余号源、就诊日期没有过期。

前端校验通过后,不要直接调预约接口,而是弹一个确认框,把就诊日期、时段、医生姓名、科室、医院全列出来让用户再确认一次。这个确认步骤在真实场景中意义重大,因为预约本身具有不可逆性,一旦提交就会占用号源,误操作的代价很高。

预约提交接口建议设计为幂等操作:前端生成一个客户端请求号 requestId,后端用唯一索引约束,重复提交请求时直接返回上一次的预约结果,避免用户因为网络波动重复点击而创建重复预约。

4.4 微信支付与订阅消息通知

支付环节是预约系统中另一个关键流程。用户提交预约后,后端生成一条预支付订单,调用微信支付统一下单接口拿到支付参数,小程序端通过wx.requestPayment拉起支付面板。支付成功回调后,后端更新预约状态,给用户发送订阅消息通知就诊时间。

订阅消息需要用户主动授权,且每次授权只能发送一次模板消息。设计通知流程时,务必在用户提交预约时发起wx.requestSubscribeMessage,同时申请"预约成功通知"和"就诊提醒"两个模板的授权;就诊提醒的发送可以通过云函数或定时任务,在就诊前一天晚上批量调用订阅消息接口触发。

提示:微信支付对个人开发者主体不开放,毕设演示阶段可以用模拟支付代替,即后端提供一个测试接口直接标记支付成功,在论文的"系统测试"章节注明模拟方式即可。千万别为了过审去接第三方支付通道,风险很高。

5. 后端业务逻辑:排班冲突检测、号源扣减与数据统计

5.1 预约接口的并发控制与防超卖

预约操作是典型的并发写场景。多个患者同时预约同一个医生的最后一个号源时,如果不能有效控制并发,就可能出现超卖。解决思路是:在数据库层面通过条件更新加行锁保证预约扣减的原子性,同时在业务层面用事务包裹"扣号源"和"建预约"两步操作。

@Transactional public Appointment createAppointment(CreateAppointmentRequest request, Long userId) { // 1. 锁定并扣减号源 Schedule schedule = scheduleMapper.selectForUpdate(request.getScheduleId()); if (schedule == null || schedule.getBookedSlots() >= schedule.getTotalSlots()) { throw new BusinessException("该时段号源已满"); } // 2. 校验用户是否已预约过该医生的同一时段 int count = appointmentMapper.countByUserIdAndSchedule(userId, request.getScheduleId()); if (count > 0) { throw new BusinessException("请勿重复预约"); } // 3. 扣减号源 schedule.setBookedSlots(schedule.getBookedSlots() + 1); scheduleMapper.updateById(schedule); // 4. 创建预约记录 Appointment appointment = new Appointment(); appointment.setUserId(userId); appointment.setScheduleId(request.getScheduleId()); appointment.setStatus(0); appointmentMapper.insert(appointment); return appointment; }

selectForUpdate是 MySQL InnoDB 引擎提供的行锁查询,事务提交后锁自动释放。它保证同一时刻只有一个事务能读取并修改这条排班记录,其他并发请求必须等待,从根源上避免了超卖。如果系统并发量进一步增大,可以考虑引入 Redis 做前置预扣减,用 Lua 脚本保证原子性,再用消息队列最终回写数据库。但对于预约挂号这类场景,数据库行锁方案已经足够稳定,架构上也最简单。

5.2 医生排班冲突检测

医生排班管理是医生端的核心功能。医生录入排班时,需要保证同一日期下没有重叠的时间段。比如某医生已经排了"周一下午 14:00-16:00",就不能再排一个"周一下午 15:00-17:00"。

冲突检测的 SQL 可以这样写:查询该医生在指定日期下的所有排班时段,然后逐一判断时间区间是否有交集。更严谨的做法是用区间重叠的条件直接写 SQL 查询是否存在冲突记录:

SELECT COUNT(*) FROM schedule WHERE doctor_id = #{doctorId} AND work_date = #{workDate} AND status = 1 AND start_time < #{newEndTime} AND end_time > #{newStartTime};

只要查询结果大于 0,就说明存在重叠。这里需要注意,数据库里存的是当天的时间段字符串(如09:00),比较时需要把字符串统一成可比较的格式,或者在表设计时直接存start_timeend_time两个 TIME 类型字段,而不是用一个time_slot字符串。

5.3 管理员端统计报表的 SQL 聚合

管理员端的统计分析功能,核心是基于 appointment 表按不同维度做 GROUP BY 聚合。常用的统计维度包括:某时间段内各科室的预约量、各医生的接诊量、预约取消率、每日号源使用率等。这类统计用 SQL 聚合实现比在内存中遍历效率高得多。

-- 按科室统计月度预约量 SELECT d.department_id, dept.name AS department_name, COUNT(a.id) AS appointment_count FROM appointment a JOIN doctor d ON a.doctor_id = d.id JOIN department dept ON d.department_id = dept.id WHERE a.created_at BETWEEN '2024-11-01' AND '2024-11-30' AND a.status != 2 GROUP BY d.department_id, dept.name ORDER BY appointment_count DESC;

这里的 JOIN 链路是 appointment → doctor → department,通过两层关联最终聚合到科室维度。回顾第 3 章的库表设计,appointment 表中只存了 doctor_id,没有冗余科室信息,就是为了保证数据规范化。统计接口在数据量大时,可以给 appointment.created_at 和 doctor_id 加联合索引,避免全表扫描。

5.4 定时任务与号源恢复机制

预约取消后号源需要恢复,这是一个容易被忽略的细节。用户取消预约时,后端不仅要更新 appointment 表的 status 为 2,还要同步将对应 schedule 表的 booked_slots 减 1。这两个操作必须放在同一个事务里执行,否则就会出现号源数据不一致的情况。

患者未主动取消、却未按时就诊的情况,需要后端跑定时任务来处理。建议每天凌晨执行一次任务,扫描就诊日期为昨天、状态仍为"已预约"的记录,批量将状态更新为"已完成"。如果系统需要支持超时自动取消,可以在用户预约后增加一个支付超时字段,例如预约后 15 分钟未支付则自动释放号源,这个也需要由定时任务扫描实现。

-- 定时任务:自动完成过期未就诊的预约 UPDATE appointment SET status = 1 WHERE appointment_date < CURDATE() AND status = 0;

定时任务的实现方式,用 Spring Boot 的@Scheduled注解即可,也可以使用 xxl-job 这类分布式调度框架。对于中小型预约系统,单机定时任务足够,不需要引入额外的调度中间件。

6. 测试方案与上线验证:五个必须提前踩的坑

6.1 功能测试与兼容性测试矩阵

功能测试要覆盖三个角色的核心路径:用户从登录到取消预约的完整链路、医生创建排班并查看患者列表、管理员审核信息并查看统计报表。兼容性测试需要覆盖 iOS 和 Android 两大平台的不同微信版本,特别注意 iPhone 的 safe area 适配和 Android 的键盘弹起遮挡问题。在小程序开发者工具里,可以模拟不同机型,但真机调试仍不可替代。

6.2 并发预约的压测验证

不要等到上线才发现超卖问题。用 JMeter 或小程序开发者工具自带的压测功能,模拟 20 个用户同时抢同一个 schedule_id 的号源,观察最终插入的预约记录数是否等于 total_slots。如果出现错误,优先排查事务是否生效、行锁是否落在正确的索引上。

6.3 取消预约后的号源回滚测试

这是最容易出 bug 的环节。测试用例是:用户 A 预约成功后,用户 B 看到剩余号数为 0;A 取消预约,此时 B 刷新列表应看到剩余号数变为 1,并能成功预约。如果 B 看到的还是 0 或者预约时报错,说明取消预约的事务没有正确回滚 booked_slots。这个场景需要重点验证,因为真实业务中医生侧和患者侧看到的数据必须完全一致。

6.4 数据库索引与慢查询验证

上线前用EXPLAIN检查核心 SQL 的索引命中情况。重点观察三条语句:用户查询预约列表的idx_user_id、排班查询的联合唯一索引uk_doctor_date_slot、统计查询的聚合索引。如果 EXPLAIN 结果中出现了Using filesort或全表扫描,需要调整索引或改写 SQL。

6.5 上线前的小程序审核注意事项

小程序首次提交审核时,重点检查两类问题:一是用户隐私协议中是否完整声明了手机号、就诊信息等个人数据的收集和使用场景;二是预约流程中是否提供了明确的用户协议和取消规则入口。微信审核团队对医疗类小程序的资质审核比较严格,毕设演示可以申请"小程序测试号"配合真机调试完成全流程验证,正式发布前再按实际主体资质补充对应的类目和文件。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询