diff --git a/hiver-admin/src/main/resources/application.yml b/hiver-admin/src/main/resources/application.yml index 79de7f07..942975ed 100644 --- a/hiver-admin/src/main/resources/application.yml +++ b/hiver-admin/src/main/resources/application.yml @@ -29,6 +29,12 @@ ie: server: port: 8888 + # 响应 gzip 压缩 店铺列表这类大 JSON 字段名高度重复 压缩率约 6-8 倍 小程序端会自动解压 + compression: + enabled: true + mime-types: application/json,application/xml,text/html,text/xml,text/plain,text/css,text/javascript,application/javascript + # 小于该阈值的响应不压缩 避免小响应白付 CPU + min-response-size: 2KB servlet: context-path: / tomcat: @@ -50,7 +56,7 @@ spring: # 数据源 datasource: # url: jdbc:mysql://154.8.162.157:3306/hiver_shop?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true&allowMultiQueries=true - url: jdbc:mysql://8.140.253.224:3306/school?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true&allowMultiQueries=true&autoReconnect=true&failOverReadOnly=false&maxReconnects=10 + url: jdbc:mysql://127.0.0.1:3306/school?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true&allowMultiQueries=true&autoReconnect=true&failOverReadOnly=false&maxReconnects=10 username: root # Jasypt加密 可到common-utils中找到JasyptUtil加解密工具类生成加密结果 格式为ENC(加密结果) 以下解密结果为123456 password: ENC(87YloapnWG6mLejOa27eLN0afFhCrbAGxoHXXrSUrGJ0trM/BndC2kx/gfoJsXIi) @@ -58,8 +64,16 @@ spring: driver-class-name: com.mysql.jdbc.Driver # Druid StatViewServlet配置 druid: - test-on-borrow: true + initial-size: 5 + min-idle: 5 + max-active: 30 + max-wait: 3000 validation-query: SELECT 1 + test-on-borrow: false + test-while-idle: true + test-on-return: false + time-between-eviction-runs-millis: 60000 + min-evictable-idle-time-millis: 300000 stat-view-servlet: # 默认true 内置监控页面首页/druid/index.html enabled: true @@ -94,7 +108,7 @@ spring: # Redis 若设有密码自行添加配置password redis: # host: 154.8.162.157 - host: 8.140.253.224 + host: 127.0.0.1 password: reddoor168 # 数据库索引 默认0 database: 1 @@ -120,7 +134,7 @@ spring: uris: http://localhost:9200 # RabbitMQ配置 rabbitmq: - host: 8.140.253.224 + host: 127.0.0.1 port: 5672 username: root password: ziyi123QQ diff --git a/hiver-admin/test-output/test-report.html b/hiver-admin/test-output/test-report.html index cd4018e9..60d9cedf 100644 --- a/hiver-admin/test-output/test-report.html +++ b/hiver-admin/test-output/test-report.html @@ -35,7 +35,7 @@ Hiver
  • - 20, 2026 17:27:21 + 21, 2026 15:37:23
  • @@ -84,7 +84,7 @@

    passTest

    -

    17:27:22 / 0.025 secs

    +

    15:37:24 / 0.022 secs

    @@ -92,9 +92,9 @@
    #test-id=1
    passTest
    -09.20.2026 17:27:22 -09.20.2026 17:27:22 -0.025 secs +09.21.2026 15:37:24 +09.21.2026 15:37:24 +0.022 secs
    @@ -104,7 +104,7 @@ Pass - 17:27:22 + 15:37:24 Test passed @@ -128,13 +128,13 @@

    Started

    -

    20, 2026 17:27:21

    +

    21, 2026 15:37:23

    Ended

    -

    20, 2026 17:27:22

    +

    21, 2026 15:37:24

    diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallOrderController.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallOrderController.java index c0448d77..73707058 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallOrderController.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallOrderController.java @@ -165,7 +165,8 @@ public class MallOrderController { @PostMapping("/cloudPrint/{id}") @ApiOperation("手动云打印订单小票") - public Result cloudPrint(@ApiParam("订单ID") @PathVariable String id) { + public Result cloudPrint(@ApiParam("订单ID") @PathVariable String id, + @RequestParam(value = "scanVerify", required = false) Boolean scanVerify) { MallOrderVO vo = mallOrderService.getOrderDetail(id); if (vo == null) { return ResultUtil.error("订单不存在"); @@ -173,7 +174,10 @@ public class MallOrderController { if (!daQuCloudPrintService.isCloudPrintShop(vo.getShopId())) { return ResultUtil.error("当前商家未配置云打印"); } - orderAsyncProducer.sendCloudPrint(id, "MANUAL-" + System.currentTimeMillis()); + String printReason = Boolean.TRUE.equals(scanVerify) + ? "SCAN_VERIFY-" + System.currentTimeMillis() + : "MANUAL-" + System.currentTimeMillis(); + orderAsyncProducer.sendCloudPrint(id, printReason); return ResultUtil.success("云打印任务已发送"); } diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ProductCategoryController.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ProductCategoryController.java index e8da4e72..c57dde68 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ProductCategoryController.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ProductCategoryController.java @@ -5,8 +5,10 @@ import cc.hiver.core.common.utils.ResultUtil; import cc.hiver.core.common.utils.SecurityUtil; import cc.hiver.core.common.vo.Result; import cc.hiver.mall.entity.ProductCategory; +import cc.hiver.mall.entity.Shop; import cc.hiver.mall.pojo.vo.ProductCategoryVo; import cc.hiver.mall.pojo.vo.ProductCategoryVo2; +import cc.hiver.mall.service.ShopService; import cc.hiver.mall.service.mybatis.ProductCategoryService; import cc.hiver.mall.service.mybatis.ProductService; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; @@ -37,6 +39,9 @@ public class ProductCategoryController { @Autowired private ProductService productService; + @Autowired + private ShopService shopService; + @Autowired private SecurityUtil securityUtil; @@ -84,6 +89,10 @@ public class ProductCategoryController { // 将该分类下的商品id删除掉 productService.deleteProductByCategoryId(productCategory.getId()); productCategoryService.removeProductCategoryCache(old.getShopId(), old.getId()); + Shop shop = shopService.get(old.getShopId()); + if (shop != null) { + shopService.refreshShopCache(shop.getId(), shop.getRegionId()); + } return ResultUtil.success("删除成功"); } diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ShopController.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ShopController.java index 8180892e..cc9d11a1 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ShopController.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ShopController.java @@ -79,6 +79,7 @@ import java.util.stream.Collectors; public class ShopController { private static final String GROUP_BUY_DEFAULT_PAGE_CACHE_PREFIX = "GROUP_BUY_DEFAULT_SHOP_PAGE:"; private static final long GROUP_BUY_DEFAULT_PAGE_CACHE_SECONDS = 30L; + private static final long SHOP_LIST_SLOW_THRESHOLD_MS = 10L; private static final DateTimeFormatter BUSINESS_TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm"); private static final String PRINTING_METHOD_BLUETOOTH = "bluetooth"; private static final String PRINTING_METHOD_CLOUD = "cloud"; @@ -458,7 +459,7 @@ public class ShopController { @ApiOperation("多条件分页获取公司列表") public Result> getByCondition(Shop shop, PageVo pageVo) { - long queryStartTime = System.currentTimeMillis(); + ShopListStageTimer timer = new ShopListStageTimer(); String regionId = shop.getRegionId(); boolean adminQuery = CharSequenceUtil.isNotBlank(shop.getShopIcon()); boolean hasKeyword = hasSearchKeyword(shop); @@ -466,17 +467,23 @@ public class ShopController { && !hasKeyword && CharSequenceUtil.isBlank(shop.getShopName()); String defaultPageCacheKey = buildDefaultGroupBuyPageCacheKey(shop, pageVo, adminQuery); + timer.note("pageCacheKey", defaultPageCacheKey == null ? "null" : defaultPageCacheKey); if (CharSequenceUtil.isNotBlank(defaultPageCacheKey)) { String cacheJson = redisTemplateHelper.get(defaultPageCacheKey); + timer.mark("pageCacheGet"); + timer.note("pageCacheBytes", cacheJson == null ? 0 : cacheJson.length()); if (CharSequenceUtil.isNotBlank(cacheJson)) { try { ShopListPageCache cache = JSONUtil.toBean(cacheJson, ShopListPageCache.class); + timer.mark("pageCacheParse"); if (cache != null && cache.getContent() != null) { if (containsUserHiddenShop(cache.getContent())) { redisTemplateHelper.delete(defaultPageCacheKey); } else { fillBaseDeliveryFee(cache.getContent(), regionId); + timer.mark("baseFee"); Page pageResult = new PageImpl<>(cache.getContent(), PageUtil.initPage(pageVo), cache.getTotalElements()); + logShopListQuery("pageCache", timer, cache.getTotalElements(), cache.getContent().size(), regionId); return new ResultUtil>().setData(pageResult); } } @@ -488,10 +495,14 @@ public class ShopController { } if (useRegionCache) { List values = redisTemplateHelper.hValues("SHOP_CACHE:" + regionId); + timer.mark("hvals"); if (values != null && !values.isEmpty()) { List allShops = new ArrayList<>(); + long hvalsBytes = 0L; for (Object v : values) { - ShopCacheDTO dto = parseShopCacheBase(v.toString()); + String shopCacheJson = v.toString(); + hvalsBytes += shopCacheJson.length(); + ShopCacheDTO dto = parseShopCacheBase(shopCacheJson); Shop s = dto.getShop(); if (s == null) { continue; @@ -552,50 +563,18 @@ public class ShopController { } allShops.add(s); } + timer.mark("parseShops"); + timer.note("hvalsShops", values.size()); + timer.note("hvalsBytes", hvalsBytes); - String sort = pageVo.getSort(); - String order = pageVo.getOrder(); - if (CharSequenceUtil.isNotBlank(sort)) { - allShops.sort((s1, s2) -> { - int compareResult = 0; - if ("saleCount".equals(sort)) { - Integer count1 = s1.getSaleCount(); - Integer count2 = s2.getSaleCount(); - Integer c1 = count1 == null ? 0 : count1; - Integer c2 = count2 == null ? 0 : count2; - compareResult = c1.compareTo(c2); - } else if ("shopScore".equals(sort)) { - BigDecimal score1 = s1.getShopScore() == null ? BigDecimal.ZERO : s1.getShopScore(); - BigDecimal score2 = s2.getShopScore() == null ? BigDecimal.ZERO : s2.getShopScore(); - compareResult = score1.compareTo(score2); - } else if ("shoprank".equals(sort)) { - Integer shoprank1 = s1.getShoprank() == null ? 0 : s1.getShoprank(); - Integer shoprank2 = s2.getShoprank() == null ? 0 : s2.getShoprank(); - compareResult = shoprank1.compareTo(shoprank2); - } - if ("desc".equalsIgnoreCase(order)) { - compareResult = -compareResult; - } - return compareResult; - }); - } - - // 稳定排序:用户端优先展示营业中的商家,后台仍将禁用商家置底。 if (adminQuery) { - allShops.sort((s1, s2) -> { - boolean disabled1 = ShopConstant.SHOP_STATUS_LOCK.equals(s1.getStatus()); - boolean disabled2 = ShopConstant.SHOP_STATUS_LOCK.equals(s2.getStatus()); - if (disabled1 != disabled2) { - return disabled1 ? 1 : -1; - } - Integer status1 = s1.getStatus() == null ? ShopConstant.SHOP_STATUS_LOCK : s1.getStatus(); - Integer status2 = s2.getStatus() == null ? ShopConstant.SHOP_STATUS_LOCK : s2.getStatus(); - return status1.compareTo(status2); - }); + applyAdminShopListSort(allShops, pageVo); } else { + applyUserShopListSort(allShops, pageVo); String currentBusinessTime = LocalTime.now().format(BUSINESS_TIME_FORMATTER); allShops.sort((s1, s2) -> compareUserShopPriority(s1, s2, currentBusinessTime)); } + timer.mark("sort"); int pageNumber = pageVo.getPageNumber() > 0 ? pageVo.getPageNumber() : 1; int pageSize = pageVo.getPageSize() > 0 ? pageVo.getPageSize() : 10; @@ -615,21 +594,27 @@ public class ShopController { productKeys.add("SHOP_PRODUCTS:" + s.getId()); } List productsJsonList = redisTemplateHelper.multiGet(productKeys); + timer.mark("mgetProducts"); + long productBytes = 0L; + int productCount = 0; if (productsJsonList != null && productsJsonList.size() == pageList.size()) { for (int i = 0; i < pageList.size(); i++) { String productsJson = productsJsonList.get(i); if (CharSequenceUtil.isNotBlank(productsJson)) { + productBytes += productsJson.length(); List productsReturn = new ArrayList<>(); List products = JSONUtil.toList(productsJson, ProductPageVO.class); + productCount += products == null ? 0 : products.size(); if (hasKeyword) { for (ProductPageVO p : products) { - if (p.getDelFlag() == 1 && p.getProductName() != null && p.getProductName().contains(shop.getKeyWord())) { + if (isSearchMatchedProduct(p, shop.getKeyWord())) { + p.setIsPush(1); productsReturn.add(p); } } }else{ for (ProductPageVO p : products) { - if (p.getDelFlag() == 1 && p.getIsPush() == 1) { + if (Integer.valueOf(1).equals(p.getDelFlag()) && Integer.valueOf(1).equals(p.getIsPush())) { productsReturn.add(p); } } @@ -640,28 +625,40 @@ public class ShopController { } } } + timer.mark("parseProducts"); + timer.note("productBytes", productBytes); + timer.note("productCount", productCount); } fillGroupDeliveryTime(pageList, regionId); + timer.mark("deliveryTime"); fillBaseDeliveryFee(pageList, regionId); + timer.mark("baseFee"); Page pageResult = new PageImpl<>(pageList, PageUtil.initPage(pageVo), allShops.size()); cacheDefaultGroupBuyPage(defaultPageCacheKey, pageList, allShops.size()); - logSlowShopListQuery("redis", queryStartTime, allShops.size(), pageList.size(), regionId); + timer.mark("pageCacheWrite"); + logShopListQuery("redis", timer, allShops.size(), pageList.size(), regionId); return new ResultUtil>().setData(pageResult); } } Page page; if (adminQuery) { page = shopService.findByCondition(shop, PageUtil.initPage(pageVo)); + timer.mark("dbQuery"); fillShopTakeawayAndProducts(page.getContent(), shop, false); + timer.mark("dbFill"); } else { // 用户端:全量查询 → 挂 takeaway → 按多时段营业状态排序 → 再分页(与缓存路径一致) Page allPage = shopService.findByCondition(shop, Pageable.unpaged()); List allShops = new ArrayList<>(allPage.getContent()); + timer.mark("dbQuery"); + timer.note("dbShops", allShops.size()); fillShopTakeawayOnly(allShops); + timer.mark("dbTakeaway"); applyUserShopListSort(allShops, pageVo); String currentBusinessTime = LocalTime.now().format(BUSINESS_TIME_FORMATTER); allShops.sort((s1, s2) -> compareUserShopPriority(s1, s2, currentBusinessTime)); + timer.mark("sort"); int pageNumber = pageVo.getPageNumber() > 0 ? pageVo.getPageNumber() : 1; int pageSize = pageVo.getPageSize() > 0 ? pageVo.getPageSize() : 10; @@ -671,15 +668,85 @@ public class ShopController { ? new ArrayList<>() : new ArrayList<>(allShops.subList(fromIndex, toIndex)); fillShopProducts(pageList, shop); + timer.mark("dbProducts"); fillGroupDeliveryTime(pageList, shop.getRegionId()); + timer.mark("deliveryTime"); fillBaseDeliveryFee(pageList, shop.getRegionId()); + timer.mark("baseFee"); page = new PageImpl<>(pageList, PageUtil.initPage(pageVo), allShops.size()); } cacheDefaultGroupBuyPage(defaultPageCacheKey, page.getContent(), page.getTotalElements()); - logSlowShopListQuery("db", queryStartTime, page.getTotalElements(), page.getContent().size(), shop.getRegionId()); + timer.mark("pageCacheWrite"); + logShopListQuery("db", timer, page.getTotalElements(), page.getContent().size(), shop.getRegionId()); return new ResultUtil>().setData(page); } + private void applyAdminShopListSort(List allShops, PageVo pageVo) { + if (allShops == null || allShops.isEmpty()) { + return; + } + String shoprankOrder = getShoprankOrder(pageVo); + String sort = pageVo == null ? null : pageVo.getSort(); + String order = pageVo == null ? null : pageVo.getOrder(); + allShops.sort((s1, s2) -> { + int compareResult = Integer.compare(getAdminShopStatusOrder(s1), getAdminShopStatusOrder(s2)); + if (compareResult != 0) { + return compareResult; + } + compareResult = compareShoprank(s1, s2, shoprankOrder); + if (compareResult != 0 || CharSequenceUtil.isBlank(sort) + || "status".equals(sort) || "shoprank".equals(sort)) { + return compareResult; + } + compareResult = compareShopBySortField(s1, s2, sort); + if ("desc".equalsIgnoreCase(order)) { + compareResult = -compareResult; + } + return compareResult; + }); + } + + private int getAdminShopStatusOrder(Shop shop) { + Integer status = shop == null ? null : shop.getStatus(); + if (ShopConstant.SHOP_STATUS_NORMAL.equals(status)) { + return 0; + } + return ShopConstant.SHOP_STATUS_LOCK.equals(status) ? 2 : 1; + } + + private String getShoprankOrder(PageVo pageVo) { + if (pageVo == null) { + return "desc"; + } + if ("shoprank".equals(pageVo.getSortOrder())) { + return CharSequenceUtil.isBlank(pageVo.getOrderOrder()) ? "desc" : pageVo.getOrderOrder(); + } + if ("shoprank".equals(pageVo.getSort())) { + return CharSequenceUtil.isBlank(pageVo.getOrder()) ? "desc" : pageVo.getOrder(); + } + return "desc"; + } + + private int compareShoprank(Shop s1, Shop s2, String order) { + Integer shoprank1 = s1.getShoprank() == null ? 0 : s1.getShoprank(); + Integer shoprank2 = s2.getShoprank() == null ? 0 : s2.getShoprank(); + int compareResult = shoprank1.compareTo(shoprank2); + return "asc".equalsIgnoreCase(order) ? compareResult : -compareResult; + } + + private int compareShopBySortField(Shop s1, Shop s2, String sort) { + if ("saleCount".equals(sort)) { + Integer c1 = s1.getSaleCount() == null ? 0 : s1.getSaleCount(); + Integer c2 = s2.getSaleCount() == null ? 0 : s2.getSaleCount(); + return c1.compareTo(c2); + } else if ("shopScore".equals(sort)) { + BigDecimal score1 = s1.getShopScore() == null ? BigDecimal.ZERO : s1.getShopScore(); + BigDecimal score2 = s2.getShopScore() == null ? BigDecimal.ZERO : s2.getShopScore(); + return score1.compareTo(score2); + } + return 0; + } + private void applyUserShopListSort(List allShops, PageVo pageVo) { if (allShops == null || allShops.isEmpty() || pageVo == null) { return; @@ -747,6 +814,9 @@ public class ShopController { Map> productsByShopId = new HashMap<>(); if (productList != null && productList.getRecords() != null) { productList.getRecords().forEach(productPageVO -> { + if (CharSequenceUtil.isNotBlank(query.getKeyWord())) { + productPageVO.setIsPush(1); + } productsByShopId.computeIfAbsent(productPageVO.getShopId(), key -> new ArrayList<>()).add(productPageVO); }); } @@ -755,6 +825,14 @@ public class ShopController { } } + private boolean isSearchMatchedProduct(ProductPageVO product, String keyword) { + return product != null + && Integer.valueOf(1).equals(product.getDelFlag()) + && CharSequenceUtil.isNotBlank(product.getProductName()) + && CharSequenceUtil.isNotBlank(keyword) + && product.getProductName().contains(keyword); + } + private void fillShopTakeawayAndProducts(List shops, Shop query) { fillShopTakeawayAndProducts(shops, query, true); } @@ -851,11 +929,42 @@ public class ShopController { return ShopBusinessHourUtil.getBusinessTimeOrder(takeaway, currentTime); } - private void logSlowShopListQuery(String source, long startTime, long totalElements, int pageSize, String regionId) { - long cost = System.currentTimeMillis() - startTime; - if (cost > 300) { - log.warn("app/shop/getByCondition slow source={}, cost={}ms, regionId={}, total={}, pageSize={}", - source, cost, regionId, totalElements, pageSize); + private void logShopListQuery(String source, ShopListStageTimer timer, long totalElements, int pageSize, String regionId) { + long cost = timer.totalMs(); + if (cost > SHOP_LIST_SLOW_THRESHOLD_MS) { + log.warn("app/shop/getByCondition slow source={}, cost={}ms, regionId={}, total={}, pageSize={}, stages=[{}]", + source, cost, regionId, totalElements, pageSize, timer.detail()); + } else if (log.isDebugEnabled()) { + log.debug("app/shop/getByCondition source={}, cost={}ms, regionId={}, total={}, pageSize={}, stages=[{}]", + source, cost, regionId, totalElements, pageSize, timer.detail()); + } + } + + /** + * 分段计时:mark 记录距上一个 mark 的耗时,note 记录传输字节数等辅助指标, + * 用于定位 getByCondition 的耗时分布(Redis 取数 / JSON 解析 / 排序 / DB)。 + */ + private static final class ShopListStageTimer { + private final long startNano = System.nanoTime(); + private final StringBuilder detail = new StringBuilder(); + private long lastNano = startNano; + + void mark(String stage) { + long now = System.nanoTime(); + detail.append(stage).append('=').append((now - lastNano) / 1_000_000L).append("ms "); + lastNano = now; + } + + void note(String name, Object value) { + detail.append(name).append('=').append(value).append(' '); + } + + long totalMs() { + return (System.nanoTime() - startNano) / 1_000_000L; + } + + String detail() { + return detail.toString().trim(); } } @@ -1032,7 +1141,7 @@ public class ShopController { if (shop.getStoreFlag() != null) { oldShop.setStoreFlag(shop.getStoreFlag()); } - + // 新增字段处理 if (shop.getShopImages() != null) { oldShop.setShopImages(shop.getShopImages()); diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/ShopServiceImpl.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/ShopServiceImpl.java index 2af53e2e..794dff14 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/ShopServiceImpl.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/ShopServiceImpl.java @@ -187,13 +187,24 @@ public class ShopServiceImpl implements ShopService { cq.where(list.toArray(arr)); if (adminQuery) { List orderList = new ArrayList<>(); - Expression disabledOrder = cb.selectCase() - .when(cb.equal(statusField, ShopConstant.SHOP_STATUS_LOCK), 1) - .otherwise(0); - orderList.add(cb.asc(disabledOrder)); - orderList.add(cb.asc(statusField)); + Expression statusOrder = cb.selectCase() + .when(cb.equal(statusField, ShopConstant.SHOP_STATUS_NORMAL), 0) + .when(cb.equal(statusField, ShopConstant.SHOP_STATUS_LOCK), 2) + .otherwise(1); + orderList.add(cb.asc(statusOrder)); + Sort.Order shoprankOrder = null; for (Sort.Order order : pageSort) { - if ("status".equals(order.getProperty())) { + if ("shoprank".equals(order.getProperty())) { + shoprankOrder = order; + break; + } + } + Path shoprankField = root.get("shoprank"); + orderList.add(shoprankOrder != null && shoprankOrder.isAscending() + ? cb.asc(shoprankField) + : cb.desc(shoprankField)); + for (Sort.Order order : pageSort) { + if ("status".equals(order.getProperty()) || "shoprank".equals(order.getProperty())) { continue; } Path sortField = root.get(order.getProperty()); @@ -384,10 +395,25 @@ public class ShopServiceImpl implements ShopService { // 第二层缓存:单独存储商品列表 String productsRedisKey = "SHOP_PRODUCTS:" + shopId; + String pushProductsRedisKey = "SHOP_PUSH_PRODUCTS:" + shopId; if (productList != null && productList.getRecords() != null && !productList.getRecords().isEmpty()) { - redisTemplateHelper.set(productsRedisKey, JSONUtil.toJsonStr(productList.getRecords())); + List products = productList.getRecords(); + redisTemplateHelper.set(productsRedisKey, JSONUtil.toJsonStr(products)); + + List pushProducts = new ArrayList<>(); + for (ProductPageVO product : products) { + if (Integer.valueOf(1).equals(product.getDelFlag()) && Integer.valueOf(1).equals(product.getIsPush())) { + pushProducts.add(product); + } + } + if (!pushProducts.isEmpty()) { + redisTemplateHelper.set(pushProductsRedisKey, JSONUtil.toJsonStr(pushProducts)); + } else { + redisTemplateHelper.delete(pushProductsRedisKey); + } } else { redisTemplateHelper.delete(productsRedisKey); + redisTemplateHelper.delete(pushProductsRedisKey); } } @@ -403,6 +429,8 @@ public class ShopServiceImpl implements ShopService { // 同步删除第二层商品缓存 String productsRedisKey = "SHOP_PRODUCTS:" + shopId; redisTemplateHelper.delete(productsRedisKey); + String pushProductsRedisKey = "SHOP_PUSH_PRODUCTS:" + shopId; + redisTemplateHelper.delete(pushProductsRedisKey); } private void removeGroupBuyDefaultPageCache(String regionId) { diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/DaQuReceiptRenderUtil.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/DaQuReceiptRenderUtil.java index 40957ad7..14974025 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/DaQuReceiptRenderUtil.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/DaQuReceiptRenderUtil.java @@ -12,6 +12,7 @@ import java.util.List; public final class DaQuReceiptRenderUtil { private static final String LINE = "--------------------------------"; private static final String TIME_PATTERN = "yyyy-MM-dd HH:mm:ss"; + private static final String APPOINTMENT_TIME_PATTERN = "yyyy-MM-dd HH:mm"; private DaQuReceiptRenderUtil() { } @@ -22,12 +23,14 @@ public final class DaQuReceiptRenderUtil { List refunds = order.getMallRefundRecord(); boolean refundPrint = isRefundPrint(printReason); boolean forcedOrderPrint = isOrderEventPrint(printReason); + boolean scanVerifyPrint = isScanVerifyPrint(printReason); boolean hasRefund = refundPrint && refunds != null && !refunds.isEmpty(); centerLarge(sb, orderNo(order)); - centerLarge(sb, orderTypeText(order, delivery, refundPrint, forcedOrderPrint)); + centerLarge(sb, orderTypeText(order, delivery, refundPrint, forcedOrderPrint, scanVerifyPrint)); if (delivery != null && Integer.valueOf(1).equals(delivery.getAppointmentDelivery())) { - largeLeft(sb, "要求送达时间:" + formatTime(delivery.getMustFinishTime())); + left(sb, "要求送达时间:"); + largeLeft(sb, formatAppointmentTime(delivery.getMustFinishTime())); } if (isFaceToFaceDelivery(order)) { largeLeft(sb, "本单编号:" + defaultString(order.getNumberCode())); @@ -143,7 +146,7 @@ public final class DaQuReceiptRenderUtil { return defaultString(order.getNumberCode()); } - private static String orderTypeText(MallOrderVO order, MallDeliveryOrder delivery, boolean refundPrint, boolean forcedOrderPrint) { + private static String orderTypeText(MallOrderVO order, MallDeliveryOrder delivery, boolean refundPrint, boolean forcedOrderPrint, boolean scanVerifyPrint) { Integer status = order.getStatus(); if (delivery != null && Integer.valueOf(1).equals(delivery.getAppointmentDelivery()) && !refundPrint) { @@ -167,6 +170,9 @@ public final class DaQuReceiptRenderUtil { && !Integer.valueOf(1).equals(order.getUserRequireMake())) { return "待消费"; } + if (scanVerifyPrint) { + return "到店核销"; + } if (Integer.valueOf(5).equals(status)) { return "已完成"; } @@ -196,6 +202,10 @@ public final class DaQuReceiptRenderUtil { return StringUtils.containsIgnoreCase(printReason, "REFUND"); } + private static boolean isScanVerifyPrint(String printReason) { + return StringUtils.containsIgnoreCase(printReason, "SCAN_VERIFY"); + } + private static boolean isFaceToFaceDelivery(MallOrderVO order) { return Integer.valueOf(1).equals(order.getDeliveryType()) && Integer.valueOf(3).equals(order.getOrderType()); @@ -293,6 +303,10 @@ public final class DaQuReceiptRenderUtil { return date == null ? "" : new SimpleDateFormat(TIME_PATTERN).format(date); } + private static String formatAppointmentTime(Date date) { + return date == null ? "" : new SimpleDateFormat(APPOINTMENT_TIME_PATTERN).format(date); + } + private static String delNode(String text) { return defaultString(text).replace("{", "").replace("}", "").replace("\"", ""); }