健身行业近年来呈现爆发式增长,传统纸质会员卡和Excel表格管理方式已经无法满足现代化健身俱乐部的运营需求。我去年为本地一家中型健身中心开发这套系统时,老板反映每月因手工统计错误导致的营收损失就超过5%。这套基于Vue+SpringBoot的智能管理系统,主要解决三个核心痛点:
系统上线后实现:
采用Vue.js 3 + Element Plus的组合主要基于:
典型代码结构示例:
typescript复制// 会员信息编辑组件
<script setup lang="ts">
const formData = reactive({
memberId: '',
healthCondition: [] as string[],
// 采用联合类型精确约束
gender: 'male' | 'female' | 'other'
})
// 提交时自动生成二维码
const generateQR = () => {
if (!formData.memberId) {
ElMessage.error('请先保存会员基本信息')
return
}
// 调用后端二维码生成接口...
}
</script>
SpringBoot 2.7 + MyBatis-Plus的选型考虑:
关键配置示例:
yaml复制# application.yml
mybatis-plus:
mapper-locations: classpath*:/mapper/**/*.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
java复制// 体测数据对比算法
public List<BodyDataVO> compareData(Long memberId) {
List<BodyData> history = bodyDataMapper.selectList(
new LambdaQueryWrapper<BodyData>()
.eq(BodyData::getMemberId, memberId)
.orderByAsc(BodyData::getTestDate)
);
return history.stream()
.map(data -> new BodyDataVO(data, calculateChangeRate(history, data)))
.collect(Collectors.toList());
}
javascript复制function checkConflict(newSession, existingSessions) {
return existingSessions.some(session =>
newSession.coachId === session.coachId &&
((newSession.startTime >= session.startTime &&
newSession.startTime < session.endTime) ||
(newSession.endTime > session.startTime &&
newSession.endTime <= session.endTime))
)
}
sql复制CREATE TABLE member_tags (
member_id BIGINT,
tag_type ENUM('消费频次','课程偏好','时段规律'),
tag_value VARCHAR(50),
update_time DATETIME
);
java复制public PushChannel selectChannel(Member member) {
if (member.getLastLoginDevice().contains("iPhone")) {
return PushChannel.APNS;
} else if (member.getWechatOpenid() != null) {
return PushChannel.WECHAT;
}
return PushChannel.SMS;
}
java复制@Transactional
public boolean bookCourse(Long courseId, Long memberId) {
Course course = courseMapper.selectById(courseId);
if (course.getRemainSeats() <= 0) {
return false;
}
int updated = courseMapper.updateRemainSeats(
courseId,
course.getVersion(),
course.getRemainSeats() - 1
);
if (updated == 0) {
throw new OptimisticLockingFailureException("课程名额已变更");
}
// 记录预约...
}
java复制public void exportMembers(OutputStream out) {
int pageSize = 1000;
int total = memberMapper.selectCount(null);
ThreadPoolExecutor executor = new ThreadPoolExecutor(
4, 8, 60, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100)
);
List<Future<ByteArrayOutputStream>> futures = new ArrayList<>();
for (int i = 0; i <= total/pageSize; i++) {
futures.add(executor.submit(
new ExportTask(i, pageSize)
));
}
// 合并处理结果...
}
sql复制CREATE INDEX idx_member_gym ON member(gym_id, register_time);
这套系统在实际运行中经受住了"618健身狂欢节"的考验,当日完成: