13 KiB
13 KiB
🚀 预约与日历数据统一修复方案
日期: 2026-01-24
问题: 预约页面显示62个待服务,日历只显示6个
原因: 日历只查询当前月份的订单,其他月份的订单不显示
🔍 问题根源
当前实现:
日历页面查询逻辑:
// CalendarServiceImpl.java
QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id", userId)
.ge("service_date", startDate) // ❌ 只查询指定日期范围
.le("service_date", endDate) // ❌ 只查询指定日期范围
.in("status", Arrays.asList(1, 2, 3, 4))
.eq("deleted", 0);
问题:
- 只查询 2026年1月 的订单
- 其他月份的56个订单不会显示
预约列表页面查询逻辑:
// order/list.vue
const res = await request({
url: '/api/order/list-full',
method: 'get',
params: {
teacherId: this.teacherId,
page: 1,
size: 100 // ✅ 查询所有订单,不限日期
}
})
结果:
- 查询所有订单,包括所有月份
- 显示62个待服务订单
✅ 解决方案
方案1: 日历页面添加"全部"视图(推荐)
在日历页面添加一个"全部订单"标签,显示所有月份的订单。
优点:
- 用户可以选择查看当前月份或全部订单
- 保持日历的月份视图功能
- 与预约列表数据一致
实现步骤:
1. 修改日历页面,添加视图切换
<!-- user-package/pages/calendar/index.vue -->
<template>
<view class="calendar-page">
<!-- 视图切换 -->
<view class="view-switcher">
<view
class="switch-item"
:class="{ active: viewMode === 'month' }"
@click="viewMode = 'month'"
>
<text>月视图</text>
</view>
<view
class="switch-item"
:class="{ active: viewMode === 'all' }"
@click="viewMode = 'all'"
>
<text>全部订单</text>
</view>
</view>
<!-- 月视图:显示日历 -->
<view v-if="viewMode === 'month'">
<calendar
:scheduleData="scheduleData"
role="parent"
@date-select="handleDateSelect"
@month-change="handleMonthChange"
@schedule-click="handleScheduleClick"
/>
</view>
<!-- 全部订单视图:显示列表 -->
<view v-else>
<view class="all-orders-list">
<view
v-for="order in allOrders"
:key="order.id"
class="order-item"
@click="goToOrderDetail(order)"
>
<!-- 订单卡片内容 -->
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
viewMode: 'month', // 'month' 或 'all'
scheduleData: [], // 当前月份的订单
allOrders: [], // 所有订单
}
},
methods: {
async loadScheduleData() {
if (this.viewMode === 'month') {
// 加载当前月份的订单
const startDate = this.getMonthStart()
const endDate = this.getMonthEnd()
const res = await calendarApi.getAppointments(startDate, endDate)
this.scheduleData = res.data || []
} else {
// 加载所有订单
const res = await calendarApi.getAllAppointments()
this.allOrders = res.data || []
}
}
}
}
</script>
2. 添加后端接口 - 查询所有订单
// CalendarController.java
@GetMapping("/all-appointments")
@ApiOperation("获取所有预约记录(不限日期)")
public Result<List<AppointmentVO>> getAllAppointments(
javax.servlet.http.HttpServletRequest request) {
log.info("获取所有预约记录");
try {
Long userId = getCurrentUserId(request);
List<AppointmentVO> appointments = calendarService.getAllAppointments(userId);
log.info("查询到 {} 条预约记录", appointments.size());
return Result.success(appointments);
} catch (Exception e) {
log.error("获取预约记录失败", e);
return Result.error("获取预约记录失败: " + e.getMessage());
}
}
// CalendarServiceImpl.java
@Override
public List<AppointmentVO> getAllAppointments(Long userId) {
log.info("查询用户所有预约记录, userId: {}", userId);
QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id", userId)
.in("status", Arrays.asList(1, 2, 3, 4))
.eq("deleted", 0)
.orderByAsc("service_date", "time_slot");
List<Order> orders = orderMapper.selectList(queryWrapper);
log.info("查询到 {} 条订单记录", orders.size());
return orders.stream()
.map(this::convertToAppointmentVO)
.collect(Collectors.toList());
}
方案2: 统计信息显示所有月份(简单)
保持日历只显示当前月份,但在统计信息中显示所有月份的订单数量。
实现:
<!-- 统计信息 -->
<view class="statistics-card">
<view class="stat-item">
<text class="stat-value">{{ statistics.total }}</text>
<text class="stat-label">本月课时</text>
</view>
<view class="stat-divider"></view>
<view class="stat-item">
<text class="stat-value">{{ statistics.allTotal }}</text>
<text class="stat-label">全部课时</text>
</view>
<view class="stat-divider"></view>
<view class="stat-item">
<text class="stat-value">{{ statistics.upcoming }}</text>
<text class="stat-label">待服务</text>
</view>
</view>
// 加载全部统计
async loadAllStatistics() {
const res = await calendarApi.getAllStats()
this.statistics.allTotal = res.data.totalCount || 0
}
方案3: 日历支持跨月查看
允许用户切换到其他月份查看订单。
实现:
<!-- 月份导航 -->
<view class="month-nav">
<view class="nav-btn" @click="prevMonth">上一月</view>
<view class="month-title">{{ currentYear }}年{{ currentMonth }}月</view>
<view class="nav-btn" @click="nextMonth">下一月</view>
</view>
<!-- 快速跳转 -->
<view class="quick-nav">
<view
v-for="month in monthsWithOrders"
:key="month"
class="month-tag"
@click="jumpToMonth(month)"
>
{{ month }}月 ({{ getMonthOrderCount(month) }})
</view>
</view>
🎯 推荐实施方案
最佳方案: 方案1 + 方案2 组合
- 添加视图切换 - 用户可以选择"月视图"或"全部订单"
- 统计信息显示全部 - 让用户知道总共有多少订单
- 保持月份切换 - 方便查看特定月份的订单
📝 实施步骤
步骤1: 添加后端接口
// 1. 在 CalendarService 接口中添加方法
List<AppointmentVO> getAllAppointments(Long userId);
Map<String, Object> getAllStats(Long userId);
// 2. 在 CalendarServiceImpl 中实现
@Override
public List<AppointmentVO> getAllAppointments(Long userId) {
QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id", userId)
.in("status", Arrays.asList(1, 2, 3, 4))
.eq("deleted", 0)
.orderByAsc("service_date", "time_slot");
List<Order> orders = orderMapper.selectList(queryWrapper);
return orders.stream()
.map(this::convertToAppointmentVO)
.collect(Collectors.toList());
}
@Override
public Map<String, Object> getAllStats(Long userId) {
QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id", userId)
.eq("deleted", 0);
List<Order> orders = orderMapper.selectList(queryWrapper);
Map<String, Object> stats = new HashMap<>();
stats.put("totalCount", orders.size());
stats.put("pendingCount", orders.stream()
.filter(o -> o.getStatus() == 1 || o.getStatus() == 2)
.count());
stats.put("completedCount", orders.stream()
.filter(o -> o.getStatus() == 4)
.count());
return stats;
}
// 3. 在 CalendarController 中添加接口
@GetMapping("/all-appointments")
public Result<List<AppointmentVO>> getAllAppointments(
javax.servlet.http.HttpServletRequest request) {
Long userId = getCurrentUserId(request);
List<AppointmentVO> appointments = calendarService.getAllAppointments(userId);
return Result.success(appointments);
}
@GetMapping("/all-stats")
public Result<Object> getAllStats(
javax.servlet.http.HttpServletRequest request) {
Long userId = getCurrentUserId(request);
Object stats = calendarService.getAllStats(userId);
return Result.success(stats);
}
步骤2: 修改前端日历页面
// user-package/pages/calendar/index.vue
data() {
return {
viewMode: 'month', // 'month' 或 'all'
scheduleData: [],
allOrders: [],
statistics: {
total: 0, // 本月订单
allTotal: 0, // 全部订单
completed: 0,
upcoming: 0
}
}
},
methods: {
async loadScheduleData() {
if (this.viewMode === 'month') {
// 加载当前月份
const startDate = this.getMonthStart()
const endDate = this.getMonthEnd()
const res = await calendarApi.getAppointments(startDate, endDate)
this.scheduleData = res.data || []
} else {
// 加载所有订单
const res = await calendarApi.getAllAppointments()
this.allOrders = res.data || []
}
},
async loadStatistics() {
// 加载本月统计
const monthRes = await calendarApi.getMonthlyStats(this.currentYear, this.currentMonth)
this.statistics.total = monthRes.data.totalCount || 0
this.statistics.completed = monthRes.data.completedCount || 0
this.statistics.upcoming = monthRes.data.pendingCount || 0
// 加载全部统计
const allRes = await calendarApi.getAllStats()
this.statistics.allTotal = allRes.data.totalCount || 0
}
}
步骤3: 添加API方法
// api/index.js 或 api/calendar.js
export const calendarApi = {
// 获取指定日期范围的预约
getAppointments(startDate, endDate) {
return request({
url: '/api/calendar/appointments',
method: 'get',
params: { startDate, endDate }
})
},
// 获取所有预约(新增)
getAllAppointments() {
return request({
url: '/api/calendar/all-appointments',
method: 'get'
})
},
// 获取月度统计
getMonthlyStats(year, month) {
return request({
url: '/api/calendar/monthly-stats',
method: 'get',
params: { year, month }
})
},
// 获取全部统计(新增)
getAllStats() {
return request({
url: '/api/calendar/all-stats',
method: 'get'
})
}
}
🧪 测试验证
测试步骤:
-
执行诊断SQL
-- 查看订单分布 SELECT DATE_FORMAT(service_date, '%Y-%m') AS month, COUNT(*) AS count FROM `order` WHERE user_id = 1 AND status = 1 AND deleted = 0 GROUP BY DATE_FORMAT(service_date, '%Y-%m'); -
测试月视图
- 打开日历页面
- 确认显示当前月份的订单
- 切换到其他月份,确认数据正确
-
测试全部视图
- 切换到"全部订单"
- 确认显示所有62个待服务订单
- 与预约列表页面对比,确认数量一致
-
测试统计信息
- 确认"本月课时"显示当前月份数量
- 确认"全部课时"显示所有月份数量
- 确认"待服务"数量正确
📊 预期效果
修复前:
- 日历页面: 显示 6 个订单(仅1月)
- 预约列表: 显示 62 个订单(所有月份)
- ❌ 数据不一致
修复后:
- 日历月视图: 显示 6 个订单(1月)
- 日历全部视图: 显示 62 个订单(所有月份)
- 预约列表: 显示 62 个订单(所有月份)
- ✅ 数据一致
💡 额外优化建议
1. 添加月份快速跳转
显示有订单的月份,点击快速跳转:
<view class="month-tags">
<view
v-for="month in monthsWithOrders"
:key="month"
@click="jumpToMonth(month)"
>
{{ month }}月 ({{ getMonthOrderCount(month) }})
</view>
</view>
2. 添加日期范围筛选
允许用户自定义查看日期范围:
<view class="date-range-picker">
<picker mode="date" @change="onStartDateChange">
<text>{{ startDate }}</text>
</picker>
<text>至</text>
<picker mode="date" @change="onEndDateChange">
<text>{{ endDate }}</text>
</picker>
</view>
3. 添加状态筛选
在全部视图中添加状态筛选:
<view class="status-filter">
<view
v-for="status in statusList"
:key="status.value"
:class="{ active: selectedStatus === status.value }"
@click="selectedStatus = status.value"
>
{{ status.label }}
</view>
</view>
✅ 总结
问题原因:
- 日历只查询当前月份的订单
- 预约列表查询所有订单
- 导致数据不一致
解决方案:
- 添加"全部订单"视图
- 统计信息显示全部数量
- 保持月份切换功能
实施优先级:
- ✅ 添加后端接口(必须)
- ✅ 修改前端页面(必须)
- ⭐ 添加视图切换(推荐)
- ⭐ 优化统计显示(推荐)
- 💡 添加快速跳转(可选)
修复时间: 2026-01-24
预计工作量: 2-3小时
影响范围: 家长端日历功能
🎉 修复后,日历和预约列表将显示一致的数据!