1008 lines
27 KiB
Markdown
1008 lines
27 KiB
Markdown
# 预约系统前端对接文档
|
||
|
||
## 📌 文档说明
|
||
|
||
**版本**:v2.0
|
||
**更新日期**:2025-12-06
|
||
**适用范围**:预约房间功能前端开发
|
||
**后端接口版本**:预约时段优化版
|
||
|
||
---
|
||
|
||
## 📋 目录
|
||
|
||
1. [业务流程概述](#业务流程概述)
|
||
2. [页面结构](#页面结构)
|
||
3. [接口调用流程](#接口调用流程)
|
||
4. [接口详细说明](#接口详细说明)
|
||
5. [数据结构定义](#数据结构定义)
|
||
6. [前端实现指南](#前端实现指南)
|
||
7. [常见问题FAQ](#常见问题faq)
|
||
8. [调试技巧](#调试技巧)
|
||
|
||
---
|
||
|
||
## 业务流程概述
|
||
|
||
### 用户预约完整流程
|
||
|
||
```
|
||
┌─────────────────┐
|
||
│ 进入预约模块 │
|
||
└────────┬────────┘
|
||
│
|
||
▼
|
||
┌─────────────────┐
|
||
│ 【房间展示页】 │
|
||
│ 1. 选择日期 │
|
||
│ 2. 查看房间列表 │
|
||
│ 3. 查看时段状态 │
|
||
└────────┬────────┘
|
||
│ 点击【预约】
|
||
▼
|
||
┌─────────────────┐
|
||
│ 【预约页】 │
|
||
│ 1. 选择时段 │
|
||
│ 2. 填写人数 │
|
||
│ 3. 设置鸽子费 │
|
||
│ 4. 填写其他信息 │
|
||
└────────┬────────┘
|
||
│ 点击【提交】
|
||
▼
|
||
┌─────────────────┐
|
||
│ 创建预约 │
|
||
│ - 成功:跳转列表 │
|
||
│ - 失败:显示错误 │
|
||
└─────────────────┘
|
||
```
|
||
|
||
### 核心概念
|
||
|
||
#### 时段定义
|
||
| 时段类型 | 时段名称 | 时间范围 | 代码值 |
|
||
|---------|---------|---------|--------|
|
||
| 凌晨 | Dawn | 00:00-05:59 | 0 |
|
||
| 上午 | Morning | 06:00-11:59 | 1 |
|
||
| 下午 | Afternoon | 12:00-17:59 | 2 |
|
||
| 晚上 | Evening | 18:00-23:59 | 3 |
|
||
|
||
#### 时段状态
|
||
| 状态值 | 含义 | 展示方式 | 可否预约 |
|
||
|-------|------|---------|---------|
|
||
| available | 可预约 | 绿色✓ | 是 |
|
||
| reserved | 已预约 | 红色✗ | 否 |
|
||
| unavailable | 不可用 | 灰色🚫 | 否 |
|
||
| using | 使用中 | 蓝色🔵 | 否 |
|
||
|
||
---
|
||
|
||
## 页面结构
|
||
|
||
### 页面1:房间展示页
|
||
|
||
|
||
**页面元素**:
|
||
```
|
||
┌──────────────────────────────────────┐
|
||
│ 预约房间 │
|
||
├──────────────────────────────────────┤
|
||
│ [ 今天 ] [ 明天 ] [ 12/08 ] ... │ ← 日期选择器
|
||
├──────────────────────────────────────┤
|
||
│ [ ] 只显示当前时段可用房间 │ ← 筛选开关
|
||
├──────────────────────────────────────┤
|
||
│ ┌────────────────────────────────┐ │
|
||
│ │ 101包间 [豪华包间] │ │
|
||
│ │ 📷 [房间图片] │ │
|
||
│ │ 💰 标准价:80元/时段 │ │
|
||
│ │ 会员价:60元/时段 │ │
|
||
│ │ 时段状态: │ │
|
||
│ │ 凌晨✓ 上午✗ 下午✓ 晚上🔵 │ │
|
||
│ │ [ 预约 ] 按钮 │ │
|
||
│ └────────────────────────────────┘ │
|
||
│ [更多房间...] │
|
||
└──────────────────────────────────────┘
|
||
```
|
||
|
||
### 页面2:预约页
|
||
|
||
|
||
**页面元素**:
|
||
```
|
||
┌──────────────────────────────────────┐
|
||
│ 创建预约 │
|
||
├──────────────────────────────────────┤
|
||
│ 预约日期:2025年12月06日 (只读) │
|
||
│ 房间号:101包间 (豪华包间) (只读) │
|
||
├──────────────────────────────────────┤
|
||
│ 预约时间: │
|
||
│ [ 上午 ▼ ] │ ← 下拉选择(可预约时段)
|
||
│ 时间范围:06:00-11:59 │
|
||
│ 价格:标准价80元 | 会员价60元 │
|
||
├──────────────────────────────────────┤
|
||
│ 最晚到店时间: │
|
||
│ [ 10:30 ] (时间选择器) │
|
||
├──────────────────────────────────────┤
|
||
│ 人数: │
|
||
│ ( ) 2人 ( ) 3人 ( ) 4人 │
|
||
│ ( ) 无需组局 │
|
||
├──────────────────────────────────────┤
|
||
│ 鸽子费: │
|
||
│ ( ) 0元 ( ) 10元 ( ) 20元 │
|
||
│ (•) 自定义:[ 30 ] 元 │
|
||
├──────────────────────────────────────┤
|
||
│ 组局名称:[ 周末开黑 ] │
|
||
│ 玩法类型:[ 德州扑克 ] │
|
||
│ ... 其他信息 ... │
|
||
├──────────────────────────────────────┤
|
||
│ [ 提交预约 ] 按钮 │
|
||
└──────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 接口调用流程
|
||
|
||
### 时序图
|
||
|
||
```
|
||
前端页面 → 后端API
|
||
│
|
||
│ 1. 进入房间展示页
|
||
├────────────────→ GET /api/SQ/GetAvailableDates
|
||
│←─────────────── 返回:未来7天日期列表
|
||
│
|
||
│ 2. 获取房间列表(默认今天)
|
||
├────────────────→ GET /api/SQ/GetRoomListWithSlotsNew?date=xxx
|
||
│←─────────────── 返回:房间列表及4个时段状态
|
||
│
|
||
│ 3. 用户切换日期
|
||
├────────────────→ GET /api/SQ/GetRoomListWithSlotsNew?date=xxx
|
||
│←─────────────── 返回:新日期的房间列表
|
||
│
|
||
│ 4. 用户点击【预约】按钮
|
||
│ 携带:roomId, date, availableSlots
|
||
│ 跳转到预约页
|
||
│
|
||
│ 5. (可选)用户选择时段后实时校验
|
||
├────────────────→ POST /api/SQ/ValidateReservationBySlot
|
||
│←─────────────── 返回:是否可以预约
|
||
│
|
||
│ 6. 用户点击【提交预约】
|
||
├────────────────→ POST /api/SQ/AddSQReservationBySlot
|
||
│←─────────────── 返回:预约结果(成功/失败)
|
||
│
|
||
│ 7. 成功后跳转到"我的预约"列表
|
||
```
|
||
|
||
---
|
||
|
||
## 接口详细说明
|
||
|
||
### 接口1:获取可选日期列表
|
||
|
||
#### 基本信息
|
||
- **接口路径**:`GET /api/SQ/GetAvailableDates`
|
||
- **调用时机**:房间展示页初始化时调用1次
|
||
- **是否需要登录**:否
|
||
|
||
#### 请求参数
|
||
无参数
|
||
|
||
#### 返回数据
|
||
```typescript
|
||
interface Response {
|
||
code: number; // 0=成功
|
||
msg: string; // 消息
|
||
data: DateItem[]; // 日期列表
|
||
}
|
||
|
||
interface DateItem {
|
||
date: number; // Unix时间戳(秒级)
|
||
dateText: string; // 文本:今天/明天/后天/日期
|
||
dateDisplay: string; // 展示文本:12月06日 周五
|
||
}
|
||
```
|
||
|
||
#### 返回示例
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"msg": "ok",
|
||
"data": [
|
||
{
|
||
"date": 1733443200,
|
||
"dateText": "今天",
|
||
"dateDisplay": "周五"
|
||
},
|
||
{
|
||
"date": 1733529600,
|
||
"dateText": "明天",
|
||
"dateDisplay": "周六"
|
||
},
|
||
{
|
||
"date": 1733616000,
|
||
"dateText": "后天",
|
||
"dateDisplay": "周日"
|
||
},
|
||
{
|
||
"date": 1733702400,
|
||
"dateText": "12月09日",
|
||
"dateDisplay": "周一"
|
||
}
|
||
// ... 共7条(今天+未来6天)
|
||
]
|
||
}
|
||
```
|
||
|
||
|
||
---
|
||
|
||
### 接口2:获取房间列表及时段状态
|
||
|
||
#### 基本信息
|
||
- **接口路径**:`GET /api/SQ/GetRoomListWithSlotsNew`
|
||
- **调用时机**:初始化、切换日期时调用
|
||
- **是否需要登录**:否
|
||
|
||
#### 请求参数
|
||
| 参数名 | 类型 | 必填 | 说明 | 示例 |
|
||
|-------|------|------|------|------|
|
||
| date | number | 是 | Unix时间戳(秒级) | 1733443200 |
|
||
| showOnlyAvailable | boolean | 否 | 是否只显示当前时段可用房间 | false |
|
||
| currentTimeSlot | number | 否 | 当前时段类型(0-3),配合showOnlyAvailable | 1 |
|
||
|
||
#### 返回数据
|
||
```typescript
|
||
interface Response {
|
||
code: number;
|
||
msg: string;
|
||
data: RoomItem[];
|
||
}
|
||
|
||
interface RoomItem {
|
||
id: number; // 房间ID
|
||
name: string; // 房间名称
|
||
room_type_name: string; // 房间类型
|
||
image_url: string; // 房间图片
|
||
capacity: number; // 容纳人数
|
||
description: string; // 房间描述
|
||
standard_price_desc: string; // 标准价格说明
|
||
member_price_desc: string; // 会员价格说明
|
||
time_slots: TimeSlot[]; // 4个时段信息
|
||
status: string; // 房间状态
|
||
is_available: boolean; // 是否可用
|
||
can_reserve: boolean; // 是否可预约
|
||
}
|
||
|
||
interface TimeSlot {
|
||
slot_type: number; // 时段类型:0-3
|
||
slot_name: string; // 时段名称:凌晨/上午/下午/晚上
|
||
status: string; // 状态:available/reserved/unavailable/using
|
||
standard_price: number; // 标准价格
|
||
member_price: number; // 会员价格
|
||
price_desc_standard: string; // 标准价格说明
|
||
price_desc_member: string; // 会员价格说明
|
||
}
|
||
```
|
||
|
||
#### 返回示例
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"msg": "ok",
|
||
"data": [
|
||
{
|
||
"id": 1,
|
||
"name": "101包间",
|
||
"room_type_name": "豪华包间",
|
||
"image_url": "https://example.com/room1.jpg",
|
||
"capacity": 8,
|
||
"description": "宽敞舒适的豪华包间",
|
||
"standard_price_desc": "80元/时段",
|
||
"member_price_desc": "60元/时段",
|
||
"time_slots": [
|
||
{
|
||
"slot_type": 0,
|
||
"slot_name": "凌晨",
|
||
"status": "available",
|
||
"standard_price": 60.00,
|
||
"member_price": 50.00,
|
||
"price_desc_standard": "60元/时段",
|
||
"price_desc_member": "50元/时段"
|
||
},
|
||
{
|
||
"slot_type": 1,
|
||
"slot_name": "上午",
|
||
"status": "reserved",
|
||
"standard_price": 80.00,
|
||
"member_price": 60.00,
|
||
"price_desc_standard": "80元/时段",
|
||
"price_desc_member": "60元/时段"
|
||
},
|
||
{
|
||
"slot_type": 2,
|
||
"slot_name": "下午",
|
||
"status": "available",
|
||
"standard_price": 80.00,
|
||
"member_price": 60.00,
|
||
"price_desc_standard": "80元/时段",
|
||
"price_desc_member": "60元/时段"
|
||
},
|
||
{
|
||
"slot_type": 3,
|
||
"slot_name": "晚上",
|
||
"status": "using",
|
||
"standard_price": 100.00,
|
||
"member_price": 80.00,
|
||
"price_desc_standard": "100元/时段",
|
||
"price_desc_member": "80元/时段"
|
||
}
|
||
],
|
||
"status": "using",
|
||
"is_available": false,
|
||
"can_reserve": true
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
|
||
|
||
### 接口3:校验是否可创建预约(可选)
|
||
|
||
#### 基本信息
|
||
- **接口路径**:`POST /api/SQ/ValidateReservationBySlot`
|
||
- **调用时机**:用户选择时段后实时校验(可选)
|
||
- **是否需要登录**:是(需要Token)
|
||
|
||
#### 请求参数
|
||
与"创建预约"接口相同,但不会真正创建预约
|
||
|
||
#### 返回数据
|
||
```typescript
|
||
interface Response {
|
||
code: number; // 0=可以创建,500=不可以
|
||
msg: string; // 原因说明
|
||
data: {
|
||
canCreate: boolean; // 是否可以创建
|
||
reason: string; // 不能创建的原因
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 返回示例
|
||
```json
|
||
// 可以创建
|
||
{
|
||
"code": 0,
|
||
"msg": "",
|
||
"data": {
|
||
"canCreate": true,
|
||
"reason": ""
|
||
}
|
||
}
|
||
|
||
// 不能创建
|
||
{
|
||
"code": 500,
|
||
"msg": "您有其它预约时间冲突",
|
||
"data": {
|
||
"canCreate": false,
|
||
"reason": "您有其它预约时间冲突"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 前端使用
|
||
```javascript
|
||
// 用户选择时段时实时校验
|
||
async function onSlotChange(timeSlotType) {
|
||
const data = {
|
||
room_id: this.roomId,
|
||
date: this.date,
|
||
time_slot_type: timeSlotType,
|
||
player_count: 4,
|
||
// ... 其他字段
|
||
};
|
||
|
||
try {
|
||
const response = await axios.post('/api/SQ/ValidateReservationBySlot', data, {
|
||
headers: { Authorization: `Bearer ${this.token}` }
|
||
});
|
||
|
||
if (response.data.code === 0) {
|
||
// 可以预约,显示价格等信息
|
||
this.showPriceInfo(timeSlotType);
|
||
} else {
|
||
// 不能预约,显示原因
|
||
this.$message.warning(response.data.msg);
|
||
}
|
||
} catch (error) {
|
||
console.error('校验失败', error);
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 接口4:创建预约(核心)
|
||
|
||
#### 基本信息
|
||
- **接口路径**:`POST /api/SQ/AddSQReservationBySlot`
|
||
- **调用时机**:用户点击【提交预约】按钮
|
||
- **是否需要登录**:是(需要Token)
|
||
|
||
#### 请求参数
|
||
```typescript
|
||
interface CreateReservationRequest {
|
||
room_id: number; // 必填,房间ID
|
||
date: number; // 必填,预约日期(Unix时间戳-秒)
|
||
time_slot_type: number; // 必填,时段类型:0-3
|
||
latest_arrival_time?: number; // 可选,最晚到店时间(Unix时间戳-秒)
|
||
is_solo_mode: boolean; // 必填,是否无需组局
|
||
player_count: number; // 必填,人数(无需组局时固定为1)
|
||
deposit_fee: number; // 必填,鸽子费(0-50整数)
|
||
title: string; // 必填,组局名称
|
||
game_type: string; // 必填,玩法类型
|
||
game_rule?: string; // 可选,游戏规则
|
||
extra_info?: string; // 可选,其他补充
|
||
is_smoking: number; // 可选,是否禁烟:0=不限,1=禁烟,2=不禁烟
|
||
gender_limit: number; // 可选,性别限制:0=不限,1=男,2=女
|
||
credit_limit?: number; // 可选,最低信誉分
|
||
min_age?: number; // 可选,最小年龄
|
||
max_age?: number; // 可选,最大年龄,0=不限
|
||
important_data?: string; // 可选,重要数据(支付相关JSON)
|
||
}
|
||
```
|
||
|
||
#### 请求示例
|
||
```json
|
||
{
|
||
"room_id": 1,
|
||
"date": 1733443200,
|
||
"time_slot_type": 1,
|
||
"latest_arrival_time": 1733461200,
|
||
"is_solo_mode": false,
|
||
"player_count": 4,
|
||
"deposit_fee": 20,
|
||
"title": "周末开黑",
|
||
"game_type": "德州扑克",
|
||
"game_rule": "经典玩法",
|
||
"extra_info": "欢迎新手",
|
||
"is_smoking": 0,
|
||
"gender_limit": 0,
|
||
"credit_limit": 3.5,
|
||
"min_age": 18,
|
||
"max_age": 0,
|
||
"important_data": "{\"paymentId\":\"ORDER123456\"}"
|
||
}
|
||
```
|
||
|
||
#### 返回数据
|
||
```typescript
|
||
interface Response {
|
||
code: number; // 0=成功,其他=失败
|
||
msg: string; // 消息
|
||
data?: {
|
||
reservation_id: number; // 预约ID
|
||
start_time: string; // 开始时间
|
||
end_time: string; // 结束时间
|
||
actual_price: number; // 实际价格
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 返回示例(成功)
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"msg": "预约成功",
|
||
"data": {
|
||
"reservation_id": 123,
|
||
"start_time": "2025-12-06 06:00:00",
|
||
"end_time": "2025-12-06 11:59:59",
|
||
"actual_price": 80.00
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 返回示例(失败)
|
||
```json
|
||
// 时间冲突
|
||
{
|
||
"code": 402,
|
||
"msg": "您有其它预约时间冲突,无法创建该预约!",
|
||
"data": null
|
||
}
|
||
|
||
// 房间已被预约
|
||
{
|
||
"code": 500,
|
||
"msg": "该时间段房间已被预约",
|
||
"data": null
|
||
}
|
||
|
||
// 鸽子费超限
|
||
{
|
||
"code": 500,
|
||
"msg": "鸽子费必须在0-50元之间",
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
#### 前端使用
|
||
```javascript
|
||
async function submitReservation() {
|
||
// 1. 构建请求数据
|
||
const data = {
|
||
room_id: this.roomId,
|
||
date: this.date,
|
||
time_slot_type: this.selectedSlot,
|
||
latest_arrival_time: this.convertToTimestamp(this.arrivalTime),
|
||
is_solo_mode: this.playerCount === 1,
|
||
player_count: this.playerCount,
|
||
deposit_fee: this.depositFee,
|
||
title: this.title,
|
||
game_type: this.gameType,
|
||
game_rule: this.gameRule,
|
||
extra_info: this.extraInfo,
|
||
is_smoking: this.isSmoking,
|
||
gender_limit: this.genderLimit,
|
||
credit_limit: this.creditLimit,
|
||
min_age: this.minAge,
|
||
max_age: this.maxAge,
|
||
important_data: this.getPaymentData()
|
||
};
|
||
|
||
// 2. 参数校验
|
||
if (!this.validate(data)) {
|
||
return;
|
||
}
|
||
|
||
// 3. 发送请求
|
||
try {
|
||
const response = await axios.post('/api/SQ/AddSQReservationBySlot', data, {
|
||
headers: { Authorization: `Bearer ${this.token}` }
|
||
});
|
||
|
||
if (response.data.code === 0) {
|
||
// 成功
|
||
this.$message.success('预约成功!');
|
||
|
||
// 可以显示预约详情
|
||
console.log('预约ID:', response.data.data.reservation_id);
|
||
console.log('时间:', response.data.data.start_time, '-', response.data.data.end_time);
|
||
console.log('价格:', response.data.data.actual_price);
|
||
|
||
// 跳转到我的预约列表
|
||
this.$router.push('/my-reservations');
|
||
} else {
|
||
// 失败
|
||
this.$message.error(response.data.msg);
|
||
}
|
||
} catch (error) {
|
||
this.$message.error('预约失败,请重试');
|
||
console.error(error);
|
||
}
|
||
}
|
||
|
||
// 参数校验
|
||
function validate(data) {
|
||
if (!data.title) {
|
||
this.$message.warning('请输入组局名称');
|
||
return false;
|
||
}
|
||
if (!data.game_type) {
|
||
this.$message.warning('请选择玩法类型');
|
||
return false;
|
||
}
|
||
if (data.deposit_fee < 0 || data.deposit_fee > 50) {
|
||
this.$message.warning('鸽子费必须在0-50元之间');
|
||
return false;
|
||
}
|
||
if (!Number.isInteger(data.deposit_fee)) {
|
||
this.$message.warning('鸽子费必须是整数');
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 数据结构定义
|
||
|
||
### TypeScript类型定义
|
||
|
||
```typescript
|
||
// ========== 基础类型 ==========
|
||
|
||
/** 时段类型枚举 */
|
||
enum TimeSlotType {
|
||
Dawn = 0, // 凌晨
|
||
Morning = 1, // 上午
|
||
Afternoon = 2, // 下午
|
||
Evening = 3 // 晚上
|
||
}
|
||
|
||
/** 时段状态枚举 */
|
||
enum TimeSlotStatus {
|
||
Available = 'available', // 可预约
|
||
Reserved = 'reserved', // 已预约
|
||
Unavailable = 'unavailable', // 不可用
|
||
Using = 'using' // 使用中
|
||
}
|
||
|
||
// ========== 日期相关 ==========
|
||
|
||
/** 日期项 */
|
||
interface DateItem {
|
||
date: number; // Unix时间戳(秒)
|
||
dateText: string; // 文本显示
|
||
dateDisplay: string; // 完整显示
|
||
}
|
||
|
||
// ========== 房间相关 ==========
|
||
|
||
/** 时段信息 */
|
||
interface TimeSlot {
|
||
slot_type: TimeSlotType; // 时段类型
|
||
slot_name: string; // 时段名称
|
||
status: TimeSlotStatus; // 时段状态
|
||
standard_price: number; // 标准价格
|
||
member_price: number; // 会员价格
|
||
price_desc_standard: string; // 标准价格说明
|
||
price_desc_member: string; // 会员价格说明
|
||
}
|
||
|
||
/** 房间信息 */
|
||
interface RoomItem {
|
||
id: number; // 房间ID
|
||
name: string; // 房间名称
|
||
room_type_name: string; // 房间类型
|
||
image_url: string; // 房间图片
|
||
capacity: number; // 容纳人数
|
||
description: string; // 房间描述
|
||
standard_price_desc: string; // 标准价格说明
|
||
member_price_desc: string; // 会员价格说明
|
||
time_slots: TimeSlot[]; // 时段列表
|
||
status: string; // 房间状态
|
||
is_available: boolean; // 是否可用
|
||
can_reserve: boolean; // 是否可预约
|
||
}
|
||
|
||
// ========== 预约相关 ==========
|
||
|
||
/** 创建预约请求 */
|
||
interface CreateReservationRequest {
|
||
room_id: number;
|
||
date: number;
|
||
time_slot_type: TimeSlotType;
|
||
latest_arrival_time?: number;
|
||
is_solo_mode: boolean;
|
||
player_count: number;
|
||
deposit_fee: number;
|
||
title: string;
|
||
game_type: string;
|
||
game_rule?: string;
|
||
extra_info?: string;
|
||
is_smoking: number;
|
||
gender_limit: number;
|
||
credit_limit?: number;
|
||
min_age?: number;
|
||
max_age?: number;
|
||
important_data?: string;
|
||
}
|
||
|
||
/** 创建预约响应 */
|
||
interface CreateReservationResponse {
|
||
reservation_id: number;
|
||
start_time: string;
|
||
end_time: string;
|
||
actual_price: number;
|
||
}
|
||
|
||
// ========== API响应 ==========
|
||
|
||
/** 通用API响应 */
|
||
interface ApiResponse<T = any> {
|
||
code: number;
|
||
msg: string;
|
||
data: T;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
|
||
## 常见问题FAQ
|
||
|
||
### Q1: 时间戳是秒级还是毫秒级?
|
||
|
||
**A:** 所有接口使用的都是**秒级时间戳**(Unix Timestamp),不是毫秒级。
|
||
|
||
```javascript
|
||
// 正确:秒级
|
||
const timestamp = Math.floor(Date.now() / 1000);
|
||
|
||
// 错误:毫秒级
|
||
const timestamp = Date.now();
|
||
```
|
||
|
||
### Q2: 如何判断当前是哪个时段?
|
||
|
||
**A:** 根据当前时间的小时数判断:
|
||
|
||
```javascript
|
||
function getCurrentTimeSlot() {
|
||
const hour = new Date().getHours();
|
||
if (hour >= 0 && hour < 6) return 0; // 凌晨
|
||
if (hour >= 6 && hour < 12) return 1; // 上午
|
||
if (hour >= 12 && hour < 18) return 2; // 下午
|
||
return 3; // 晚上
|
||
}
|
||
```
|
||
|
||
### Q3: 最晚到店时间如何处理?
|
||
|
||
**A:** 最晚到店时间必须在所选时段的时间范围内:
|
||
|
||
```javascript
|
||
// 1. 获取时段的时间范围
|
||
const timeRanges = {
|
||
0: { min: '00:00', max: '05:59' },
|
||
1: { min: '06:00', max: '11:59' },
|
||
2: { min: '12:00', max: '17:59' },
|
||
3: { min: '18:00', max: '23:59' }
|
||
};
|
||
|
||
// 2. 限制时间选择器的范围
|
||
const range = timeRanges[selectedSlot];
|
||
<input type="time" :min="range.min" :max="range.max">
|
||
|
||
// 3. 转换为时间戳
|
||
const [hour, minute] = arrivalTime.split(':');
|
||
const d = new Date(date * 1000);
|
||
d.setHours(Number(hour), Number(minute), 0, 0);
|
||
const timestamp = Math.floor(d.getTime() / 1000);
|
||
```
|
||
|
||
### Q4: "无需组局"模式如何处理?
|
||
|
||
**A:** 当选择"无需组局"时:
|
||
|
||
```javascript
|
||
// 1. 人数固定为1
|
||
if (playerCount === 1) {
|
||
form.is_solo_mode = true;
|
||
form.player_count = 1;
|
||
}
|
||
|
||
// 2. 后端会拒绝其他人加入该预约
|
||
```
|
||
|
||
### Q5: 鸽子费的限制是什么?
|
||
|
||
**A:** 鸽子费必须满足:
|
||
- 范围:0-50元
|
||
- 类型:整数(不能有小数)
|
||
|
||
```javascript
|
||
// 校验
|
||
if (depositFee < 0 || depositFee > 50) {
|
||
alert('鸽子费必须在0-50元之间');
|
||
return false;
|
||
}
|
||
if (!Number.isInteger(depositFee)) {
|
||
alert('鸽子费必须是整数');
|
||
return false;
|
||
}
|
||
```
|
||
|
||
### Q6: 如何处理时间冲突?
|
||
|
||
**A:** 后端会自动检测时间冲突,返回错误码402:
|
||
|
||
```javascript
|
||
if (response.data.code === 402) {
|
||
alert('您有其它预约时间冲突,无法创建该预约!');
|
||
// 可以引导用户查看"我的预约"
|
||
}
|
||
```
|
||
|
||
### Q7: Token如何传递?
|
||
|
||
**A:** 所有需要登录的接口都需要在请求头中携带Token:
|
||
|
||
```javascript
|
||
// Axios示例
|
||
axios.post('/api/SQ/AddSQReservationBySlot', data, {
|
||
headers: {
|
||
Authorization: `Bearer ${localStorage.getItem('token')}`
|
||
}
|
||
});
|
||
|
||
// 或配置全局拦截器
|
||
axios.interceptors.request.use(config => {
|
||
const token = localStorage.getItem('token');
|
||
if (token) {
|
||
config.headers.Authorization = `Bearer ${token}`;
|
||
}
|
||
return config;
|
||
});
|
||
```
|
||
|
||
### Q8: 如何处理已过时段?
|
||
|
||
**A:** 后端会自动过滤已过去的时段,前端不需要额外处理。如果某个时段已过去,它会在`time_slots`中显示为`unavailable`或不返回。
|
||
|
||
### Q9: 房间图片加载失败怎么办?
|
||
|
||
**A:** 建议添加图片加载失败的占位图:
|
||
|
||
```vue
|
||
<img
|
||
:src="room.image_url"
|
||
:alt="room.name"
|
||
@error="handleImageError"
|
||
>
|
||
|
||
<script>
|
||
function handleImageError(e) {
|
||
e.target.src = '/default-room.png'; // 默认图片
|
||
}
|
||
</script>
|
||
```
|
||
|
||
### Q10: 如何实现实时刷新房间状态?
|
||
|
||
**A:** 可以使用定时轮询或WebSocket:
|
||
|
||
```javascript
|
||
// 方式1:定时轮询(简单)
|
||
let timer = null;
|
||
|
||
onMounted(() => {
|
||
loadRooms();
|
||
timer = setInterval(() => {
|
||
loadRooms();
|
||
}, 30000); // 每30秒刷新一次
|
||
});
|
||
|
||
onUnmounted(() => {
|
||
if (timer) clearInterval(timer);
|
||
});
|
||
|
||
// 方式2:WebSocket(实时性更好,需要后端支持)
|
||
// 连接WebSocket监听房间状态变化
|
||
```
|
||
|
||
---
|
||
|
||
## 调试技巧
|
||
|
||
### 1. 使用浏览器开发者工具
|
||
|
||
#### 查看网络请求
|
||
```
|
||
F12 → Network → XHR
|
||
- 查看请求URL、参数、响应
|
||
- 检查状态码
|
||
- 查看响应时间
|
||
```
|
||
|
||
#### 查看控制台日志
|
||
```javascript
|
||
// 添加详细日志
|
||
console.log('请求参数:', data);
|
||
console.log('响应数据:', response.data);
|
||
console.error('错误信息:', error);
|
||
```
|
||
|
||
### 2. Postman测试接口
|
||
|
||
#### 测试步骤
|
||
1. 先调用登录接口获取Token
|
||
2. 复制Token到环境变量
|
||
3. 测试各个接口
|
||
4. 保存常用请求到Collection
|
||
|
||
#### 示例请求
|
||
```
|
||
GET http://localhost:5000/api/SQ/GetAvailableDates
|
||
|
||
GET http://localhost:5000/api/SQ/GetRoomListWithSlotsNew?date=1733443200
|
||
|
||
POST http://localhost:5000/api/SQ/AddSQReservationBySlot
|
||
Headers:
|
||
Authorization: Bearer eyJhbGc...
|
||
Body: { ... }
|
||
```
|
||
|
||
### 3. 常见错误排查
|
||
|
||
| 错误 | 可能原因 | 解决方法 |
|
||
|------|---------|---------|
|
||
| 401 Unauthorized | Token过期或无效 | 重新登录获取Token |
|
||
| 404 Not Found | 接口路径错误 | 检查URL是否正确 |
|
||
| 500 Internal Server Error | 服务器内部错误 | 查看后端日志 |
|
||
| CORS错误 | 跨域配置问题 | 联系后端配置CORS |
|
||
| 参数错误 | 参数格式不正确 | 检查参数类型和值 |
|
||
|
||
### 4. 开发环境代理配置
|
||
|
||
#### Vite配置示例
|
||
```javascript
|
||
// vite.config.js
|
||
export default {
|
||
server: {
|
||
proxy: {
|
||
'/api': {
|
||
target: 'http://localhost:5000',
|
||
changeOrigin: true
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### Vue CLI配置示例
|
||
```javascript
|
||
// vue.config.js
|
||
module.exports = {
|
||
devServer: {
|
||
proxy: {
|
||
'/api': {
|
||
target: 'http://localhost:5000',
|
||
changeOrigin: true
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 附录
|
||
|
||
### A. 错误码对照表
|
||
|
||
| 错误码 | 说明 | 处理建议 |
|
||
|-------|------|---------|
|
||
| 0 | 成功 | 继续业务流程 |
|
||
| 400 | 业务错误 | 显示错误信息 |
|
||
| 401 | 未授权 | 跳转到登录页 |
|
||
| 402 | 时间冲突 | 提示用户选择其他时段 |
|
||
| 403 | 权限不足 | 提示权限不足 |
|
||
| 404 | 资源不存在 | 提示资源不存在 |
|
||
| 500 | 系统错误 | 提示系统错误,稍后重试 |
|
||
|
||
### B. 测试数据
|
||
|
||
```javascript
|
||
// 测试用日期时间戳
|
||
const testDates = {
|
||
today: Math.floor(Date.now() / 1000),
|
||
tomorrow: Math.floor(Date.now() / 1000) + 86400,
|
||
nextWeek: Math.floor(Date.now() / 1000) + 604800
|
||
};
|
||
|
||
// 测试用房间ID
|
||
const testRoomIds = [1, 2, 3];
|
||
|
||
// 测试用时段类型
|
||
const testTimeSlots = [0, 1, 2, 3];
|
||
```
|
||
|
||
### C. 联系方式
|
||
|
||
**技术支持**:
|
||
- 邮箱:jianweie@163.com
|
||
- 文档版本:v2.0
|
||
- 更新日期:2025-12-06
|
||
|
||
---
|
||
|
||
**祝开发顺利!** 🚀
|
||
|