|
@@ -24,10 +24,13 @@ import shop.alien.store.service.StoreBookingCategoryService;
|
|
|
import shop.alien.store.service.StoreBookingTableService;
|
|
import shop.alien.store.service.StoreBookingTableService;
|
|
|
import shop.alien.util.common.JwtUtil;
|
|
import shop.alien.util.common.JwtUtil;
|
|
|
|
|
|
|
|
|
|
+import java.math.BigInteger;
|
|
|
|
|
+import java.text.Collator;
|
|
|
import java.util.ArrayList;
|
|
import java.util.ArrayList;
|
|
|
import java.util.Collections;
|
|
import java.util.Collections;
|
|
|
import java.util.Comparator;
|
|
import java.util.Comparator;
|
|
|
import java.util.Date;
|
|
import java.util.Date;
|
|
|
|
|
+import java.util.Locale;
|
|
|
import java.util.HashMap;
|
|
import java.util.HashMap;
|
|
|
import java.util.LinkedHashMap;
|
|
import java.util.LinkedHashMap;
|
|
|
import java.util.List;
|
|
import java.util.List;
|
|
@@ -46,6 +49,9 @@ import java.util.stream.Collectors;
|
|
|
@Transactional
|
|
@Transactional
|
|
|
public class StoreBookingTableServiceImpl extends ServiceImpl<StoreBookingTableMapper, StoreTable> implements StoreBookingTableService {
|
|
public class StoreBookingTableServiceImpl extends ServiceImpl<StoreBookingTableMapper, StoreTable> implements StoreBookingTableService {
|
|
|
|
|
|
|
|
|
|
+ /** 通用桌号「汉字及其他」组内排序 */
|
|
|
|
|
+ private static final Collator CHINESE_COLLATOR = Collator.getInstance(Locale.CHINA);
|
|
|
|
|
+
|
|
|
private final StoreBookingCategoryService storeBookingCategoryService;
|
|
private final StoreBookingCategoryService storeBookingCategoryService;
|
|
|
private final UserReservationMapper userReservationMapper;
|
|
private final UserReservationMapper userReservationMapper;
|
|
|
|
|
|
|
@@ -56,8 +62,8 @@ public class StoreBookingTableServiceImpl extends ServiceImpl<StoreBookingTableM
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
- public List<StoreTable> getTableList(Integer storeId, Integer categoryId) {
|
|
|
|
|
- log.info("StoreBookingTableServiceImpl.getTableList?storeId={}, categoryId={}", storeId, categoryId);
|
|
|
|
|
|
|
+ public List<StoreTable> getTableList(Integer storeId, Integer categoryId, Integer type) {
|
|
|
|
|
+ log.info("StoreBookingTableServiceImpl.getTableList?storeId={}, categoryId={}, type={}", storeId, categoryId, type);
|
|
|
|
|
|
|
|
LambdaQueryWrapper<StoreTable> wrapper = new LambdaQueryWrapper<>();
|
|
LambdaQueryWrapper<StoreTable> wrapper = new LambdaQueryWrapper<>();
|
|
|
wrapper.eq(StoreTable::getStoreId, storeId);
|
|
wrapper.eq(StoreTable::getStoreId, storeId);
|
|
@@ -66,25 +72,36 @@ public class StoreBookingTableServiceImpl extends ServiceImpl<StoreBookingTableM
|
|
|
if (categoryId != null) {
|
|
if (categoryId != null) {
|
|
|
wrapper.eq(StoreTable::getCategoryId, categoryId);
|
|
wrapper.eq(StoreTable::getCategoryId, categoryId);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ if (Integer.valueOf(1).equals(type) || Integer.valueOf(2).equals(type)) {
|
|
|
|
|
+ wrapper.eq(StoreTable::getType, type);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
// 查询所有数据,然后在Java中进行排序
|
|
// 查询所有数据,然后在Java中进行排序
|
|
|
List<StoreTable> list = this.list(wrapper);
|
|
List<StoreTable> list = this.list(wrapper);
|
|
|
|
|
+
|
|
|
|
|
+ if (Integer.valueOf(2).equals(type)) {
|
|
|
|
|
+ // 通用(type=2):纯数字 → 字母+数字(同美食规则) → 汉字及其他;纯数字按数值正序,前导零按位长次之
|
|
|
|
|
+ list.sort(Comparator
|
|
|
|
|
+ .comparing(StoreTable::getCategoryId, Comparator.nullsLast(Integer::compareTo))
|
|
|
|
|
+ .thenComparing((a, b) -> compareGenericTypeTableNumbers(a.getTableNumber(), b.getTableNumber())));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // type 为 null 或 1:保持原逻辑(字母桌号优先于纯数字等,与历史一致)
|
|
|
|
|
+ list.sort(Comparator
|
|
|
|
|
+ .comparing(StoreTable::getCategoryId, Comparator.nullsLast(Integer::compareTo))
|
|
|
|
|
+ .thenComparing(table -> parseTableNumberForSort(table.getTableNumber())));
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // 自定义排序:根据类别、字母(A-Z)、数字(由小到大)顺序排列
|
|
|
|
|
- list.sort(Comparator
|
|
|
|
|
- .comparing(StoreTable::getCategoryId, Comparator.nullsLast(Integer::compareTo)) // 先按类别排序
|
|
|
|
|
- .thenComparing(table -> parseTableNumberForSort(table.getTableNumber()))); // 再按桌号排序
|
|
|
|
|
-
|
|
|
|
|
- log.info("getTableList 完成 storeId={} categoryId={} tableCount={}", storeId, categoryId, list.size());
|
|
|
|
|
|
|
+ log.info("getTableList 完成 storeId={} categoryId={} type={} tableCount={}", storeId, categoryId, type, list.size());
|
|
|
return list;
|
|
return list;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
- public List<StoreBookingTableVo> getTableListWithCategoryName(Integer storeId, Integer categoryId) {
|
|
|
|
|
- log.info("StoreBookingTableServiceImpl.getTableListWithCategoryName?storeId={}, categoryId={}", storeId, categoryId);
|
|
|
|
|
|
|
+ public List<StoreBookingTableVo> getTableListWithCategoryName(Integer storeId, Integer categoryId, Integer type) {
|
|
|
|
|
+ log.info("StoreBookingTableServiceImpl.getTableListWithCategoryName?storeId={}, categoryId={}, type={}", storeId, categoryId, type);
|
|
|
|
|
|
|
|
// 先查询桌号列表
|
|
// 先查询桌号列表
|
|
|
- List<StoreTable> tableList = getTableList(storeId, categoryId);
|
|
|
|
|
|
|
+ List<StoreTable> tableList = getTableList(storeId, categoryId, type);
|
|
|
|
|
|
|
|
// 查询所有分类信息,构建categoryId -> categoryName的映射
|
|
// 查询所有分类信息,构建categoryId -> categoryName的映射
|
|
|
List<StoreBookingCategory> categoryList = storeBookingCategoryService.list(
|
|
List<StoreBookingCategory> categoryList = storeBookingCategoryService.list(
|
|
@@ -118,12 +135,12 @@ public class StoreBookingTableServiceImpl extends ServiceImpl<StoreBookingTableM
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
- public IPage<StoreBookingTableVo> getTableListPage(Integer pageNum, Integer pageSize, Integer storeId, Integer categoryId) {
|
|
|
|
|
- log.info("StoreBookingTableServiceImpl.getTableListPage?pageNum={}, pageSize={}, storeId={}, categoryId={}",
|
|
|
|
|
- pageNum, pageSize, storeId, categoryId);
|
|
|
|
|
|
|
+ public IPage<StoreBookingTableVo> getTableListPage(Integer pageNum, Integer pageSize, Integer storeId, Integer categoryId, Integer type) {
|
|
|
|
|
+ log.info("StoreBookingTableServiceImpl.getTableListPage?pageNum={}, pageSize={}, storeId={}, categoryId={}, type={}",
|
|
|
|
|
+ pageNum, pageSize, storeId, categoryId, type);
|
|
|
|
|
|
|
|
// 先查询所有数据(因为需要自定义排序)
|
|
// 先查询所有数据(因为需要自定义排序)
|
|
|
- List<StoreBookingTableVo> allList = getTableListWithCategoryName(storeId, categoryId);
|
|
|
|
|
|
|
+ List<StoreBookingTableVo> allList = getTableListWithCategoryName(storeId, categoryId, type);
|
|
|
|
|
|
|
|
// 计算分页信息
|
|
// 计算分页信息
|
|
|
int total = allList.size();
|
|
int total = allList.size();
|
|
@@ -171,7 +188,7 @@ public class StoreBookingTableServiceImpl extends ServiceImpl<StoreBookingTableM
|
|
|
log.info("listTablesGroupedByMerchant 开始 merchantId={} tableName={}", merchantId, tableName);
|
|
log.info("listTablesGroupedByMerchant 开始 merchantId={} tableName={}", merchantId, tableName);
|
|
|
try {
|
|
try {
|
|
|
// merchantId 在本项目中与门店 storeId 语义一致
|
|
// merchantId 在本项目中与门店 storeId 语义一致
|
|
|
- List<StoreBookingTableVo> all = getTableListWithCategoryName(merchantId, null);
|
|
|
|
|
|
|
+ List<StoreBookingTableVo> all = getTableListWithCategoryName(merchantId, null, null);
|
|
|
all = filterBookingTablesByNameLike(all, tableName);
|
|
all = filterBookingTablesByNameLike(all, tableName);
|
|
|
Map<Integer, List<StoreBookingTableVo>> byCategory = groupTableVosByCategoryPreserveOrder(all);
|
|
Map<Integer, List<StoreBookingTableVo>> byCategory = groupTableVosByCategoryPreserveOrder(all);
|
|
|
Map<Integer, String> categoryNameMap = loadCategoryNamesForStoreAndGroupKeys(merchantId, byCategory.keySet());
|
|
Map<Integer, String> categoryNameMap = loadCategoryNamesForStoreAndGroupKeys(merchantId, byCategory.keySet());
|
|
@@ -366,6 +383,69 @@ public class StoreBookingTableServiceImpl extends ServiceImpl<StoreBookingTableM
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
|
|
+ * 通用预订(type=2)桌号分组:0 纯数字、1 字母+数字(与美食相同解析规则)、2 汉字及其他、3 空
|
|
|
|
|
+ */
|
|
|
|
|
+ private static int classifyGenericTypeTableName(String tableNumber) {
|
|
|
|
|
+ if (tableNumber == null || tableNumber.trim().isEmpty()) {
|
|
|
|
|
+ return 3;
|
|
|
|
|
+ }
|
|
|
|
|
+ String s = tableNumber.trim();
|
|
|
|
|
+ if (s.matches("\\d+")) {
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ boolean hasAsciiLetter = s.chars().anyMatch(c -> (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'));
|
|
|
|
|
+ boolean hasDigit = s.chars().anyMatch(Character::isDigit);
|
|
|
|
|
+ if (hasAsciiLetter && hasDigit) {
|
|
|
|
|
+ return 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ return 2;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 纯数字桌号:数值正序;同值按位数再按字典序(满足 1、2、001、002 等场景)
|
|
|
|
|
+ */
|
|
|
|
|
+ private static int comparePureNumericTableNames(String a, String b) {
|
|
|
|
|
+ String sa = a.trim();
|
|
|
|
|
+ String sb = b.trim();
|
|
|
|
|
+ BigInteger na = new BigInteger(sa);
|
|
|
|
|
+ BigInteger nb = new BigInteger(sb);
|
|
|
|
|
+ int c = na.compareTo(nb);
|
|
|
|
|
+ if (c != 0) {
|
|
|
|
|
+ return c;
|
|
|
|
|
+ }
|
|
|
|
|
+ int len = Integer.compare(sa.length(), sb.length());
|
|
|
|
|
+ if (len != 0) {
|
|
|
|
|
+ return len;
|
|
|
|
|
+ }
|
|
|
|
|
+ return sa.compareTo(sb);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 通用(type=2)桌号比较:先分组(纯数字 / 字母+数字 / 汉字),组内再按规则比
|
|
|
|
|
+ */
|
|
|
|
|
+ private static int compareGenericTypeTableNumbers(String a, String b) {
|
|
|
|
|
+ int ca = classifyGenericTypeTableName(a);
|
|
|
|
|
+ int cb = classifyGenericTypeTableName(b);
|
|
|
|
|
+ if (ca != cb) {
|
|
|
|
|
+ return Integer.compare(ca, cb);
|
|
|
|
|
+ }
|
|
|
|
|
+ switch (ca) {
|
|
|
|
|
+ case 0:
|
|
|
|
|
+ return comparePureNumericTableNames(a, b);
|
|
|
|
|
+ case 1:
|
|
|
|
|
+ return parseTableNumberForSortStatic(a).compareTo(parseTableNumberForSortStatic(b));
|
|
|
|
|
+ case 2:
|
|
|
|
|
+ String ta = a == null ? "" : a.trim();
|
|
|
|
|
+ String tb = b == null ? "" : b.trim();
|
|
|
|
|
+ return CHINESE_COLLATOR.compare(ta, tb);
|
|
|
|
|
+ default:
|
|
|
|
|
+ return CHINESE_COLLATOR.compare(
|
|
|
|
|
+ a == null ? "" : a.trim(),
|
|
|
|
|
+ b == null ? "" : b.trim());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
* 解析桌号用于排序
|
|
* 解析桌号用于排序
|
|
|
* 规则:字母(A-Z)优先,然后数字(由小到大)
|
|
* 规则:字母(A-Z)优先,然后数字(由小到大)
|
|
|
* 排序逻辑:
|
|
* 排序逻辑:
|
|
@@ -377,6 +457,10 @@ public class StoreBookingTableServiceImpl extends ServiceImpl<StoreBookingTableM
|
|
|
* @return 排序键
|
|
* @return 排序键
|
|
|
*/
|
|
*/
|
|
|
private String parseTableNumberForSort(String tableNumber) {
|
|
private String parseTableNumberForSort(String tableNumber) {
|
|
|
|
|
+ return parseTableNumberForSortStatic(tableNumber);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static String parseTableNumberForSortStatic(String tableNumber) {
|
|
|
if (tableNumber == null || tableNumber.isEmpty()) {
|
|
if (tableNumber == null || tableNumber.isEmpty()) {
|
|
|
return "ZZZZZZZZZZ9999999999"; // 空值排在最后
|
|
return "ZZZZZZZZZZ9999999999"; // 空值排在最后
|
|
|
}
|
|
}
|