简介
本文件面向DouPHP小程序“咨询服务”与“预约系统”的开发与维护,聚焦以下目标:
- 服务时间选择、预约确认通知、咨询师分配机制等核心能力
- 时间槽管理、预约冲突检测、通知提醒系统等关键组件的架构说明
- 用户体验优化:日历视图展示、时间选择交互、预约状态跟踪
- 开发示例:预约表单构建、时间验证逻辑、邮件短信通知接入思路
- 常见问题:时间冲突处理、预约取消流程、数据同步问题
项目结构
咨询与预约在系统中分为两条主线:
- 前台咨询提交(网站与API):用于收集用户咨询信息,支持验证码、防刷、成功页跳转
- 小程序预约(book模块):基于排班与时间槽的预约体系,提供医生/项目维度下的日期与时间段选择、剩余量计算、状态提示
graph TB
subgraph "前端"
WX["小程序页面<br/>pages/book/list.ts"]
WEB["网站页面<br/>front/controller/consultation/ConsultationController.php"]
end
subgraph "后端接口"
API["API控制器<br/>api/controller/consultation/ConsultationController.php"]
ADMIN["后台控制器<br/>admin/controller/consultation/ConsultationController.php"]
end
subgraph "业务层"
BOOK_SVC["_'/module/book/core/service/book/BookService.php"]
ADMIN_SVC["admin/service/consultation/ConsultationService.php"]
end
WX --> BOOK_SVC
WEB --> API
WEB --> ADMIN
ADMIN --> ADMIN_SVC
核心组件
- 小程序预约列表与时间面板:负责按医生/项目维度加载可预约日期与时间段,过滤上午/下午时段,并展示剩余量与状态提示
- 预约服务(BookService):计算时间槽可用性、统计已预约数量、判断用户是否已预约、生成统一状态提示
- 前台咨询控制器:渲染咨询表单、校验输入、防刷与验证码校验、写入数据并跳转成功页
- API咨询控制器:接收JSON请求、参数校验、限流保护、落库返回结果
- 后台咨询控制器与服务:分页展示、批量删除、状态切换、审计日志
架构总览
下图展示了从用户选择到后端处理的完整调用链,包括时间槽查询、冲突检测与状态提示。
sequenceDiagram
participant U as "用户"
participant WX as "小程序页面<br/>list.ts"
participant BS as "预约服务<br/>BookService"
participant DB as "数据库"
participant FE as "网站前台<br/>ConsultationController"
participant API as "API控制器<br/>ConsultationController"
U->>WX : 选择日期/医生/上下午
WX->>BS : 获取时间段(time_list)
BS->>DB : 查询该日期的时段与容量
DB-->>BS : 时段集合
BS->>DB : 统计已预约数/用户是否已预约
DB-->>BS : 计数/布尔
BS-->>WX : 返回time_list(含剩余量/状态提示)
WX->>U : 展示可用时段与状态
U->>FE : 提交咨询表单
FE->>FE : 校验/验证码/防刷
FE->>API : POST 提交咨询
API->>API : 参数校验/限流
API->>DB : 写入咨询记录
DB-->>API : 成功
API-->>FE : 返回成功
FE-->>U : 跳转成功页
详细组件分析
小程序预约时间选择与状态展示
- 选择医生后,根据上下午筛选时间段;调用后端接口获取时间槽列表
- 时间槽包含开始/结束时间、剩余量、是否已满、是否停诊、用户是否已预约等字段
- 前端根据status_tip显示“已约满/已预约/停诊”等提示
flowchart TD
Start(["进入时间面板"]) --> Load["请求时间段列表"]
Load --> Filter{"上午/下午?"}
Filter --> |上午| AM["过滤 start_time < 12:00"]
Filter --> |下午| PM["过滤 start_time >= 12:00"]
AM --> Render["渲染可用时段"]
PM --> Render
Render --> End(["完成"])
时间槽管理与冲突检测(BookService)
- 生成时间槽时进行多重校验:未来时间、最早/最晚预约限制、容量与已预约数计算
- 统计已预约数时排除无效状态或处于延迟释放中的记录,避免重复占用
- 用户维度检查同一时段是否已预约,统一输出状态提示
flowchart TD
S(["开始"]) --> T1["遍历时段映射"]
T1 --> C1{"是否在未来?"}
C1 --> |否| Skip["跳过"]
C1 --> |是| C2{"满足最早/最晚限制?"}
C2 --> |否| Skip
C2 --> |是| Count["统计已预约数"]
Count --> Rem["计算剩余量"]
Rem --> CheckUser{"用户是否已预约?"}
CheckUser --> |是| Tip1["标记为已预约"]
CheckUser --> |否| Full{"剩余<=0?"}
Full --> |是| Tip2["标记为约满"]
Full --> |否| Tip3["标记为可预约"]
Tip1 --> Next["加入返回列表"]
Tip2 --> Next
Tip3 --> Next
Skip --> Next
Next --> E(["结束"])
前台咨询提交流程(网站)
- 渲染表单、注入CSRF令牌、导航与SEO信息
- 提交时执行表单校验、Honeypot防机器人、验证码校验、IP限流
- 成功后跳转至成功页
sequenceDiagram
participant B as "浏览器"
participant F as "网站前台控制器"
participant V as "表单校验/验证码"
participant L as "限流检查"
participant D as "数据库"
B->>F : GET /consultation
F-->>B : 渲染表单(含token)
B->>F : POST /consultation.store
F->>V : 校验输入/验证码
V-->>F : 通过/失败
F->>L : IP限流检查
L-->>F : 通过/拒绝
F->>D : 写入咨询记录
D-->>F : 成功
F-->>B : 跳转成功页
API咨询提交(小程序/第三方)
- 接收POST请求,参数校验,IP限流,写入数据并返回统一响应
- 错误时返回422/429状态码及错误信息
sequenceDiagram
participant C as "客户端"
participant A as "API控制器"
participant S as "业务服务"
participant DB as "数据库"
C->>A : POST /api/consultation
A->>S : validateConsultationData()
S-->>A : {data, wrong}
alt 校验失败
A-->>C : 422 错误信息
else 校验通过
A->>A : isWaterByIp(ip)
alt 触发限流
A-->>C : 429 限流
else 未限流
A->>DB : storeConsultation(data, ip, time)
DB-->>A : 成功
A-->>C : 200 成功
end
end
后台咨询管理
- 列表分页、状态切换、批量删除、审计日志
- 使用AR模型进行数据格式化与分页
classDiagram
class ConsultationController {
+index(request) Response
+status(request) void
+delAll(formRequest) Response
}
class ConsultationService {
+buildConsultationListData(page) array
+toggleStatusAndRedirect(id) void
+delAllFromPost(post) void
}
ConsultationController --> ConsultationService : "依赖"
依赖关系分析
- 小程序页面依赖后端时间槽接口,时间槽由BookService计算,涉及数据库查询与状态聚合
- 网站前台与API均依赖各自的控制器与校验/限流逻辑,最终写入数据库
- 后台管理依赖Admin Service进行数据操作与审计
graph LR
WX["小程序 list.ts"] --> BS["BookService"]
FE["网站前台 Controller"] --> API["API Controller"]
API --> DB["数据库"]
FE --> DB
ADMIN["后台 Controller"] --> ADMIN_SVC["Admin Service"]
ADMIN_SVC --> DB
性能考量
- 时间槽计算需避免全表扫描:建议对book表的item_id、book_date、start_time建立复合索引,提升slotBookedCount查询效率
- 缓存策略:对热门日期/医生的时间槽可短期缓存,减少重复计算
- 限流与防刷:API与前台均实现IP限流,防止恶意提交
- 异步通知:建议在事务完成后异步发送通知(邮件/短信),降低主流程耗时
故障排查指南
-
时间冲突处理
- 现象:同一时段多人同时预约导致超卖
- 排查:检查slotBookedCount统计逻辑是否包含有效状态与延迟释放记录;确认并发写入时的原子性
- 参考:_'/module/book/core/service/book/BookService.php:542-557
-
预约取消流程
- 现象:取消后时段仍显示约满
- 排查:确认取消状态与released_at字段是否正确更新;检查状态枚举中哪些被视为有效
- 参考:_'/module/book/core/service/book/BookService.php:542-557
-
数据同步问题
- 现象:小程序显示时间与后台不一致
- 排查:核对前后端时间格式(HH:MM)、时区设置、缓存刷新策略
- 参考:miniprogram/company/pages/book/list.ts:122-160
-
验证码与限流
- 现象:频繁提交被拒
- 排查:检查Honeypot与IP限流配置;确认验证码开关与校验逻辑
- 参考:front/controller/consultation/ConsultationController.php:110-148
- 参考:api/controller/consultation/ConsultationController.php:58-76
结论
- 小程序预约通过时间槽管理与状态聚合,提供清晰的可用性与提示信息
- 网站与API咨询提交具备完善的校验、防刷与限流机制,保障数据安全
- 后台管理提供便捷的数据维护与审计能力
- 建议结合索引与缓存优化性能,并通过异步通知提升用户体验
附录
- 多语言提示
- 中文繁体错误提示与限制文案
- 英文错误提示与限制文案
- 参考:
- languages/zh_tw/book.lang.php:78-105
- languages/en_us/book.lang.php:85-105