时间槽调整

This commit is contained in:
Jack 2025-11-06 00:57:46 +08:00
parent ea0afa5bdb
commit 2ab4495920
6 changed files with 125 additions and 97 deletions

View File

@ -83,6 +83,9 @@ public class ShopStoreBase implements Serializable {
@ApiModelProperty(value = "店铺营业状态1-营业中2-已打烊3-开业(活动)筹备中;")
private Integer store_biz_state;
@ApiModelProperty(value = "开业(活动)筹备具体时间 yyyy-MM-dd HH:mm:ss")
private Date store_biz_opening_dtime;
@ApiModelProperty(value = "上级店铺编号:创建店铺决定,所属分销商-不可更改! 佣金公平性考虑")
private Integer shop_parent_id;

View File

@ -1,5 +1,6 @@
package com.suisung.mall.common.utils;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.util.Pair;
@ -10,7 +11,10 @@ import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoField;
import java.util.*;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
@Slf4j
public class DateTimeUtils {
@ -375,11 +379,11 @@ public class DateTimeUtils {
* endTimeStr 结束时间字符串支持格式如 HH:mm, HH:mm:ss, HH:mm:ss.SSS
* @return 返回一个Map包含交集的时间段(startTimeStr和endTimeStr)如果无交集则返回空Map
*/
public static Map<String, String> findTimeInterSection(List<Map<String, String>> timeList) {
public static Pair<String, String> findTimeInterSection(List<Pair<String, String>> timeList) {
// 参数校验
if (timeList == null || timeList.isEmpty()) {
log.warn("时间段列表为空或null无法计算交集");
return new HashMap<>();
return null;
}
try {
@ -387,14 +391,14 @@ public class DateTimeUtils {
LocalTime earliestEndTime = null;
// 遍历所有时间段
for (Map<String, String> timeMap : timeList) {
if (timeMap == null || !timeMap.containsKey("startTimeStr") || !timeMap.containsKey("endTimeStr")) {
for (Pair<String, String> timeMap : timeList) {
if (timeMap == null || StrUtil.hasBlank(timeMap.getFirst(), timeMap.getSecond())) {
log.warn("时间段数据不完整或格式不正确: {}", timeMap);
continue;
}
String startTimeStr = timeMap.get("startTimeStr");
String endTimeStr = timeMap.get("endTimeStr");
String startTimeStr = timeMap.getFirst();
String endTimeStr = timeMap.getSecond();
if (startTimeStr == null || endTimeStr == null) {
log.warn("时间段的开始或结束时间为空: startTime={}, endTime={}", startTimeStr, endTimeStr);
@ -416,18 +420,15 @@ public class DateTimeUtils {
// 检查是否存在交集
if (latestStartTime != null && earliestEndTime != null && !latestStartTime.isAfter(earliestEndTime)) {
Map<String, String> result = new HashMap<>();
result.put("startTimeStr", latestStartTime.toString());
result.put("endTimeStr", earliestEndTime.toString());
return result;
return Pair.of(latestStartTime.toString(), earliestEndTime.toString());
} else {
// 无交集情况
log.debug("给定的时间段列表无交集");
return new HashMap<>();
return null;
}
} catch (Exception e) {
log.error("计算时间段交集时发生异常", e);
return new HashMap<>();
return null;
}
}
@ -619,38 +620,24 @@ public class DateTimeUtils {
System.out.println("=== 测试 findTimeIntersection ===");
// 测试正常交集情况
List<Map<String, String>> timeList1 = new ArrayList<>();
Map<String, String> range1 = new HashMap<>();
range1.put("startTimeStr", "06:00");
range1.put("endTimeStr", "17:00");
timeList1.add(range1);
List<Pair<String, String>> timeList1 = new ArrayList<>();
timeList1.add(Pair.of("06:00", "17:00"));
timeList1.add(Pair.of("10:00", "18:00"));
Map<String, String> range2 = new HashMap<>();
range2.put("startTimeStr", "06:00");
range2.put("endTimeStr", "17:00");
timeList1.add(range2);
Map<String, String> intersection1 = findTimeInterSection(timeList1);
Pair<String, String> intersection1 = findTimeInterSection(timeList1);
System.out.println("交集结果1: " + intersection1); // 应该是 10:00 - 17:00
// 测试无交集情况
List<Map<String, String>> timeList2 = new ArrayList<>();
Map<String, String> range3 = new HashMap<>();
range3.put("startTimeStr", "09:00");
range3.put("endTimeStr", "12:00");
timeList2.add(range3);
List<Pair<String, String>> timeList2 = new ArrayList<>();
timeList2.add(Pair.of("09:00", "12:00"));
timeList2.add(Pair.of("13:00", "17:00"));
Map<String, String> range4 = new HashMap<>();
range4.put("startTimeStr", "13:00");
range4.put("endTimeStr", "17:00");
timeList2.add(range4);
Map<String, String> intersection2 = findTimeInterSection(timeList2);
System.out.println("交集结果2: " + intersection2); // 应该是空Map
Pair<String, String> intersection2 = findTimeInterSection(timeList2);
System.out.println("交集结果2: " + intersection2); // 应该是null
// 测试空列表
Map<String, String> intersection3 = findTimeInterSection(null);
System.out.println("交集结果3 (null输入): " + intersection3); // 应该是空Map
Pair<String, String> intersection3 = findTimeInterSection(null);
System.out.println("交集结果3 (null输入): " + intersection3); // 应该是null
}

View File

@ -324,7 +324,7 @@ public class UserOrderController extends BaseControllerImpl {
@ApiOperation(value = "可预约订单的时间槽", notes = "结算中心页面,可预约订单的时间槽")
@RequestMapping(value = "/booking_time_args", method = RequestMethod.GET)
public CommonResult listInvoice(@RequestParam(name = "store_ids", defaultValue = "") String store_ids) {
public CommonResult genBookingOrderArgList(@RequestParam(name = "store_ids", defaultValue = "") String store_ids) {
List<BookingArgDTO> list = shopOrderInfoService.genBookingOrderArgList(store_ids);
return CommonResult.success(list);
}

View File

@ -1016,93 +1016,104 @@ public class ShopOrderInfoServiceImpl extends BaseServiceImpl<ShopOrderInfoMappe
*/
@Override
public List<BookingArgDTO> genBookingOrderArgList(String storeIds) {
// 初始化默认营业时间
Map<String, String> timesMap = new HashMap<>();
// 初始化营业时间对象
Pair<String, String> timesPair = null;
// 如果storeId不为空则尝试获取店铺信息
if (StrUtil.isNotBlank(storeIds)) {
List<Map<String, String>> timesMapList = selStoreBizTimeMapList(storeIds);
// 多个店铺的营业时间段集合
List<Pair<String, String>> timesMapList = selStoreBizTimeMapList(storeIds);
if (!CollUtil.isEmpty(timesMapList)) {
timesMap = DateTimeUtils.findTimeInterSection(timesMapList);
// 获取多个店铺的营业时间段的一个交集
timesPair = DateTimeUtils.findTimeInterSection(timesMapList);
}
}
if (timesPair == null || StrUtil.isBlank(timesPair.getFirst()) || StrUtil.isBlank(timesPair.getSecond())) {
// 没有具体的营业时间段
logger.info("[生成预约参数] 未找到营业时间段");
return Collections.emptyList();
}
// 显示几天的时间槽默认7天
int daysCnt = 7;
List<BookingArgDTO> result = new ArrayList<>();
// 生成未来7天的数据
Date now = new Date();
for (int i = 0; i < 7; i++) {
Date currentDate = DateUtil.offsetDay(now, i);
// 判断今天还能不能立即下单和预约下单就有今天的时间槽不能就没有今天的时间槽
boolean canBookingToday = DateTimeUtils.isTimeInRange(timesPair.getFirst(), timesPair.getSecond(), new Date());
// 生成7天的可预约时间槽数据
Date startDate = new Date();
if (!canBookingToday) {
// 如果今天不能下单和预约则从明天开始生成时间槽
startDate = DateUtil.offsetDay(new Date(), 1);
}
for (int i = 0; i < daysCnt; i++) {
startDate = DateUtil.offsetDay(startDate, i);
BookingArgDTO bookingArgDTO = new BookingArgDTO();
// 设置日期相关信息
String dateStr = DateUtil.format(currentDate, "yyyy-MM-dd");
String displayDateStr = DateUtil.format(currentDate, "MM月dd日");
String dateStr = DateUtil.format(startDate, "yyyy-MM-dd");
String displayDateStr = DateUtil.format(startDate, "MM月dd日");
// 安全获取星期信息
String weekStr = "星期";
try {
weekStr = DateTimeUtils.getWeekOfDate(currentDate);
weekStr = DateTimeUtils.getWeekOfDate(startDate);
} catch (Exception e) {
logger.warn("[生成预约参数] 获取星期信息异常使用默认值date: {}", dateStr);
}
// 设置date_title
// 设置date_title - 优化后的代码
String dateTitle;
if (i == 0) {
bookingArgDTO.setDate_title("今天(" + weekStr + "");
dateTitle = canBookingToday ? "今天" : "明天";
} else if (i == 1) {
bookingArgDTO.setDate_title("明天(" + weekStr + "");
dateTitle = canBookingToday ? "明天" : "后天";
} else {
bookingArgDTO.setDate_title(displayDateStr + "" + weekStr + "");
dateTitle = displayDateStr;
}
bookingArgDTO.setDate_title(dateTitle + "" + weekStr + "");
bookingArgDTO.setDate_str(displayDateStr);
bookingArgDTO.setDate(dateStr);
// 生成时间项
List<BookingArgDTO.BookingArgItem> items = new ArrayList<>();
// List<BookingArgDTO.BookingArgItem> items = new ArrayList<>();
// 如果是今天始终添加"立即送出"选项
if (i == 0) {
BookingArgDTO.BookingArgItem immediateItem = new BookingArgDTO.BookingArgItem();
immediateItem.setTime_title("立即送出");
immediateItem.setBooking_at(0L);
immediateItem.setBooking_state(1);
immediateItem.setBooking_begin_time("");
immediateItem.setBooking_end_time("");
items.add(immediateItem);
}
// 如果是今天且在配送时间内添加"立即送出"选项
// if (i == 0 && canBookingToday) {
// BookingArgDTO.BookingArgItem immediateItem = new BookingArgDTO.BookingArgItem();
// immediateItem.setTime_title("立即送出");
// immediateItem.setBooking_at(0L);
// immediateItem.setBooking_state(1);
// immediateItem.setBooking_begin_time("");
// immediateItem.setBooking_end_time("");
// items.add(immediateItem);
// }
// 只有当 timesMap 不为空时才生成其他时间槽
if (!ObjectUtil.isEmpty(timesMap) && StrUtil.isNotBlank(timesMap.get("startTimeStr")) && StrUtil.isNotBlank(timesMap.get("endTimeStr"))) {
String startTimeStr = timesMap.get("startTimeStr");
String endTimeStr = timesMap.get("endTimeStr");
List<BookingArgDTO.BookingArgItem> timeSlots = generateTimeSlots(dateStr, startTimeStr, endTimeStr, i == 0);
if (i == 0) {
// 对于今天移除除"立即送出"外的所有时间槽
items.addAll(timeSlots.stream().filter(item -> item.getBooking_state() != 1).collect(Collectors.toList()));
} else {
// 对于其他日期添加所有时间槽
items.addAll(timeSlots);
}
String startTimeStr = timesPair.getFirst();
String endTimeStr = timesPair.getSecond();
boolean isToday = i == 0 && canBookingToday;
// 生成时间项
List<BookingArgDTO.BookingArgItem> items = generateTimeSlots(dateStr, startTimeStr, endTimeStr, isToday);
// if (i == 0 && canBookingToday) {
// items.addAll(timeSlots.stream().filter(item -> item.getBooking_state() != 1).collect(Collectors.toList()));
// } else {
// items.addAll(timeSlots);
// }
bookingArgDTO.setWorking_hours(String.format("%s-%s", startTimeStr, endTimeStr));
} else if (i == 0) {
// 如果timesMap为空今天只保留"立即送出"选项
logger.debug("[生成预约参数] timesMap为空今天只生成立即送出选项");
} else {
// 如果timesMap为空其他日期不生成任何时间槽
logger.debug("[生成预约参数] timesMap为空不生成{}的预约时间槽", dateStr);
continue; // 跳过当前日期
}
bookingArgDTO.setItems(items);
result.add(bookingArgDTO);
}
logger.debug("[生成预约参数] 成功生成预约参数storeId: {}, timesMap: {}, 参数数量: {}",
storeIds, timesMap, result.size());
storeIds, timesPair, result.size());
return result;
}
@ -1221,12 +1232,14 @@ public class ShopOrderInfoServiceImpl extends BaseServiceImpl<ShopOrderInfoMappe
}
/**
* 根据 storeIds一个或多个 storeid 34,23,43,23,先对id去重再获取多个店铺的营业时间 List<map{startTimeStr, endTimeStr}> 列表list
* 根据 storeIds一个或多个 storeid 34,23,43,23,先对id去重
* 再获取多个店铺的营业时间 List<map{startTimeStr, endTimeStr}> 列表list
* 启动如果遇到某个店铺是开业活动筹备中的获取他的开始营业的的日期和营业时间段组合出特有营业时间段
*
* @param storeIds 以逗号分隔的店铺ID字符串
* @return 包含店铺营业时间信息的列表每个元素为包含opening_hours和close_hours的Map
*/
private List<Map<String, String>> selStoreBizTimeMapList(String storeIds) {
private List<Pair<String, String>> selStoreBizTimeMapList(String storeIds) {
// 参数校验
if (StrUtil.isBlank(storeIds)) {
return Collections.emptyList();
@ -1257,9 +1270,7 @@ public class ShopOrderInfoServiceImpl extends BaseServiceImpl<ShopOrderInfoMappe
return shopStoreInfos.stream()
.filter(Objects::nonNull)
.map(storeInfo -> {
Map<String, String> timeSlot = new HashMap<>();
timeSlot.put("startTimeStr", storeInfo.getStore_opening_hours());
timeSlot.put("endTimeStr", storeInfo.getStore_close_hours());
Pair<String, String> timeSlot = Pair.of(storeInfo.getStore_opening_hours(), storeInfo.getStore_close_hours());
return timeSlot;
})
.collect(Collectors.toList());

View File

@ -5,8 +5,8 @@
<sql id="Base_Column_List">
store_id
, user_id, store_name, store_grade_id, store_logo, store_slogan, store_domain, store_area, store_district_id,
store_address, store_latitude, store_longitude, store_is_selfsupport, store_type, store_is_open, store_biz_state,
ringtone_is_enable, shop_parent_id, store_2nd_category_id,
store_address, store_latitude, store_longitude, store_is_selfsupport, store_type, store_is_open,
store_biz_state, store_biz_opening_dtime, ringtone_is_enable, shop_parent_id, store_2nd_category_id,
store_category_id, store_state_id, store_time, store_end_time, product_category_ids, store_o2o_tags,
store_o2o_flag, store_o2o_merchant_id, store_circle, subsite_id, lkl_merchant_no, lkl_term_no, wx_qrcode,
split_ratio, packing_fee, created_at, updated_at

27
pom.xml
View File

@ -540,12 +540,39 @@
<artifactId>maven-dependency-plugin</artifactId>
</plugin>
<!-- 使用 Docker 命令删除(如果支持远程操作) -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>remove-remote-image</id>
<phase>clean</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>curl</executable>
<arguments>
<argument>-X</argument>
<argument>DELETE</argument>
<argument>${docker.registry}/mall/${project.artifactId}:${project.version}</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>${docker.maven.plugin.version}</version>
<!--如果想在项目打包时构建镜像添加-->
<executions>
<!-- 使用 Docker 命令删除(如果支持远程操作) -->
<execution>
<id>build-image</id>
<phase>package</phase>