From d357906f3b10b51bd6d115d3ffeeeea35687de86 Mon Sep 17 00:00:00 2001 From: wangfukang <15630117759@163.com> Date: Sun, 20 Sep 2026 11:09:09 +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 --- .../src/main/resources/application.yml | 7 + hiver-admin/test-output/test-report.html | 16 +- .../java/cc/hiver/core/dao/WorkerDao.java | 4 + .../java/cc/hiver/core/entity/Worker.java | 4 + .../cc/hiver/core/service/WorkerService.java | 2 + .../core/serviceimpl/JPushServiceImpl.java | 1 + .../core/serviceimpl/WorkerServiceImpl.java | 5 + .../MallDeliveryOrderController.java | 67 +++ .../mall/controller/MallOrderController.java | 22 + .../mall/controller/OrderController.java | 2 +- .../mall/controller/ShopAreaController.java | 79 ++- .../hiver/mall/controller/ShopController.java | 366 +++++++++--- .../controller/ShopTakeawayController.java | 7 + .../controller/UserAddressController.java | 37 +- .../mall/controller/WorkerController.java | 37 +- .../dao/mapper/MallDeliveryOrderMapper.java | 10 + .../hiver/mall/entity/MallDeliveryOrder.java | 6 + .../main/java/cc/hiver/mall/entity/Shop.java | 9 + .../java/cc/hiver/mall/entity/ShopArea.java | 10 +- .../cc/hiver/mall/entity/ShopTakeaway.java | 11 + .../cc/hiver/mall/entity/UserAddress.java | 8 + .../cc/hiver/mall/mq/OrderAsyncProducer.java | 31 ++ .../mall/mq/OrderCloudPrintConsumer.java | 50 ++ .../cc/hiver/mall/mq/OrderQueueConfig.java | 28 + .../mall/pojo/dto/BusinessHourPeriod.java | 22 + .../query/MallDeliveryOrderPageQuery.java | 9 + .../hiver/mall/service/ShopAreaService.java | 4 +- .../mybatis/MallDeliveryOrderService.java | 10 + .../mall/serviceimpl/ShopAreaServiceImpl.java | 108 +++- .../mall/serviceimpl/ShopServiceImpl.java | 117 ++-- .../serviceimpl/ShopTakeawayServiceImpl.java | 59 +- .../mybatis/MallDeliveryOrderServiceImpl.java | 58 +- .../mybatis/MallOrderGroupServiceImpl.java | 1 + .../mybatis/MallOrderServiceImpl.java | 39 ++ .../mybatis/MallRefundRecordServiceImpl.java | 58 +- .../mall/utils/DaQuCloudPrintService.java | 106 ++++ .../cc/hiver/mall/utils/DaQuPrinterUtil.java | 521 ++++++++++++++++++ .../mall/utils/DaQuReceiptRenderUtil.java | 313 +++++++++++ .../mall/utils/ShopBusinessHourUtil.java | 218 ++++++++ .../resources/db/shop_area_geo_polygon.sql | 2 + .../main/resources/db/shop_cloud_print.sql | 4 + .../main/resources/db/shop_starting_price.sql | 2 + .../db/shop_takeaway_business_hours.sql | 16 + .../resources/db/transfer_worker_delivery.sql | 8 + .../main/resources/db/user_address_geo.sql | 3 + .../mapper/MallDeliveryOrderMapper.xml | 130 ++++- .../main/resources/mapper/ShopAreaMapper.xml | 65 ++- .../resources/mapper/ShopTakeawayMapper.xml | 10 +- .../resources/mapper/UserAddressMapper.xml | 6 +- 49 files changed, 2454 insertions(+), 254 deletions(-) create mode 100644 hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/mq/OrderCloudPrintConsumer.java create mode 100644 hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/dto/BusinessHourPeriod.java create mode 100644 hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/DaQuCloudPrintService.java create mode 100644 hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/DaQuPrinterUtil.java create mode 100644 hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/DaQuReceiptRenderUtil.java create mode 100644 hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/ShopBusinessHourUtil.java create mode 100644 hiver-modules/hiver-mall/src/main/resources/db/shop_area_geo_polygon.sql create mode 100644 hiver-modules/hiver-mall/src/main/resources/db/shop_cloud_print.sql create mode 100644 hiver-modules/hiver-mall/src/main/resources/db/shop_starting_price.sql create mode 100644 hiver-modules/hiver-mall/src/main/resources/db/shop_takeaway_business_hours.sql create mode 100644 hiver-modules/hiver-mall/src/main/resources/db/transfer_worker_delivery.sql create mode 100644 hiver-modules/hiver-mall/src/main/resources/db/user_address_geo.sql diff --git a/hiver-admin/src/main/resources/application.yml b/hiver-admin/src/main/resources/application.yml index 758473f8..79de7f07 100644 --- a/hiver-admin/src/main/resources/application.yml +++ b/hiver-admin/src/main/resources/application.yml @@ -3,6 +3,12 @@ jasypt: encryptor: password: hiver +daqu: + printer: + appid: 1550073157890342912 + appSecret: cxtFP8nYWx7VC48ov9V5QJ1HpGenWu4a + apiBaseUrl: https://api.trenditiot.com + ie: aliyun: green: @@ -537,6 +543,7 @@ logging: jpush: appKey: 130f556e8473c9b558777fe3 masterSecret: 2b4e5196dfc40a78db36480d + apnsProduction: true aliyun: openapi: accessKeyId: 56640 diff --git a/hiver-admin/test-output/test-report.html b/hiver-admin/test-output/test-report.html index 267b60c5..174185cb 100644 --- a/hiver-admin/test-output/test-report.html +++ b/hiver-admin/test-output/test-report.html @@ -35,7 +35,7 @@ Hiver
  • -九月 09, 2026 10:15:14 +九月 19, 2026 15:49:28
  • @@ -84,7 +84,7 @@

    passTest

    -

    10:15:14 上午 / 0.021 secs

    +

    15:49:29 下午 / 0.022 secs

    @@ -92,9 +92,9 @@
    #test-id=1
    passTest
    -09.09.2026 10:15:14 -09.09.2026 10:15:14 -0.021 secs +09.19.2026 15:49:29 +09.19.2026 15:49:29 +0.022 secs
    @@ -104,7 +104,7 @@ Pass - 10:15:14 + 15:49:29 Test passed @@ -128,13 +128,13 @@

    Started

    -

    九月 09, 2026 10:15:14

    +

    九月 19, 2026 15:49:28

    Ended

    -

    九月 09, 2026 10:15:14

    +

    九月 19, 2026 15:49:29

    diff --git a/hiver-core/src/main/java/cc/hiver/core/dao/WorkerDao.java b/hiver-core/src/main/java/cc/hiver/core/dao/WorkerDao.java index 1284d127..842c2f0a 100644 --- a/hiver-core/src/main/java/cc/hiver/core/dao/WorkerDao.java +++ b/hiver-core/src/main/java/cc/hiver/core/dao/WorkerDao.java @@ -27,6 +27,10 @@ public interface WorkerDao extends HiverBaseDao { @Query("update Worker w set w.isFullTime=?2 where w.workerId=?1") void changeFullTime(String id, Integer isFullTime); + @Modifying + @Query("update Worker w set w.canTransferOrder=?2 where w.workerId=?1") + void changeCanTransferOrder(String id, Integer canTransferOrder); + @Modifying @Query("update Worker w set w.workerStatus=?2 where w.workerId = ?1") void delById(String id, Integer workerStatusDisable); diff --git a/hiver-core/src/main/java/cc/hiver/core/entity/Worker.java b/hiver-core/src/main/java/cc/hiver/core/entity/Worker.java index 01264a95..fa1946b1 100644 --- a/hiver-core/src/main/java/cc/hiver/core/entity/Worker.java +++ b/hiver-core/src/main/java/cc/hiver/core/entity/Worker.java @@ -203,6 +203,10 @@ public class Worker implements Serializable { @Column(name = "is_full_time") private Integer isFullTime = 0; + @ApiModelProperty(value = "鏄惁鍙互鎺ヤ腑杞崟锛0鍚 1鏄") + @Column(name = "can_transfer_order") + private Integer canTransferOrder = 0; + @ApiModelProperty(value = "璇勫垎") @Column(name = "score") private BigDecimal score; diff --git a/hiver-core/src/main/java/cc/hiver/core/service/WorkerService.java b/hiver-core/src/main/java/cc/hiver/core/service/WorkerService.java index c0d71375..9b4fc08c 100644 --- a/hiver-core/src/main/java/cc/hiver/core/service/WorkerService.java +++ b/hiver-core/src/main/java/cc/hiver/core/service/WorkerService.java @@ -56,6 +56,8 @@ public interface WorkerService extends HiverBaseService { void changeFullTime(String id, Integer isFullTime); + void changeCanTransferOrder(String id, Integer canTransferOrder); + /** * 鍒犻櫎锛堜慨鏀逛负绂佺敤鐘舵侊級 * diff --git a/hiver-core/src/main/java/cc/hiver/core/serviceimpl/JPushServiceImpl.java b/hiver-core/src/main/java/cc/hiver/core/serviceimpl/JPushServiceImpl.java index 49ba54f0..846097e0 100644 --- a/hiver-core/src/main/java/cc/hiver/core/serviceimpl/JPushServiceImpl.java +++ b/hiver-core/src/main/java/cc/hiver/core/serviceimpl/JPushServiceImpl.java @@ -83,6 +83,7 @@ public class JPushServiceImpl implements JPushService { .setApnsProduction(Boolean.TRUE.equals(apnsProduction)) .build()) .build(); + System.out.println("JPush send target: " + registrationId + ", apnsProduction: " + apnsProduction + ", orderId: " + orderId); PushResult result = jPushClient.sendPush(payload); System.out.println("Push result: " + result); } catch (Exception e) { diff --git a/hiver-core/src/main/java/cc/hiver/core/serviceimpl/WorkerServiceImpl.java b/hiver-core/src/main/java/cc/hiver/core/serviceimpl/WorkerServiceImpl.java index b7e74f94..40d5c47c 100644 --- a/hiver-core/src/main/java/cc/hiver/core/serviceimpl/WorkerServiceImpl.java +++ b/hiver-core/src/main/java/cc/hiver/core/serviceimpl/WorkerServiceImpl.java @@ -253,6 +253,11 @@ public class WorkerServiceImpl implements WorkerService { workerDao.changeFullTime(id, isFullTime); } + @Override + public void changeCanTransferOrder(String id, Integer canTransferOrder) { + workerDao.changeCanTransferOrder(id, canTransferOrder); + } + /** * 鍒犻櫎锛堜慨鏀逛负绂佺敤鐘舵侊級 * diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallDeliveryOrderController.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallDeliveryOrderController.java index 257f8dd7..6e2d9315 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallDeliveryOrderController.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/MallDeliveryOrderController.java @@ -257,10 +257,65 @@ public class MallDeliveryOrderController { q.setTransferDelivery(1); q.setDeliveryType(1); q.setOrder("transferDelivery"); + if (Boolean.TRUE.equals(q.getTransferWorkerView())) { + q.setShopId(null); + q.setStatus(1); + q.setTransferArriveEmpty(true); + } IPage page = mallDeliveryOrderService.pageDelivery(q); return new ResultUtil().setData(page); } + @PostMapping("/transferAccept") + @ApiOperation(value = "閰嶉佸憳鎺ヤ腑杞厤閫佸崟") + public Result transferAccept(@RequestParam String deliveryId, + @RequestParam String workerId, + @RequestParam(required = false) String workerName, + @RequestParam(required = false) String workerMobile) { + Worker worker = workerService.findByWorkerId(workerId); + if (worker == null) { + return ResultUtil.error("閰嶉佸憳涓嶅瓨鍦"); + } + if (!Integer.valueOf(1).equals(worker.getCanTransferOrder())) { + return ResultUtil.error("褰撳墠閰嶉佸憳鏈紑鍚腑杞帴鍗"); + } + MallDeliveryOrder delivery = mallDeliveryOrderService.getById(deliveryId); + if (delivery == null) { + return ResultUtil.error("閰嶉佸崟涓嶅瓨鍦"); + } + if (!Integer.valueOf(1).equals(delivery.getTransferDelivery())) { + return ResultUtil.error("闈炰腑杞厤閫佸崟"); + } + if (!Integer.valueOf(1).equals(delivery.getStatus())) { + return ResultUtil.error("褰撳墠涓浆鍗曚笉鍙帴鍗"); + } + if (delivery.getTransferArriveTime() != null) { + return ResultUtil.error("璇ヤ腑杞崟宸查佽揪涓浆鐐"); + } + if (StrUtil.isNotBlank(delivery.getTransferWorkerId()) && !workerId.equals(delivery.getTransferWorkerId())) { + return ResultUtil.error("璇ヤ腑杞崟宸茶鎺ュ崟"); + } + if (StrUtil.isBlank(workerName)) { + workerName = worker.getWorkerName(); + } + if (StrUtil.isBlank(workerMobile)) { + workerMobile = worker.getMobile(); + } + LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); + updateWrapper.eq(MallDeliveryOrder::getId, deliveryId) + .eq(MallDeliveryOrder::getTransferDelivery, 1) + .eq(MallDeliveryOrder::getStatus, 1) + .isNull(MallDeliveryOrder::getTransferArriveTime) + .and(w -> w.isNull(MallDeliveryOrder::getTransferWorkerId).or().eq(MallDeliveryOrder::getTransferWorkerId, "")) + .set(MallDeliveryOrder::getTransferWorkerId, workerId) + .set(MallDeliveryOrder::getTransferWorkerName, workerName) + .set(MallDeliveryOrder::getTransferWorkerMobile, workerMobile); + if (!mallDeliveryOrderService.update(updateWrapper)) { + return ResultUtil.error("璇ヤ腑杞崟宸茶鎺ュ崟"); + } + return ResultUtil.success("鎺ュ崟鎴愬姛"); + } + @PostMapping("/transferArrive") @ApiOperation(value = "鍟嗗閫佽揪涓浆鐐") public Result transferArrive(@RequestParam String deliveryId, @@ -581,4 +636,16 @@ public class MallDeliveryOrderController { result.put("data", mallDeliveryOrderService.countOrdersLimit(regionId)); return new ResultUtil>().setData(result); } + + @PostMapping("/countOrdersPage") + @ApiOperation(value = "鍚庡彴鍒嗛〉鏌ヨ閰嶉佸憳閰嶉佸崟閲忔帓鍚", notes = "鏀寔鏃ユ湡鑼冨洿锛岃繑鍥炲叏閮ㄦ帓鍚嶅垎椤垫暟鎹") + public Result countOrdersPage(@RequestBody MallDeliveryOrderPageQuery q) { + return new ResultUtil().setData(mallDeliveryOrderService.countOrdersPage(q)); + } + + @PostMapping("/countTransferOrdersPage") + @ApiOperation(value = "鍚庡彴鍒嗛〉鏌ヨ涓浆閰嶉佸憳閰嶉佸崟閲忔帓鍚", notes = "鏀寔鏃ユ湡鑼冨洿锛岃繑鍥炲叏閮ㄦ帓鍚嶅垎椤垫暟鎹") + public Result countTransferOrdersPage(@RequestBody MallDeliveryOrderPageQuery q) { + return new ResultUtil().setData(mallDeliveryOrderService.countTransferOrdersPage(q)); + } } 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 accefca6..c0448d77 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 @@ -5,12 +5,14 @@ import cc.hiver.core.common.vo.Result; import cc.hiver.mall.entity.MallOrder; import cc.hiver.mall.entity.MallOrderGroup; import cc.hiver.mall.entity.MallSettlementRecord; +import cc.hiver.mall.mq.OrderAsyncProducer; import cc.hiver.mall.pojo.dto.CreateOrderDTO; import cc.hiver.mall.pojo.query.MallOrderPageQuery; import cc.hiver.mall.pojo.vo.MallOrderVO; import cc.hiver.mall.service.mybatis.MallOrderGroupService; import cc.hiver.mall.service.mybatis.MallOrderService; import cc.hiver.mall.service.mybatis.MallSettlementRecordService; +import cc.hiver.mall.utils.DaQuCloudPrintService; import cc.hiver.mall.utils.ShopGroupOrderCacheUtil; import cc.hiver.mall.utils.UserPendingOrderCacheUtil; import com.baomidou.mybatisplus.core.metadata.IPage; @@ -48,6 +50,12 @@ public class MallOrderController { @Autowired private MallSettlementRecordService mallSettlementRecordService; + @Autowired + private OrderAsyncProducer orderAsyncProducer; + + @Autowired + private DaQuCloudPrintService daQuCloudPrintService; + /** * 涓嬪崟锛堟櫘閫氳喘涔 / 鍙戣捣鎷煎洟 / 鍙傚洟锛 */ @@ -155,6 +163,20 @@ public class MallOrderController { return new ResultUtil().setData(vo); } + @PostMapping("/cloudPrint/{id}") + @ApiOperation("鎵嬪姩浜戞墦鍗拌鍗曞皬绁") + public Result cloudPrint(@ApiParam("璁㈠崟ID") @PathVariable String id) { + MallOrderVO vo = mallOrderService.getOrderDetail(id); + if (vo == null) { + return ResultUtil.error("璁㈠崟涓嶅瓨鍦"); + } + if (!daQuCloudPrintService.isCloudPrintShop(vo.getShopId())) { + return ResultUtil.error("褰撳墠鍟嗗鏈厤缃簯鎵撳嵃"); + } + orderAsyncProducer.sendCloudPrint(id, "MANUAL-" + System.currentTimeMillis()); + return ResultUtil.success("浜戞墦鍗颁换鍔″凡鍙戦"); + } + /** * 鏍规嵁鍟嗗缁撶畻娴佹按鍏宠仈璁㈠崟 */ diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/OrderController.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/OrderController.java index d81502a1..f9058a99 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/OrderController.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/OrderController.java @@ -471,7 +471,7 @@ public class OrderController { //鑾峰彇AccessToken鍦板潃 String wechatQrcodeAccessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET"; - wechatQrcodeAccessTokenUrl = wechatQrcodeAccessTokenUrl.replace("APPID", "wx6d7d4fb58d1502db").replace("APPSECRET", "3a2c8cd00926764bbd12fd7361e01f1d"); + wechatQrcodeAccessTokenUrl = wechatQrcodeAccessTokenUrl.replace("APPID", "wx21a1caccef085db7").replace("APPSECRET", "dd1642569f7484664d62ff0fd811bc54"); try { final URL url = new URL(wechatQrcodeAccessTokenUrl); 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 05a25797..f8ee15e8 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 @@ -11,6 +11,8 @@ import cc.hiver.mall.entity.ShopArea; import cc.hiver.mall.service.ShopAreaService; import cc.hiver.mall.service.ShopService; import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; @@ -307,6 +309,7 @@ public class ShopAreaController { shopArea.setCenterLng(null); shopArea.setCenterLat(null); shopArea.setRadiusMeters(null); + shopArea.setGeoPolygon(null); shopArea.setAreaKind(1); return null; } @@ -322,17 +325,75 @@ public class ShopAreaController { } else if (commissionRatio < 0 || commissionRatio > 100) { return ResultUtil.error("杩斾剑姣斾緥闇涓0鎴1-100涔嬮棿鐨勬暣鏁"); } - boolean hasLng = shopArea.getCenterLng() != null; - boolean hasLat = shopArea.getCenterLat() != null; - boolean hasRadius = shopArea.getRadiusMeters() != null; - if (hasLng || hasLat || hasRadius) { - if (!hasLng || !hasLat) { - return ResultUtil.error("鍖哄煙涓績缁忕含搴﹂渶鍚屾椂璁剧疆"); + shopArea.setCenterLng(null); + shopArea.setCenterLat(null); + shopArea.setRadiusMeters(null); + String polygon = normalizeGeoPolygon(shopArea.getGeoPolygon()); + if (polygon == null && StrUtil.isNotBlank(shopArea.getGeoPolygon())) { + return ResultUtil.error("鍖归厤鑼冨洿鑷冲皯闇瑕3涓悎娉曞潗鏍囩偣"); + } + shopArea.setGeoPolygon(polygon); + return null; + } + + private String normalizeGeoPolygon(String geoPolygon) { + if (StrUtil.isBlank(geoPolygon)) { + return null; + } + try { + JSONArray source = JSONUtil.parseArray(geoPolygon); + if (source.size() < 3) { + return null; } - if (!hasRadius || shopArea.getRadiusMeters() <= 0) { - return ResultUtil.error("鍖归厤鍗婂緞闇涓烘鏁存暟锛堢背锛"); + JSONArray normalized = new JSONArray(); + for (Object item : source) { + Double lng = null; + Double lat = null; + if (item instanceof JSONArray) { + JSONArray point = (JSONArray) item; + if (point.size() >= 2) { + lng = point.getDouble(0); + lat = point.getDouble(1); + } + } else if (item instanceof java.util.List) { + java.util.List point = (java.util.List) item; + if (point.size() >= 2) { + lng = toDouble(point.get(0)); + lat = toDouble(point.get(1)); + } + } else if (item instanceof java.util.Map) { + java.util.Map point = (java.util.Map) item; + lng = toDouble(point.get("lng")); + lat = toDouble(point.get("lat")); + } + if (!isValidLngLat(lng, lat)) { + return null; + } + JSONArray point = new JSONArray(); + point.add(lng); + point.add(lat); + normalized.add(point); } + return normalized.toString(); + } catch (Exception e) { + return null; } - return null; + } + + private Double toDouble(Object value) { + if (value == null) { + return null; + } + try { + return Double.valueOf(String.valueOf(value)); + } catch (Exception e) { + return null; + } + } + + private boolean isValidLngLat(Double lng, Double lat) { + return lng != null && lat != null + && lng >= -180 && lng <= 180 + && lat >= -90 && lat <= 90; } } 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 51d66929..8180892e 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 @@ -44,6 +44,8 @@ import cc.hiver.mall.service.ShopService; import cc.hiver.mall.service.ShopTakeawayService; import cc.hiver.mall.service.ShopUserService; import cc.hiver.mall.service.mybatis.BaseDeliveryFeeSettingService; +import cc.hiver.mall.utils.DaQuPrinterUtil; +import cc.hiver.mall.utils.ShopBusinessHourUtil; import cc.hiver.mall.utils.UpdateUtils; import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.json.JSONObject; @@ -57,6 +59,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; import org.springframework.web.bind.annotation.*; import java.math.BigDecimal; @@ -75,8 +78,10 @@ import java.util.stream.Collectors; @RequestMapping("/hiver/app/shop/") 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 = 5 * 60L; + private static final long GROUP_BUY_DEFAULT_PAGE_CACHE_SECONDS = 30L; 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"; @Autowired private ShopService shopService; @@ -108,6 +113,9 @@ public class ShopController { @Autowired private BaseDeliveryFeeSettingService baseDeliveryFeeSettingService; + @Autowired + private DaQuPrinterUtil daQuPrinterUtil; + @RequestMapping(value = "/getAll", method = RequestMethod.GET) @ApiOperation("鑾峰彇鍏ㄩ儴鏁版嵁") public Result> getAll() { @@ -220,6 +228,143 @@ public class ShopController { return ResultUtil.success("缂栬緫鎴愬姛"); } + @RequestMapping(value = "/bindPrinter", method = RequestMethod.POST) + @ResponseBody + @ApiOperation("缁戝畾澶ц秼浜戞墦鍗版満") + public Result bindPrinter(DaQuPrinterBindRequest request) { + if (request == null) { + return ResultUtil.error("鍙傛暟涓嶈兘涓虹┖"); + } + String sn = request.getSn() == null ? "" : request.getSn().trim(); + String key = request.getKey() == null ? "" : request.getKey().trim(); + String shopId = request.getShopId() == null ? "" : request.getShopId().trim(); + if (CharSequenceUtil.isBlank(shopId)) { + return ResultUtil.error("搴楅摵id涓嶈兘涓虹┖锛岃鍏堜繚瀛樺簵閾哄悗鍐嶇粦瀹氭墦鍗版満"); + } + Shop shop = shopService.get(shopId); + if (shop == null) { + return ResultUtil.error("搴楅摵涓嶅瓨鍦"); + } + if (CharSequenceUtil.isBlank(sn)) { + return ResultUtil.error("璇疯緭鍏ユ墦鍗版満SN"); + } + if (CharSequenceUtil.isBlank(key)) { + return ResultUtil.error("璇疯緭鍏ヨ澶囩粦瀹氱爜"); + } + String name = request.getName(); + if (CharSequenceUtil.isBlank(name)) { + name = request.getShopName(); + } + if (CharSequenceUtil.isBlank(name)) { + name = shop.getShopName(); + } + try { + DaQuPrinterUtil.DaQuResponse response = daQuPrinterUtil.addPrinter(sn, key, name); + if (response != null && (response.isSuccess() || Integer.valueOf(31412).equals(response.getCode()))) { + shop.setPrinterSn(sn); + shop.setPrinterName(name); + shopService.update(shop); + shopService.refreshShopCache(shop.getId(), shop.getRegionId()); + String successMessage = response.isSuccess() ? "鎵撳嵃鏈虹粦瀹氭垚鍔" : "鎵撳嵃鏈哄凡缁戝畾锛屽凡鍏宠仈鍒板綋鍓嶅晢瀹"; + return new ResultUtil().setData(shop, successMessage); + } + String message = response == null || CharSequenceUtil.isBlank(response.getMessage()) + ? "鎵撳嵃鏈虹粦瀹氬け璐" + : response.getMessage(); + return ResultUtil.error(message); + } catch (Exception e) { + log.error("Bind DaQu printer failed. sn={}", sn, e); + return ResultUtil.error("鎵撳嵃鏈虹粦瀹氬け璐ワ細" + e.getMessage()); + } + } + + @RequestMapping(value = "/printConfig", method = RequestMethod.GET) + @ResponseBody + @ApiOperation("鏌ヨ搴楅摵鎵撳嵃閰嶇疆") + public Result getPrintConfig(@RequestParam String shopId) { + if (CharSequenceUtil.isBlank(shopId)) { + return ResultUtil.error("搴楅摵id涓嶈兘涓虹┖"); + } + Shop shop = shopService.get(shopId); + if (shop == null) { + return ResultUtil.error("搴楅摵涓嶅瓨鍦"); + } + return new ResultUtil().setData(buildPrintConfig(shop)); + } + + @RequestMapping(value = "/printConfig", method = RequestMethod.POST) + @ResponseBody + @ApiOperation("淇濆瓨搴楅摵鎵撳嵃閰嶇疆") + public Result savePrintConfig(PrintConfigRequest request) { + if (request == null || CharSequenceUtil.isBlank(request.getShopId())) { + return ResultUtil.error("搴楅摵id涓嶈兘涓虹┖"); + } + Shop shop = shopService.get(request.getShopId()); + if (shop == null) { + return ResultUtil.error("搴楅摵涓嶅瓨鍦"); + } + String printingMethod = normalizePrintingMethod(request.getPrintingMethod()); + if (PRINTING_METHOD_CLOUD.equals(printingMethod) && CharSequenceUtil.isBlank(shop.getPrinterSn())) { + return ResultUtil.error("璇峰厛缁戝畾浜戞墦鍗版満"); + } + shop.setPrintingMethod(printingMethod); + shopService.update(shop); + shopService.refreshShopCache(shop.getId(), shop.getRegionId()); + return new ResultUtil().setData(buildPrintConfig(shop), "淇濆瓨鎴愬姛"); + } + + @RequestMapping(value = "/printTest", method = RequestMethod.POST) + @ResponseBody + @ApiOperation("浜戞墦鍗版祴璇") + public Result printTest(PrintConfigRequest request) { + if (request == null || CharSequenceUtil.isBlank(request.getShopId())) { + return ResultUtil.error("搴楅摵id涓嶈兘涓虹┖"); + } + Shop shop = shopService.get(request.getShopId()); + if (shop == null) { + return ResultUtil.error("搴楅摵涓嶅瓨鍦"); + } + if (CharSequenceUtil.isBlank(shop.getPrinterSn())) { + return ResultUtil.error("璇峰厛缁戝畾浜戞墦鍗版満"); + } + try { + DaQuPrinterUtil.PrintRequest printRequest = new DaQuPrinterUtil.PrintRequest(); + printRequest.setSn(shop.getPrinterSn()); + printRequest.setVoice(""); + printRequest.setContent("Cloud Print Test
    " + + "Shop: " + shop.getShopName() + "
    " + + "SN: " + shop.getPrinterSn() + "
    " + + "--------------------------------
    "); + printRequest.setCopies(1); + printRequest.setExpiresInSeconds(600); + printRequest.setOutTradeNo("SHOP-TEST-" + shop.getId() + "-" + System.currentTimeMillis()); + DaQuPrinterUtil.DaQuResponse response = daQuPrinterUtil.print(printRequest); + if (response != null && response.isSuccess()) { + return new ResultUtil().setData(response.getData(), "娴嬭瘯鎵撳嵃宸插彂閫"); + } + return ResultUtil.error(response == null ? "娴嬭瘯鎵撳嵃澶辫触" : response.getMessage()); + } catch (Exception e) { + log.error("Cloud printer test failed. shopId={}", shop.getId(), e); + return ResultUtil.error("娴嬭瘯鎵撳嵃澶辫触锛" + e.getMessage()); + } + } + + private String normalizePrintingMethod(String printingMethod) { + if (PRINTING_METHOD_CLOUD.equalsIgnoreCase(printingMethod)) { + return PRINTING_METHOD_CLOUD; + } + return PRINTING_METHOD_BLUETOOTH; + } + + private PrintConfigResponse buildPrintConfig(Shop shop) { + PrintConfigResponse response = new PrintConfigResponse(); + response.setShopId(shop.getId()); + response.setPrintingMethod(normalizePrintingMethod(shop.getPrintingMethod())); + response.setPrinterSn(shop.getPrinterSn()); + response.setPrinterName(shop.getPrinterName()); + return response; + } + @RequestMapping(value = "/modifyShopNameById", method = RequestMethod.PUT) @ResponseBody @ApiOperation("鏍规嵁搴楅摵id淇敼搴楅摵鍚") @@ -316,6 +461,10 @@ public class ShopController { long queryStartTime = System.currentTimeMillis(); String regionId = shop.getRegionId(); boolean adminQuery = CharSequenceUtil.isNotBlank(shop.getShopIcon()); + boolean hasKeyword = hasSearchKeyword(shop); + boolean useRegionCache = CharSequenceUtil.isNotBlank(regionId) + && !hasKeyword + && CharSequenceUtil.isBlank(shop.getShopName()); String defaultPageCacheKey = buildDefaultGroupBuyPageCacheKey(shop, pageVo, adminQuery); if (CharSequenceUtil.isNotBlank(defaultPageCacheKey)) { String cacheJson = redisTemplateHelper.get(defaultPageCacheKey); @@ -337,7 +486,7 @@ public class ShopController { } } } - if (CharSequenceUtil.isNotBlank(regionId)) { + if (useRegionCache) { List values = redisTemplateHelper.hValues("SHOP_CACHE:" + regionId); if (values != null && !values.isEmpty()) { List allShops = new ArrayList<>(); @@ -378,7 +527,7 @@ public class ShopController { continue; } } - if (CharSequenceUtil.isNotBlank(shop.getKeyWord())) { + if (hasKeyword) { String kw = shop.getKeyWord(); boolean match = false; if (s.getShopName() != null && s.getShopName().contains(kw)) { @@ -460,7 +609,7 @@ public class ShopController { } // --- 鏍稿績浼樺寲锛氳幏鍙栧綋鍓嶉〉鐨勫晢鍝佹暟鎹紙浜屽眰缂撳瓨鏋舵瀯鐨勬牳蹇冩嫾瑁咃級 --- - if (!pageList.isEmpty()) { + if (!adminQuery && !pageList.isEmpty()) { List productKeys = new ArrayList<>(); for (Shop s : pageList) { productKeys.add("SHOP_PRODUCTS:" + s.getId()); @@ -472,7 +621,7 @@ public class ShopController { if (CharSequenceUtil.isNotBlank(productsJson)) { List productsReturn = new ArrayList<>(); List products = JSONUtil.toList(productsJson, ProductPageVO.class); - if (CharSequenceUtil.isNotBlank(shop.getKeyWord())) { + if (hasKeyword) { for (ProductPageVO p : products) { if (p.getDelFlag() == 1 && p.getProductName() != null && p.getProductName().contains(shop.getKeyWord())) { productsReturn.add(p); @@ -501,48 +650,125 @@ public class ShopController { return new ResultUtil>().setData(pageResult); } } - final Page page = shopService.findByCondition(shop, PageUtil.initPage(pageVo)); + Page page; + if (adminQuery) { + page = shopService.findByCondition(shop, PageUtil.initPage(pageVo)); + fillShopTakeawayAndProducts(page.getContent(), shop, false); + } else { + // 鐢ㄦ埛绔細鍏ㄩ噺鏌ヨ 鈫 鎸 takeaway 鈫 鎸夊鏃舵钀ヤ笟鐘舵佹帓搴 鈫 鍐嶅垎椤碉紙涓庣紦瀛樿矾寰勪竴鑷达級 + Page allPage = shopService.findByCondition(shop, Pageable.unpaged()); + List allShops = new ArrayList<>(allPage.getContent()); + fillShopTakeawayOnly(allShops); + applyUserShopListSort(allShops, pageVo); + String currentBusinessTime = LocalTime.now().format(BUSINESS_TIME_FORMATTER); + allShops.sort((s1, s2) -> compareUserShopPriority(s1, s2, currentBusinessTime)); + + int pageNumber = pageVo.getPageNumber() > 0 ? pageVo.getPageNumber() : 1; + int pageSize = pageVo.getPageSize() > 0 ? pageVo.getPageSize() : 10; + int fromIndex = (pageNumber - 1) * pageSize; + int toIndex = Math.min(fromIndex + pageSize, allShops.size()); + List pageList = fromIndex >= allShops.size() + ? new ArrayList<>() + : new ArrayList<>(allShops.subList(fromIndex, toIndex)); + fillShopProducts(pageList, shop); + fillGroupDeliveryTime(pageList, shop.getRegionId()); + fillBaseDeliveryFee(pageList, shop.getRegionId()); + 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()); + return new ResultUtil>().setData(page); + } - final List shopIdList = new ArrayList<>(); - page.getContent().forEach(e -> { - shopIdList.add(e.getId()); - }); - if(shopIdList.size() > 0){ - //鏌ヨ涓氬姟淇℃伅 - List shopTakeaways = shopTakeawayService.selectListByshopId(shopIdList); - //鏌ヨ鎺ㄨ崘鍟嗗搧 - final ProductPageQuery productPageQuery = new ProductPageQuery(); - productPageQuery.setPageNum(1); - productPageQuery.setPageSize(100); - productPageQuery.setShopIdList(shopIdList); - productPageQuery.setDelFlag(1); - if(CharSequenceUtil.isBlank(shop.getKeyWord())){ - productPageQuery.setIsPush(ShopUserConstant.SHOP_ADMIN_COST[1]); - }else{ - productPageQuery.setProductName(shop.getKeyWord()); + private void applyUserShopListSort(List allShops, PageVo pageVo) { + if (allShops == null || allShops.isEmpty() || pageVo == null) { + return; + } + String sort = pageVo.getSort(); + String order = pageVo.getOrder(); + if (CharSequenceUtil.isBlank(sort)) { + return; + } + allShops.sort((s1, s2) -> { + int compareResult = 0; + if ("saleCount".equals(sort)) { + Integer c1 = s1.getSaleCount() == null ? 0 : s1.getSaleCount(); + Integer c2 = s2.getSaleCount() == null ? 0 : s2.getSaleCount(); + 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); } - IPage productList = shopService.getShareList(productPageQuery); - - Map> productsByShopId = new HashMap<>(); - if(productList.getRecords().size() > 0){ - productList.getRecords().forEach(productPageVO -> { - productsByShopId.computeIfAbsent(productPageVO.getShopId(), key -> new ArrayList<>()).add(productPageVO); - }); + if ("desc".equalsIgnoreCase(order)) { + compareResult = -compareResult; } - Map takeawayByShopId = new HashMap<>(); - for(ShopTakeaway shopTakeawa : shopTakeaways) { - takeawayByShopId.put(shopTakeawa.getShopId(), shopTakeawa); + return compareResult; + }); + } + + private void fillShopTakeawayOnly(List shops) { + if (shops == null || shops.isEmpty()) { + return; + } + List shopIdList = shops.stream().map(Shop::getId).collect(Collectors.toList()); + List shopTakeaways = shopTakeawayService.selectListByshopId(shopIdList); + Map takeawayByShopId = new HashMap<>(); + if (shopTakeaways != null) { + for (ShopTakeaway takeaway : shopTakeaways) { + takeawayByShopId.put(takeaway.getShopId(), takeaway); } - page.getContent().forEach(e -> { - e.setProducts(productsByShopId.getOrDefault(e.getId(), new ArrayList<>())); - e.setShopTakeaway(takeawayByShopId.get(e.getId())); + } + for (Shop shopItem : shops) { + shopItem.setShopTakeaway(takeawayByShopId.get(shopItem.getId())); + } + } + + private void fillShopProducts(List shops, Shop query) { + if (shops == null || shops.isEmpty()) { + return; + } + List shopIdList = shops.stream().map(Shop::getId).collect(Collectors.toList()); + final ProductPageQuery productPageQuery = new ProductPageQuery(); + productPageQuery.setPageNum(1); + productPageQuery.setPageSize(100); + productPageQuery.setShopIdList(shopIdList); + productPageQuery.setDelFlag(1); + if (CharSequenceUtil.isBlank(query.getKeyWord())) { + productPageQuery.setIsPush(ShopUserConstant.SHOP_ADMIN_COST[1]); + } else { + productPageQuery.setProductName(query.getKeyWord()); + } + IPage productList = shopService.getShareList(productPageQuery); + Map> productsByShopId = new HashMap<>(); + if (productList != null && productList.getRecords() != null) { + productList.getRecords().forEach(productPageVO -> { + productsByShopId.computeIfAbsent(productPageVO.getShopId(), key -> new ArrayList<>()).add(productPageVO); }); - fillGroupDeliveryTime(page.getContent(), shop.getRegionId()); - fillBaseDeliveryFee(page.getContent(), shop.getRegionId()); } - cacheDefaultGroupBuyPage(defaultPageCacheKey, page.getContent(), page.getTotalElements()); - logSlowShopListQuery("db", queryStartTime, page.getTotalElements(), page.getContent().size(), shop.getRegionId()); - return new ResultUtil>().setData(page); + for (Shop shopItem : shops) { + shopItem.setProducts(productsByShopId.getOrDefault(shopItem.getId(), new ArrayList<>())); + } + } + + private void fillShopTakeawayAndProducts(List shops, Shop query) { + fillShopTakeawayAndProducts(shops, query, true); + } + + private void fillShopTakeawayAndProducts(List shops, Shop query, boolean includeProducts) { + if (shops == null || shops.isEmpty()) { + return; + } + fillShopTakeawayOnly(shops); + if (includeProducts) { + fillShopProducts(shops, query); + } + fillGroupDeliveryTime(shops, query.getRegionId()); + fillBaseDeliveryFee(shops, query.getRegionId()); } private String buildDefaultGroupBuyPageCacheKey(Shop shop, PageVo pageVo, boolean adminQuery) { @@ -560,7 +786,7 @@ public class ShopController { if (shop.getIsStudent() != null || CharSequenceUtil.isNotBlank(shop.getShopArea()) || CharSequenceUtil.isNotBlank(shop.getShopType()) || - CharSequenceUtil.isNotBlank(shop.getKeyWord()) || + hasSearchKeyword(shop) || CharSequenceUtil.isNotBlank(shop.getShopName())) { return null; } @@ -578,6 +804,12 @@ public class ShopController { return dto; } + private boolean hasSearchKeyword(Shop shop) { + return shop != null + && CharSequenceUtil.isNotBlank(shop.getKeyWord()) + && !"zhuyesearch".equals(shop.getKeyWord()); + } + private boolean containsUserHiddenShop(List shops) { for (Shop shop : shops) { if (!isUserVisibleShop(shop)) { @@ -616,32 +848,7 @@ public class ShopController { private int getBusinessTimeOrder(Shop shop, String currentTime) { ShopTakeaway takeaway = shop == null ? null : shop.getShopTakeaway(); - if (takeaway == null) { - return 1; - } - String begin = normalizeBusinessTime(takeaway.getBusinessHourBegin()); - String end = normalizeBusinessTime(takeaway.getBusinessHourEnd()); - if (CharSequenceUtil.isBlank(begin) || CharSequenceUtil.isBlank(end)) { - return 1; - } - if (begin.equals(end)) { - return 0; - } - boolean inBusinessTime; - if (begin.compareTo(end) <= 0) { - inBusinessTime = begin.compareTo(currentTime) <= 0 && end.compareTo(currentTime) >= 0; - } else { - inBusinessTime = begin.compareTo(currentTime) <= 0 || end.compareTo(currentTime) >= 0; - } - return inBusinessTime ? 0 : 1; - } - - private String normalizeBusinessTime(String value) { - if (CharSequenceUtil.isBlank(value)) { - return ""; - } - String time = value.trim(); - return time.length() >= 5 ? time.substring(0, 5) : time; + return ShopBusinessHourUtil.getBusinessTimeOrder(takeaway, currentTime); } private void logSlowShopListQuery(String source, long startTime, long totalElements, int pageSize, String regionId) { @@ -894,4 +1101,27 @@ public class ShopController { shopService.refreshShopCache(shop.getId(), shop.getRegionId()); return ResultUtil.data(shop); } + + @Data + public static class DaQuPrinterBindRequest { + private String shopId; + private String sn; + private String key; + private String name; + private String shopName; + } + + @Data + public static class PrintConfigRequest { + private String shopId; + private String printingMethod; + } + + @Data + public static class PrintConfigResponse { + private String shopId; + private String printingMethod; + private String printerSn; + private String printerName; + } } diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ShopTakeawayController.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ShopTakeawayController.java index 1f5988a0..abe30953 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ShopTakeawayController.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ShopTakeawayController.java @@ -24,6 +24,7 @@ import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.*; import java.time.LocalDateTime; @@ -43,6 +44,12 @@ public class ShopTakeawayController { @Autowired private ShopTakeawayService shopTakeawayService; + @InitBinder + public void initBinder(WebDataBinder binder) { + // form 鎻愪氦鏃犳硶缁戝畾 List锛岃惀涓氭椂娈靛彧鐢 businessHours JSON + binder.setDisallowedFields("businessHourList"); + } + @RequestMapping(value = "/getByShopId", method = RequestMethod.GET) @ApiOperation("鏍规嵁搴楅摵id鑾峰彇澶栧崠涓氬姟閰嶇疆") public Result getByShopId( diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/UserAddressController.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/UserAddressController.java index 8575630f..ec8a0f81 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/UserAddressController.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/UserAddressController.java @@ -2,8 +2,10 @@ package cc.hiver.mall.controller; import cc.hiver.core.common.utils.ResultUtil; import cc.hiver.core.common.vo.Result; +import cc.hiver.mall.entity.ShopArea; import cc.hiver.mall.entity.UserAddress; import cc.hiver.mall.pojo.vo.UserAddressVo; +import cc.hiver.mall.service.ShopAreaService; import cc.hiver.mall.service.mybatis.UserAddressService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -26,10 +28,16 @@ public class UserAddressController { @Autowired private UserAddressService userAddressService; + @Autowired + private ShopAreaService shopAreaService; + @RequestMapping(value = "/save", method = RequestMethod.POST) @ApiOperation(value = "鏂板鐢ㄦ埛鏀惰揣鍦板潃") public Result save(UserAddress userAddress) { - + Result validateResult = validateSocialAddress(userAddress); + if (validateResult != null) { + return validateResult; + } // 濡傛灉鏄涓鏉″湴鍧鎴栬呬紶杩囨潵灏辨槸榛樿锛岃缃粯璁ら昏緫鍙湪杩欓噷澧炲姞 // 涓轰簡瀹夊叏璧疯杩欓噷鐩存帴璋冪敤 save锛屼笉澶勭悊澶嶆潅閫昏緫 boolean result = userAddressService.save(userAddress); @@ -58,6 +66,10 @@ public class UserAddressController { if (StringUtils.isBlank(userAddress.getRegionId())) { userAddress.setRegionId(old.getRegionId()); } + Result validateResult = validateSocialAddress(userAddress); + if (validateResult != null) { + return validateResult; + } boolean result = userAddressService.updateById(userAddress); if (result) { @@ -118,4 +130,27 @@ public class UserAddressController { return ResultUtil.success("璁剧疆鎴愬姛"); } + private Result validateSocialAddress(UserAddress userAddress) { + if (userAddress == null || StringUtils.isBlank(userAddress.getRegionId())) { + return null; + } + ShopArea region = shopAreaService.get(userAddress.getRegionId()); + if (region == null || !Integer.valueOf(2).equals(region.getAreaKind())) { + return null; + } + if (userAddress.getAddressLng() == null || userAddress.getAddressLat() == null) { + return ResultUtil.error("璇烽夋嫨甯﹀畾浣嶇殑鏀惰揣鍦板潃"); + } + ShopArea matched = shopAreaService.matchByLocation( + userAddress.getAddressLat().doubleValue(), + userAddress.getAddressLng().doubleValue() + ); + if (matched == null || !userAddress.getRegionId().equals(matched.getId())) { + return ResultUtil.error("鏀惰揣鍦板潃涓嶅湪褰撳墠鍖哄煙閰嶉佽寖鍥村唴"); + } + userAddress.setAreaId(null); + userAddress.setFloor(null); + return null; + } + } diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/WorkerController.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/WorkerController.java index 0b400ea2..ee29e574 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/WorkerController.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/WorkerController.java @@ -140,10 +140,12 @@ public class WorkerController { if(u.getRegion().equals(worker.getRegion())){ return new ResultUtil().setData(worker); }else{ - String oldRegion = worker.getRegion(); - worker.setRegion(u.getRegion()); - workerService.update(worker); - syncWorkerRegionCache(oldRegion, worker); + if(worker.getIsFullTime() != 1){ + String oldRegion = worker.getRegion(); + worker.setRegion(u.getRegion()); + workerService.update(worker); + syncWorkerRegionCache(oldRegion, worker); + } return new ResultUtil().setData(worker); } }else{ @@ -325,6 +327,33 @@ public class WorkerController { return ResultUtil.success("鎿嶄綔鎴愬姛"); } + @RequestMapping(value = "/admin/transferOrder/{workerId}", method = RequestMethod.POST) + @ApiOperation(value = "鍚庡彴璁剧疆閰嶉佸憳鏄惁鍙互鎺ヤ腑杞崟") + public Result changeCanTransferOrder(@ApiParam("閰嶉佸憳鍞竴id鏍囪瘑") @PathVariable String workerId, + @RequestParam("canTransferOrder") Integer canTransferOrder) { + Worker worker = workerService.findByWorkerId(workerId); + if (worker == null) { + return ResultUtil.error("閰嶉佸憳涓嶅瓨鍦"); + } + if (canTransferOrder == null || (canTransferOrder != 0 && canTransferOrder != 1)) { + return ResultUtil.error("涓浆鎺ュ崟鐘舵佸弬鏁伴敊璇"); + } + workerService.changeCanTransferOrder(workerId, canTransferOrder); + worker = workerService.findByWorkerId(workerId); + if (worker == null) { + return ResultUtil.error("閰嶉佸憳涓嶅瓨鍦"); + } + worker.setCanTransferOrder(canTransferOrder); + if (StrUtil.isNotBlank(worker.getRegion())) { + WorkerRedisVo workerRedisVo = workerRedisCacheUtil.get(worker.getRegion(), worker.getWorkerId()); + if (workerRedisVo != null) { + workerRedisVo.setWorker(worker); + workerRedisCacheUtil.update(worker.getRegion(), workerRedisVo); + } + } + return ResultUtil.success("鎿嶄綔鎴愬姛"); + } + /** * 閰嶉佸憳涓婄嚎 * diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/MallDeliveryOrderMapper.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/MallDeliveryOrderMapper.java index 56298d6b..f84d87bf 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/MallDeliveryOrderMapper.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/MallDeliveryOrderMapper.java @@ -53,6 +53,16 @@ public interface MallDeliveryOrderMapper extends BaseMapper { List countOrdersLimit(@Param("regionId") String regionId); + /** + * 鍚庡彴锛氭寜鏃ユ湡鑼冨洿鍒嗛〉鏌ヨ閰嶉佸憳閰嶉佸崟閲忔帓鍚嶏紙鍏ㄩ儴鏁版嵁锛 + */ + IPage countOrdersPage(IPage page, @Param("q") MallDeliveryOrderPageQuery q); + + /** + * 鍚庡彴锛氭寜鏃ユ湡鑼冨洿鍒嗛〉鏌ヨ涓浆閰嶉佸憳閰嶉佸崟閲忔帓鍚嶏紙鍏ㄩ儴鏁版嵁锛 + */ + IPage countTransferOrdersPage(IPage page, @Param("q") MallDeliveryOrderPageQuery q); + List> countOrdersByStatus(@Param("workerId") String workerId); MallDeliveryOrder selectByGroupId(@Param("orderId") String orderId); diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallDeliveryOrder.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallDeliveryOrder.java index 894835d6..4133e225 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallDeliveryOrder.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallDeliveryOrder.java @@ -109,6 +109,12 @@ public class MallDeliveryOrder implements Serializable { private String transferArriveImage; @ApiModelProperty(value = "涓浆鍙栭鐮") private String transferPickupCode; + @ApiModelProperty(value = "涓浆閰嶉佸憳ID") + private String transferWorkerId; + @ApiModelProperty(value = "涓浆閰嶉佸憳鍚嶇О") + private String transferWorkerName; + @ApiModelProperty(value = "涓浆閰嶉佸憳鐢佃瘽") + private String transferWorkerMobile; @Transient @TableField(exist = false) @ApiModelProperty(value = "鍟嗗鍑洪鏃堕棿") 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 a75dbff5..4de41eea 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 @@ -178,6 +178,9 @@ public class Shop extends HiverBaseEntity { @ApiModelProperty(value = "1澶栧崠鍟嗗 / 2鍥㈣喘鍟嗗") private Integer merchantType; + @ApiModelProperty(value = "璧烽佷环鏍") + private BigDecimal startingPrice; + @ApiModelProperty(value = "鏄庡帹浜伓瑙嗛鍦板潃") private String openKitchenVideoUrl; @@ -217,6 +220,12 @@ public class Shop extends HiverBaseEntity { @ApiModelProperty(value = "涓浆鍦扮偣鍚嶇О") private String transferAddressName; + @ApiModelProperty(value = "澶ц秼浜戞墦鍗版満SN") + private String printerSn; + + @ApiModelProperty(value = "澶ц秼浜戞墦鍗版満鍚嶇О") + private String printerName; + @Transient @TableField(exist = false) @ApiModelProperty(value = "搴楅摵鎶戒剑绛夎缃") 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 18cf04a7..0d060e39 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 @@ -64,17 +64,21 @@ public class ShopArea extends HiverBaseEntity { @ApiModelProperty(value = "杩斾剑姣斾緥锛屾寜鐧惧垎姣旇绠") private Integer commissionRatio = 0; - @ApiModelProperty(value = "鍖哄煙涓績缁忓害锛堜粎涓绾у尯鍩燂紝鐢ㄤ簬瀹氫綅鑷姩鍖归厤锛") + @ApiModelProperty(value = "鍖哄煙涓績缁忓害锛堟棫瀛楁锛屼粎涓绾у尯鍩燂級") @Column(precision = 12, scale = 6) private BigDecimal centerLng; - @ApiModelProperty(value = "鍖哄煙涓績绾害锛堜粎涓绾у尯鍩燂紝鐢ㄤ簬瀹氫綅鑷姩鍖归厤锛") + @ApiModelProperty(value = "鍖哄煙涓績绾害锛堟棫瀛楁锛屼粎涓绾у尯鍩燂級") @Column(precision = 12, scale = 6) private BigDecimal centerLat; - @ApiModelProperty(value = "鑷姩鍖归厤鍗婂緞锛堢背锛屼粎涓绾у尯鍩燂級") + @ApiModelProperty(value = "鑷姩鍖归厤鍗婂緞锛堟棫瀛楁锛岀背锛屼粎涓绾у尯鍩燂級") private Integer radiusMeters; + @ApiModelProperty(value = "瀹氫綅鑷姩鍖归厤澶氳竟褰㈠潗鏍嘕SON锛堜粎涓绾у尯鍩燂紝GCJ-02锛岀粡绾害鏁扮粍锛") + @Column(columnDefinition = "text") + private String geoPolygon; + @ApiModelProperty(value = "鍖哄煙绫诲瀷锛1鏍″洯鍖哄煙 2绀句細鍖哄煙锛堜粎涓绾у尯鍩燂級") @Column(nullable = false, columnDefinition = "int default 1") private Integer areaKind = 1; diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/ShopTakeaway.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/ShopTakeaway.java index bde29c40..21a76212 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/ShopTakeaway.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/ShopTakeaway.java @@ -16,6 +16,7 @@ limitations under the License. package cc.hiver.mall.entity; import cc.hiver.core.base.HiverBaseEntity; +import cc.hiver.mall.pojo.dto.BusinessHourPeriod; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import io.swagger.annotations.ApiModel; @@ -26,7 +27,9 @@ import org.hibernate.annotations.DynamicUpdate; import javax.persistence.Entity; import javax.persistence.Table; +import javax.persistence.Transient; import java.math.BigDecimal; +import java.util.List; /** * 搴楅摵澶栧崠涓氬姟閰嶇疆瀹炰綋绫 @@ -71,6 +74,14 @@ public class ShopTakeaway extends HiverBaseEntity { @ApiModelProperty(value = "钀ヤ笟缁撴潫鏃堕棿") private String businessHourEnd; + @ApiModelProperty(value = "钀ヤ笟鏃舵JSON锛屼緥锛歔{\"begin\":\"09:00\",\"end\":\"14:00\"}]") + private String businessHours; + + @Transient + @TableField(exist = false) + @ApiModelProperty(value = "钀ヤ笟鏃舵鍒楄〃") + private List businessHourList; + @ApiModelProperty(value = "鐘舵 0姝e父钀ヤ笟 1鏆傚仠钀ヤ笟 2鍐荤粨") private Integer status; diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/UserAddress.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/UserAddress.java index 647e6d7e..55f0b76e 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/UserAddress.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/UserAddress.java @@ -7,6 +7,8 @@ import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; +import java.math.BigDecimal; + @Data @EqualsAndHashCode(callSuper = true) @ApiModel(value = "鐢ㄦ埛鏀惰揣鍦板潃") @@ -45,6 +47,12 @@ public class UserAddress extends HiverBaseEntity { @ApiModelProperty(value = "鍖哄煙鍚嶇О") private String areaName; + @ApiModelProperty(value = "鏀惰揣鍦板潃缁忓害锛堢ぞ浼氬尯鍩熻嚜鐢卞湴鍧锛") + private BigDecimal addressLng; + + @ApiModelProperty(value = "鏀惰揣鍦板潃绾害锛堢ぞ浼氬尯鍩熻嚜鐢卞湴鍧锛") + private BigDecimal addressLat; + @ApiModelProperty(value = "鏄惁榛樿鍦板潃 (0鍚 1鏄)") private Integer isDefault; } diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/mq/OrderAsyncProducer.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/mq/OrderAsyncProducer.java index 5f84054a..b6fce075 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/mq/OrderAsyncProducer.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/mq/OrderAsyncProducer.java @@ -53,6 +53,37 @@ public class OrderAsyncProducer { log.info("銆愯鍗昅Q銆戝凡鍙戝嚭閰嶉佸畬鎴愬紓姝ユ敹灏句换鍔, deliveryId={}", params.get("deliveryId")); } + public void sendCloudPrint(String orderId, String printReason) { + sendCloudPrint(orderId, printReason, 0); + } + + public void sendCloudPrint(String orderId, String printReason, int retryCount) { + Map msg = new HashMap<>(); + msg.put("orderId", orderId); + msg.put("printReason", printReason); + msg.put("retryCount", retryCount); + msg.put("timestamp", System.currentTimeMillis()); + rabbitTemplate.convertAndSend(OrderQueueConfig.ORDER_DIRECT_EXCHANGE, OrderQueueConfig.ASYNC_PRINT_ROUTING, JSON.toJSONString(msg)); + log.info("銆愪簯鎵撳嵃MQ銆戝凡鍙戝嚭浜戞墦鍗颁换鍔, orderId={}, reason={}, retryCount={}", orderId, printReason, retryCount); + } + + public void sendCloudPrintDelayRetry(String orderId, String printReason, int retryCount, long delayMillis) { + Map msg = new HashMap<>(); + msg.put("orderId", orderId); + msg.put("printReason", printReason); + msg.put("retryCount", retryCount); + msg.put("timestamp", System.currentTimeMillis()); + rabbitTemplate.convertAndSend(OrderQueueConfig.ORDER_DIRECT_EXCHANGE, + OrderQueueConfig.ASYNC_PRINT_RETRY_DELAY_ROUTING, + JSON.toJSONString(msg), + message -> { + message.getMessageProperties().setExpiration(String.valueOf(delayMillis)); + return message; + }); + log.info("銆愪簯鎵撳嵃MQ銆戝凡鍙戝嚭浜戞墦鍗板欢杩熼噸璇曚换鍔, orderId={}, reason={}, retryCount={}, delayMillis={}", + orderId, printReason, retryCount, delayMillis); + } + /** * 鍙戦侀娆/鍞悗鐢宠瓒呮椂寤舵椂娑堟伅锛堥粯璁1灏忔椂鍚庤嚜鍔ㄥ悓鎰忥級 * @param refundId 閫娆捐褰旾D锛圡allRefundRecord.id锛 diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/mq/OrderCloudPrintConsumer.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/mq/OrderCloudPrintConsumer.java new file mode 100644 index 00000000..eb192753 --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/mq/OrderCloudPrintConsumer.java @@ -0,0 +1,50 @@ +package cc.hiver.mall.mq; + +import cc.hiver.mall.utils.DaQuCloudPrintService; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class OrderCloudPrintConsumer { + private static final int MAX_RETRY_COUNT = 3; + private static final long[] RETRY_DELAY_MILLIS = { + 60 * 1000L, + 3 * 60 * 1000L, + 5 * 60 * 1000L + }; + + @Autowired + private DaQuCloudPrintService daQuCloudPrintService; + + @Autowired + private OrderAsyncProducer orderAsyncProducer; + + @RabbitListener(queues = OrderQueueConfig.ASYNC_PRINT_QUEUE) + public void handleCloudPrint(String message) { + String orderId = null; + String printReason = null; + int retryCount = 0; + try { + JSONObject body = JSON.parseObject(message); + orderId = body.getString("orderId"); + printReason = body.getString("printReason"); + retryCount = body.getIntValue("retryCount"); + daQuCloudPrintService.printOrder(orderId, printReason); + } catch (Exception e) { + if (orderId != null && retryCount < MAX_RETRY_COUNT) { + int nextRetryCount = retryCount + 1; + long delayMillis = RETRY_DELAY_MILLIS[Math.min(retryCount, RETRY_DELAY_MILLIS.length - 1)]; + log.warn("銆愪簯鎵撳嵃MQ銆戝鐞嗗け璐ワ紝鍑嗗寤惰繜閲嶈瘯銆俹rderId={}, reason={}, retryCount={}, delayMillis={}, err={}", + orderId, printReason, nextRetryCount, delayMillis, e.getMessage()); + orderAsyncProducer.sendCloudPrintDelayRetry(orderId, printReason, nextRetryCount, delayMillis); + return; + } + log.error("銆愪簯鎵撳嵃MQ銆戝鐞嗗け璐ワ紝宸茶揪鍒版渶澶ч噸璇曟鏁帮紝涓嶅奖鍝嶈鍗曚富娴佺▼銆俶essage={}, err={}", message, e.getMessage(), e); + } + } +} diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/mq/OrderQueueConfig.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/mq/OrderQueueConfig.java index add55809..e2a397e9 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/mq/OrderQueueConfig.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/mq/OrderQueueConfig.java @@ -25,6 +25,11 @@ public class OrderQueueConfig { public static final String ASYNC_CACHE_QUEUE = "order.async.cache.queue"; public static final String ASYNC_CACHE_ROUTING = "order.async.cache.routing.key"; + public static final String ASYNC_PRINT_QUEUE = "order.async.print.queue"; + public static final String ASYNC_PRINT_ROUTING = "order.async.print.routing.key"; + public static final String ASYNC_PRINT_RETRY_DELAY_QUEUE = "order.async.print.retry.delay.queue"; + public static final String ASYNC_PRINT_RETRY_DELAY_ROUTING = "order.async.print.retry.delay.routing.key"; + // 寤舵椂娑堟伅 DLX 閰嶇疆 // 鍘熺悊锛氬皢娑堟伅鍙戣嚦 delay 闃熷垪(娌℃湁娑堣垂鑰)锛岀瓑杩囨湡鍚庯紝鐢 rabbitmq 鑷姩鎶涘叆 dead 浜ゆ崲鏈猴紝鏈缁堣繘鍏 dead 闃熷垪渚涙秷璐广 public static final String DELAY_EXCHANGE = "order.delay.exchange"; @@ -62,6 +67,29 @@ public class OrderQueueConfig { return BindingBuilder.bind(asyncCacheQueue()).to(orderDirectExchange()).with(ASYNC_CACHE_ROUTING); } + @Bean + public Queue asyncPrintQueue() { + return new Queue(ASYNC_PRINT_QUEUE, true); + } + + @Bean + public Binding bindingAsyncPrintQueue() { + return BindingBuilder.bind(asyncPrintQueue()).to(orderDirectExchange()).with(ASYNC_PRINT_ROUTING); + } + + @Bean + public Queue asyncPrintRetryDelayQueue() { + Map args = new HashMap<>(2); + args.put("x-dead-letter-exchange", ORDER_DIRECT_EXCHANGE); + args.put("x-dead-letter-routing-key", ASYNC_PRINT_ROUTING); + return new Queue(ASYNC_PRINT_RETRY_DELAY_QUEUE, true, false, false, args); + } + + @Bean + public Binding bindingAsyncPrintRetryDelayQueue() { + return BindingBuilder.bind(asyncPrintRetryDelayQueue()).to(orderDirectExchange()).with(ASYNC_PRINT_RETRY_DELAY_ROUTING); + } + // ----------------- 姝讳俊(寤舵椂)鏋舵瀯閰嶇疆 ----------------- @Bean diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/dto/BusinessHourPeriod.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/dto/BusinessHourPeriod.java new file mode 100644 index 00000000..0913237b --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/dto/BusinessHourPeriod.java @@ -0,0 +1,22 @@ +package cc.hiver.mall.pojo.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** + * 钀ヤ笟鏃舵 + */ +@Data +@ApiModel("钀ヤ笟鏃舵") +public class BusinessHourPeriod implements Serializable { + private static final long serialVersionUID = 1L; + + @ApiModelProperty("寮濮嬫椂闂 HH:mm") + private String begin; + + @ApiModelProperty("缁撴潫鏃堕棿 HH:mm") + private String end; +} diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/query/MallDeliveryOrderPageQuery.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/query/MallDeliveryOrderPageQuery.java index 448b77b1..8a740788 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/query/MallDeliveryOrderPageQuery.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/query/MallDeliveryOrderPageQuery.java @@ -68,6 +68,15 @@ public class MallDeliveryOrderPageQuery extends HiverBasePageQuery { @ApiModelProperty("鏄惁鍙煡璇㈡湭閫佽揪涓浆鐐") private Boolean transferArriveEmpty; + @ApiModelProperty("涓浆閰嶉佸憳ID") + private String transferWorkerId; + + @ApiModelProperty("鏄惁閰嶉佸憳涓浆鎺ュ崟瑙嗚") + private Boolean transferWorkerView; + + @ApiModelProperty("閰嶉佸憳涓浆瑙嗚鏄惁鏌ヨ宸叉帴鍗曞緟閫佽揪") + private Boolean transferWorkerAccepted; + @ApiModelProperty("鎺掑簭瑙勫垯锛堝鏋滄湁鍊间笖涓篸eliveryFee锛屽垯鎸変剑閲戦檷搴忥級") private String order; diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/ShopAreaService.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/ShopAreaService.java index 82d271c7..9fd98228 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/ShopAreaService.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/ShopAreaService.java @@ -59,8 +59,8 @@ public interface ShopAreaService extends HiverBaseService { ShopArea findTopShopAreaById(String id); /** - * 鏍规嵁缁忕含搴﹀尮閰嶄竴绾у尯鍩燂紙鐐+鍗婂緞锛 - * 浠呰繑鍥炲崐寰勫唴鍛戒腑鐨勬牎鍖猴紱閮戒笉鍦ㄥ崐寰勫唴鍒欒繑鍥 null + * 鏍规嵁缁忕含搴﹀尮閰嶄竴绾у尯鍩燂紙鐐瑰湪澶氳竟褰㈠唴锛 + * 浠呰繑鍥炲尮閰嶈寖鍥村唴鍛戒腑鐨勫尯鍩燂紱鏈粯鍒惰寖鍥存垨鏈懡涓垯杩斿洖 null * * @param lat 绾害 * @param lng 缁忓害 diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallDeliveryOrderService.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallDeliveryOrderService.java index cc3760fa..22b0b695 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallDeliveryOrderService.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/MallDeliveryOrderService.java @@ -82,6 +82,16 @@ public interface MallDeliveryOrderService extends IService { List countOrdersLimit(String regionId); + /** + * 鍚庡彴锛氭寜鏃ユ湡鑼冨洿鍒嗛〉鏌ヨ閰嶉佸憳閰嶉佸崟閲忔帓鍚 + */ + IPage countOrdersPage(MallDeliveryOrderPageQuery q); + + /** + * 鍚庡彴锛氭寜鏃ユ湡鑼冨洿鍒嗛〉鏌ヨ涓浆閰嶉佸憳閰嶉佸崟閲忔帓鍚 + */ + IPage countTransferOrdersPage(MallDeliveryOrderPageQuery q); + List> countOrdersByType(String regionId); List> countOrdersByTypeAdmin(MallDeliveryOrderPageQuery q); diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/ShopAreaServiceImpl.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/ShopAreaServiceImpl.java index 0e9e4d0d..663a5b7b 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/ShopAreaServiceImpl.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/ShopAreaServiceImpl.java @@ -7,13 +7,14 @@ import cc.hiver.mall.dao.ShopAreaDao; import cc.hiver.mall.entity.ShopArea; import cc.hiver.mall.service.ShopAreaService; import cn.hutool.core.text.CharSequenceUtil; +import cn.hutool.json.JSONArray; import cn.hutool.json.JSONUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.math.BigDecimal; +import java.util.ArrayList; import java.util.List; /** @@ -25,7 +26,6 @@ import java.util.List; @Service @Transactional public class ShopAreaServiceImpl implements ShopAreaService { - private static final double EARTH_RADIUS_METERS = 6371000D; @Autowired private ShopAreaDao shopAreaDao; @@ -113,32 +113,98 @@ public class ShopAreaServiceImpl implements ShopAreaService { if (rootAreas == null || rootAreas.isEmpty()) { return null; } - ShopArea best = null; - double bestDistance = Double.MAX_VALUE; for (ShopArea area : rootAreas) { - BigDecimal centerLat = area.getCenterLat(); - BigDecimal centerLng = area.getCenterLng(); - Integer radiusMeters = area.getRadiusMeters(); - if (centerLat == null || centerLng == null || radiusMeters == null || radiusMeters <= 0) { + List polygon = parseGeoPolygon(area.getGeoPolygon()); + if (polygon.size() < 3) { continue; } - double distance = distanceMeters(lat, lng, centerLat.doubleValue(), centerLng.doubleValue()); - if (distance <= radiusMeters && distance < bestDistance) { - best = area; - bestDistance = distance; + if (containsPoint(polygon, lng, lat)) { + return area; } } - return best; + return null; } - private double distanceMeters(double lat1, double lng1, double lat2, double lng2) { - double dLat = Math.toRadians(lat2 - lat1); - double dLng = Math.toRadians(lng2 - lng1); - double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) - + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) - * Math.sin(dLng / 2) * Math.sin(dLng / 2); - double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); - return EARTH_RADIUS_METERS * c; + private List parseGeoPolygon(String geoPolygon) { + List points = new ArrayList<>(); + if (CharSequenceUtil.isBlank(geoPolygon)) { + return points; + } + try { + JSONArray array = JSONUtil.parseArray(geoPolygon); + for (Object item : array) { + Double pointLng = null; + Double pointLat = null; + if (item instanceof JSONArray) { + JSONArray point = (JSONArray) item; + if (point.size() >= 2) { + pointLng = point.getDouble(0); + pointLat = point.getDouble(1); + } + } else if (item instanceof java.util.List) { + java.util.List point = (java.util.List) item; + if (point.size() >= 2) { + pointLng = toDouble(point.get(0)); + pointLat = toDouble(point.get(1)); + } + } else if (item instanceof java.util.Map) { + java.util.Map point = (java.util.Map) item; + pointLng = toDouble(point.get("lng")); + pointLat = toDouble(point.get("lat")); + } + if (isValidLngLat(pointLng, pointLat)) { + points.add(new double[]{pointLng, pointLat}); + } + } + } catch (Exception ignored) { + return new ArrayList<>(); + } + return points; + } + + private Double toDouble(Object value) { + if (value == null) { + return null; + } + try { + return Double.valueOf(String.valueOf(value)); + } catch (Exception e) { + return null; + } + } + + private boolean isValidLngLat(Double lng, Double lat) { + return lng != null && lat != null + && lng >= -180 && lng <= 180 + && lat >= -90 && lat <= 90; + } + + private boolean containsPoint(List polygon, double lng, double lat) { + boolean inside = false; + for (int i = 0, j = polygon.size() - 1; i < polygon.size(); j = i++) { + double[] pi = polygon.get(i); + double[] pj = polygon.get(j); + if (isPointOnSegment(lng, lat, pj[0], pj[1], pi[0], pi[1])) { + return true; + } + boolean intersects = ((pi[1] > lat) != (pj[1] > lat)) + && (lng < (pj[0] - pi[0]) * (lat - pi[1]) / (pj[1] - pi[1]) + pi[0]); + if (intersects) { + inside = !inside; + } + } + return inside; + } + + private boolean isPointOnSegment(double x, double y, double x1, double y1, double x2, double y2) { + double cross = (x - x1) * (y2 - y1) - (y - y1) * (x2 - x1); + if (Math.abs(cross) > 1e-10) { + return false; + } + return x >= Math.min(x1, x2) - 1e-10 + && x <= Math.max(x1, x2) + 1e-10 + && y >= Math.min(y1, y2) - 1e-10 + && y <= Math.max(y1, y2) + 1e-10; } @Override 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 08b387f6..2af53e2e 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 @@ -40,6 +40,7 @@ import cc.hiver.mall.productpicture.service.ProductPictureService; import cc.hiver.mall.service.ShopService; import cc.hiver.mall.service.mybatis.ProductGroupBuyPriceService; import cc.hiver.mall.utils.DateUtil; +import cc.hiver.mall.utils.ShopBusinessHourUtil; import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.core.metadata.IPage; @@ -56,8 +57,6 @@ import org.springframework.transaction.annotation.Transactional; import javax.persistence.criteria.*; import java.math.BigDecimal; -import java.time.LocalTime; -import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -71,7 +70,6 @@ import java.util.Map; @Transactional public class ShopServiceImpl implements ShopService { private static final String GROUP_BUY_DEFAULT_PAGE_CACHE_PREFIX = "GROUP_BUY_DEFAULT_SHOP_PAGE:"; - private static final DateTimeFormatter BUSINESS_TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm"); @Autowired private ShopDao shopDao; @@ -115,12 +113,11 @@ public class ShopServiceImpl implements ShopService { public Page findByCondition(Shop shop, Pageable pageable) { boolean adminQuery = CharSequenceUtil.isNotBlank(shop.getShopIcon()); Sort pageSort = pageable.getSort(); - if (adminQuery) { + if (pageable.isPaged()) { pageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), Sort.unsorted()); } else { - pageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), Sort.unsorted()); + pageable = Pageable.unpaged(); } - String currentBusinessTime = LocalTime.now().format(BUSINESS_TIME_FORMATTER); return shopDao.findAll(new Specification() { @Nullable @Override @@ -136,26 +133,30 @@ public class ShopServiceImpl implements ShopService { final List list = new ArrayList<>(); if (CharSequenceUtil.isNotBlank(shop.getKeyWord()) && !"zhuyesearch".equals(shop.getKeyWord())) { String keyword = shop.getKeyWord(); - com.baomidou.mybatisplus.core.conditions.query.QueryWrapper qw = new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<>(); - qw.select("shop_id").like("product_name", keyword); - List productList = productMapper.selectList(qw); - - List shopIds = new ArrayList<>(); - if (productList != null && !productList.isEmpty()) { - for (cc.hiver.mall.entity.Product p : productList) { - if (p.getShopId() != null && !shopIds.contains(p.getShopId())) { - shopIds.add(p.getShopId()); + if (adminQuery) { + list.add(cb.like(ShopNameField, '%' + keyword + '%')); + } else { + com.baomidou.mybatisplus.core.conditions.query.QueryWrapper qw = new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<>(); + qw.select("distinct shop_id").like("product_name", keyword); + List productShopIdList = productMapper.selectObjs(qw); + + List shopIds = new ArrayList<>(); + if (productShopIdList != null && !productShopIdList.isEmpty()) { + for (Object shopId : productShopIdList) { + if (shopId != null) { + shopIds.add(String.valueOf(shopId)); + } } } - } - - if (!shopIds.isEmpty()) { - Path idField = root.get("id"); - Predicate namePredicate = cb.like(ShopNameField, '%' + keyword + '%'); - Predicate idPredicate = idField.in(shopIds); - list.add(cb.or(namePredicate, idPredicate)); - } else { - list.add(cb.like(ShopNameField, '%' + keyword + '%')); + + if (!shopIds.isEmpty()) { + Path idField = root.get("id"); + Predicate namePredicate = cb.like(ShopNameField, '%' + keyword + '%'); + Predicate idPredicate = idField.in(shopIds); + list.add(cb.or(namePredicate, idPredicate)); + } else { + list.add(cb.like(ShopNameField, '%' + keyword + '%')); + } } } if (CharSequenceUtil.isNotBlank(shop.getShopName())) { @@ -200,10 +201,8 @@ public class ShopServiceImpl implements ShopService { } cq.orderBy(orderList); } else if (!isCountQuery(cq)) { + // 鐢ㄦ埛绔惀涓氭椂娈垫帓搴忔敼鐢卞唴瀛樻寜 businessHours JSON 鍏ㄩ噺鎺掑簭鍚庡啀鍒嗛〉锛屾澶勪粎淇濈暀璇锋眰渚ф瑕佹帓搴 List orderList = new ArrayList<>(); - orderList.add(cb.asc(buildShopStatusOrder(statusField, cb))); - orderList.add(cb.asc(buildTakeawayStatusOrder(root, cq, cb))); - orderList.add(cb.asc(buildBusinessTimeOrder(root, cq, cb, currentBusinessTime))); for (Sort.Order order : pageSort) { if ("status".equals(order.getProperty())) { continue; @@ -211,7 +210,9 @@ public class ShopServiceImpl implements ShopService { Path sortField = root.get(order.getProperty()); orderList.add(order.isAscending() ? cb.asc(sortField) : cb.desc(sortField)); } - cq.orderBy(orderList); + if (!orderList.isEmpty()) { + cq.orderBy(orderList); + } } return null; } @@ -223,63 +224,6 @@ public class ShopServiceImpl implements ShopService { return Long.class.equals(resultType) || long.class.equals(resultType); } - private Expression buildShopStatusOrder(Path statusField, CriteriaBuilder cb) { - return cb.selectCase() - .when(cb.equal(statusField, ShopConstant.SHOP_STATUS_NORMAL), 0) - .otherwise(1); - } - - private Expression buildTakeawayStatusOrder(Root root, CriteriaQuery cq, CriteriaBuilder cb) { - Subquery statusQuery = cq.subquery(Integer.class); - Root takeawayRoot = statusQuery.from(ShopTakeaway.class); - statusQuery.select(cb.min(takeawayRoot.get("status"))); - statusQuery.where(cb.equal(takeawayRoot.get("shopId"), root.get("id"))); - return cb.selectCase() - .when(cb.isNull(statusQuery), 99) - .otherwise(statusQuery); - } - - private Expression buildBusinessTimeOrder(Root root, CriteriaQuery cq, CriteriaBuilder cb, String currentTime) { - Subquery beginQuery = buildTakeawayStringSubquery(root, cq, cb, "businessHourBegin"); - Subquery endQuery = buildTakeawayStringSubquery(root, cq, cb, "businessHourEnd"); - Expression now = cb.literal(currentTime); - Expression missingTime = cb.or( - cb.isNull(beginQuery), - cb.isNull(endQuery), - cb.equal(beginQuery, ""), - cb.equal(endQuery, "") - ); - Expression sameDayRange = cb.lessThanOrEqualTo(beginQuery, endQuery); - Expression allDayRange = cb.equal(beginQuery, endQuery); - Expression inSameDayRange = cb.and( - cb.lessThanOrEqualTo(beginQuery, now), - cb.greaterThanOrEqualTo(endQuery, now) - ); - Expression inOvernightRange = cb.or( - cb.lessThanOrEqualTo(beginQuery, now), - cb.greaterThanOrEqualTo(endQuery, now) - ); - Expression sameDayResult = cb.selectCase() - .when(inSameDayRange, 0) - .otherwise(1); - Expression overnightResult = cb.selectCase() - .when(inOvernightRange, 0) - .otherwise(1); - return cb.selectCase() - .when(missingTime, 1) - .when(allDayRange, 0) - .when(sameDayRange, sameDayResult) - .otherwise(overnightResult); - } - - private Subquery buildTakeawayStringSubquery(Root root, CriteriaQuery cq, CriteriaBuilder cb, String fieldName) { - Subquery subquery = cq.subquery(String.class); - Root takeawayRoot = subquery.from(ShopTakeaway.class); - subquery.select(cb.least(takeawayRoot.get(fieldName))); - subquery.where(cb.equal(takeawayRoot.get("shopId"), root.get("id"))); - return subquery; - } - @Override public Shop findByShopName(String ShopName) { return shopDao.findByShopName(ShopName); @@ -419,6 +363,9 @@ public class ShopServiceImpl implements ShopService { cacheDTO.setShop(shop); ShopTakeaway takeaway = shopTakeawayMapper.selectByPrimaryKey(shopId); + if (takeaway != null) { + ShopBusinessHourUtil.fillBusinessHourList(takeaway); + } cacheDTO.setShopTakeaway(takeaway); ProductPageQuery query = new ProductPageQuery(); diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/ShopTakeawayServiceImpl.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/ShopTakeawayServiceImpl.java index 751e5d7c..11a06ccf 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/ShopTakeawayServiceImpl.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/ShopTakeawayServiceImpl.java @@ -20,6 +20,7 @@ import cc.hiver.mall.entity.Shop; import cc.hiver.mall.entity.ShopTakeaway; import cc.hiver.mall.service.ShopService; import cc.hiver.mall.service.ShopTakeawayService; +import cc.hiver.mall.utils.ShopBusinessHourUtil; import cn.hutool.core.text.CharSequenceUtil; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.extern.slf4j.Slf4j; @@ -49,7 +50,9 @@ public class ShopTakeawayServiceImpl extends ServiceImpl selectListByshopId(List shopIdList) { - return shopTakeawayMapper.selectListByshopId(shopIdList); + List list = shopTakeawayMapper.selectListByshopId(shopIdList); + if (list != null) { + for (ShopTakeaway takeaway : list) { + ShopBusinessHourUtil.fillBusinessHourList(takeaway); + } + } + return list; } } diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallDeliveryOrderServiceImpl.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallDeliveryOrderServiceImpl.java index 827294df..da617d9c 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallDeliveryOrderServiceImpl.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallDeliveryOrderServiceImpl.java @@ -18,6 +18,7 @@ import cc.hiver.mall.pojo.query.MallDeliveryOrderPageQuery; import cc.hiver.mall.pojo.query.MallRefundRecordPageQuery; import cc.hiver.mall.pojo.vo.MallOrderFreeVO; import cc.hiver.mall.pojo.vo.MallOrderVO; +import cc.hiver.mall.pojo.vo.WorkerRedisVo; import cc.hiver.mall.service.mybatis.*; import cc.hiver.mall.utils.*; import cn.hutool.json.JSONUtil; @@ -129,6 +130,9 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl workerRedisVoList = workerRedisCacheUtil.getAll(delivery.getRegionId()); + if (workerRedisVoList == null || workerRedisVoList.isEmpty()) { + return; + } + String pushId = StringUtils.defaultIfBlank(delivery.getOrderId(), delivery.getId()); + Set clientIds = new LinkedHashSet<>(); + for (WorkerRedisVo workerRedisVo : workerRedisVoList) { + Worker worker = workerRedisVo == null ? null : workerRedisVo.getWorker(); + if (worker == null + || !Integer.valueOf(1).equals(worker.getCanTransferOrder()) + || !Integer.valueOf(1).equals(worker.getIsOnLine()) + || Integer.valueOf(3).equals(worker.getWorkerStatus()) + || StringUtils.isBlank(worker.getClientId())) { + continue; + } + clientIds.add(worker.getClientId()); + } + for (String clientId : clientIds) { + try { + jPushService.sendPushNotification(clientId, "鎮ㄦ湁涓绗旀柊鐨勪腑杞厤閫佸崟锛岃鍙婃椂鎺ュ崟", pushId); + } catch (Exception e) { + log.warn("涓浆閰嶉佹帹閫佸け璐, deliveryId={}, err={}", delivery.getId(), e.getMessage()); + } + } + } + private String resolveShopPushClientId(MallOrder order) { if (order == null || StringUtils.isBlank(order.getShopId())) { return null; @@ -1131,6 +1173,18 @@ public class MallDeliveryOrderServiceImpl extends ServiceImpl countOrdersPage(MallDeliveryOrderPageQuery q) { + IPage page = new Page<>(q.getPageNum(), q.getPageSize()); + return this.baseMapper.countOrdersPage(page, q); + } + + @Override + public IPage countTransferOrdersPage(MallDeliveryOrderPageQuery q) { + IPage page = new Page<>(q.getPageNum(), q.getPageSize()); + return this.baseMapper.countTransferOrdersPage(page, q); + } + @Override public List> countOrdersByType(String regionId) { return this.baseMapper.countOrdersByType(regionId); diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderGroupServiceImpl.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderGroupServiceImpl.java index 22ff8fd9..08ca3c15 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderGroupServiceImpl.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderGroupServiceImpl.java @@ -186,6 +186,7 @@ public class MallOrderGroupServiceImpl extends ServiceImpl duw = new LambdaUpdateWrapper<>(); duw.eq(MallDeliveryOrder::getOrderId, delivery.getOrderId()) - .set(MallDeliveryOrder::getStatus, 4); + .set(MallDeliveryOrder::getStatus, deliveryTargetStatus); mallDeliveryOrderMapper.update(null, duw); //鏇存柊缂撳瓨 - LambdaQueryWrapper qw = new LambdaQueryWrapper<>(); - qw.eq(MallDeliveryOrder::getOrderId, delivery.getOrderId()); - MallDeliveryOrder deliveryOrder = mallDeliveryOrderMapper.selectOne(qw); workerOrderCacheUtil.remove(delivery.getWorkerId(),delivery.getId()); } }else{ //鏇存柊閰嶉佸崟 LambdaUpdateWrapper duw = new LambdaUpdateWrapper<>(); duw.eq(MallDeliveryOrder::getOrderId, mallRefundRecord.getOrderId()) - .set(MallDeliveryOrder::getStatus, 4); + .set(MallDeliveryOrder::getStatus, deliveryTargetStatus); mallDeliveryOrderMapper.update(null, duw); //鏇存柊缂撳瓨 LambdaQueryWrapper qw = new LambdaQueryWrapper<>(); qw.eq(MallDeliveryOrder::getOrderId, mallRefundRecord.getOrderId()); MallDeliveryOrder deliveryOrder = mallDeliveryOrderMapper.selectOne(qw); - workerOrderCacheUtil.remove(deliveryOrder.getWorkerId(),deliveryOrder.getId()); + if (deliveryOrder != null) { + workerOrderCacheUtil.remove(deliveryOrder.getWorkerId(),deliveryOrder.getId()); + } } } refundWechatForRefundRecord(order, mallRefundRecord); @@ -980,6 +984,8 @@ public class MallRefundRecordServiceImpl extends ServiceImpl duw = new LambdaUpdateWrapper<>(); + duw.eq(MallDeliveryOrder::getId, delivery.getId()) + .set(MallDeliveryOrder::getStatus, 4); + mallDeliveryOrderMapper.update(null, duw); + if (delivery.getWorkerId() != null) { + workerOrderCacheUtil.remove(delivery.getWorkerId(), delivery.getId()); + } + } + /** * 鏍规嵁璁㈠崟ID鏌ユ壘閰嶉佸崟 */ diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/DaQuCloudPrintService.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/DaQuCloudPrintService.java new file mode 100644 index 00000000..9d4f4af5 --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/DaQuCloudPrintService.java @@ -0,0 +1,106 @@ +package cc.hiver.mall.utils; + +import cc.hiver.mall.entity.Shop; +import cc.hiver.mall.pojo.vo.MallOrderVO; +import cc.hiver.mall.service.ShopService; +import cc.hiver.mall.service.mybatis.MallOrderService; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.concurrent.TimeUnit; + +@Component +public class DaQuCloudPrintService { + private static final Logger log = LoggerFactory.getLogger(DaQuCloudPrintService.class); + public static final String PRINTING_METHOD_CLOUD = "cloud"; + private static final String PRINT_LOCK_KEY_PREFIX = "CLOUD_PRINT:LOCK:"; + private static final String PRINT_SUCCESS_KEY_PREFIX = "CLOUD_PRINT:SUCCESS:"; + + @Autowired + private MallOrderService mallOrderService; + + @Autowired + private ShopService shopService; + + @Autowired + private DaQuPrinterUtil daQuPrinterUtil; + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + public boolean isCloudPrintShop(String shopId) { + if (StringUtils.isBlank(shopId)) { + return false; + } + Shop shop = shopService.findById(shopId); + return isCloudPrintShop(shop); + } + + public boolean isCloudPrintShop(Shop shop) { + return shop != null + && PRINTING_METHOD_CLOUD.equalsIgnoreCase(shop.getPrintingMethod()) + && StringUtils.isNotBlank(shop.getPrinterSn()); + } + + public DaQuPrinterUtil.DaQuResponse printOrder(String orderId, String printReason) throws Exception { + if (StringUtils.isBlank(orderId)) { + throw new IllegalArgumentException("orderId is blank"); + } + MallOrderVO order = mallOrderService.getOrderDetail(orderId); + if (order == null) { + throw new IllegalArgumentException("order not found: " + orderId); + } + Shop shop = shopService.findById(order.getShopId()); + if (!isCloudPrintShop(shop)) { + log.info("Skip cloud print, shop is not cloud printer. orderId={}, shopId={}", orderId, order.getShopId()); + return null; + } + String content = DaQuReceiptRenderUtil.render(order, printReason); + DaQuPrinterUtil.PrintRequest request = new DaQuPrinterUtil.PrintRequest(); + request.setSn(shop.getPrinterSn()); + request.setVoice(DaQuReceiptRenderUtil.voiceCode(printReason)); + request.setContent(content); + request.setCopies(1); + request.setExpiresInSeconds(7200); + String outTradeNo = buildOutTradeNo(orderId, printReason); + request.setOutTradeNo(outTradeNo); + String successKey = PRINT_SUCCESS_KEY_PREFIX + outTradeNo; + if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(successKey))) { + log.info("Skip cloud print, already succeeded. orderId={}, outTradeNo={}", orderId, outTradeNo); + return null; + } + String lockKey = PRINT_LOCK_KEY_PREFIX + outTradeNo; + Boolean locked = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "1", 5, TimeUnit.MINUTES); + if (!Boolean.TRUE.equals(locked)) { + throw new IllegalStateException("same cloud print outTradeNo is processing: " + outTradeNo); + } + try { + DaQuPrinterUtil.DaQuResponse response = daQuPrinterUtil.print(request); + if (response == null || !response.isSuccess()) { + log.warn("Cloud print failed. orderId={}, shopId={}, printerSn={}, responseCode={}, message={}", + orderId, order.getShopId(), shop.getPrinterSn(), + response == null ? null : response.getCode(), + response == null ? null : response.getMessage()); + throw new IllegalStateException("Cloud print failed: " + + (response == null ? "empty response" : response.getCode() + ":" + response.getMessage())); + } else { + stringRedisTemplate.opsForValue().set(successKey, "1", 7, TimeUnit.DAYS); + log.info("Cloud print accepted. orderId={}, shopId={}, printerSn={}, outTradeNo={}, data={}", + orderId, order.getShopId(), shop.getPrinterSn(), outTradeNo, response.getData()); + } + return response; + } finally { + stringRedisTemplate.delete(lockKey); + } + } + + private String buildOutTradeNo(String orderId, String printReason) { + String reason = StringUtils.defaultIfBlank(printReason, "AUTO"); + String value = orderId + "-" + reason; + return value.length() > 100 ? value.substring(0, 100) : value; + } +} diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/DaQuPrinterUtil.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/DaQuPrinterUtil.java new file mode 100644 index 00000000..b331e0e6 --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/DaQuPrinterUtil.java @@ -0,0 +1,521 @@ +package cc.hiver.mall.utils; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import okhttp3.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.util.DigestUtils; +import org.springframework.util.StringUtils; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +@Component +public class DaQuPrinterUtil { + private static final Logger log = LoggerFactory.getLogger(DaQuPrinterUtil.class); + private static final MediaType JSON_MEDIA_TYPE = MediaType.parse("application/json;charset=UTF-8"); + + private final OkHttpClient httpClient = new OkHttpClient.Builder() + .connectTimeout(10, TimeUnit.SECONDS) + .readTimeout(20, TimeUnit.SECONDS) + .writeTimeout(20, TimeUnit.SECONDS) + .build(); + + @Value("${daqu.printer.appid:}") + private String appId; + + @Value("${daqu.printer.appSecret:}") + private String appSecret; + + @Value("${daqu.printer.apiBaseUrl:https://api.trenditiot.com}") + private String apiBaseUrl; + + public DaQuResponse addPrinter(String sn, String key, String name) throws IOException { + return addPrinters(Collections.singletonList(new PrinterBindRequest(sn, key, name))); + } + + public DaQuResponse addPrinters(List printers) throws IOException { + return post("/openapi/addPrinter", printers); + } + + public DaQuResponse editPrinters(List printers) throws IOException { + return post("/openapi/editPrinter", printers); + } + + public DaQuResponse delPrinter(String sn) throws IOException { + return delPrinters(Collections.singletonList(sn)); + } + + public DaQuResponse delPrinters(List snList) throws IOException { + return post("/openapi/delPrinter", snList); + } + + public DaQuResponse print(PrintRequest printRequest) throws IOException { + return post("/openapi/print", printRequest); + } + + public DaQuResponse getPrintStatus(String sn, String printId) throws IOException { + return post("/openapi/getPrintStatus", new PrintStatusRequest(sn, printId)); + } + + public DaQuResponse getDeviceStatus(String sn) throws IOException { + return post("/openapi/getDeviceStatus", new SnRequest(sn)); + } + + public DaQuResponse batchGetDeviceStatus(List snList) throws IOException { + return post("/openapi/batchGetDeviceStatus", snList); + } + + public DaQuResponse cleanWaitingQueue(String sn) throws IOException { + return post("/openapi/cleanWaitingQueue", new SnRequest(sn)); + } + + public DaQuResponse setVolume(String sn, int volume) throws IOException { + return post("/openapi/setVolume", new VolumeRequest(sn, volume)); + } + + public DaQuResponse setImage(String sn, int index, String imageBase64) throws IOException { + return post("/openapi/setImage", new ImageRequest(sn, index, imageBase64)); + } + + public DaQuResponse payInVoice(PayInVoiceRequest request) throws IOException { + return post("/openapi/payInVoice", request); + } + + public String buildSign(String uid, long stime, String requestBody) { + checkConfig(); + String origin = uid + appId + stime + appSecret; + if (requestBody != null) { + origin += requestBody; + } + return DigestUtils.md5DigestAsHex(origin.getBytes(StandardCharsets.UTF_8)); + } + + private DaQuResponse post(String path, Object requestBody) throws IOException { + checkConfig(); + String body = requestBody == null ? null : JSON.toJSONString(requestBody); + String uid = UUID.randomUUID().toString(); + long stime = System.currentTimeMillis() / 1000; + String sign = buildSign(uid, stime, body); + + RequestBody okhttpBody = RequestBody.create(JSON_MEDIA_TYPE, body == null ? "" : body); + Request request = new Request.Builder() + .url(buildUrl(path)) + .addHeader("Content-Type", "application/json;charset=UTF-8") + .addHeader("appid", appId) + .addHeader("uid", uid) + .addHeader("stime", String.valueOf(stime)) + .addHeader("sign", sign) + .post(okhttpBody) + .build(); + + try (Response response = httpClient.newCall(request).execute()) { + String responseBody = response.body() == null ? "" : response.body().string(); + if (!response.isSuccessful()) { + log.error("DaQu printer request failed. path={}, httpStatus={}, body={}", path, response.code(), responseBody); + throw new IOException("DaQu printer request failed, httpStatus=" + response.code()); + } + return JSON.parseObject(responseBody, DaQuResponse.class); + } + } + + private String buildUrl(String path) { + String baseUrl = apiBaseUrl; + while (baseUrl.endsWith("/")) { + baseUrl = baseUrl.substring(0, baseUrl.length() - 1); + } + return baseUrl + path; + } + + private void checkConfig() { + if (!StringUtils.hasText(appId) || !StringUtils.hasText(appSecret)) { + throw new IllegalStateException("DaQu printer config is missing: daqu.printer.appid/daqu.printer.appSecret"); + } + } + + public static class DaQuResponse { + private Integer code; + private String message; + private Object data; + + public boolean isSuccess() { + return code != null && code == 0; + } + + public JSONObject getDataObject() { + if (data == null) { + return null; + } + if (data instanceof JSONObject) { + return (JSONObject) data; + } + return JSON.parseObject(JSON.toJSONString(data)); + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + } + + public static class PrinterBindRequest { + private String sn; + private String key; + private String name; + private Integer lang; + + public PrinterBindRequest() { + } + + public PrinterBindRequest(String sn, String key, String name) { + this.sn = sn; + this.key = key; + this.name = name; + } + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getLang() { + return lang; + } + + public void setLang(Integer lang) { + this.lang = lang; + } + } + + public static class PrinterEditRequest { + private String sn; + private String name; + private Integer lang; + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getLang() { + return lang; + } + + public void setLang(Integer lang) { + this.lang = lang; + } + } + + public static class PrintRequest { + private String sn; + private String voice; + private Integer voicePlayTimes; + private Integer voicePlayInterval; + private String content; + private Integer copies; + private Integer expiresInSeconds; + private String outTradeNo; + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + + public String getVoice() { + return voice; + } + + public void setVoice(String voice) { + this.voice = voice; + } + + public Integer getVoicePlayTimes() { + return voicePlayTimes; + } + + public void setVoicePlayTimes(Integer voicePlayTimes) { + this.voicePlayTimes = voicePlayTimes; + } + + public Integer getVoicePlayInterval() { + return voicePlayInterval; + } + + public void setVoicePlayInterval(Integer voicePlayInterval) { + this.voicePlayInterval = voicePlayInterval; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public Integer getCopies() { + return copies; + } + + public void setCopies(Integer copies) { + this.copies = copies; + } + + public Integer getExpiresInSeconds() { + return expiresInSeconds; + } + + public void setExpiresInSeconds(Integer expiresInSeconds) { + this.expiresInSeconds = expiresInSeconds; + } + + public String getOutTradeNo() { + return outTradeNo; + } + + public void setOutTradeNo(String outTradeNo) { + this.outTradeNo = outTradeNo; + } + } + + public static class PayInVoiceRequest { + private String sn; + private Integer payChannel; + private Integer payAmount; + private Integer voicePlayTimes; + private Integer voicePlayInterval; + private Integer expiresInSeconds; + private String outTradeNo; + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + + public Integer getPayChannel() { + return payChannel; + } + + public void setPayChannel(Integer payChannel) { + this.payChannel = payChannel; + } + + public Integer getPayAmount() { + return payAmount; + } + + public void setPayAmount(Integer payAmount) { + this.payAmount = payAmount; + } + + public Integer getVoicePlayTimes() { + return voicePlayTimes; + } + + public void setVoicePlayTimes(Integer voicePlayTimes) { + this.voicePlayTimes = voicePlayTimes; + } + + public Integer getVoicePlayInterval() { + return voicePlayInterval; + } + + public void setVoicePlayInterval(Integer voicePlayInterval) { + this.voicePlayInterval = voicePlayInterval; + } + + public Integer getExpiresInSeconds() { + return expiresInSeconds; + } + + public void setExpiresInSeconds(Integer expiresInSeconds) { + this.expiresInSeconds = expiresInSeconds; + } + + public String getOutTradeNo() { + return outTradeNo; + } + + public void setOutTradeNo(String outTradeNo) { + this.outTradeNo = outTradeNo; + } + } + + public static class PrintStatusRequest { + private String sn; + private String printId; + + public PrintStatusRequest() { + } + + public PrintStatusRequest(String sn, String printId) { + this.sn = sn; + this.printId = printId; + } + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + + public String getPrintId() { + return printId; + } + + public void setPrintId(String printId) { + this.printId = printId; + } + } + + public static class SnRequest { + private String sn; + + public SnRequest() { + } + + public SnRequest(String sn) { + this.sn = sn; + } + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + } + + public static class VolumeRequest { + private String sn; + private Integer volume; + + public VolumeRequest() { + } + + public VolumeRequest(String sn, Integer volume) { + this.sn = sn; + this.volume = volume; + } + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + + public Integer getVolume() { + return volume; + } + + public void setVolume(Integer volume) { + this.volume = volume; + } + } + + public static class ImageRequest { + private String sn; + private Integer index; + private String imageBase64; + + public ImageRequest() { + } + + public ImageRequest(String sn, Integer index, String imageBase64) { + this.sn = sn; + this.index = index; + this.imageBase64 = imageBase64; + } + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + + public Integer getIndex() { + return index; + } + + public void setIndex(Integer index) { + this.index = index; + } + + public String getImageBase64() { + return imageBase64; + } + + public void setImageBase64(String imageBase64) { + this.imageBase64 = imageBase64; + } + } +} 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 new file mode 100644 index 00000000..a7636fcd --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/DaQuReceiptRenderUtil.java @@ -0,0 +1,313 @@ +package cc.hiver.mall.utils; + +import cc.hiver.mall.entity.*; +import cc.hiver.mall.pojo.vo.MallOrderVO; +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.text.SimpleDateFormat; +import java.util.Date; +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 DaQuReceiptRenderUtil() { + } + + public static String render(MallOrderVO order, String printReason) { + StringBuilder sb = new StringBuilder(); + MallDeliveryOrder delivery = order.getDeliveryInfo(); + List refunds = order.getMallRefundRecord(); + boolean refundPrint = isRefundPrint(printReason); + boolean forcedOrderPrint = isOrderEventPrint(printReason); + boolean hasRefund = refundPrint && refunds != null && !refunds.isEmpty(); + + centerLarge(sb, orderNo(order)); + centerLarge(sb, orderTypeText(order, delivery, refundPrint, forcedOrderPrint)); + if (delivery != null && Integer.valueOf(1).equals(delivery.getAppointmentDelivery())) { + left(sb, "瑕佹眰閫佽揪鏃堕棿:" + formatTime(delivery.getMustFinishTime())); + } + left(sb, defaultString(order.getShopName())); + left(sb, "涓嬪崟鏃堕棿:" + formatTime(order.getCreateTime())); + if (!hasRefund) { + if (Integer.valueOf(1).equals(order.getDeliveryType())) { + left(sb, "棰勮閫佽揪鏃堕棿:" + formatTime(delivery == null ? null : delivery.getMustFinishTime())); + } else if (Integer.valueOf(1).equals(order.getUserRequireMake())) { + left(sb, "鏍搁攢鏃堕棿:" + formatTime(order.getCreateTime())); + } + } else { + if (Integer.valueOf(1).equals(order.getUserRequireMake()) && Integer.valueOf(2).equals(order.getDeliveryType())) { + left(sb, "鏍搁攢鏃堕棿:" + formatTime(order.getCreateTime())); + } + left(sb, "鐢宠閫娆炬椂闂:" + formatTime(refunds.get(0).getCreateTime())); + } + separator(sb); + + if (shouldPrintDeliveryAddress(order, refundPrint, forcedOrderPrint)) { + largeLeft(sb, delivery == null ? "" : delivery.getReceiverName()); + } + left(sb, "鑱旂郴鐢佃瘽: " + maskPhoneLastFour(order.getReceiverPhone())); + if (shouldPrintDeliveryAddress(order, refundPrint, forcedOrderPrint)) { + largeLeft(sb, "鍦板潃:" + (delivery == null ? "" : delivery.getReceiverAddress())); + } + left(sb, "椤惧鐢佃瘽宸茶闅愯棌锛屾偍鍙櫥褰曞晢瀹剁鎴栭獞鎵嬬鏌ョ湅"); + separator(sb); + + if (order.getGoodsList() != null) { + for (MallOrderGoods goods : order.getGoodsList()) { + largeLeft(sb, defaultString(goods.getProductName())); + if (StringUtils.contains(goods.getSpecs(), ",")) { + left(sb, delNode(goods.getSpecs())); + } + largeLeft(sb, "锟" + amount(goods.getPrice()) + " X" + safeQuantity(goods.getQuantity())); + } + } + separator(sb); + left(sb, "閰 閫 璐癸細" + amount(order.getDeliveryFee())); + if (positive(order.getPackageFee())) { + left(sb, "鎵 鍖 璐癸細" + amount(order.getPackageFee())); + } + left(sb, "鍟嗗搧閲戦锛" + amount(order.getGoodsAmount())); + if (order.getUserCoupon() != null && !order.getUserCoupon().isEmpty()) { + MallUserCoupon coupon = order.getUserCoupon().get(0); + left(sb, "浼 鎯 鍒革細-" + amount(coupon.getDiscountAmount())); + } + if (positive(order.getFreeAmount())) { + left(sb, "閿﹂菠鍏嶅崟锛-" + amount(order.getFreeAmount())); + } + left(sb, "鍚堣閲戦锛" + amount(safe(order.getGoodsAmount()).add(safe(order.getDeliveryFee())).add(safe(order.getPackageFee())))); + left(sb, (hasRefund ? "搴旈閲戦锛" : "瀹炰粯閲戦锛") + amount(order.getTotalAmount())); + largeLeft(sb, "澶囨敞锛" + defaultString(order.getRemark())); + br(sb); + + if (hasRefund) { + MallRefundRecord refund = refunds.get(0); + left(sb, "閫娆惧師鍥:" + refundReason(refund)); + appendRefundGoods(sb, refund); + } + separator(sb); + left(sb, "鍟嗗搧鍙栧埌鍚庯紝濡傛湁浠讳綍鍟嗗搧闂锛岃鍙婃椂鑱旂郴鍟嗗鍜屽钩鍙帮紝瀹㈡湇灏嗕负鎮ㄦ湇鍔★紝璋㈣阿鎮ㄧ殑鎯犻【"); + br(sb); + centerLarge(sb, "鍗婂緞閲"); + center(sb, "涓囩墿鎷煎洟鏇寸渷閽"); + br(sb); + return sb.toString(); + } + + public static String voiceCode(String printReason) { + return StringUtils.containsIgnoreCase(printReason, "refund") ? "5" : "10"; + } + + private static void appendRefundGoods(StringBuilder sb, MallRefundRecord refund) { + if (refund.getItems() == null || refund.getItems().isEmpty()) { + return; + } + separator(sb); + for (MallReturnOrderGoods goods : refund.getItems()) { + largeLeft(sb, defaultString(goods.getProductName())); + if (StringUtils.contains(goods.getSpecs(), ",")) { + left(sb, delNode(goods.getSpecs())); + } + largeLeft(sb, "锟" + amount(goods.getPrice()) + " X" + safeQuantity(goods.getQuantity())); + } + } + + private static boolean shouldPrintDeliveryAddress(MallOrderVO order, boolean refundPrint, boolean forcedOrderPrint) { + if (!Integer.valueOf(1).equals(order.getDeliveryType()) || refundPrint) { + return false; + } + if (forcedOrderPrint) { + return true; + } + Integer status = order.getStatus(); + return !Integer.valueOf(7).equals(status) + && !Integer.valueOf(11).equals(status) + && !Integer.valueOf(5).equals(status) + && !Integer.valueOf(6).equals(status) + && !Integer.valueOf(8).equals(status) + && !Integer.valueOf(12).equals(status); + } + + private static String orderNo(MallOrderVO order) { + MallDeliveryOrder delivery = order.getDeliveryInfo(); + if (Integer.valueOf(1).equals(order.getDeliveryType()) + && Integer.valueOf(3).equals(order.getOrderType()) + && delivery != null + && StringUtils.isNotBlank(delivery.getNumberCode())) { + return delivery.getNumberCode(); + } + return defaultString(order.getNumberCode()); + } + + private static String orderTypeText(MallOrderVO order, MallDeliveryOrder delivery, boolean refundPrint, boolean forcedOrderPrint) { + Integer status = order.getStatus(); + if (delivery != null && Integer.valueOf(1).equals(delivery.getAppointmentDelivery()) + && Integer.valueOf(11).equals(status)) { + return "棰勭害鍗"; + } + if (delivery != null && Integer.valueOf(1).equals(delivery.getTransferDelivery()) + && !Integer.valueOf(7).equals(status) && !Integer.valueOf(11).equals(status)) { + return "鍙栭鐮侊紙" + defaultString(delivery.getTransferPickupCode()) + "锛"; + } + if (refundPrint) { + return "鐢宠閫娆"; + } + if (Integer.valueOf(1).equals(order.getDeliveryType()) && Integer.valueOf(3).equals(order.getOrderType())) { + return "闈㈠闈㈤厤閫"; + } + if (!forcedOrderPrint) { + if (Integer.valueOf(7).equals(status) || Integer.valueOf(11).equals(status)) { + return "鐢宠閫娆"; + } + if (Integer.valueOf(3).equals(status) && Integer.valueOf(2).equals(order.getDeliveryType()) + && !Integer.valueOf(1).equals(order.getUserRequireMake())) { + return "寰呮秷璐"; + } + if (Integer.valueOf(5).equals(status)) { + return "宸插畬鎴"; + } + if (Integer.valueOf(6).equals(status)) { + return "宸插彇娑"; + } + if (Integer.valueOf(8).equals(status)) { + return "宸查娆"; + } + if (Integer.valueOf(12).equals(status)) { + return "宸插敭鍚"; + } + } + if (Integer.valueOf(0).equals(order.getIsPack()) && order.getOtherOrder() == null) { + return "鍒板簵-鍫傞"; + } + if (Integer.valueOf(1).equals(order.getDeliveryType()) && Integer.valueOf(1).equals(order.getIsPack())) { + return "閰嶉"; + } + if (Integer.valueOf(1).equals(order.getIsPack()) && order.getOtherOrder() == null) { + return "鍒板簵-鎵撳寘"; + } + return ""; + } + + private static boolean isRefundPrint(String printReason) { + return StringUtils.containsIgnoreCase(printReason, "REFUND"); + } + + private static boolean isOrderEventPrint(String printReason) { + return StringUtils.containsIgnoreCase(printReason, "ACCEPT_ORDER") + || StringUtils.containsIgnoreCase(printReason, "SHOP_INSTANT_MAKE"); + } + + private static String refundReason(MallRefundRecord refund) { + return getCancelReasonDescription(refund.getReason()) + " " + getRefundTypeText(refund) + "|" + getRefundReasonTypeText(refund); + } + + private static String getCancelReasonDescription(String reason) { + if (StringUtils.isBlank(reason)) { + return ""; + } + int chineseColonIndex = reason.indexOf('锛'); + int englishColonIndex = reason.indexOf(':'); + int colonIndex = chineseColonIndex >= 0 ? chineseColonIndex : englishColonIndex; + return colonIndex >= 0 ? reason.substring(colonIndex + 1) : reason; + } + + private static String getRefundTypeText(MallRefundRecord refund) { + if (Integer.valueOf(1).equals(refund.getRefundType())) { + return "閫鍟嗗搧"; + } + if (Integer.valueOf(2).equals(refund.getRefundType())) { + return "閫閰嶉佽垂"; + } + return "鍏ㄩ閫娆"; + } + + private static String getRefundReasonTypeText(MallRefundRecord refund) { + if (Integer.valueOf(1).equals(refund.getRefundTypeStatus())) { + return "鍟嗗鍘熷洜"; + } + if (Integer.valueOf(2).equals(refund.getRefundTypeStatus())) { + return "閰嶉佸憳鍘熷洜"; + } + if (Integer.valueOf(3).equals(refund.getRefundTypeStatus())) { + return StringUtils.contains(refund.getLinkId(), "W") ? "閰嶉佸憳鍘熷洜" : "鍟嗗鍘熷洜"; + } + return "骞冲彴閫娆"; + } + + private static void centerLarge(StringBuilder sb, String text) { + sb.append("").append(clean(text)).append("
    "); + } + + private static void largeLeft(StringBuilder sb, String text) { + sb.append("").append(clean(text)).append("
    "); + } + + private static void center(StringBuilder sb, String text) { + sb.append("").append(clean(text)).append("
    "); + } + + private static void left(StringBuilder sb, String text) { + sb.append("").append(clean(text)).append("
    "); + } + + private static void separator(StringBuilder sb) { + center(sb, LINE); + } + + private static void br(StringBuilder sb) { + sb.append("
    "); + } + + private static String maskPhoneLastFour(String phone) { + if (StringUtils.isBlank(phone)) { + return ""; + } + String value = String.valueOf(phone); + if (value.length() <= 4) { + return value; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < value.length() - 4; i++) { + sb.append('*'); + } + return sb.append(value.substring(value.length() - 4)).toString(); + } + + private static String formatTime(Date date) { + return date == null ? "" : new SimpleDateFormat(TIME_PATTERN).format(date); + } + + private static String delNode(String text) { + return defaultString(text).replace("{", "").replace("}", "").replace("\"", ""); + } + + private static int safeQuantity(Integer quantity) { + return quantity == null ? 0 : quantity; + } + + private static boolean positive(BigDecimal amount) { + return amount != null && amount.compareTo(BigDecimal.ZERO) > 0; + } + + private static BigDecimal safe(BigDecimal amount) { + return amount == null ? BigDecimal.ZERO : amount; + } + + private static String amount(BigDecimal amount) { + return safe(amount).stripTrailingZeros().toPlainString(); + } + + private static String defaultString(String text) { + return text == null ? "" : text; + } + + private static String clean(String text) { + return defaultString(text) + .replaceAll("[\\ud800-\\udfff]", "") + .replace("<", "锛") + .replace(">", "锛") + .replace("&", "锛"); + } +} diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/ShopBusinessHourUtil.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/ShopBusinessHourUtil.java new file mode 100644 index 00000000..cae6e757 --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/ShopBusinessHourUtil.java @@ -0,0 +1,218 @@ +package cc.hiver.mall.utils; + +import cc.hiver.mall.entity.ShopTakeaway; +import cc.hiver.mall.pojo.dto.BusinessHourPeriod; +import cn.hutool.core.text.CharSequenceUtil; +import cn.hutool.json.JSONUtil; + +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * 鍟嗗钀ヤ笟鏃舵宸ュ叿锛堟敮鎸佸鏃舵銆佽法澶滐級 + */ +public final class ShopBusinessHourUtil { + + public static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm"); + + private ShopBusinessHourUtil() { + } + + public static String normalizeTime(String value) { + if (CharSequenceUtil.isBlank(value)) { + return ""; + } + String time = value.trim(); + int colonIndex = time.indexOf(':'); + if (colonIndex < 0) { + return ""; + } + String hourPart = time.substring(0, colonIndex).trim(); + int lastSpaceIndex = hourPart.lastIndexOf(' '); + int lastTIndex = hourPart.lastIndexOf('T'); + int cutIndex = Math.max(lastSpaceIndex, lastTIndex); + if (cutIndex >= 0 && cutIndex + 1 < hourPart.length()) { + hourPart = hourPart.substring(cutIndex + 1); + } + String minutePart = time.substring(colonIndex + 1).trim(); + if (minutePart.length() > 2) { + minutePart = minutePart.substring(0, 2); + } + try { + int hour = Integer.parseInt(hourPart); + int minute = Integer.parseInt(minutePart); + if (hour < 0 || hour > 23 || minute < 0 || minute > 59) { + return ""; + } + return String.format("%02d:%02d", hour, minute); + } catch (Exception e) { + return ""; + } + } + + public static List parsePeriods(ShopTakeaway takeaway) { + if (takeaway == null) { + return Collections.emptyList(); + } + List periods = parsePeriods(takeaway.getBusinessHours()); + if (!periods.isEmpty()) { + return periods; + } + String begin = normalizeTime(takeaway.getBusinessHourBegin()); + String end = normalizeTime(takeaway.getBusinessHourEnd()); + if (CharSequenceUtil.isBlank(begin) || CharSequenceUtil.isBlank(end)) { + return Collections.emptyList(); + } + BusinessHourPeriod period = new BusinessHourPeriod(); + period.setBegin(begin); + period.setEnd(end); + return Collections.singletonList(period); + } + + public static List parsePeriods(String businessHoursJson) { + if (CharSequenceUtil.isBlank(businessHoursJson)) { + return Collections.emptyList(); + } + try { + List list = JSONUtil.toList(businessHoursJson.trim(), BusinessHourPeriod.class); + if (list == null || list.isEmpty()) { + return Collections.emptyList(); + } + List result = new ArrayList<>(); + for (BusinessHourPeriod item : list) { + if (item == null) { + continue; + } + String begin = normalizeTime(item.getBegin()); + String end = normalizeTime(item.getEnd()); + if (CharSequenceUtil.isBlank(begin) || CharSequenceUtil.isBlank(end)) { + continue; + } + BusinessHourPeriod period = new BusinessHourPeriod(); + period.setBegin(begin); + period.setEnd(end); + result.add(period); + } + return result; + } catch (Exception e) { + return Collections.emptyList(); + } + } + + public static String toJson(List periods) { + List cleaned = cleanPeriods(periods); + if (cleaned.isEmpty()) { + return null; + } + return JSONUtil.toJsonStr(cleaned); + } + + public static List cleanPeriods(List periods) { + if (periods == null || periods.isEmpty()) { + return Collections.emptyList(); + } + List result = new ArrayList<>(); + for (BusinessHourPeriod item : periods) { + if (item == null) { + continue; + } + String begin = normalizeTime(item.getBegin()); + String end = normalizeTime(item.getEnd()); + if (CharSequenceUtil.isBlank(begin) || CharSequenceUtil.isBlank(end)) { + continue; + } + BusinessHourPeriod period = new BusinessHourPeriod(); + period.setBegin(begin); + period.setEnd(end); + result.add(period); + } + return result; + } + + /** + * 瑙勮寖鍖栧啓鍏ワ細鍚屾 businessHours JSON锛屽苟鍥炲~ begin/end锛堝彇棣栨椂娈碉紝鍏煎鏃ч昏緫锛 + */ + public static void normalizeForSave(ShopTakeaway takeaway) { + if (takeaway == null) { + return; + } + List periods = parsePeriods(takeaway.getBusinessHours()); + if (periods.isEmpty() && takeaway.getBusinessHourList() != null) { + periods = cleanPeriods(takeaway.getBusinessHourList()); + } + if (periods.isEmpty()) { + String begin = normalizeTime(takeaway.getBusinessHourBegin()); + String end = normalizeTime(takeaway.getBusinessHourEnd()); + if (CharSequenceUtil.isNotBlank(begin) && CharSequenceUtil.isNotBlank(end)) { + BusinessHourPeriod period = new BusinessHourPeriod(); + period.setBegin(begin); + period.setEnd(end); + periods = Collections.singletonList(period); + } + } + if (periods.isEmpty()) { + takeaway.setBusinessHours(null); + takeaway.setBusinessHourList(Collections.emptyList()); + return; + } + takeaway.setBusinessHours(JSONUtil.toJsonStr(periods)); + takeaway.setBusinessHourList(periods); + takeaway.setBusinessHourBegin(periods.get(0).getBegin()); + takeaway.setBusinessHourEnd(periods.get(0).getEnd()); + } + + public static void fillBusinessHourList(ShopTakeaway takeaway) { + if (takeaway == null) { + return; + } + takeaway.setBusinessHourList(parsePeriods(takeaway)); + } + + /** + * @return 0=钀ヤ笟涓紝1=闈炶惀涓氫腑 + */ + public static int getBusinessTimeOrder(ShopTakeaway takeaway, String currentTime) { + return isInBusinessHours(takeaway, currentTime) ? 0 : 1; + } + + public static boolean isInBusinessHours(ShopTakeaway takeaway) { + return isInBusinessHours(takeaway, LocalTime.now().format(TIME_FORMATTER)); + } + + public static boolean isInBusinessHours(ShopTakeaway takeaway, String currentTime) { + List periods = parsePeriods(takeaway); + if (periods.isEmpty()) { + return false; + } + String now = normalizeTime(currentTime); + if (CharSequenceUtil.isBlank(now)) { + now = LocalTime.now().format(TIME_FORMATTER); + } + for (BusinessHourPeriod period : periods) { + if (isInSinglePeriod(period.getBegin(), period.getEnd(), now)) { + return true; + } + } + return false; + } + + public static boolean isInSinglePeriod(String begin, String end, String currentTime) { + String b = normalizeTime(begin); + String e = normalizeTime(end); + String now = normalizeTime(currentTime); + if (CharSequenceUtil.isBlank(b) || CharSequenceUtil.isBlank(e) || CharSequenceUtil.isBlank(now)) { + return false; + } + if (b.equals(e)) { + return true; + } + if (b.compareTo(e) <= 0) { + return b.compareTo(now) <= 0 && e.compareTo(now) >= 0; + } + // 璺ㄥ锛氬 22:00-02:00 + return b.compareTo(now) <= 0 || e.compareTo(now) >= 0; + } +} diff --git a/hiver-modules/hiver-mall/src/main/resources/db/shop_area_geo_polygon.sql b/hiver-modules/hiver-mall/src/main/resources/db/shop_area_geo_polygon.sql new file mode 100644 index 00000000..a89e1525 --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/resources/db/shop_area_geo_polygon.sql @@ -0,0 +1,2 @@ +ALTER TABLE `t_shop_area` + ADD COLUMN `geo_polygon` text DEFAULT NULL COMMENT '瀹氫綅鑷姩鍖归厤澶氳竟褰㈠潗鏍嘕SON锛堜粎涓绾у尯鍩燂紝GCJ-02锛'; diff --git a/hiver-modules/hiver-mall/src/main/resources/db/shop_cloud_print.sql b/hiver-modules/hiver-mall/src/main/resources/db/shop_cloud_print.sql new file mode 100644 index 00000000..0bf21d74 --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/resources/db/shop_cloud_print.sql @@ -0,0 +1,4 @@ +ALTER TABLE t_shop + ADD COLUMN printing_method VARCHAR(20) NOT NULL DEFAULT 'bluetooth' COMMENT '鎵撳嵃鏂瑰紡 bluetooth:钃濈墮 cloud:浜戞墦鍗', + ADD COLUMN printer_sn VARCHAR(50) DEFAULT NULL COMMENT '澶ц秼浜戞墦鍗版満SN', + ADD COLUMN printer_name VARCHAR(50) DEFAULT NULL COMMENT '澶ц秼浜戞墦鍗版満鍚嶇О'; diff --git a/hiver-modules/hiver-mall/src/main/resources/db/shop_starting_price.sql b/hiver-modules/hiver-mall/src/main/resources/db/shop_starting_price.sql new file mode 100644 index 00000000..2cf96b30 --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/resources/db/shop_starting_price.sql @@ -0,0 +1,2 @@ +ALTER TABLE t_shop + ADD COLUMN starting_price DECIMAL(10, 2) NOT NULL DEFAULT 0.00 COMMENT '璧烽佷环鏍'; diff --git a/hiver-modules/hiver-mall/src/main/resources/db/shop_takeaway_business_hours.sql b/hiver-modules/hiver-mall/src/main/resources/db/shop_takeaway_business_hours.sql new file mode 100644 index 00000000..34b4caf9 --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/resources/db/shop_takeaway_business_hours.sql @@ -0,0 +1,16 @@ +-- 鍟嗗澶栧崠钀ヤ笟鏃舵锛堝鏃舵 JSON锛 +ALTER TABLE `t_shop_takeaway` + ADD COLUMN `business_hours` text DEFAULT NULL COMMENT '钀ヤ笟鏃舵JSON锛屼緥锛歔{"begin":"09:00","end":"14:00"},{"begin":"17:00","end":"22:00"}]' AFTER `business_hour_end`; + +-- 鍘嗗彶鍗曟椂娈垫暟鎹洖濉 +UPDATE `t_shop_takeaway` +SET `business_hours` = CONCAT( + '[{"begin":"', + LEFT(TRIM(`business_hour_begin`), 5), + '","end":"', + LEFT(TRIM(`business_hour_end`), 5), + '"}]' +) +WHERE (`business_hours` IS NULL OR `business_hours` = '') + AND `business_hour_begin` IS NOT NULL AND TRIM(`business_hour_begin`) <> '' + AND `business_hour_end` IS NOT NULL AND TRIM(`business_hour_end`) <> ''; diff --git a/hiver-modules/hiver-mall/src/main/resources/db/transfer_worker_delivery.sql b/hiver-modules/hiver-mall/src/main/resources/db/transfer_worker_delivery.sql new file mode 100644 index 00000000..794b806b --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/resources/db/transfer_worker_delivery.sql @@ -0,0 +1,8 @@ +-- 閰嶉佸憳涓浆鎺ュ崟鑳藉姏涓庝腑杞厤閫佸憳璁板綍 +ALTER TABLE `t_worker` + ADD COLUMN `can_transfer_order` TINYINT NULL DEFAULT 0 COMMENT '鏄惁鍙互鎺ヤ腑杞崟锛0鍚 1鏄' AFTER `is_full_time`; + +ALTER TABLE `mall_delivery_order` + ADD COLUMN `transfer_worker_id` VARCHAR(64) NULL COMMENT '涓浆閰嶉佸憳ID' AFTER `transfer_pickup_code`, + ADD COLUMN `transfer_worker_name` VARCHAR(64) NULL COMMENT '涓浆閰嶉佸憳鍚嶇О' AFTER `transfer_worker_id`, + ADD COLUMN `transfer_worker_mobile` VARCHAR(32) NULL COMMENT '涓浆閰嶉佸憳鐢佃瘽' AFTER `transfer_worker_name`; diff --git a/hiver-modules/hiver-mall/src/main/resources/db/user_address_geo.sql b/hiver-modules/hiver-mall/src/main/resources/db/user_address_geo.sql new file mode 100644 index 00000000..a947e3e5 --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/resources/db/user_address_geo.sql @@ -0,0 +1,3 @@ +ALTER TABLE `t_user_address` + ADD COLUMN `address_lng` decimal(12,6) DEFAULT NULL COMMENT '鏀惰揣鍦板潃缁忓害锛堢ぞ浼氬尯鍩熻嚜鐢卞湴鍧锛', + ADD COLUMN `address_lat` decimal(12,6) DEFAULT NULL COMMENT '鏀惰揣鍦板潃绾害锛堢ぞ浼氬尯鍩熻嚜鐢卞湴鍧锛'; diff --git a/hiver-modules/hiver-mall/src/main/resources/mapper/MallDeliveryOrderMapper.xml b/hiver-modules/hiver-mall/src/main/resources/mapper/MallDeliveryOrderMapper.xml index d44ee984..95b7b3ec 100644 --- a/hiver-modules/hiver-mall/src/main/resources/mapper/MallDeliveryOrderMapper.xml +++ b/hiver-modules/hiver-mall/src/main/resources/mapper/MallDeliveryOrderMapper.xml @@ -47,6 +47,9 @@ + + + @@ -60,7 +63,8 @@ d.region_id,d.remark, d.all_count, d.phone_number, d.get_codes, d.get_pictures, d.is_big, d.is_return,d.worker_name, d.arrive_time,d.new_worker,d.worker_phone, d.transfer_delivery,d.transfer_address_id,d.transfer_address_name, - d.transfer_arrive_time,d.transfer_arrive_image,d.transfer_pickup_code + d.transfer_arrive_time,d.transfer_arrive_image,d.transfer_pickup_code, + d.transfer_worker_id,d.transfer_worker_name,d.transfer_worker_mobile FROM mall_delivery_order d @@ -118,6 +122,23 @@ AND d.transfer_arrive_time IS NOT NULL and d.status not in (-1,4) + + AND d.status = 1 + AND d.transfer_arrive_time IS NULL + + + AND d.transfer_worker_id = #{q.transferWorkerId} + + + AND (d.transfer_worker_id IS NULL OR d.transfer_worker_id = '') + + + + + + AND d.transfer_worker_id = #{q.transferWorkerId} + + ORDER BY @@ -160,7 +181,8 @@ d.region_id,d.remark, d.all_count, d.phone_number, d.get_codes, d.get_pictures, d.is_big, d.is_return,d.worker_name, d.arrive_time,d.new_worker,d.worker_phone, d.transfer_delivery,d.transfer_address_id,d.transfer_address_name, - d.transfer_arrive_time,d.transfer_arrive_image,d.transfer_pickup_code + d.transfer_arrive_time,d.transfer_arrive_image,d.transfer_pickup_code, + d.transfer_worker_id,d.transfer_worker_name,d.transfer_worker_mobile FROM mall_delivery_order d LEFT JOIN ( SELECT delivery_order_id, MAX(reassign_time) AS latest_reassign_time @@ -226,7 +248,8 @@ d.region_id,d.remark, d.all_count, d.phone_number, d.get_codes, d.get_pictures, d.is_big,d.is_return,d.worker_name,d.arrive_time,d.new_worker,d.worker_phone, d.transfer_delivery,d.transfer_address_id,d.transfer_address_name, - d.transfer_arrive_time,d.transfer_arrive_image,d.transfer_pickup_code + d.transfer_arrive_time,d.transfer_arrive_image,d.transfer_pickup_code, + d.transfer_worker_id,d.transfer_worker_name,d.transfer_worker_mobile FROM mall_delivery_order d d.status not in (-1,4) @@ -299,7 +322,8 @@ d.region_id,d.remark, d.all_count, d.phone_number, d.get_codes, d.get_pictures, d.is_big,d.is_return,d.worker_name,d.arrive_time,d.new_worker,d.worker_phone, d.transfer_delivery,d.transfer_address_id,d.transfer_address_name, - d.transfer_arrive_time,d.transfer_arrive_image,d.transfer_pickup_code + d.transfer_arrive_time,d.transfer_arrive_image,d.transfer_pickup_code, + d.transfer_worker_id,d.transfer_worker_name,d.transfer_worker_mobile FROM mall_delivery_order d LEFT JOIN mall_order o ON o.id = d.order_id LEFT JOIN ( @@ -308,7 +332,14 @@ GROUP BY delivery_order_id ) rr ON rr.delivery_order_id = d.id - d.status not in (-1,4) + + + AND d.status = #{q.status} + + + AND d.status not in (-1,4) + + AND d.region_id = #{q.regionId} @@ -327,9 +358,6 @@ AND d.shop_name like concat('%',#{q.shopName},'%') - - AND d.status = #{q.status} - AND d.get_area_id = #{q.getAreaId} @@ -359,13 +387,20 @@ AND d.transfer_arrive_time IS NULL - ORDER BY (CASE WHEN o.shop_make_time IS NULL THEN 1 ELSE 0 END) ASC, - o.shop_make_time ASC, - (CASE WHEN d.must_finish_time IS NOT NULL AND d.must_finish_time < NOW() THEN 0 ELSE 1 END) ASC, - (CASE WHEN rr.latest_reassign_time IS NULL THEN 1 ELSE 0 END) ASC, - rr.latest_reassign_time DESC, - (CASE WHEN d.must_finish_time IS NULL THEN 1 ELSE 0 END) ASC, - d.must_finish_time ASC,d.delivery_fee DESC + + + ORDER BY d.must_finish_time DESC + + + ORDER BY (CASE WHEN o.shop_make_time IS NULL THEN 1 ELSE 0 END) ASC, + o.shop_make_time ASC, + (CASE WHEN d.must_finish_time IS NOT NULL AND d.must_finish_time < NOW() THEN 0 ELSE 1 END) ASC, + (CASE WHEN rr.latest_reassign_time IS NULL THEN 1 ELSE 0 END) ASC, + rr.latest_reassign_time DESC, + (CASE WHEN d.must_finish_time IS NULL THEN 1 ELSE 0 END) ASC, + d.must_finish_time ASC,d.delivery_fee DESC + + + + + + + + select @@ -39,12 +44,14 @@ 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) + commission_ratio, center_lng, center_lat, radius_meters, geo_polygon, area_kind) values (#{id,jdbcType=VARCHAR}, #{createBy,jdbcType=VARCHAR}, #{createTime,jdbcType=TIMESTAMP}, #{delFlag,jdbcType=INTEGER}, #{updateBy,jdbcType=VARCHAR}, #{updateTime,jdbcType=TIMESTAMP}, #{isParent,jdbcType=BIT}, #{parentId,jdbcType=VARCHAR}, #{sortOrder,jdbcType=DECIMAL}, #{status,jdbcType=INTEGER}, #{title,jdbcType=VARCHAR}, #{isCanteen,jdbcType=INTEGER}, #{deliveryEnabled,jdbcType=INTEGER}, - #{parentAgentId,jdbcType=VARCHAR}, #{parentAgentName,jdbcType=VARCHAR}, #{commissionRatio,jdbcType=INTEGER}) + #{parentAgentId,jdbcType=VARCHAR}, #{parentAgentName,jdbcType=VARCHAR}, #{commissionRatio,jdbcType=INTEGER}, + #{centerLng,jdbcType=DECIMAL}, #{centerLat,jdbcType=DECIMAL}, #{radiusMeters,jdbcType=INTEGER}, + #{geoPolygon,jdbcType=LONGVARCHAR}, #{areaKind,jdbcType=INTEGER}) insert into t_shop_area @@ -97,6 +104,21 @@ commission_ratio, + + center_lng, + + + center_lat, + + + radius_meters, + + + geo_polygon, + + + area_kind, + @@ -147,6 +169,21 @@ #{commissionRatio,jdbcType=INTEGER}, + + #{centerLng,jdbcType=DECIMAL}, + + + #{centerLat,jdbcType=DECIMAL}, + + + #{radiusMeters,jdbcType=INTEGER}, + + + #{geoPolygon,jdbcType=LONGVARCHAR}, + + + #{areaKind,jdbcType=INTEGER}, + @@ -197,6 +234,21 @@ commission_ratio = #{commissionRatio,jdbcType=INTEGER}, + + center_lng = #{centerLng,jdbcType=DECIMAL}, + + + center_lat = #{centerLat,jdbcType=DECIMAL}, + + + radius_meters = #{radiusMeters,jdbcType=INTEGER}, + + + geo_polygon = #{geoPolygon,jdbcType=LONGVARCHAR}, + + + area_kind = #{areaKind,jdbcType=INTEGER}, + where id = #{id,jdbcType=VARCHAR} @@ -216,7 +268,12 @@ delivery_enabled = #{deliveryEnabled,jdbcType=INTEGER}, parent_agent_id = #{parentAgentId,jdbcType=VARCHAR}, parent_agent_name = #{parentAgentName,jdbcType=VARCHAR}, - commission_ratio = #{commissionRatio,jdbcType=INTEGER} + commission_ratio = #{commissionRatio,jdbcType=INTEGER}, + center_lng = #{centerLng,jdbcType=DECIMAL}, + center_lat = #{centerLat,jdbcType=DECIMAL}, + radius_meters = #{radiusMeters,jdbcType=INTEGER}, + geo_polygon = #{geoPolygon,jdbcType=LONGVARCHAR}, + area_kind = #{areaKind,jdbcType=INTEGER} where id = #{id,jdbcType=VARCHAR} \ No newline at end of file diff --git a/hiver-modules/hiver-mall/src/main/resources/mapper/ShopTakeawayMapper.xml b/hiver-modules/hiver-mall/src/main/resources/mapper/ShopTakeawayMapper.xml index 6b8c9c8a..b7379af0 100644 --- a/hiver-modules/hiver-mall/src/main/resources/mapper/ShopTakeawayMapper.xml +++ b/hiver-modules/hiver-mall/src/main/resources/mapper/ShopTakeawayMapper.xml @@ -16,6 +16,7 @@ + @@ -26,7 +27,7 @@ id,create_by, create_time, update_time, update_by, - del_flag,shop_id,shop_name,region_id,commission_rate_more,virtual_group_commission_rate,commission_rate_one,business_hour_begin,business_hour_end,status,type,is_delivery,cooking_time,shoprank,is_price_lock,join_time + del_flag,shop_id,shop_name,region_id,commission_rate_more,virtual_group_commission_rate,commission_rate_one,business_hour_begin,business_hour_end,business_hours,status,type,is_delivery,cooking_time,shoprank,is_price_lock,join_time