1. 美容预约微信小程序项目概述
最近在整理过往项目时,翻出了两年前为本地美容院开发的预约小程序源码。这个项目虽然体量不大,但完整实现了在线预约、服务展示、会员管理等核心功能,上线后客户反馈非常实用。今天就把这个项目的完整开发思路和关键代码分享给大家,特别适合想入门微信小程序开发的朋友参考。
这个小程序采用微信原生开发框架,后端使用Node.js + MySQL架构。从技术实现角度看,它涵盖了小程序开发中最常见的几种场景:表单提交、微信登录、支付对接、消息模板推送等。我会重点解析几个典型功能模块的实现逻辑,并附上可运行的代码片段。
提示:本文提供的源码已去除敏感业务信息,保留了完整的技术实现,可直接用于学习或二次开发。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心功能模块解析
2.1 预约系统设计
美容行业预约的核心需求是时间排期管理。我们设计了双层校验机制:
- 前端实时获取可预约时段
- 后端提交时再次校验时间冲突
javascript复制// 获取可预约时间段的接口实现
function getAvailableSlots(serviceId, date) {
// 1. 从数据库获取该服务所需时长
const duration = await Service.findById(serviceId).select('duration');
// 2. 查询该日期已有预约
const bookings = await Booking.find({
date: date,
status: {$ne: 'cancelled'}
});
// 3. 生成可预约时间段
let slots = [];
const startHour = 9; // 营业开始时间
const endHour = 20; // 营业结束时间
for(let hour = startHour; hour < endHour; hour++) {
for(let minute = 0; minute < 60; minute += 30) { // 每半小时一个slot
const slotTime = new Date(date);
slotTime.setHours(hour, minute, 0, 0);
// 检查时间段是否可用
let isAvailable = true;
bookings.forEach(booking => {
if(isTimeOverlap(slotTime, duration, booking)) {
isAvailable = false;
}
});
if(isAvailable) {
slots.push({
time: slotTime,
display: `${hour}:${minute === 0 ? '00' : minute}`
});
}
}
}
return slots;
}
这个算法考虑了:
- 不同服务项目的持续时间差异
- 现有的预约记录
- 营业时间限制
- 半小时为最小时间单位
2.2 微信登录与用户系统
美容行业需要识别会员身份来提供差异化服务。我们采用微信开放平台账号体系,关键实现:
javascript复制// 小程序端登录代码
wx.login({
success: res => {
if(res.code) {
wx.getUserInfo({
success: userRes => {
// 发送code和用户信息到后端
wx.request({
url: 'https://yourdomain.com/api/login',
method: 'POST',
data: {
code: res.code,
encryptedData: userRes.encryptedData,
iv: userRes.iv
},
success: loginRes => {
// 登录成功处理
}
});
}
});
}
}
});
// 后端解密处理
const decryptData = (encryptedData, iv, sessionKey) => {
const decipher = crypto.createDecipheriv('aes-128-cbc', sessionKey, iv);
let decoded = decipher.update(encryptedData, 'base64', 'utf8');
decoded += decipher.final('utf8');
return JSON.parse(decoded);
};
注意事项:
- 必须在小程序后台配置合法域名
- session_key需要缓存但不可泄露
- 用户拒绝授权时需要降级处理
2.3 支付与消息通知
美容预约通常需要支付定金。我们实现了完整的微信支付流程:
javascript复制// 发起支付
wx.requestPayment({
timeStamp: '',
nonceStr: '',
package: '',
signType: 'MD5',
paySign: '',
success: (res) => {
// 支付成功处理
wx.request({
url: 'https://yourdomain.com/api/confirmBooking',
method: 'POST',
data: {
bookingId: '',
transactionId: res.transactionId
}
});
// 发送模板消息
wx.request({
url: 'https://yourdomain.com/api/sendTemplateMsg',
method: 'POST',
data: {
formId: '', // 收集的formId
templateId: '', // 申请的消息模板ID
page: 'pages/booking/detail?id=xxx'
}
});
}
});
关键点:
- 支付成功后必须验证支付结果
- 模板消息需要提前收集formId
- 消息模板需要申请并审核
3. 数据库设计要点
美容预约系统的数据模型需要考虑:
- 服务项目信息
- 美容师排班
- 预约记录
- 会员信息
sql复制CREATE TABLE `services` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`description` text,
`duration` int(11) NOT NULL COMMENT '分钟',
`price` decimal(10,2) NOT NULL,
`category` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `staff` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`position` varchar(50) DEFAULT NULL,
`avatar` varchar(255) DEFAULT NULL,
`skills` text COMMENT 'JSON数组存储擅长项目',
PRIMARY KEY (`id`)
);
CREATE TABLE `bookings` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`service_id` int(11) NOT NULL,
`staff_id` int(11) DEFAULT NULL,
`date` date NOT NULL,
`start_time` time NOT NULL,
`end_time` time NOT NULL,
`status` enum('pending','confirmed','completed','cancelled') DEFAULT 'pending',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `service_id` (`service_id`),
KEY `staff_id` (`staff_id`)
);
优化技巧:
- 为常用查询字段建立索引
- 时间字段分开存储便于查询
- 使用ENUM类型约束状态值
4. 前端界面实现技巧
4.1 日历组件优化
美容预约需要直观的日期选择。我们基于小程序picker组件做了二次开发:
javascript复制// 自定义日历组件
Component({
properties: {
// 可预约日期数据
availableDates: {
type: Array,
value: []
}
},
data: {
months: [],
currentMonth: ''
},
methods: {
// 生成月份数据
generateMonths() {
const months = [];
const today = new Date();
for(let i = 0; i < 3; i++) { // 显示3个月
const date = new Date(today);
date.setMonth(today.getMonth() + i);
const month = {
name: `${date.getFullYear()}年${date.getMonth() + 1}月`,
days: this.generateDays(date)
};
months.push(month);
}
this.setData({
months: months,
currentMonth: months[0].name
});
},
// 生成某月的日期数据
generateDays(date) {
const year = date.getFullYear();
const month = date.getMonth();
const daysInMonth = new Date(year, month + 1, 0).getDate();
const days = [];
for(let i = 1; i <= daysInMonth; i++) {
const dayDate = new Date(year, month, i);
const weekday = dayDate.getDay();
days.push({
date: i,
weekday: ['日','一','二','三','四','五','六'][weekday],
available: this.checkAvailable(dayDate)
});
}
return days;
}
}
});
4.2 服务项目展示
采用卡片式布局展示服务项目,关键样式技巧:
css复制/* 服务卡片样式 */
.service-card {
display: flex;
margin: 15rpx;
padding: 20rpx;
border-radius: 10rpx;
box-shadow: 0 2rpx 6rpx rgba(0,0,0,0.1);
}
.service-image {
width: 160rpx;
height: 160rpx;
border-radius: 8rpx;
}
.service-info {
flex: 1;
margin-left: 20rpx;
}
.service-name {
font-size: 32rpx;
font-weight: bold;
margin-bottom: 10rpx;
}
.service-duration {
font-size: 24rpx;
color: #888;
margin-bottom: 15rpx;
}
.service-price {
color: #e64340;
font-size: 36rpx;
}
5. 项目部署与上线
5.1 小程序审核要点
美容类小程序审核较严格,需要注意:
- 服务类目选择"生活服务-美容/美发/美甲"
- 内容不能涉及医疗美容
- 预约项目描述要明确
- 支付环节需明确说明退款政策
5.2 服务器配置建议
bash复制# PM2启动脚本
pm2 start app.js --name beauty-booking \
--instances max \
--env production \
--output /var/log/beauty/out.log \
--error /var/log/beauty/err.log \
--time
推荐配置:
- 2核4G起步
- 开启HTTPS
- 配置定时备份
- 监控关键接口性能
6. 源码结构与使用说明
完整项目结构如下:
code复制├── client/ # 小程序端代码
│ ├── pages/ # 页面目录
│ │ ├── index/ # 首页
│ │ ├── booking/ # 预约流程
│ │ └── user/ # 个人中心
│ ├── components/ # 公共组件
│ ├── utils/ # 工具函数
│ └── app.js # 小程序入口
├── server/ # 服务端代码
│ ├── controllers/ # 控制器
│ ├── models/ # 数据模型
│ ├── routes/ # 路由
│ ├── config/ # 配置文件
│ └── app.js # 服务入口
├── database/ # 数据库脚本
└── README.md # 项目说明
快速启动步骤:
- 导入SQL文件初始化数据库
- 配置server/config/database.js
- 安装依赖:npm install
- 启动服务:npm start
- 小程序端修改project.config.json中的appid
- 使用微信开发者工具导入client目录
7. 常见问题与解决方案
7.1 预约时间冲突问题
现象:多个用户同时预约同一时段导致冲突
解决方案:
- 使用数据库事务
- 添加乐观锁
- 前端增加加载状态防止重复提交
javascript复制// 使用事务处理预约
const session = await Booking.startSession();
session.startTransaction();
try {
// 1. 检查时间是否可用
const available = await checkAvailability(bookingData, { session });
if(!available) {
throw new Error('该时段已被预约');
}
// 2. 创建预约记录
const booking = await Booking.create([bookingData], { session });
// 3. 创建支付订单
const order = await Order.create({
bookingId: booking[0]._id,
amount: bookingData.amount
}, { session });
await session.commitTransaction();
return order;
} catch (err) {
await session.abortTransaction();
throw err;
} finally {
session.endSession();
}
7.2 微信登录失败问题
可能原因:
- code过期(5分钟有效期)
- session_key失效
- 用户更换微信账号
处理方案:
- 捕获特定错误码
- 引导用户重新登录
- 做好错误日志记录
javascript复制// 错误处理中间件
app.use((err, req, res, next) => {
if(err.code === 'INVALID_WX_CODE') {
return res.status(401).json({
code: 401,
message: '微信登录失效,请重新登录',
data: {
reLogin: true
}
});
}
// 其他错误处理...
});
这个美容预约小程序项目虽然已经过去两年,但其中的技术实现仍然具有参考价值。特别是在处理预约冲突、微信生态对接等方面,很多设计思路可以直接复用到新项目中。源码我已经整理好放在GitHub上,需要完整代码的朋友可以私信我获取。
