8a7936ba4e
- 添加预约模块详细设计文档(LLD-预约模块详细设计.md) - 添加签到模块详细设计文档(LLD-签到模块详细设计.md) - 添加API接口文档(API接口文档.md) 文档包含: - 模块概述与边界定义 - 数据模型设计(含SQL建表语句) - 领域模型设计 - 业务流程设计 - 接口设计 - 核心代码设计 - 高并发处理方案 - 缓存设计 - 定时任务设计 - 异常处理 - 附录(枚举定义、错误码)~
25 KiB
25 KiB
健身房管理系统 API 接口文档
文档编号: GYM-API-001
版本: v1.0
日期: 2026-02-28
作者: 张翔
状态: 初稿
文档修订历史
| 版本 | 日期 | 作者 | 修订内容 |
|---|---|---|---|
| v1.0 | 2026-02-28 | 张翔 | 初稿 |
一、接口规范
1.1 基础信息
| 项目 | 说明 |
|---|---|
| 协议 | HTTPS |
| 请求方式 | GET / POST / PUT / DELETE |
| 数据格式 | JSON |
| 字符编码 | UTF-8 |
| 时间格式 | yyyy-MM-dd HH:mm:ss |
| 时区 | Asia/Shanghai |
1.2 请求头
Content-Type: application/json
Authorization: Bearer {token}
X-Tenant-Id: {tenantId}
X-Store-Id: {storeId}
X-Request-Id: {uuid}
1.3 响应格式
{
"code": 0,
"message": "success",
"data": {},
"timestamp": 1709123456789
}
1.4 错误码定义
| 错误码 | 说明 |
|---|---|
| 0 | 成功 |
| 400 | 请求参数错误 |
| 401 | 未授权 |
| 403 | 无权限 |
| 404 | 资源不存在 |
| 409 | 资源冲突 |
| 429 | 请求过于频繁 |
| 500 | 服务器内部错误 |
二、会员模块 API
2.1 会员信息
2.1.1 获取会员信息
GET /api/v1/members/{memberId}
请求参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| memberId | Long | 是 | 会员ID |
响应示例
{
"code": 0,
"message": "success",
"data": {
"memberId": 1001,
"memberNo": "M20260001",
"name": "张三",
"phone": "138****8888",
"avatar": "https://xxx.com/avatar.jpg",
"gender": 1,
"birthday": "1990-01-15",
"level": 2,
"levelName": "VIP会员",
"exp": 1500,
"status": 1,
"createdAt": "2026-01-01 10:00:00"
}
}
2.1.2 获取会员卡列表
GET /api/v1/members/{memberId}/cards
响应示例
{
"code": 0,
"message": "success",
"data": [
{
"cardId": 1,
"cardName": "年卡",
"cardType": 1,
"status": 1,
"validFrom": "2026-01-01",
"validTo": "2026-12-31",
"remainDays": 306,
"benefits": [
{
"benefitId": 1,
"benefitType": 1,
"benefitName": "时长权益",
"remainValue": "306天"
}
]
}
]
}
2.1.3 获取会员权益
GET /api/v1/members/{memberId}/benefits
响应示例
{
"code": 0,
"message": "success",
"data": {
"timeBenefits": [
{
"benefitId": 1,
"name": "年卡",
"validFrom": "2026-01-01",
"validTo": "2026-12-31",
"remainDays": 306
}
],
"countBenefits": [
{
"benefitId": 2,
"name": "私教课时包",
"totalCount": 20,
"usedCount": 5,
"remainCount": 15
}
],
"balanceBenefits": [
{
"benefitId": 3,
"name": "储值账户",
"balance": 1000.00
}
]
}
}
2.2 会员二维码
2.2.1 获取签到二维码
GET /api/v1/members/{memberId}/qrcode
响应示例
{
"code": 0,
"message": "success",
"data": {
"qrcode": "MEMBER_1001_1709123456",
"expireAt": "2026-02-28 10:35:00",
"refreshInterval": 60
}
}
三、预约模块 API
3.1 课程查询
3.1.1 获取课程列表
GET /api/v1/courses
请求参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| tenantId | Long | 是 | 租户ID |
| storeId | Long | 否 | 门店ID |
| type | Integer | 否 | 课程类型:1-团课 2-私教 3-线上 |
| category | String | 否 | 课程分类 |
| status | Integer | 否 | 状态:1-上架 |
| page | Integer | 否 | 页码,默认1 |
| size | Integer | 否 | 每页数量,默认20 |
响应示例
{
"code": 0,
"message": "success",
"data": {
"total": 50,
"list": [
{
"courseId": 1,
"name": "瑜伽基础课",
"type": 1,
"category": "瑜伽",
"duration": 60,
"capacity": 20,
"difficulty": 1,
"calories": 200,
"coverImage": "https://xxx.com/course.jpg",
"price": 1,
"priceValue": 1,
"status": 1
}
]
}
}
3.1.2 获取课程详情
GET /api/v1/courses/{courseId}
响应示例
{
"code": 0,
"message": "success",
"data": {
"courseId": 1,
"name": "瑜伽基础课",
"type": 1,
"category": "瑜伽",
"description": "适合初学者的瑜伽课程",
"duration": 60,
"capacity": 20,
"minCapacity": 5,
"difficulty": 1,
"calories": 200,
"equipment": "瑜伽垫",
"coverImage": "https://xxx.com/course.jpg",
"price": 1,
"priceType": 1,
"priceValue": 1,
"advanceDays": 7,
"cancelHours": 2,
"status": 1
}
}
3.2 预约时段
3.2.1 获取可预约时段
GET /api/v1/slots
请求参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| tenantId | Long | 是 | 租户ID |
| storeId | Long | 是 | 门店ID |
| resourceType | Integer | 是 | 资源类型:1-团课 2-私教 3-场地 |
| resourceId | Long | 否 | 资源ID |
| date | Date | 是 | 日期 |
| page | Integer | 否 | 页码 |
| size | Integer | 否 | 每页数量 |
响应示例
{
"code": 0,
"message": "success",
"data": {
"total": 10,
"list": [
{
"slotId": 1,
"resourceType": 1,
"resourceId": 1,
"resourceName": "瑜伽基础课",
"coachId": 100,
"coachName": "王教练",
"venueId": 1,
"venueName": "瑜伽室A",
"startTime": "2026-02-28 10:00:00",
"endTime": "2026-02-28 11:00:00",
"capacity": 20,
"bookedCount": 15,
"remainCount": 5,
"status": 1,
"price": 1,
"priceType": 1,
"priceValue": 1,
"bookingStart": "2026-02-21 10:00:00",
"bookingEnd": "2026-02-28 08:00:00",
"cancelDeadline": "2026-02-28 08:00:00"
}
]
}
}
3.2.2 获取时段详情
GET /api/v1/slots/{slotId}
响应示例
{
"code": 0,
"message": "success",
"data": {
"slotId": 1,
"resourceType": 1,
"resourceId": 1,
"resourceName": "瑜伽基础课",
"resourceImage": "https://xxx.com/course.jpg",
"coachId": 100,
"coachName": "王教练",
"coachAvatar": "https://xxx.com/coach.jpg",
"venueId": 1,
"venueName": "瑜伽室A",
"startTime": "2026-02-28 10:00:00",
"endTime": "2026-02-28 11:00:00",
"capacity": 20,
"bookedCount": 15,
"remainCount": 5,
"waitlistCount": 3,
"minCapacity": 5,
"status": 1,
"price": 1,
"priceType": 1,
"priceValue": 1,
"canBook": true,
"canCancel": true,
"bookingStart": "2026-02-21 10:00:00",
"bookingEnd": "2026-02-28 08:00:00",
"cancelDeadline": "2026-02-28 08:00:00"
}
}
3.3 预约操作
3.3.1 创建预约
POST /api/v1/bookings
请求参数
{
"tenantId": 1,
"storeId": 1,
"memberId": 1001,
"slotId": 1,
"source": "app"
}
响应示例
{
"code": 0,
"message": "预约成功",
"data": {
"bookingId": 2001,
"bookingNo": "B20260228001",
"slotId": 1,
"resourceName": "瑜伽基础课",
"coachName": "王教练",
"venueName": "瑜伽室A",
"startTime": "2026-02-28 10:00:00",
"endTime": "2026-02-28 11:00:00",
"status": 1,
"priceType": 1,
"priceValue": 1,
"benefitDeducted": {
"benefitId": 1,
"benefitType": 1,
"benefitName": "年卡",
"deductedValue": "1次"
},
"cancelDeadline": "2026-02-28 08:00:00"
}
}
3.3.2 取消预约
POST /api/v1/bookings/{bookingId}/cancel
请求参数
{
"reason": "临时有事"
}
响应示例
{
"code": 0,
"message": "取消成功",
"data": {
"bookingId": 2001,
"status": 2,
"refundAmount": 0,
"refundBenefit": {
"benefitId": 1,
"refundValue": "1次"
}
}
}
3.3.3 获取预约列表
GET /api/v1/bookings
请求参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| memberId | Long | 是 | 会员ID |
| status | Integer | 否 | 状态:1-已预约 2-已取消 3-已完成 |
| startDate | Date | 否 | 开始日期 |
| endDate | Date | 否 | 结束日期 |
| page | Integer | 否 | 页码 |
| size | Integer | 否 | 每页数量 |
响应示例
{
"code": 0,
"message": "success",
"data": {
"total": 25,
"list": [
{
"bookingId": 2001,
"bookingNo": "B20260228001",
"resourceType": 1,
"resourceName": "瑜伽基础课",
"coachName": "王教练",
"venueName": "瑜伽室A",
"startTime": "2026-02-28 10:00:00",
"endTime": "2026-02-28 11:00:00",
"status": 1,
"checkinStatus": 0,
"canCancel": true,
"cancelDeadline": "2026-02-28 08:00:00"
}
]
}
}
3.3.4 获取预约详情
GET /api/v1/bookings/{bookingId}
响应示例
{
"code": 0,
"message": "success",
"data": {
"bookingId": 2001,
"bookingNo": "B20260228001",
"memberId": 1001,
"memberName": "张三",
"memberPhone": "138****8888",
"slotId": 1,
"resourceType": 1,
"resourceId": 1,
"resourceName": "瑜伽基础课",
"resourceImage": "https://xxx.com/course.jpg",
"coachId": 100,
"coachName": "王教练",
"coachAvatar": "https://xxx.com/coach.jpg",
"venueId": 1,
"venueName": "瑜伽室A",
"startTime": "2026-02-28 10:00:00",
"endTime": "2026-02-28 11:00:00",
"status": 1,
"checkinStatus": 0,
"checkinAt": null,
"priceType": 1,
"priceValue": 1,
"benefitId": 1,
"source": "app",
"createdAt": "2026-02-25 10:00:00",
"cancelDeadline": "2026-02-28 08:00:00",
"canCancel": true,
"canCheckin": true
}
}
3.4 候补队列
3.4.1 加入候补
POST /api/v1/waitlist
请求参数
{
"tenantId": 1,
"memberId": 1001,
"slotId": 1
}
响应示例
{
"code": 0,
"message": "加入候补成功",
"data": {
"waitlistId": 1,
"slotId": 1,
"queueNo": 4,
"estimatedWaitTime": "约30分钟"
}
}
3.4.2 取消候补
DELETE /api/v1/waitlist/{waitlistId}
响应示例
{
"code": 0,
"message": "取消候补成功"
}
四、签到模块 API
4.1 签到操作
4.1.1 二维码签到
POST /api/v1/checkin/qrcode
请求参数
{
"tenantId": 1,
"storeId": 1,
"qrcode": "MEMBER_1001_1709123456",
"deviceId": 1,
"type": 1,
"bookingId": null
}
响应示例
{
"code": 0,
"message": "签到成功",
"data": {
"checkinId": 1001,
"memberId": 1001,
"memberName": "张三",
"memberPhone": "138****8888",
"memberLevel": "VIP会员",
"checkinType": "入场签到",
"checkinTime": "2026-02-28 10:30:00",
"benefitDeducted": {
"type": "时长权益",
"value": "年卡有效期至2026-12-31"
},
"warnings": []
}
}
4.1.2 人脸识别签到
POST /api/v1/checkin/face
请求参数
{
"tenantId": 1,
"storeId": 1,
"faceFeature": "base64_encoded_feature",
"deviceId": 1,
"type": 1,
"bookingId": null
}
响应示例
{
"code": 0,
"message": "签到成功",
"data": {
"checkinId": 1002,
"memberId": 1001,
"memberName": "张三",
"memberPhone": "138****8888",
"memberLevel": "VIP会员",
"checkinType": "入场签到",
"checkinTime": "2026-02-28 10:31:00",
"benefitDeducted": {
"type": "时长权益",
"value": "年卡有效期至2026-12-31"
},
"warnings": []
}
}
4.1.3 NFC签到
POST /api/v1/checkin/nfc
请求参数
{
"tenantId": 1,
"storeId": 1,
"nfcId": "NFC_CARD_1001",
"deviceId": 1,
"type": 1,
"bookingId": null
}
响应示例
{
"code": 0,
"message": "签到成功",
"data": {
"checkinId": 1003,
"memberId": 1001,
"memberName": "张三",
"memberPhone": "138****8888",
"memberLevel": "VIP会员",
"checkinType": "入场签到",
"checkinTime": "2026-02-28 10:32:00",
"benefitDeducted": {
"type": "时长权益",
"value": "年卡有效期至2026-12-31"
},
"warnings": []
}
}
4.1.4 教练代签
POST /api/v1/checkin/manual
请求参数
{
"tenantId": 1,
"storeId": 1,
"memberId": 1001,
"bookingId": 2001,
"operatorId": 100,
"operatorName": "李教练",
"remark": "会员已到场"
}
响应示例
{
"code": 0,
"message": "代签成功",
"data": {
"checkinId": 1004,
"memberId": 1001,
"memberName": "张三",
"checkinType": "私教签到",
"checkinTime": "2026-02-28 10:33:00",
"operatorName": "李教练"
}
}
4.2 人脸管理
4.2.1 注册人脸
POST /api/v1/face/register
Content-Type: multipart/form-data
请求参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| memberId | Long | 是 | 会员ID |
| faceImage | File | 是 | 人脸照片 |
响应示例
{
"code": 0,
"message": "人脸注册成功",
"data": {
"faceId": 1,
"qualityScore": 95.5,
"status": "正常"
}
}
4.2.2 更新人脸
PUT /api/v1/face/{memberId}
Content-Type: multipart/form-data
请求参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| faceImage | File | 是 | 人脸照片 |
响应示例
{
"code": 0,
"message": "人脸更新成功",
"data": {
"faceId": 1,
"qualityScore": 96.2,
"status": "正常"
}
}
4.2.3 删除人脸
DELETE /api/v1/face/{memberId}
响应示例
{
"code": 0,
"message": "人脸删除成功"
}
4.3 签到记录
4.3.1 查询签到记录
GET /api/v1/checkin/records
请求参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| memberId | Long | 是 | 会员ID |
| startDate | Date | 否 | 开始日期 |
| endDate | Date | 否 | 结束日期 |
| type | Integer | 否 | 签到类型 |
| page | Integer | 否 | 页码 |
| size | Integer | 否 | 每页数量 |
响应示例
{
"code": 0,
"message": "success",
"data": {
"total": 25,
"list": [
{
"checkinId": 1001,
"type": "入场签到",
"method": "二维码",
"checkinTime": "2026-02-28 10:30:00",
"storeName": "中关村店",
"status": "成功"
},
{
"checkinId": 1002,
"type": "课程签到",
"method": "人脸识别",
"checkinTime": "2026-02-27 19:00:00",
"courseName": "瑜伽课",
"coachName": "王教练",
"status": "成功"
}
]
}
}
4.3.2 查询签到统计
GET /api/v1/checkin/statistics
请求参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| tenantId | Long | 是 | 租户ID |
| storeId | Long | 否 | 门店ID |
| startDate | Date | 是 | 开始日期 |
| endDate | Date | 是 | 结束日期 |
响应示例
{
"code": 0,
"message": "success",
"data": {
"totalCount": 1500,
"entryCount": 800,
"courseCount": 500,
"privateCount": 150,
"activityCount": 50,
"activeMemberCount": 350,
"newMemberCount": 25,
"peakHour": 19,
"peakCount": 120,
"avgDuration": 90,
"dailyTrend": [
{"date": "2026-02-01", "count": 50},
{"date": "2026-02-02", "count": 55}
]
}
}
4.4 设备管理
4.4.1 设备心跳
POST /api/v1/device/heartbeat
请求参数
{
"deviceId": 1,
"deviceCode": "DEVICE_001",
"status": 1,
"timestamp": "2026-02-28T10:30:00"
}
响应示例
{
"code": 0,
"message": "success"
}
4.4.2 设备列表
GET /api/v1/device/list
请求参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| tenantId | Long | 是 | 租户ID |
| storeId | Long | 否 | 门店ID |
响应示例
{
"code": 0,
"message": "success",
"data": [
{
"deviceId": 1,
"name": "前台人脸机",
"code": "DEVICE_001",
"type": "人脸识别机",
"location": "前台入口",
"status": "在线",
"lastHeartbeat": "2026-02-28 10:30:00"
}
]
}
五、场地模块 API
5.1 场地查询
5.1.1 获取场地列表
GET /api/v1/venues
请求参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| tenantId | Long | 是 | 租户ID |
| storeId | Long | 是 | 门店ID |
| type | Integer | 否 | 场地类型 |
| status | Integer | 否 | 状态 |
响应示例
{
"code": 0,
"message": "success",
"data": {
"total": 10,
"list": [
{
"venueId": 1,
"name": "瑜伽室A",
"type": 1,
"typeName": "瑜伽室",
"area": 100.5,
"capacity": 25,
"openTime": "07:00",
"closeTime": "22:00",
"pricePerHour": 100.00,
"status": 1,
"images": [
"https://xxx.com/venue1.jpg",
"https://xxx.com/venue2.jpg"
]
}
]
}
}
5.1.2 获取场地可用时段
GET /api/v1/venues/{venueId}/slots
请求参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| date | Date | 是 | 日期 |
响应示例
{
"code": 0,
"message": "success",
"data": [
{
"slotId": 1,
"startTime": "2026-02-28 10:00:00",
"endTime": "2026-02-28 11:00:00",
"status": 1,
"price": 100.00
}
]
}
六、教练模块 API
6.1 教练查询
6.1.1 获取教练列表
GET /api/v1/coaches
请求参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| tenantId | Long | 是 | 租户ID |
| storeId | Long | 否 | 门店ID |
| specialty | String | 否 | 专长 |
| status | Integer | 否 | 状态 |
响应示例
{
"code": 0,
"message": "success",
"data": {
"total": 20,
"list": [
{
"coachId": 100,
"name": "王教练",
"avatar": "https://xxx.com/coach.jpg",
"gender": 1,
"specialty": "瑜伽,普拉提",
"experience": 5,
"rating": 4.8,
"courseCount": 120,
"status": 1
}
]
}
}
6.1.2 获取教练可预约时段
GET /api/v1/coaches/{coachId}/slots
请求参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| date | Date | 是 | 日期 |
响应示例
{
"code": 0,
"message": "success",
"data": [
{
"slotId": 1,
"startTime": "2026-02-28 10:00:00",
"endTime": "2026-02-28 11:00:00",
"status": 1,
"price": 300.00
}
]
}
七、数据统计 API
7.1 运营数据
7.1.1 获取运营概览
GET /api/v1/statistics/overview
请求参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| tenantId | Long | 是 | 租户ID |
| storeId | Long | 否 | 门店ID |
| date | Date | 是 | 日期 |
响应示例
{
"code": 0,
"message": "success",
"data": {
"date": "2026-02-28",
"memberStats": {
"totalMembers": 1500,
"newMembers": 25,
"activeMembers": 350,
"activeRate": 23.3
},
"checkinStats": {
"totalCount": 500,
"entryCount": 300,
"courseCount": 150,
"privateCount": 50
},
"bookingStats": {
"totalCount": 200,
"successCount": 180,
"cancelCount": 20,
"successRate": 90.0
},
"revenueStats": {
"totalRevenue": 50000.00,
"courseRevenue": 30000.00,
"privateRevenue": 15000.00,
"otherRevenue": 5000.00
}
}
}
7.1.2 获取趋势数据
GET /api/v1/statistics/trend
请求参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| tenantId | Long | 是 | 租户ID |
| storeId | Long | 否 | 门店ID |
| startDate | Date | 是 | 开始日期 |
| endDate | Date | 是 | 结束日期 |
| metric | String | 是 | 指标:checkin/booking/revenue |
响应示例
{
"code": 0,
"message": "success",
"data": {
"metric": "checkin",
"trend": [
{"date": "2026-02-01", "value": 450},
{"date": "2026-02-02", "value": 480},
{"date": "2026-02-03", "value": 520}
],
"total": 1450,
"average": 483.3,
"max": 520,
"min": 450
}
}
八、消息通知 API
8.1 通知管理
8.1.1 获取通知列表
GET /api/v1/notifications
请求参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| memberId | Long | 是 | 会员ID |
| type | Integer | 否 | 通知类型 |
| isRead | Boolean | 否 | 是否已读 |
| page | Integer | 否 | 页码 |
| size | Integer | 否 | 每页数量 |
响应示例
{
"code": 0,
"message": "success",
"data": {
"total": 50,
"unreadCount": 10,
"list": [
{
"notificationId": 1,
"type": 1,
"typeName": "预约提醒",
"title": "课程预约成功",
"content": "您已成功预约瑜伽基础课,时间为2026-02-28 10:00-11:00",
"isRead": false,
"createdAt": "2026-02-25 10:00:00"
}
]
}
}
8.1.2 标记通知已读
PUT /api/v1/notifications/{notificationId}/read
响应示例
{
"code": 0,
"message": "success"
}
8.1.3 全部标记已读
PUT /api/v1/notifications/read-all
请求参数
{
"memberId": 1001
}
响应示例
{
"code": 0,
"message": "success"
}
九、错误响应示例
9.1 参数错误
{
"code": 400,
"message": "参数错误: memberId不能为空",
"data": null,
"timestamp": 1709123456789
}
9.2 未授权
{
"code": 401,
"message": "未授权,请先登录",
"data": null,
"timestamp": 1709123456789
}
9.3 业务异常
{
"code": 400,
"message": "预约失败:课程已满",
"data": {
"errorCode": "SLOT_FULL",
"errorDetail": "当前时段已预约满,请选择其他时段"
},
"timestamp": 1709123456789
}
十、版本历史
| 版本 | 日期 | 作者 | 变更内容 |
|---|---|---|---|
| v1.0 | 2026-02-28 | 张翔 | 初稿 |