1. 项目背景与核心需求
社区休闲场地预约系统是当前智慧社区建设中的重要组成部分。随着城市居民生活水平提高,社区内的篮球场、羽毛球场、游泳池等公共设施使用需求激增,但传统的人工登记管理方式存在诸多痛点:
- 场地使用情况不透明,居民常白跑一趟
- 高峰期排队混乱,易引发纠纷
- 管理员工作量大,统计困难
- 支付方式单一,现金交易不便
我们团队采用uniapp+SpringBoot技术栈开发的这套系统,实现了以下核心功能:
- 微信小程序端可视化展示场地空闲时段
- 在线预约与智能冲突检测
- 多种支付方式集成(微信支付、会员卡扣次)
- 后台数据统计与分析报表
实际运营数据显示,系统上线后场地利用率提升40%,管理人力成本降低60%,居民投诉率下降85%
2. 技术架构设计
2.1 整体技术选型
前端技术栈:
- uniapp:跨端开发框架,一套代码同时生成微信小程序、H5等多端应用
- uView UI:专为uniapp优化的UI组件库
- ECharts:可视化图表展示场地使用热力图
后端技术栈:
- SpringBoot 2.7:快速构建微服务架构
- MyBatis-Plus:简化数据库操作
- Redis:缓存热点数据(如场地实时状态)
- Quartz:定时任务处理过期预约
数据库设计:
sql复制CREATE TABLE `venue` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL COMMENT '场地名称',
`type` tinyint NOT NULL COMMENT '1篮球场 2羽毛球场 3游泳池',
`status` tinyint DEFAULT '0' COMMENT '0可用 1维修中',
`price` decimal(10,2) NOT NULL COMMENT '小时单价',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `reservation` (
`id` int NOT NULL AUTO_INCREMENT,
`user_id` int NOT NULL,
`venue_id` int NOT NULL,
`start_time` datetime NOT NULL,
`end_time` datetime NOT NULL,
`status` tinyint DEFAULT '0' COMMENT '0待支付 1已预约 2已取消',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_venue_time` (`venue_id`,`start_time`,`end_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
2.2 关键技术实现
2.2.1 预约冲突检测算法
核心难点在于高效检测时间重叠,我们采用数据库索引+内存计算双重校验:
java复制// 检查同一场地是否存在时间重叠的预约
public boolean checkTimeConflict(Integer venueId, LocalDateTime start, LocalDateTime end) {
// 先查缓存
String cacheKey = "venue:" + venueId + ":reservations";
List<Reservation> cacheList = redisTemplate.opsForList().range(cacheKey, 0, -1);
if (CollectionUtils.isEmpty(cacheList)) {
// 缓存未命中查数据库
cacheList = reservationMapper.selectList(
new LambdaQueryWrapper<Reservation>()
.eq(Reservation::getVenueId, venueId)
.eq(Reservation::getStatus, 1) // 已预约状态
.between(Reservation::getStartTime, start.minusHours(2), end.plusHours(2))
);
redisTemplate.opsForList().rightPushAll(cacheKey, cacheList);
redisTemplate.expire(cacheKey, 5, TimeUnit.MINUTES);
}
return cacheList.stream().anyMatch(r ->
!(end.isBefore(r.getStartTime()) || start.isAfter(r.getEndTime()))
);
}
2.2.2 高并发场景优化
针对秒杀式抢场地的场景,我们采用三级防护:
- 前端防抖+按钮禁用
- 乐观锁控制数据库更新
- Redis分布式锁防止超卖
java复制public boolean makeReservation(ReservationDTO dto) {
// 获取分布式锁
String lockKey = "lock:venue:" + dto.getVenueId() + ":" + dto.getStartTime();
boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
if (!locked) {
throw new BusinessException("当前预约人数过多,请稍后再试");
}
try {
// 检查场地状态
Venue venue = venueMapper.selectById(dto.getVenueId());
if (venue.getStatus() != 0) {
throw new BusinessException("该场地暂不可用");
}
// 检查时间冲突
if (checkTimeConflict(dto.getVenueId(), dto.getStartTime(), dto.getEndTime())) {
throw new BusinessException("该时段已被预约");
}
// 创建预约记录
Reservation reservation = new Reservation();
BeanUtils.copyProperties(dto, reservation);
reservation.setStatus(0); // 待支付状态
return reservationMapper.insert(reservation) > 0;
} finally {
redisTemplate.delete(lockKey);
}
}
3. 前端实现细节
3.1 场地日历组件开发
使用uni-app的picker组件改造实现可视化预约日历:
javascript复制// components/venue-calendar.vue
export default {
props: {
venueId: Number,
date: String
},
data() {
return {
timeSlots: [],
selected: []
}
},
methods: {
async loadData() {
const res = await uni.request({
url: '/api/reservation/available',
data: { venueId: this.venueId, date: this.date }
});
this.timeSlots = res.data.map(item => ({
time: item.time,
available: item.available,
price: item.price
}));
},
selectSlot(index) {
if (!this.timeSlots[index].available) return;
this.$set(this.timeSlots[index], 'selected', !this.timeSlots[index].selected);
this.selected = this.timeSlots.filter(item => item.selected);
}
},
mounted() {
this.loadData();
}
}
3.2 微信支付集成
关键支付流程处理:
javascript复制// pages/payment/index.vue
methods: {
async handleWechatPay() {
const res = await uni.request({
url: '/api/payment/create',
method: 'POST',
data: {
orderId: this.orderId,
amount: this.amount
}
});
uni.requestPayment({
provider: 'wxpay',
timeStamp: res.data.timeStamp,
nonceStr: res.data.nonceStr,
package: res.data.package,
signType: 'MD5',
paySign: res.data.paySign,
success: () => {
this.$emit('payment-success');
},
fail: (err) => {
uni.showToast({ title: '支付失败', icon: 'none' });
}
});
}
}
4. 部署与运维方案
4.1 服务器环境配置
推荐部署方案:
- 开发环境:HBuilderX + 微信开发者工具联调
- 生产环境:
- 前端:腾讯云静态网站托管(自动部署小程序)
- 后端:2核4G云服务器(Docker容器化部署)
- 数据库:阿里云RDS MySQL 5.7(主从架构)
Nginx关键配置:
nginx复制server {
listen 80;
server_name api.yourdomain.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 微信小程序域名校验
location /MP_verify_xxxx.txt {
alias /data/www/wechat/MP_verify_xxxx.txt;
}
}
4.2 监控与日志
建议配置:
- Spring Boot Actuator健康检查
- ELK日志收集系统
- 小程序错误监控(使用uni-app的onError全局捕获)
yaml复制# application.yml
management:
endpoints:
web:
exposure:
include: health,info,metrics
endpoint:
health:
show-details: always
5. 典型问题解决方案
5.1 微信登录态维护
常见问题:用户频繁需要重新登录
解决方案:采用双Token机制(access_token + refresh_token)
java复制// Token生成策略
public String generateToken(User user) {
// access_token 有效期2小时
String accessToken = Jwts.builder()
.setSubject(user.getId().toString())
.setExpiration(new Date(System.currentTimeMillis() + 7200000))
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
// refresh_token 有效期7天
String refreshToken = Jwts.builder()
.setSubject(user.getId().toString())
.setExpiration(new Date(System.currentTimeMillis() + 604800000))
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
redisTemplate.opsForValue().set(
"user:" + user.getId() + ":refresh",
refreshToken,
7, TimeUnit.DAYS
);
return accessToken + "||" + refreshToken;
}
5.2 大文件上传问题
场地图片上传采用分片上传方案:
javascript复制// utils/upload.js
export function uploadFile(filePath) {
return new Promise((resolve, reject) => {
const uploadTask = uni.uploadFile({
url: '/api/upload/chunk',
filePath: filePath,
name: 'file',
formData: {
chunkIndex: 0,
totalChunks: 1,
fileHash: ''
},
success: (res) => {
if (res.statusCode === 200) {
resolve(JSON.parse(res.data));
} else {
reject(new Error('上传失败'));
}
},
fail: (err) => {
reject(err);
}
});
uploadTask.onProgressUpdate((res) => {
console.log('上传进度:' + res.progress);
});
});
}
6. 项目优化方向
- 智能推荐系统:基于用户历史预约数据推荐相似场地
- 人脸识别签到:防止场地冒用现象
- 物联网集成:智能门禁控制场地使用权限
- 数据分析看板:为物业提供运营决策支持
实际开发中我们发现,预约系统的稳定性比功能丰富度更重要。初期建议先确保核心流程的可靠性,再逐步扩展增值功能。我们团队在灰度发布阶段,通过A/B测试发现,简化预约步骤能提升30%的转化率——将原本5步的流程缩减到3步后,用户流失率显著下降。
