From 2983e4240df828981a1ff712adb7a9c2eb9ecbce Mon Sep 17 00:00:00 2001 From: wangfukang <15630117759@163.com> Date: Tue, 29 Sep 2026 19:44:20 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=B9=E6=8E=A5=E6=8B=BC=E5=9B=A2=E6=95=B0?= =?UTF-8?q?=E6=8D=AE1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hiver-admin/test-output/test-report.html | 16 +++---- .../AdminMallOrderGroupController.java | 12 ++--- .../mall/controller/ShopAreaController.java | 11 +++++ .../hiver/mall/controller/ShopController.java | 6 +++ .../main/java/cc/hiver/mall/entity/Shop.java | 3 ++ .../java/cc/hiver/mall/entity/ShopArea.java | 4 ++ .../hiver/mall/quartz/GroupBuyExpireTask.java | 47 ++++++++++++++++--- .../db/shop_area_express_errand_enabled.sql | 2 + .../resources/db/shop_store_consume_only.sql | 2 + .../main/resources/mapper/ShopAreaMapper.xml | 19 ++++++-- 10 files changed, 97 insertions(+), 25 deletions(-) create mode 100644 hiver-modules/hiver-mall/src/main/resources/db/shop_area_express_errand_enabled.sql create mode 100644 hiver-modules/hiver-mall/src/main/resources/db/shop_store_consume_only.sql diff --git a/hiver-admin/test-output/test-report.html b/hiver-admin/test-output/test-report.html index 7daf3683..a53f3663 100644 --- a/hiver-admin/test-output/test-report.html +++ b/hiver-admin/test-output/test-report.html @@ -35,7 +35,7 @@ Hiver
  • -¾ÅÔ 22, 2026 11:55:05 +¾ÅÔ 29, 2026 18:08:31
  • @@ -84,7 +84,7 @@

    passTest

    -

    11:55:05 ÉÏÎç / 0.025 secs

    +

    18:08:32 ÏÂÎç / 0.03 secs

    @@ -92,9 +92,9 @@
    #test-id=1
    passTest
    -09.22.2026 11:55:05 -09.22.2026 11:55:05 -0.025 secs +09.29.2026 18:08:32 +09.29.2026 18:08:32 +0.03 secs
    @@ -104,7 +104,7 @@ Pass - 11:55:05 + 18:08:32 Test passed @@ -128,13 +128,13 @@

    Started

    -

    ¾ÅÔ 22, 2026 11:55:05

    +

    ¾ÅÔ 29, 2026 18:08:31

    Ended

    -

    ¾ÅÔ 22, 2026 11:55:05

    +

    ¾ÅÔ 29, 2026 18:08:32

    diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/AdminMallOrderGroupController.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/AdminMallOrderGroupController.java index fb9a3d10..30322adb 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/AdminMallOrderGroupController.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/AdminMallOrderGroupController.java @@ -97,6 +97,7 @@ public class AdminMallOrderGroupController { private String productName; private String productPicture; private String productId; + private java.math.BigDecimal storeOriginalPrice; private Shop shopItem; } @@ -400,6 +401,7 @@ public class AdminMallOrderGroupController { vo.setProductName(buildDisplayProductName(group, product)); vo.setProductPicture(group.getProductPicture()); vo.setProductId(group.getProductId()); + vo.setStoreOriginalPrice(getStoreOriginalPrice(product == null ? null : product.getAttributeListPrice())); vo.setShopItem(shop); return vo; } @@ -409,14 +411,10 @@ public class AdminMallOrderGroupController { if (StringUtils.isBlank(productName) && product != null) { productName = product.getProductName(); } - String specPrice = getFirstSpecPrice(product == null ? null : product.getAttributeListPrice()); - if (StringUtils.isBlank(productName) || StringUtils.isBlank(specPrice)) { - return productName; - } - return productName + "-店内原价" + specPrice + "元"; + return productName; } - private String getFirstSpecPrice(String attributeListPrice) { + private java.math.BigDecimal getStoreOriginalPrice(String attributeListPrice) { if (StringUtils.isBlank(attributeListPrice)) { return null; } @@ -426,7 +424,7 @@ public class AdminMallOrderGroupController { return null; } JSONObject firstSpec = specs.getJSONObject(0); - return firstSpec == null ? null : firstSpec.getStr("specPrice"); + return firstSpec == null ? null : firstSpec.getBigDecimal("specPrice"); } catch (Exception e) { log.warn("解析商品规格原价失败 attributeListPrice={}: {}", attributeListPrice, e.getMessage()); return null; diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ShopAreaController.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ShopAreaController.java index f8ee15e8..f0258e4e 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ShopAreaController.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ShopAreaController.java @@ -311,6 +311,7 @@ public class ShopAreaController { shopArea.setRadiusMeters(null); shopArea.setGeoPolygon(null); shopArea.setAreaKind(1); + shopArea.setExpressErrandEnabled(1); return null; } Integer areaKind = shopArea.getAreaKind(); @@ -319,6 +320,16 @@ public class ShopAreaController { } else if (areaKind != 1 && areaKind != 2) { return ResultUtil.error("区域类型仅支持:1校园区域,2社会区域"); } + if (shopArea.getAreaKind() != 2) { + shopArea.setExpressErrandEnabled(1); + } else { + Integer expressErrandEnabled = shopArea.getExpressErrandEnabled(); + if (expressErrandEnabled == null) { + shopArea.setExpressErrandEnabled(1); + } else if (expressErrandEnabled != 0 && expressErrandEnabled != 1) { + return ResultUtil.error("快递/跑腿开关仅支持:1开启,0关闭"); + } + } Integer commissionRatio = shopArea.getCommissionRatio(); if (commissionRatio == null) { shopArea.setCommissionRatio(0); 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 7c39e4b3..168ca74b 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 @@ -145,6 +145,9 @@ public class ShopController { shop.setRegion(""); shop.setRegionId(null); } + if (shop.getStoreConsumeOnly() == null) { + shop.setStoreConsumeOnly(0); + } shopService.save(shop); @@ -196,6 +199,9 @@ public class ShopController { oldShop.setRegion(""); oldShop.setRegionId(null); } + if (shop.getStoreConsumeOnly() != null) { + oldShop.setStoreConsumeOnly(shop.getStoreConsumeOnly()); + } UpdateUtils.copyNonNullProperties(shop, oldShop); // 4. 更新数据库(此时更新的是带有完整数据的 oldShop,不会误清空其他字段) shopService.update(oldShop); diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/Shop.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/Shop.java index 4de41eea..83769faa 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/Shop.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/Shop.java @@ -187,6 +187,9 @@ public class Shop extends HiverBaseEntity { @ApiModelProperty(value = "是否支持堂食 0否 1是") private Integer supportDineIn; + @ApiModelProperty(value = "是否只做到店消费 0否 1是") + private Integer storeConsumeOnly; + @ApiModelProperty(value = "是否支持商家自配送 0否 1是") private Integer supportShopDelivery; diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/ShopArea.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/ShopArea.java index 0d060e39..f520c472 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/ShopArea.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/ShopArea.java @@ -83,6 +83,10 @@ public class ShopArea extends HiverBaseEntity { @Column(nullable = false, columnDefinition = "int default 1") private Integer areaKind = 1; + @ApiModelProperty(value = "社会区域是否开启快递/跑腿:1开启,0关闭") + @Column(nullable = false, columnDefinition = "int default 1") + private Integer expressErrandEnabled = 1; + @Transient @TableField(exist = false) @ApiModelProperty(value = "父节点名称") diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/quartz/GroupBuyExpireTask.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/quartz/GroupBuyExpireTask.java index eed60ede..f217dbe8 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/quartz/GroupBuyExpireTask.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/quartz/GroupBuyExpireTask.java @@ -35,6 +35,8 @@ public class GroupBuyExpireTask { private static final String SHOP_CACHE_PREFIX = "SHOP_CACHE:"; private static final String SHOP_PRODUCTS_PREFIX = "SHOP_PRODUCTS:"; private static final String SHOP_GROUP_ORDERS_PREFIX = "SHOP_GROUP_ORDERS:"; + private static final String MOCK_SHOP_SALE_MAX_PREFIX = "MOCK_SHOP_SALE_MAX:"; + private static final String MOCK_PRODUCT_SALE_MAX_PREFIX = "MOCK_PRODUCT_SALE_MAX:"; private static final int MOCK_GROUP_SHOP_COUNT = 20; private static final int MOCK_GROUP_TARGET_MEMBERS = 2; private static final int SALE_SHOP_COUNT = 40; @@ -202,18 +204,21 @@ public class GroupBuyExpireTask { private boolean increaseShopSaleCache(Map.Entry shopEntry, int increment) { String shopId = getShopId(shopEntry); - ShopCacheDTO cacheDTO = parseShopCacheDTO(shopEntry.getValue()); + Object latestShopCache = StringUtils.isBlank(shopId) ? null : redisTemplateHelper.hGet(buildShopCacheKey(MOCK_REGION_ID), shopId); + ShopCacheDTO cacheDTO = parseShopCacheDTO(latestShopCache != null ? latestShopCache : shopEntry.getValue()); if (StringUtils.isBlank(shopId) || cacheDTO == null || cacheDTO.getShop() == null || increment <= 0) { return false; } Shop shop = cacheDTO.getShop(); - int oldSaleCount = shop.getSaleCount() == null ? 0 : shop.getSaleCount(); if (!increaseProductTailWarnCache(shopId, increment)) { return false; } - shop.setSaleCount(oldSaleCount + increment); + int oldSaleCount = maxSaleValue(shop.getSaleCount(), redisTemplateHelper.hGet(buildMockShopSaleMaxKey(MOCK_REGION_ID), shopId)); + int newSaleCount = oldSaleCount + increment; + shop.setSaleCount(newSaleCount); redisTemplateHelper.hPut(buildShopCacheKey(MOCK_REGION_ID), shopId, JSONUtil.toJsonStr(cacheDTO)); + redisTemplateHelper.hPut(buildMockShopSaleMaxKey(MOCK_REGION_ID), shopId, String.valueOf(newSaleCount)); return true; } @@ -233,7 +238,9 @@ public class GroupBuyExpireTask { List productIndexes = new ArrayList<>(); for (int i = 0; i < productArray.size(); i++) { JSONObject productObj = productArray.getJSONObject(i); - if (productObj != null && Integer.valueOf(1).equals(productObj.getInt("delFlag", 1))) { + if (productObj != null + && StringUtils.isNotBlank(productObj.getStr("id")) + && Integer.valueOf(1).equals(productObj.getInt("delFlag", 1))) { productIndexes.add(i); } } @@ -244,10 +251,14 @@ public class GroupBuyExpireTask { Collections.shuffle(productIndexes); int productCount = Math.min(productIndexes.size(), totalIncrement); List productIncrements = randomPositiveParts(totalIncrement, productCount); + String productSaleMaxKey = buildMockProductSaleMaxKey(shopId); for (int i = 0; i < productCount; i++) { JSONObject productObj = productArray.getJSONObject(productIndexes.get(i)); - int oldTailWarn = productObj.getInt("tailWarn", 0); - productObj.set("tailWarn", oldTailWarn + productIncrements.get(i)); + String productId = productObj.getStr("id"); + int oldTailWarn = maxSaleValue(productObj.getInt("tailWarn", 0), redisTemplateHelper.hGet(productSaleMaxKey, productId)); + int newTailWarn = oldTailWarn + productIncrements.get(i); + productObj.set("tailWarn", newTailWarn); + redisTemplateHelper.hPut(productSaleMaxKey, productId, String.valueOf(newTailWarn)); } redisTemplateHelper.set(productsKey, productArray.toString()); return true; @@ -381,4 +392,28 @@ public class GroupBuyExpireTask { private String buildShopGroupOrdersKey(String shopId) { return SHOP_GROUP_ORDERS_PREFIX + shopId; } + + private String buildMockShopSaleMaxKey(String regionId) { + return MOCK_SHOP_SALE_MAX_PREFIX + regionId; + } + + private String buildMockProductSaleMaxKey(String shopId) { + return MOCK_PRODUCT_SALE_MAX_PREFIX + shopId; + } + + private int maxSaleValue(Integer currentValue, Object cachedMaxValue) { + int current = currentValue == null ? 0 : Math.max(0, currentValue); + return Math.max(current, parseSaleValue(cachedMaxValue)); + } + + private int parseSaleValue(Object value) { + if (value == null) { + return 0; + } + try { + return Math.max(0, Integer.parseInt(value.toString())); + } catch (Exception e) { + return 0; + } + } } diff --git a/hiver-modules/hiver-mall/src/main/resources/db/shop_area_express_errand_enabled.sql b/hiver-modules/hiver-mall/src/main/resources/db/shop_area_express_errand_enabled.sql new file mode 100644 index 00000000..ab604bba --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/resources/db/shop_area_express_errand_enabled.sql @@ -0,0 +1,2 @@ +ALTER TABLE `t_shop_area` + ADD COLUMN `express_errand_enabled` int(11) NOT NULL DEFAULT 1 COMMENT '社会区域是否开启快递/跑腿:1开启,0关闭'; diff --git a/hiver-modules/hiver-mall/src/main/resources/db/shop_store_consume_only.sql b/hiver-modules/hiver-mall/src/main/resources/db/shop_store_consume_only.sql new file mode 100644 index 00000000..61d8ebf4 --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/resources/db/shop_store_consume_only.sql @@ -0,0 +1,2 @@ +ALTER TABLE `t_shop` + ADD COLUMN `store_consume_only` TINYINT NOT NULL DEFAULT 0 COMMENT '是否只做到店消费 0否 1是' AFTER `support_dine_in`; diff --git a/hiver-modules/hiver-mall/src/main/resources/mapper/ShopAreaMapper.xml b/hiver-modules/hiver-mall/src/main/resources/mapper/ShopAreaMapper.xml index 496add9f..6e96f805 100644 --- a/hiver-modules/hiver-mall/src/main/resources/mapper/ShopAreaMapper.xml +++ b/hiver-modules/hiver-mall/src/main/resources/mapper/ShopAreaMapper.xml @@ -23,11 +23,12 @@ + id, create_by, create_time, del_flag, update_by, update_time, is_parent, parent_id, sort_order, status, title, is_canteen, delivery_enabled, parent_agent_id, parent_agent_name, - commission_ratio, center_lng, center_lat, radius_meters, geo_polygon, area_kind + commission_ratio, center_lng, center_lat, radius_meters, geo_polygon, area_kind, express_errand_enabled