Browse Source

大屏、应急接口

zhangxin 1 year ago
parent
commit
3e510cc7c8
51 changed files with 2572 additions and 314 deletions
  1. 16 283
      base_sql/bucket_sql/xuankuang_ddl_20230904.sql
  2. 288 0
      base_sql/bucket_sql/xuankuang_dml_20230904.sql
  3. 7 0
      pom.xml
  4. 35 0
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/warewms/car/CarInfoController.java
  5. 58 0
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/warewms/screen/VisualDataScreenController.java
  6. 22 1
      ruoyi-admin/src/main/java/com/ruoyi/xuankuang/controller/test/XuanKuangTestApiController.java
  7. 2 2
      ruoyi-admin/src/main/resources/application-dev.yml
  8. 5 0
      ruoyi-common/pom.xml
  9. 4 0
      ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
  10. 43 0
      ruoyi-common/src/main/java/com/ruoyi/common/enums/Granularity.java
  11. 38 0
      ruoyi-common/src/main/java/com/ruoyi/common/enums/TimeHorizon.java
  12. 18 0
      ruoyi-common/src/main/java/com/ruoyi/common/utils/time/SplitedTimeParam.java
  13. 955 0
      ruoyi-common/src/main/java/com/ruoyi/common/utils/time/TimeUtils.java
  14. 2 0
      ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
  15. 59 0
      warewms-ams/src/main/java/com/ruoyi/ams/agv/car/domain/CarInfo.java
  16. 21 0
      warewms-ams/src/main/java/com/ruoyi/ams/agv/car/dto/CarInfoDTO.java
  17. 17 0
      warewms-ams/src/main/java/com/ruoyi/ams/agv/car/mapper/CarInfoMapper.java
  18. 22 0
      warewms-ams/src/main/java/com/ruoyi/ams/agv/car/service/ICarInfoService.java
  19. 57 0
      warewms-ams/src/main/java/com/ruoyi/ams/agv/car/service/impl/CarInfoServiceImpl.java
  20. 11 0
      warewms-ams/src/main/java/com/ruoyi/ams/agv/car/vo/CarInfoVO.java
  21. 40 5
      warewms-ams/src/main/java/com/ruoyi/ams/agv/ndc/service/impl/SocketBufferServiceImpl.java
  22. 4 4
      warewms-ams/src/main/java/com/ruoyi/ams/inv/mapper/InvLotLocIdMapper.java
  23. 4 0
      warewms-ams/src/main/java/com/ruoyi/ams/inv/service/IInvLotLocIdService.java
  24. 11 0
      warewms-ams/src/main/java/com/ruoyi/ams/inv/service/impl/InvLotLocIdServiceImpl.java
  25. 29 0
      warewms-ams/src/main/java/com/ruoyi/ams/screen/dto/LargeScreenInvLotLocIdDTO.java
  26. 26 0
      warewms-ams/src/main/java/com/ruoyi/ams/screen/dto/LargeScreenWcsTaskDTO.java
  27. 19 0
      warewms-ams/src/main/java/com/ruoyi/ams/screen/dto/SkuLiquidLevelDTO.java
  28. 19 0
      warewms-ams/src/main/java/com/ruoyi/ams/screen/dto/SkuQtyInfoDTO.java
  29. 17 0
      warewms-ams/src/main/java/com/ruoyi/ams/screen/dto/VisualDataScreenSkuQtyDTO.java
  30. 34 0
      warewms-ams/src/main/java/com/ruoyi/ams/screen/dto/VisualDataScreenSkuQtyReqDTO.java
  31. 20 0
      warewms-ams/src/main/java/com/ruoyi/ams/screen/dto/WcsRgvInfoConvertDTO.java
  32. 20 0
      warewms-ams/src/main/java/com/ruoyi/ams/screen/dto/WcsRgvInfoDTO.java
  33. 41 0
      warewms-ams/src/main/java/com/ruoyi/ams/screen/service/VisualDataScreenService.java
  34. 234 0
      warewms-ams/src/main/java/com/ruoyi/ams/screen/service/impl/VisualDataScreenServiceImpl.java
  35. 2 0
      warewms-ams/src/main/java/com/ruoyi/ams/task/service/IWcsTaskService.java
  36. 5 1
      warewms-ams/src/main/java/com/ruoyi/ams/task/service/impl/WcsTaskServiceImpl.java
  37. 14 0
      warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/domain/dto/EmergencyOrderDTO.java
  38. 10 0
      warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/domain/dto/SkuAgitatedTankAttrDTO.java
  39. 26 0
      warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/domain/dto/WcsResponseDTO.java
  40. 25 2
      warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/service/StirringTankClientService.java
  41. 101 0
      warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/service/WmsDocOrderSubService.java
  42. 30 1
      warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/service/WmsToWcsApiService.java
  43. 8 0
      warewms-ams/src/main/resources/mapper/ams/CarInfoMapper.xml
  44. 87 14
      warewms-base/src/main/java/com/ruoyi/base/constant/Constant.java
  45. 1 1
      warewms-base/src/main/java/com/ruoyi/base/mapper/BaseLocationInfoMapper.java
  46. 9 0
      warewms-base/src/main/java/com/ruoyi/base/service/IBaseLocationInfoService.java
  47. 6 0
      warewms-base/src/main/java/com/ruoyi/base/service/IBaseSkuService.java
  48. 17 0
      warewms-base/src/main/java/com/ruoyi/base/service/impl/BaseLocationInfoServiceImpl.java
  49. 10 0
      warewms-base/src/main/java/com/ruoyi/base/service/impl/BaseSkuServiceImpl.java
  50. 12 0
      warewms-base/src/main/resources/mapper/base/BaseLocationInfoMapper.xml
  51. 11 0
      warewms-hard/src/main/java/com/ruoyi/hard/xuankang/StirringTankClient.java

File diff suppressed because it is too large
+ 16 - 283
base_sql/bucket_sql/xuankuang_ddl_20230904.sql


File diff suppressed because it is too large
+ 288 - 0
base_sql/bucket_sql/xuankuang_dml_20230904.sql


+ 7 - 0
pom.xml

@@ -36,6 +36,7 @@
         <jwt.version>0.9.1</jwt.version>
         <skipTests>true</skipTests>
         <guava.version>23.0</guava.version>
+        <joda.time.version>2.9.9</joda.time.version>
     </properties>
 
     <!-- 依赖声明 -->
@@ -228,6 +229,12 @@
                 <version>${warewms.version}</version>
             </dependency>
 
+            <dependency>
+                <groupId>joda-time</groupId>
+                <artifactId>joda-time</artifactId>
+                <version>${joda.time.version}</version>
+            </dependency>
+
         </dependencies>
     </dependencyManagement>
 

+ 35 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/warewms/car/CarInfoController.java

@@ -0,0 +1,35 @@
+package com.ruoyi.web.controller.warewms.car;
+
+import com.ruoyi.ams.agv.car.service.ICarInfoService;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 容器管理Controller
+ * 
+ * @author ruoyi
+ * @date 2022-11-01
+ */
+@RestController
+@RequestMapping("/car")
+public class CarInfoController extends BaseController
+{
+    @Autowired
+    private ICarInfoService carInfoService;
+
+    /**
+     * agv车辆信息
+     */
+    @GetMapping("/queryCarInfo")
+    @ApiOperation("agv车辆信息")
+    public AjaxResult queryCarInfo()
+    {
+        return AjaxResult.success(carInfoService.queryCarInfo());
+    }
+
+}

+ 58 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/warewms/screen/VisualDataScreenController.java

@@ -0,0 +1,58 @@
+package com.ruoyi.web.controller.warewms.screen;
+
+
+import com.ruoyi.ams.screen.dto.LargeScreenInvLotLocIdDTO;
+import com.ruoyi.ams.screen.dto.VisualDataScreenSkuQtyReqDTO;
+import com.ruoyi.ams.screen.service.VisualDataScreenService;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.util.List;
+
+@RestController
+@RequestMapping("/largeScreen")
+public class VisualDataScreenController extends BaseController {
+
+    @Autowired
+    private VisualDataScreenService visualDataScreenService;
+
+    /**
+     * 查询大屏AGV任务列表
+     */
+    @GetMapping("/selectLargeScreenWcsTaskList")
+    @ApiOperation("查询大屏AGV任务列表")
+    public AjaxResult selectLargeScreenWcsTaskList(@RequestParam Integer size) {
+        return AjaxResult.success(visualDataScreenService.selectLargeScreenWcsTaskList(size));
+    }
+
+    @PostMapping(value = "/queryVisualDataScreenSkuQtyDTOList")
+    @ApiOperation("查询物料时间区域内入库/出库总量 按时间粒度分割")
+    public AjaxResult queryVisualDataScreenSkuQtyDTOList(@RequestBody @Valid VisualDataScreenSkuQtyReqDTO visualDataScreenSkuQtyReqDTO) {
+        return AjaxResult.success(visualDataScreenService.queryVisualDataScreenSkuQtyDTOList(visualDataScreenSkuQtyReqDTO));
+    }
+
+    @GetMapping("/queryLargeScreenInvLotLocIdDTOList")
+    @ApiOperation("查询库位库存信息列表")
+    public AjaxResult queryLargeScreenInvLotLocIdDTOList(@RequestParam Integer size) {
+        List<LargeScreenInvLotLocIdDTO> largeScreenInvLotLocIdDTOList = visualDataScreenService.queryLargeScreenInvLotLocIdDTOList(size);
+        return AjaxResult.success(largeScreenInvLotLocIdDTOList);
+    }
+
+    @GetMapping("/querySkuLiquidLevel")
+    @ApiOperation("获取搅拌槽液位值")
+    public AjaxResult querySkuLiquidLevel(@RequestParam List<String> skuList) {
+        return AjaxResult.success(visualDataScreenService.querySkuLiquidLevel(skuList));
+    }
+
+    @GetMapping("/queryWcsRgvInfo")
+    @ApiOperation("四向车车辆信息")
+    public AjaxResult queryWcsRgvInfo()
+    {
+        return AjaxResult.success(visualDataScreenService.queryWcsRgvInfo());
+    }
+
+}

+ 22 - 1
ruoyi-admin/src/main/java/com/ruoyi/xuankuang/controller/test/XuanKuangTestApiController.java

@@ -1,9 +1,15 @@
 package com.ruoyi.xuankuang.controller.test;
 
 import com.alibaba.fastjson.JSON;
-import com.ruoyi.ams.xuankuang.domain.form.*;
+import com.ruoyi.ams.xuankuang.domain.dto.EmergencyOrderDTO;
+import com.ruoyi.ams.xuankuang.domain.form.AgvInTaskForm;
+import com.ruoyi.ams.xuankuang.domain.form.BillTaskForm;
+import com.ruoyi.ams.xuankuang.domain.form.CallbackBbmForm;
+import com.ruoyi.ams.xuankuang.domain.form.OutTaskForm;
 import com.ruoyi.ams.xuankuang.domain.vo.WcsResponseVo;
+import com.ruoyi.ams.xuankuang.service.WmsDocOrderSubService;
 import com.ruoyi.ams.xuankuang.service.WmsToWcsApiService;
+import com.ruoyi.common.core.domain.AjaxResult;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -20,6 +26,9 @@ public class XuanKuangTestApiController {
     @Autowired
     private WmsToWcsApiService WmsToWcsApiService;
 
+    @Autowired
+    private WmsDocOrderSubService wmsDocOrderSubService;
+
     /**
      * wms出库任务下发接口
      *
@@ -32,6 +41,18 @@ public class XuanKuangTestApiController {
         return WmsToWcsApiService.wmsOutTask(outTaskForm);
     }
 
+    /**
+     * wms指定库位出库(应急)
+     *
+     * @param emergencyOrderDTO
+     * @return
+     */
+    @ApiOperation("wms指定库位出库(应急)")
+    @PostMapping("/emergencyInitOrder")
+    public AjaxResult emergencyInitOrder(@RequestBody EmergencyOrderDTO emergencyOrderDTO) {
+        return wmsDocOrderSubService.emergencyInitOrderDetails(emergencyOrderDTO.getOrderNo(), emergencyOrderDTO.getLocationId());
+    }
+
     /**
      * wms工单任务下发接口
      *

+ 2 - 2
ruoyi-admin/src/main/resources/application-dev.yml

@@ -6,9 +6,9 @@ spring:
         druid:
             # 主库数据源
             master:
-                url: jdbc:mysql://localhost:3306/warewms-xuankuang_cy?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8
+                url: jdbc:mysql://localhost:3306/warewms_xuankuang_zx?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8
                 username: root
-                password: 123456
+                password: root
                 driverClassName: com.mysql.cj.jdbc.Driver
             # 从库数据源
             slave:

+ 5 - 0
ruoyi-common/pom.xml

@@ -162,6 +162,11 @@
             <version>4.5.2</version>
         </dependency>
 
+        <dependency>
+            <groupId>joda-time</groupId>
+            <artifactId>joda-time</artifactId>
+        </dependency>
+
         <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>

+ 4 - 0
ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java

@@ -234,6 +234,10 @@ public class Constants
      */
     public static final String EMPTY_PALLET_INV_SORT = "emptyPalletInvSort";
 
+    /**
+     * 空托盘库位排序的子场景
+     */
+    public static final String BUCKET_CACHE_OUT = "bucketCacheOut";
 
     public static final String TRACE_ID = "mdcId";
 

+ 43 - 0
ruoyi-common/src/main/java/com/ruoyi/common/enums/Granularity.java

@@ -0,0 +1,43 @@
+package com.ruoyi.common.enums;
+
+import org.apache.commons.compress.utils.Lists;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public enum Granularity {
+    //以小时计
+    HOUR("hh"),
+
+    //以天计
+    DAY("dd"),
+
+    //以月计
+    MONTH("mm"),
+
+    //以年计
+    YEAR("yy");
+
+    private String suffix;
+
+    Granularity(String suffix) {
+        this.suffix = suffix;
+    }
+
+    public String getSuffix() {
+        return suffix;
+    }
+
+
+    public static List<Map<String, Object>> mapList() {
+        List<Map<String, Object>> list = Lists.newArrayList();
+        for (Granularity granularity : Granularity.values()) {
+            Map<String, Object> map = new HashMap<>();
+            map.put("code", granularity.getSuffix());
+            map.put("granularity", granularity);
+            list.add(map);
+        }
+        return list;
+    }
+}

+ 38 - 0
ruoyi-common/src/main/java/com/ruoyi/common/enums/TimeHorizon.java

@@ -0,0 +1,38 @@
+package com.ruoyi.common.enums;
+
+public enum TimeHorizon {
+    /**
+     * 当天
+     */
+    CURRENT_DAY("1", "当天"),
+    /**
+     * 24小时
+     */
+    LAST_HOURS("2", "24小时"),
+    /**
+     * 最近7天
+     */
+    LAST_DAYS("3", "最近7天"),
+
+    /**
+     * 最近30天
+     */
+    LAST_MONTHS("4", "最近30天");
+
+    private String code;
+
+    private String desc;
+
+    TimeHorizon(String code, String desc) {
+        this.code = code;
+        this.desc = desc;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+}

+ 18 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/time/SplitedTimeParam.java

@@ -0,0 +1,18 @@
+package com.ruoyi.common.utils.time;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 切割完成的时间
+ */
+@Data
+public class SplitedTimeParam implements Serializable {
+
+    private static final long serialVersionUID = 8136854862084752561L;
+
+    private String beginTime;
+
+    private String endTime;
+}

+ 955 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/time/TimeUtils.java

@@ -0,0 +1,955 @@
+package com.ruoyi.common.utils.time;
+
+import cn.hutool.core.comparator.CompareUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.google.common.collect.Lists;
+import com.ruoyi.common.enums.Granularity;
+import com.ruoyi.common.enums.TimeHorizon;
+import com.ruoyi.common.utils.DateUtils;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.joda.time.DateTime;
+
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Slf4j
+public class TimeUtils {
+
+    /**
+     * 时间格式(yyyyMMdd)
+     */
+    public final static String YEARMONTHDAY_PATTERN = "yyyyMMdd";
+    /**
+     * 时间格式(yyyy)
+     */
+    public final static String YEAR_PATTERN = "yyyy";
+    /**
+     * 时间格式(yyyyMM)
+     */
+    public final static String MONTHS_PATTERN = "yyyyMM";
+    /**
+     * 时间格式(yyyy-MM)
+     */
+    public final static String MONTH_PATTERN = "yyyy-MM";
+    /**
+     * 时间格式(yyyy-MM-dd)
+     */
+    public final static String DATE_PATTERN = "yyyy-MM-dd";
+    /**
+     * 时间格式(yyyy-MM-dd HH)
+     */
+    public static final String DATE_HOUR_PATTERN = "yyyy-MM-dd HH";
+    /**
+     * 时间格式(yyyy-MM-dd HH:mm:ss)
+     */
+    public final static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
+    /**
+     * 时间格式(yyyy-MM-dd HH:mm:ss)
+     */
+    public final static String DATE_TIME_PATTERN_MSG = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
+
+
+    /**
+     * 日期解析
+     *
+     * @param date    日期
+     * @param pattern 格式,如:DateUtils.DATE_TIME_PATTERN
+     * @return 返回Date
+     */
+    @SneakyThrows
+    public static Date parse(String date, String pattern) {
+        return new SimpleDateFormat(pattern).parse(date);
+    }
+
+
+    /**
+     * 日期格式化 日期格式为:yyyy-MM-dd
+     *
+     * @param date    日期
+     * @param pattern 格式,如:DateUtils.DATE_TIME_PATTERN
+     * @return 返回yyyy-MM-dd格式日期
+     */
+    public static String format(Date date, String pattern) {
+        if (ObjectUtil.isNull(date)) {
+            return null;
+        }
+        SimpleDateFormat df = new SimpleDateFormat(pattern);
+        return df.format(date);
+    }
+
+
+    /**
+     * 获取起始时间之间包含的小时,返回一个小时的开始时间,以yyyy-MM-dd HH:mm:ss格式返回
+     *
+     * @param startTm
+     * @param endTm
+     * @return ["2021-10-01 01:00:00","2021-10-01 02:00:00","2021-10-01 03:00:00"]
+     */
+    public static List<String> getHourListBetween(String startTm, String endTm) {
+        Date beginDate = parse(startTm, DATE_TIME_PATTERN);
+        Date endDate = parse(endTm, DATE_TIME_PATTERN);
+        //重置成了开始时间的月初时间
+        Date resetDate = parse(format(parse(startTm, DATE_HOUR_PATTERN), DATE_TIME_PATTERN), DATE_TIME_PATTERN);
+        resetDate = beginDate.compareTo(resetDate) > 0 ? DateUtils.addHours(resetDate, 1) : resetDate;
+
+        List<String> hourList = Lists.newArrayList();
+        while (resetDate.compareTo(endDate) <= 0) {
+            hourList.add(format(resetDate, DATE_TIME_PATTERN));
+            resetDate = DateUtils.addHours(resetDate, 1);
+        }
+
+        return hourList;
+    }
+
+
+    /**
+     * 获取起始时间之间包含的日期,返回一天的开始时间,以yyyy-MM-dd HH:mm:ss格式返回
+     *
+     * @param startTm
+     * @param endTm
+     * @return ["2021-10-01 00:00:00","2021-10-02 00:00:00","2021-10-03 00:00:00"]
+     */
+    @SneakyThrows
+    public static List<String> getDateListBetween(String startTm, String endTm) {
+        Date beginDate = parse(startTm, DATE_TIME_PATTERN);
+        Date endDate = parse(endTm, DATE_TIME_PATTERN);
+        //重置成了开始时间的每天开始时间
+        Date resetDate = parse(format(parse(startTm, DATE_PATTERN), DATE_TIME_PATTERN), DATE_TIME_PATTERN);
+        resetDate = beginDate.compareTo(resetDate) > 0 ? DateUtils.addDays(resetDate, 1) : resetDate;
+
+        List<String> dateList = Lists.newArrayList();
+        while (resetDate.compareTo(endDate) <= 0) {
+            dateList.add(format(resetDate, DATE_TIME_PATTERN));
+            resetDate = DateUtils.addDays(resetDate, 1);
+        }
+
+        return dateList;
+    }
+
+
+    /**
+     * 获取起始时间之间包含的月份,返回月初的时间,以yyyy-MM-dd HH:mm:ss格式返回
+     *
+     * @param startTm
+     * @param endTm
+     * @return ["2021-10-01 00:00:00","2021-11-01 00:00:00","2021-12-01 00:00:00"]
+     */
+    @SneakyThrows
+    public static List<String> getMonthListBetween(String startTm, String endTm) {
+        Date beginDate = parse(startTm, DATE_TIME_PATTERN);
+        Date endDate = parse(endTm, DATE_TIME_PATTERN);
+        //重置成了开始时间的月初时间
+        Date resetDate = parse(format(parse(startTm, MONTH_PATTERN), DATE_TIME_PATTERN), DATE_TIME_PATTERN);
+        resetDate = beginDate.compareTo(resetDate) > 0 ? DateUtils.addMonths(resetDate, 1) : resetDate;
+
+        List<String> monthList = Lists.newArrayList();
+        while (resetDate.compareTo(endDate) <= 0) {
+            monthList.add(format(resetDate, DATE_TIME_PATTERN));
+            resetDate = DateUtils.addMonths(resetDate, 1);
+        }
+        return monthList;
+    }
+
+
+    /**
+     * 获取起始时间之间包含的年份,返回年初的时间,以yyyy-MM-dd HH:mm:ss格式返回
+     *
+     * @param startTm 2019-09-28 16:34:00
+     * @param endTm   2021-12-19 10:36:11
+     * @return ["2020-01-01 00:00:00","2021-01-01 00:00:00"]
+     */
+    @SneakyThrows
+    public static List<String> getYearListBetween(String startTm, String endTm) {
+        Date beginDate = parse(startTm, DATE_TIME_PATTERN);
+        Date endDate = parse(endTm, DATE_TIME_PATTERN);
+        //重置成了开始时间的月初时间
+        Date resetDate = parse(format(parse(startTm, YEAR_PATTERN), DATE_TIME_PATTERN), DATE_TIME_PATTERN);
+        resetDate = beginDate.compareTo(resetDate) > 0 ? DateUtils.addDays(resetDate, 1) : resetDate;
+
+        List<String> yearList = Lists.newArrayList();
+        while (resetDate.compareTo(endDate) <= 0) {
+            yearList.add(format(resetDate, DATE_TIME_PATTERN));
+            resetDate = DateUtils.addYears(resetDate, 1);
+        }
+
+        return yearList;
+    }
+
+    /**
+     * 切割时间,返回时间列表
+     *
+     * @param startTime   开始时间
+     * @param endTime     结束时间
+     * @param granularity 切割时间的粒度 小时-Granularity.HOUR 天-Granularity.DAY 月-Granularity.MONTH
+     * @return
+     */
+    public static List<SplitedTimeParam> getSplitedTimeList(Long startTime, Long endTime, Granularity granularity) {
+        Map<String, SplitedTimeParam> splitedTimeGroupByTime = getSplitedTimeGroupByTime(timestampToDate(startTime), timestampToDate(endTime), granularity);
+        return splitedTimeGroupByTime.entrySet().stream().map(item -> item.getValue()).collect(Collectors.toList());
+    }
+
+    /**
+     * 切割时间
+     *
+     * @param startTime   开始时间
+     * @param endTime     结束时间
+     * @param granularity 切割时间的粒度 小时-Granularity.HOUR 天-Granularity.DAY 月-Granularity.MONTH
+     * @return
+     */
+    public static Map<String, SplitedTimeParam> getSplitedTimeGroupByTime(Long startTime, Long endTime, Granularity granularity) {
+        return getSplitedTimeGroupByTime(timestampToDate(startTime), timestampToDate(endTime), granularity);
+    }
+
+    /**
+     * 切割时间
+     *
+     * @param startTm     开始时间 "yyyy-MM-dd HH:mm:ss"
+     * @param endTm       结束时间 "yyyy-MM-dd HH:mm:ss"
+     * @param granularity 切割时间的粒度 小时-Granularity.HOUR 天-Granularity.DAY 月-Granularity.MONTH
+     * @return
+     */
+    public static Map<String, SplitedTimeParam> getSplitedTimeGroupByTime(String startTm, String endTm, Granularity granularity) {
+        Date beginDate = parse(startTm, DATE_TIME_PATTERN);
+        Date endDate = parse(endTm, DATE_TIME_PATTERN);
+        return getSplitedTimeGroupByTime(beginDate, endDate, granularity);
+    }
+
+    /**
+     * 切割时间  20211109-仅支持小时日月的切割
+     *
+     * @param beginDate   开始时间
+     * @param endDate     结束时间
+     * @param granularity 切割时间的粒度 小时-Granularity.HOUR 天-Granularity.DAY 月-Granularity.MONTH
+     * @return
+     */
+    public static Map<String, SplitedTimeParam> getSplitedTimeGroupByTime(Date beginDate, Date endDate, Granularity granularity) {
+        switch (granularity) {
+            case HOUR:
+                return getSplitedTimeMapByHour(beginDate, endDate);
+            case DAY:
+                return getSplitedTimeMapByDay(beginDate, endDate);
+            case MONTH:
+                return getSplitedTimeMapByMonth(beginDate, endDate);
+            case YEAR:
+                return getSplitedTimeMapByYear(beginDate, endDate);
+            default:
+                return getSplitedTimeMapByDay(beginDate, endDate);
+        }
+    }
+
+    /**
+     * 按小时切割时间,返回一个列表
+     *
+     * @param startTm 开始时间 "yyyy-MM-dd HH:mm:ss"
+     * @param endTm   结束时间 "yyyy-MM-dd HH:mm:ss"
+     * @return [{"beginTime":"2021-11-03 22:28:59","endTime":"2021-11-03 22:59:59"},{"beginTime":"2021-11-03 23:00:00","endTime":"2021-11-03 23:56:50"}]
+     */
+    public static List<SplitedTimeParam> getSplitedTimeListByHour(String startTm, String endTm) {
+        Date beginDate = parse(startTm, DATE_TIME_PATTERN);
+        Date endDate = parse(endTm, DATE_TIME_PATTERN);
+        Map<String, SplitedTimeParam> splitedTimeParamMap = getSplitedTimeMapByHour(beginDate, endDate);
+        return Lists.newArrayList(splitedTimeParamMap.values());
+    }
+
+    /**
+     * 按小时切割时间,返回一个列表
+     *
+     * @param beginDate 开始时间
+     * @param endDate   结束时间
+     * @return [{"beginTime":"2021-11-03 22:28:59","endTime":"2021-11-03 22:59:59"},{"beginTime":"2021-11-03 23:00:00","endTime":"2021-11-03 23:56:50"}]
+     */
+    public static List<SplitedTimeParam> getSplitedTimeListByHour(Date beginDate, Date endDate) {
+        Map<String, SplitedTimeParam> splitedTimeParamMap = getSplitedTimeMapByHour(beginDate, endDate);
+        return Lists.newArrayList(splitedTimeParamMap.values());
+    }
+
+    /**
+     * 按小时切割时间,返回一个映射
+     *
+     * @param startTm 开始时间 "yyyy-MM-dd HH:mm:ss"
+     * @param endTm   结束时间 "yyyy-MM-dd HH:mm:ss"
+     * @return {"2021-11-03 22:00:00":{"beginTime":"2021-11-03 22:28:59","endTime":"2021-11-03 22:59:59"},"2021-11-03 23:00:00":{"beginTime":"2021-11-03 23:00:00","endTime":"2021-11-03 23:56:50"}}
+     */
+    public static Map<String, SplitedTimeParam> getSplitedTimeMapByHour(String startTm, String endTm) {
+        Date beginDate = parse(startTm, DATE_TIME_PATTERN);
+        Date endDate = parse(endTm, DATE_TIME_PATTERN);
+        return getSplitedTimeMapByHour(beginDate, endDate);
+    }
+
+    /**
+     * 按小时切割时间,返回一个映射
+     *
+     * @param beginDate 开始时间
+     * @param endDate   结束时间
+     * @return {"2021-11-03 22:00:00":{"beginTime":"2021-11-03 22:28:59","endTime":"2021-11-03 22:59:59"},"2021-11-03 23:00:00":{"beginTime":"2021-11-03 23:00:00","endTime":"2021-11-03 23:56:50"}}
+     */
+    public static Map<String, SplitedTimeParam> getSplitedTimeMapByHour(Date beginDate, Date endDate) {
+        String startTm = format(beginDate, DATE_TIME_PATTERN);
+        String endTm = format(endDate, DATE_TIME_PATTERN);
+
+        Map<String, SplitedTimeParam> splitedTimeMap = new LinkedHashMap<>();
+        if (CompareUtil.compare(endDate, beginDate) < 0) {
+            log.warn("endDate is earlier than beginDate, beginDate:{}, endDate:{}", startTm, endTm);
+            return splitedTimeMap;
+        }
+        Date resetDate = parse(format(parse(startTm, DATE_HOUR_PATTERN), DATE_TIME_PATTERN), DATE_TIME_PATTERN);
+        while (CompareUtil.compare(resetDate, endDate) <= 0) {
+            SplitedTimeParam splitedTimeParam = new SplitedTimeParam();
+            if (CompareUtil.compare(resetDate, beginDate) <= 0) {
+                splitedTimeParam.setBeginTime(startTm);
+            } else if (CompareUtil.compare(resetDate, beginDate) > 0) {
+                splitedTimeParam.setBeginTime(format(resetDate, DATE_TIME_PATTERN));
+            }
+            if (CompareUtil.compare(DateUtils.addHours(resetDate, 1), endDate) > 0) {
+                splitedTimeParam.setEndTime(endTm);
+            } else if (CompareUtil.compare(DateUtils.addHours(resetDate, 1), endDate) <= 0) {
+                Date timePeriodEndDate = DateUtils.addSeconds(DateUtils.addHours(resetDate, 1), -1);
+                splitedTimeParam.setEndTime(format(timePeriodEndDate, DATE_TIME_PATTERN));
+            }
+            splitedTimeMap.put(format(resetDate, DATE_TIME_PATTERN), splitedTimeParam);
+            resetDate = DateUtils.addHours(resetDate, 1);
+        }
+        return splitedTimeMap;
+    }
+
+    /**
+     * 按天切割时间,返回一个列表
+     *
+     * @param startTm 开始时间 "yyyy-MM-dd HH:mm:ss"
+     * @param endTm   结束时间 "yyyy-MM-dd HH:mm:ss"
+     * @return [{"beginTime":"2021-11-02 22:28:59","endTime":"2021-11-02 23:59:59"},{"beginTime":"2021-11-03 00:00:00","endTime":"2021-11-03 23:56:50"}]
+     */
+    public static List<SplitedTimeParam> getSplitedTimeListByDay(String startTm, String endTm) {
+        Date beginDate = parse(startTm, DATE_TIME_PATTERN);
+        Date endDate = parse(endTm, DATE_TIME_PATTERN);
+        Map<String, SplitedTimeParam> splitedTimeParamMap = getSplitedTimeMapByDay(beginDate, endDate);
+        return Lists.newArrayList(splitedTimeParamMap.values());
+    }
+
+
+    /**
+     * 按天切割时间,返回一个列表
+     *
+     * @param beginDate 开始时间
+     * @param endDate   结束时间
+     * @return [{"beginTime":"2021-11-02 22:28:59","endTime":"2021-11-02 23:59:59"},{"beginTime":"2021-11-03 00:00:00","endTime":"2021-11-03 23:56:50"}]
+     */
+    public static List<SplitedTimeParam> getSplitedTimeListByDay(Date beginDate, Date endDate) {
+        Map<String, SplitedTimeParam> splitedTimeParamMap = getSplitedTimeMapByDay(beginDate, endDate);
+        return Lists.newArrayList(splitedTimeParamMap.values());
+    }
+
+
+    /**
+     * 按天分割时间,返回一个映射
+     *
+     * @param startTm 开始时间 "yyyy-MM-dd HH:mm:ss"
+     * @param endTm   结束时间 "yyyy-MM-dd HH:mm:ss"
+     * @return {"2021-11-02 00:00:00":{"beginTime":"2021-11-02 22:28:59","endTime":"2021-11-02 23:59:59"},"2021-11-03 00:00:00":{"beginTime":"2021-11-03 00:00:00","endTime":"2021-11-03 23:56:50"}}
+     */
+    public static Map<String, SplitedTimeParam> getSplitedTimeMapByDay(String startTm, String endTm) {
+        Date beginDate = parse(startTm, DATE_TIME_PATTERN);
+        Date endDate = parse(endTm, DATE_TIME_PATTERN);
+        return getSplitedTimeMapByDay(beginDate, endDate);
+    }
+
+
+    /**
+     * 按天分割时间,返回一个映射
+     *
+     * @param beginDate 开始时间
+     * @param endDate   结束时间
+     * @return {"2021-11-02 00:00:00":{"beginTime":"2021-11-02 22:28:59","endTime":"2021-11-02 23:59:59"},"2021-11-03 00:00:00":{"beginTime":"2021-11-03 00:00:00","endTime":"2021-11-03 23:56:50"}}
+     */
+    public static Map<String, SplitedTimeParam> getSplitedTimeMapByDay(Date beginDate, Date endDate) {
+        String startTm = format(beginDate, DATE_TIME_PATTERN);
+        String endTm = format(endDate, DATE_TIME_PATTERN);
+
+        Map<String, SplitedTimeParam> splitedTimeMap = new LinkedHashMap<>();
+        if (CompareUtil.compare(endDate, beginDate) < 0) {
+            log.warn("endDate is earlier than beginDate, beginDate:{}, endDate:{}", startTm, endTm);
+            return splitedTimeMap;
+        }
+        Date resetDate = parse(format(parse(startTm, DATE_PATTERN), DATE_TIME_PATTERN), DATE_TIME_PATTERN);
+        while (CompareUtil.compare(resetDate, endDate) <= 0) {
+            SplitedTimeParam splitedTimeParam = new SplitedTimeParam();
+            if (CompareUtil.compare(resetDate, beginDate) <= 0) {
+                splitedTimeParam.setBeginTime(startTm);
+            } else if (CompareUtil.compare(resetDate, beginDate) > 0) {
+                splitedTimeParam.setBeginTime(format(resetDate, DATE_TIME_PATTERN));
+            }
+
+            if (CompareUtil.compare(DateUtils.addDays(resetDate, 1), endDate) > 0) {
+                splitedTimeParam.setEndTime(endTm);
+            } else if (CompareUtil.compare(DateUtils.addDays(resetDate, 1), endDate) <= 0) {
+                Date timePeriodEndDate = DateUtils.addSeconds(DateUtils.addDays(resetDate, 1), -1);
+                splitedTimeParam.setEndTime(format(timePeriodEndDate, DATE_TIME_PATTERN));
+            }
+            splitedTimeMap.put(format(resetDate, DATE_TIME_PATTERN), splitedTimeParam);
+            resetDate = DateUtils.addDays(resetDate, 1);
+        }
+        return splitedTimeMap;
+    }
+
+
+    /**
+     * 按月切割时间,返回一个列表
+     *
+     * @param startTm 开始时间 "yyyy-MM-dd HH:mm:ss"
+     * @param endTm   结束时间 "yyyy-MM-dd HH:mm:ss"
+     * @return [{"beginTime":"2021-10-02 22:28:59","endTime":"2021-10-31 23:59:59"},{"beginTime":"2021-11-01 00:00:00","endTime":"2021-11-03 23:56:50"}]
+     */
+    public static List<SplitedTimeParam> getSplitedTimeListByMonth(String startTm, String endTm) {
+        Date beginDate = parse(startTm, DATE_TIME_PATTERN);
+        Date endDate = parse(endTm, DATE_TIME_PATTERN);
+        Map<String, SplitedTimeParam> splitedTimeParamMap = getSplitedTimeMapByMonth(beginDate, endDate);
+        return Lists.newArrayList(splitedTimeParamMap.values());
+    }
+
+
+    /**
+     * 按月切割时间,返回一个列表
+     *
+     * @param beginDate 开始时间
+     * @param endDate   结束时间
+     * @return [{"beginTime":"2021-10-02 22:28:59","endTime":"2021-10-31 23:59:59"},{"beginTime":"2021-11-01 00:00:00","endTime":"2021-11-03 23:56:50"}]
+     */
+    public static List<SplitedTimeParam> getSplitedTimeListByMonth(Date beginDate, Date endDate) {
+        Map<String, SplitedTimeParam> splitedTimeParamMap = getSplitedTimeMapByMonth(beginDate, endDate);
+        return Lists.newArrayList(splitedTimeParamMap.values());
+    }
+
+
+    /**
+     * 按月分割时间,返回一个映射
+     *
+     * @param startTm 开始时间 "yyyy-MM-dd HH:mm:ss"
+     * @param endTm   结束时间 "yyyy-MM-dd HH:mm:ss"
+     * @return {"2021-10-01 00:00:00":{"beginTime":"2021-10-02 22:28:59","endTime":"2021-10-31 23:59:59"},"2021-11-01 00:00:00":{"beginTime":"2021-11-01 00:00:00","endTime":"2021-11-03 23:56:50"}}
+     */
+    public static Map<String, SplitedTimeParam> getSplitedTimeMapByMonth(String startTm, String endTm) {
+        Date beginDate = parse(startTm, DATE_TIME_PATTERN);
+        Date endDate = parse(endTm, DATE_TIME_PATTERN);
+        return getSplitedTimeMapByMonth(beginDate, endDate);
+    }
+
+    public static void main(String[] args) {
+        System.out.println(getSplitedTimeMapByMonth("2023-08-07 22:28:59", "2023-09-07 23:59:58"));
+        System.out.println(getSplitedTimeMapByDay("2023-08-03 22:28:59", "2023-08-07 23:59:58"));
+    }
+
+    /**
+     * 按月分割时间,返回一个映射
+     *
+     * @param beginDate 开始时间
+     * @param endDate   结束时间
+     * @return {"2021-10-01 00:00:00":{"beginTime":"2021-10-02 22:28:59","endTime":"2021-10-31 23:59:59"},"2021-11-01 00:00:00":{"beginTime":"2021-11-01 00:00:00","endTime":"2021-11-03 23:56:50"}}
+     */
+    public static Map<String, SplitedTimeParam> getSplitedTimeMapByMonth(Date beginDate, Date endDate) {
+        String startTm = format(beginDate, DATE_TIME_PATTERN);
+        String endTm = format(endDate, DATE_TIME_PATTERN);
+
+        Map<String, SplitedTimeParam> splitedTimeMap = new LinkedHashMap<>();
+        if (CompareUtil.compare(endDate, beginDate) < 0) {
+            log.warn("endDate is earlier than beginDate, beginDate:{}, endDate:{}", startTm, endTm);
+            return splitedTimeMap;
+        }
+        Date resetDate = parse(format(parse(startTm, MONTH_PATTERN), DATE_TIME_PATTERN), DATE_TIME_PATTERN);
+        while (CompareUtil.compare(resetDate, endDate) <= 0) {
+            SplitedTimeParam splitedTimeParam = new SplitedTimeParam();
+            if (CompareUtil.compare(resetDate, beginDate) <= 0) {
+                splitedTimeParam.setBeginTime(startTm);
+            } else if (CompareUtil.compare(resetDate, beginDate) > 0) {
+                splitedTimeParam.setBeginTime(format(resetDate, DATE_TIME_PATTERN));
+            }
+            if (CompareUtil.compare(DateUtils.addMonths(resetDate, 1), endDate) > 0) {
+                splitedTimeParam.setEndTime(endTm);
+            } else if (CompareUtil.compare(DateUtils.addMonths(resetDate, 1), endDate) <= 0) {
+                Date timePeriodEndDate = DateUtils.addSeconds(DateUtils.addMonths(resetDate, 1), -1);
+                splitedTimeParam.setEndTime(format(timePeriodEndDate, DATE_TIME_PATTERN));
+            }
+            splitedTimeMap.put(format(resetDate, DATE_TIME_PATTERN), splitedTimeParam);
+            resetDate = DateUtils.addMonths(resetDate, 1);
+        }
+        return splitedTimeMap;
+    }
+
+    /**
+     * 按年分割时间,返回一个映射
+     *
+     * @param startTm 开始时间
+     * @param endTm   结束时间
+     * @return {2022-01-01 00:00:00=SplitedTimeParam(beginTime=2022-04-03 00:00:00, endTime=2022-12-31 23:59:59), 2023-01-01 00:00:00=SplitedTimeParam(beginTime=2023-01-01 00:00:00, endTime=2023-04-03 00:00:00)}
+     */
+    public static Map<String, SplitedTimeParam> getSplitedTimeMapByYear(String startTm, String endTm) {
+        Date beginDate = parse(startTm, DATE_TIME_PATTERN);
+        Date endDate = parse(endTm, DATE_TIME_PATTERN);
+        return getSplitedTimeMapByYear(beginDate, endDate);
+    }
+
+    /**
+     * 按年分割时间,返回一个映射
+     *
+     * @param beginDate 开始时间
+     * @param endDate   结束时间
+     * @return {2022-01-01 00:00:00=SplitedTimeParam(beginTime=2022-04-03 00:00:00, endTime=2022-12-31 23:59:59), 2023-01-01 00:00:00=SplitedTimeParam(beginTime=2023-01-01 00:00:00, endTime=2023-04-03 00:00:00)}
+     */
+    public static Map<String, SplitedTimeParam> getSplitedTimeMapByYear(Date beginDate, Date endDate) {
+        String startTm = format(beginDate, DATE_TIME_PATTERN);
+        String endTm = format(endDate, DATE_TIME_PATTERN);
+
+        Map<String, SplitedTimeParam> splitedTimeMap = new LinkedHashMap<>();
+        if (CompareUtil.compare(endDate, beginDate) < 0) {
+            log.warn("endDate is earlier than beginDate, beginDate:{}, endDate:{}", startTm, endTm);
+            return splitedTimeMap;
+        }
+        Date resetDate = parse(format(parse(startTm, YEAR_PATTERN), DATE_TIME_PATTERN), DATE_TIME_PATTERN);
+        while (CompareUtil.compare(resetDate, endDate) <= 0) {
+            SplitedTimeParam splitedTimeParam = new SplitedTimeParam();
+            if (CompareUtil.compare(resetDate, beginDate) <= 0) {
+                splitedTimeParam.setBeginTime(startTm);
+            } else if (CompareUtil.compare(resetDate, beginDate) > 0) {
+                splitedTimeParam.setBeginTime(format(resetDate, DATE_TIME_PATTERN));
+            }
+            if (CompareUtil.compare(DateUtils.addYears(resetDate, 1), endDate) > 0) {
+                splitedTimeParam.setEndTime(endTm);
+            } else if (CompareUtil.compare(DateUtils.addYears(resetDate, 1), endDate) <= 0) {
+                Date timePeriodEndDate = DateUtils.addSeconds(DateUtils.addYears(resetDate, 1), -1);
+                splitedTimeParam.setEndTime(format(timePeriodEndDate, DATE_TIME_PATTERN));
+            }
+            splitedTimeMap.put(format(resetDate, DATE_TIME_PATTERN), splitedTimeParam);
+            resetDate = DateUtils.addYears(resetDate, 1);
+        }
+        return splitedTimeMap;
+    }
+
+    /**
+     * 获得当前时间的所在天的第一秒
+     *
+     * @return yyyy-MM-dd HH:mm:ss
+     */
+    public static String getDayBeginTime() {
+        return getDayBeginTime(new Date());
+    }
+
+    /**
+     * 获得当前时间的所在天的第一秒
+     *
+     * @param currentDate 当前时间
+     * @return yyyy-MM-dd HH:mm:ss
+     */
+    public static String getDayBeginTime(Date currentDate) {
+        String currentTime = format(currentDate, DATE_TIME_PATTERN);
+        return getDayBeginTime(currentTime);
+    }
+
+    /**
+     * 获得当前时间的所在天的起始时间
+     *
+     * @param currentTime 当前时间 yyyy-MM-dd HH:mm:ss
+     * @return yyyy-MM-dd HH:mm:ss
+     */
+    public static String getDayBeginTime(String currentTime) {
+        return format(parse(currentTime, DATE_PATTERN), DATE_TIME_PATTERN);
+    }
+
+
+    /**
+     * 获得当前时间的所在天的最后一秒
+     *
+     * @return yyyy-MM-dd HH:mm:ss
+     */
+    public static String getDayEndTime() {
+        String currentTime = format(new Date(), DATE_TIME_PATTERN);
+        return getDayEndTime(currentTime);
+    }
+
+
+    /**
+     * 获得当前时间的所在天的最后一秒
+     *
+     * @param currentDate 当前时间
+     * @return yyyy-MM-dd HH:mm:ss
+     */
+    public static String getDayEndTime(Date currentDate) {
+        String currentTime = format(currentDate, DATE_TIME_PATTERN);
+        return getDayEndTime(currentTime);
+    }
+
+    /**
+     * 获得当前时间的所在天的最后一秒
+     *
+     * @param currentTime 当前时间 yyyy-MM-dd HH:mm:ss
+     * @return yyyy-MM-dd HH:mm:ss
+     */
+    public static String getDayEndTime(String currentTime) {
+        Date resetDate = parse(getDayBeginTime(currentTime), DATE_TIME_PATTERN);
+        return format(DateUtils.addSeconds(DateUtils.addDays(resetDate, 1), -1), DATE_TIME_PATTERN);
+    }
+
+    /**
+     * 获得当前时间的所在月的第一秒
+     *
+     * @return yyyy-MM-dd HH:mm:ss
+     */
+    public static String getMonthBeginTime() {
+        String currentTime = format(new Date(), DATE_TIME_PATTERN);
+        return getMonthBeginTime(currentTime);
+    }
+
+    /**
+     * 获得当前时间的所在月的第一秒
+     *
+     * @param currentDate 当前时间
+     * @return yyyy-MM-dd HH:mm:ss
+     */
+    public static String getMonthBeginTime(Date currentDate) {
+        String currentTime = format(currentDate, DATE_TIME_PATTERN);
+        return getMonthBeginTime(currentTime);
+    }
+
+    /**
+     * 获得当前时间的所在月的第一秒
+     *
+     * @param currentTime 当前时间 yyyy-MM-dd HH:mm:ss
+     * @return yyyy-MM-dd HH:mm:ss
+     */
+    public static String getMonthBeginTime(String currentTime) {
+        return format(parse(currentTime, MONTH_PATTERN), DATE_TIME_PATTERN);
+    }
+
+
+    /**
+     * 获得当前时间的所在月的最后一秒
+     *
+     * @return yyyy-MM-dd HH:mm:ss
+     */
+    public static String getMonthEndTime() {
+        String currentTime = format(new Date(), DATE_TIME_PATTERN);
+        return getMonthEndTime(currentTime);
+    }
+
+    /**
+     * 获得当前时间的所在月的最后一秒
+     *
+     * @param currentDate 当前时间
+     * @return yyyy-MM-dd HH:mm:ss
+     */
+    public static String getMonthEndTime(Date currentDate) {
+        String currentTime = format(currentDate, DATE_TIME_PATTERN);
+        return getMonthEndTime(currentTime);
+    }
+
+    /**
+     * 获得当前时间的所在月的最后一秒
+     *
+     * @param currentTime 当前时间 yyyy-MM-dd HH:mm:ss
+     * @return yyyy-MM-dd HH:mm:ss
+     */
+    public static String getMonthEndTime(String currentTime) {
+        Date resetDate = parse(getMonthBeginTime(currentTime), DATE_TIME_PATTERN);
+        return format(DateUtils.addSeconds(DateUtils.addMonths(resetDate, 1), -1), DATE_TIME_PATTERN);
+    }
+
+    /**
+     * 获得当前时间的所在年的第一秒
+     *
+     * @return yyyy-MM-dd HH:mm:ss
+     */
+    public static String getYearBeginTime() {
+        String currentTime = format(new Date(), DATE_TIME_PATTERN);
+        return getYearBeginTime(currentTime);
+    }
+
+    /**
+     * 获得当前时间的所在年的第一秒
+     *
+     * @param currentDate 当前时间
+     * @return yyyy-MM-dd HH:mm:ss
+     */
+    public static String getYearBeginTime(Date currentDate) {
+        String currentTime = format(currentDate, DATE_TIME_PATTERN);
+        return getYearBeginTime(currentTime);
+    }
+
+    /**
+     * 获得当前时间的所在年的第一秒
+     *
+     * @param currentTime 当前时间 yyyy-MM-dd HH:mm:ss
+     * @return yyyy-MM-dd HH:mm:ss
+     */
+    public static String getYearBeginTime(String currentTime) {
+        return format(parse(currentTime, YEAR_PATTERN), DATE_TIME_PATTERN);
+    }
+
+
+    /**
+     * 获得当前时间的所在年的最后一秒
+     *
+     * @return yyyy-MM-dd HH:mm:ss
+     */
+    public static String getYearEndTime() {
+        String currentTime = format(new Date(), DATE_TIME_PATTERN);
+        return getYearEndTime(currentTime);
+    }
+
+    /**
+     * 获得当前时间的所在年的最后一秒
+     *
+     * @param currentDate 当前时间
+     * @return yyyy-MM-dd HH:mm:ss
+     */
+    public static String getYearEndTime(Date currentDate) {
+        String currentTime = format(currentDate, DATE_TIME_PATTERN);
+        return getYearEndTime(currentTime);
+    }
+
+    /**
+     * 获得当前时间的所在年的最后一秒
+     *
+     * @param currentTime 当前时间 yyyy-MM-dd HH:mm:ss
+     * @return yyyy-MM-dd HH:mm:ss
+     */
+    public static String getYearEndTime(String currentTime) {
+        Date resetDate = parse(getYearBeginTime(currentTime), DATE_TIME_PATTERN);
+        return format(DateUtils.addSeconds(DateUtils.addYears(resetDate, 1), -1), DATE_TIME_PATTERN);
+    }
+
+    /**
+     * 字符串时间转时间戳
+     *
+     * @param currentTime 当前时间
+     * @param pattern     日期格式
+     * @return 返回时间戳
+     */
+    public static Long dateToTimestamp(String currentTime, String pattern) {
+        return parse(currentTime, pattern).getTime();
+    }
+
+    /**
+     * 时间转时间戳
+     *
+     * @param currentDate 当前时间
+     * @return 返回时间戳
+     */
+    public static Long dateToTimestamp(Date currentDate) {
+        return currentDate.getTime();
+    }
+
+    /**
+     * 时间戳转时间
+     *
+     * @param currentTimestamp 当前时间戳
+     * @return 返回日期
+     */
+    public static Date timestampToDate(Long currentTimestamp) {
+        return new Date(currentTimestamp);
+    }
+
+    /**
+     * 时间戳转时间
+     *
+     * @param currentTimestamp 当前时间戳
+     * @param pattern          字符串格式
+     * @return 返回日期
+     */
+    public static String timestampToDate(Long currentTimestamp, String pattern) {
+        Date date = new Date(currentTimestamp);
+        return format(date, pattern);
+    }
+
+
+    /**
+     * 传入一个时间,获取此时间在tb中属于哪个时间段的读数,则获取的这个时间段的开始时间
+     *
+     * @param currentDate 传入的时间
+     * @param interval    传入读数的频率,不能大于60
+     * @return
+     */
+    public static Date getBeginTime(Date currentDate, Integer interval) {
+        interval = interval > 60 ? 60 : interval;
+        Calendar currentCalendar = Calendar.getInstance();
+        currentCalendar.setTime(currentDate);
+
+        int beginTimeMinute = currentCalendar.get(Calendar.MINUTE) / interval * interval;
+        currentCalendar.set(Calendar.MINUTE, beginTimeMinute);
+        return currentCalendar.getTime();
+    }
+
+
+    /**
+     * 传入一个时间,获取此时间在tb中属于哪个时间段的读数,则获取的这个时间段的开始时间
+     *
+     * @param currentDate 传入的时间 yyyy-MM-dd HH:mm:ss
+     * @param interval    传入读数的频率,不能大于60
+     * @return
+     */
+    public static Date getBeginTime(String currentDate, Integer interval) {
+        return getBeginTime(parse(currentDate, DATE_TIME_PATTERN), interval);
+    }
+
+
+    /**
+     * 传入一个时间,获取此时间在tb中属于哪个时间段的读数,则获取的这个时间段的开始时间
+     *
+     * @param currentTimeStamp 传入的时间戳
+     * @param interval         传入读数的频率,不能大于60
+     * @return
+     */
+    public static Date getBeginTime(Long currentTimeStamp, Integer interval) {
+        return getBeginTime(new Date(currentTimeStamp), interval);
+    }
+
+
+    /**
+     * 传入一个时间,获取此时间在tb中属于哪个时间段的读数,则获取的这个时间段的开始时间,间隔时间默认为15
+     *
+     * @param currentDate 传入的时间 yyyy-MM-dd HH:mm:ss
+     * @return
+     */
+    public static Date getBeginTime(Date currentDate) {
+        return getBeginTime(currentDate, 15);
+    }
+
+
+    /**
+     * 传入一个时间,获取此时间在tb中属于哪个时间段的读数,则获取的这个时间段的结束时间
+     *
+     * @param currentDate 传入的时间 yyyy-MM-dd HH:mm:ss
+     * @param interval    传入读数的频率,不能大于60
+     * @return
+     */
+    public static Date getEndTime(Date currentDate, Integer interval) {
+        interval = interval > 60 ? 60 : interval;
+        Calendar currentCalendar = Calendar.getInstance();
+        currentCalendar.setTime(currentDate);
+
+        int beginTimeMinute = currentCalendar.get(Calendar.MINUTE) / interval * (interval + 1);
+        currentCalendar.set(Calendar.MINUTE, beginTimeMinute);
+        return currentCalendar.getTime();
+    }
+
+
+    /**
+     * 传入一个时间,获取此时间在tb中属于哪个时间段的读数,则获取的这个时间段的结束时间
+     *
+     * @param currentDate 传入的时间 yyyy-MM-dd HH:mm:ss
+     * @param interval    传入读数的频率,不能大于60
+     * @return
+     */
+    public static Date getEndTime(String currentDate, Integer interval) {
+        return getEndTime(parse(currentDate, DATE_TIME_PATTERN), interval);
+    }
+
+
+    /**
+     * 传入一个时间,获取此时间在tb中属于哪个时间段的读数,则获取的这个时间段的结束时间
+     *
+     * @param currentTimeStamp 传入的时间戳
+     * @param interval         传入读数的频率,不能大于60
+     * @return
+     */
+    private static Date getEndTime(Long currentTimeStamp, Integer interval) {
+        return getEndTime(new Date(currentTimeStamp), interval);
+    }
+
+
+    /**
+     * 传入一个时间,获取此时间在tb中属于哪个时间段的读数,则获取的这个时间段的结束时间,间隔时间默认为15
+     *
+     * @param currentDate 传入的时间 yyyy-MM-dd HH:mm:ss
+     * @return
+     */
+    private static Date getEndTime(Date currentDate) {
+        return getEndTime(currentDate, 15);
+    }
+
+
+    /**
+     * 对日期的【小时】进行加/减
+     *
+     * @param date  日期
+     * @param hours 小时数,负数为减
+     * @return 加/减几小时后的日期
+     */
+    public static String addDateHours(Date date, int hours) {
+        DateTime dateTime = new DateTime(date);
+        return format(dateTime.plusHours(hours).toDate(), DATE_TIME_PATTERN);
+    }
+
+    /**
+     * 对日期的【天】进行加/减
+     *
+     * @param date 日期
+     * @param days 天数,负数为减
+     * @return 加/减几天后的日期
+     */
+    public static String addDateDays(Date date, int days) {
+        DateTime dateTime = new DateTime(date);
+        return format(dateTime.plusDays(days).toDate(), DATE_TIME_PATTERN);
+    }
+
+    /**
+     * 根据传入时间获取时间
+     * @param currentTime
+     * @param granularity
+     * @return
+     */
+    public static SplitedTimeParam getSplitTimeByGranularity(String currentTime, Granularity granularity) {
+        SplitedTimeParam splitedTimeParam = new SplitedTimeParam();
+        Map<String, String> dateMap = new HashMap<>();
+
+        if (CompareUtil.compare(granularity, Granularity.DAY) == 0) {
+            splitedTimeParam.setBeginTime(getDayBeginTime(currentTime));
+            splitedTimeParam.setEndTime(getDayEndTime(currentTime));
+            return splitedTimeParam;
+        }
+        if (CompareUtil.compare(granularity, Granularity.MONTH) == 0) {
+            splitedTimeParam.setBeginTime(getMonthBeginTime(currentTime));
+            splitedTimeParam.setEndTime(getMonthEndTime(currentTime));
+            return splitedTimeParam;
+        }
+        if (CompareUtil.compare(granularity, Granularity.YEAR) == 0) {
+            splitedTimeParam.setBeginTime(getYearBeginTime(currentTime));
+            splitedTimeParam.setEndTime(getYearEndTime(currentTime));
+            return splitedTimeParam;
+        }
+        return splitedTimeParam;
+    }
+
+    /**
+     * 根据时间范围获取时间
+     *
+     * @param timeHorizon
+     * @return
+     */
+    public static Map<String, String> getDateTimeByTimeHorizon(String timeHorizon) {
+        Date date = Calendar.getInstance().getTime();
+        Map<String, String> dateMap = new HashMap<>();
+        if (StringUtils.equals(timeHorizon, TimeHorizon.CURRENT_DAY.getCode())) {
+            dateMap.put("beginTime", getDayBeginTime(date));
+            dateMap.put("endTime", getDayEndTime(date));
+            return dateMap;
+        }
+
+        if (StringUtils.equals(timeHorizon, TimeHorizon.LAST_HOURS.getCode())) {
+            dateMap.put("beginTime", addDateHours(date, -24));
+            dateMap.put("endTime", format(date, DATE_TIME_PATTERN));
+            return dateMap;
+        }
+
+        if (StringUtils.equals(timeHorizon, TimeHorizon.LAST_DAYS.getCode())) {
+            dateMap.put("beginTime", addDateDays(date, -7));
+            dateMap.put("endTime", format(date, DATE_TIME_PATTERN));
+            return dateMap;
+        }
+        dateMap.put("beginTime", addDateDays(date, -30));
+        dateMap.put("endTime", format(date, DATE_TIME_PATTERN));
+        return dateMap;
+    }
+
+
+}

+ 2 - 0
ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java

@@ -119,6 +119,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
                 .antMatchers("/Wms/Wcs/**").permitAll()
                 .antMatchers("/dev-api/test/tank/**").permitAll()
                 .antMatchers("/dev-api/test/wcs2/**").permitAll()
+                .antMatchers("/largeScreen/**").permitAll()
+                .antMatchers("/car/**").permitAll()
                 // 库位视图
                 .antMatchers("/ams/locationView/**").permitAll()
                 // 除上面外的所有请求全部需要鉴权认证

+ 59 - 0
warewms-ams/src/main/java/com/ruoyi/ams/agv/car/domain/CarInfo.java

@@ -0,0 +1,59 @@
+package com.ruoyi.ams.agv.car.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.ruoyi.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 入库单明细对象 wms_doc_asn_details
+ * 
+ * @author ruoyi
+ * @date 2022-11-14
+ */
+@Data
+public class CarInfo extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "id")
+    private String id;
+
+    @ApiModelProperty(value = "车编号")
+    @TableField(value = "carNo")
+    private String carNo;
+
+    @ApiModelProperty(value = "仓库编号")
+    private String warehouseId;
+
+    @ApiModelProperty(value = "状态")
+    private String state;
+
+    @ApiModelProperty(value = "是否启用")
+    private String activeFlag;
+
+    @ApiModelProperty(value = "电池")
+    private String battery;
+
+    @ApiModelProperty(value = "x轴")
+    private String x;
+
+    @ApiModelProperty(value = "y轴")
+    private String y;
+
+    @ApiModelProperty(value = "时间")
+    private String userdefine1;
+
+    @ApiModelProperty(value = "时间")
+    private String userdefine2;
+
+    @ApiModelProperty(value = "时间")
+    private String userdefine3;
+
+    @ApiModelProperty(value = "时间")
+    private String userdefine4;
+
+    @ApiModelProperty(value = "时间")
+    private String userdefine5;
+
+}

+ 21 - 0
warewms-ams/src/main/java/com/ruoyi/ams/agv/car/dto/CarInfoDTO.java

@@ -0,0 +1,21 @@
+package com.ruoyi.ams.agv.car.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class CarInfoDTO implements Serializable {
+
+    private static final long serialVersionUID = 4857035237485972793L;
+
+    @ApiModelProperty(value = "车辆编号")
+    private String carNo;
+
+    @ApiModelProperty(value = "电池")
+    private String battery;
+
+    @ApiModelProperty(value = "状态")
+    private String state;
+}

+ 17 - 0
warewms-ams/src/main/java/com/ruoyi/ams/agv/car/mapper/CarInfoMapper.java

@@ -0,0 +1,17 @@
+package com.ruoyi.ams.agv.car.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.ams.agv.car.domain.CarInfo;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 入库单明细Mapper接口
+ *
+ * @author ruoyi
+ * @date 2022-11-03
+ */
+@Mapper
+public interface CarInfoMapper extends BaseMapper<CarInfo> {
+
+
+}

+ 22 - 0
warewms-ams/src/main/java/com/ruoyi/ams/agv/car/service/ICarInfoService.java

@@ -0,0 +1,22 @@
+package com.ruoyi.ams.agv.car.service;
+
+import com.ruoyi.ams.agv.car.dto.CarInfoDTO;
+
+import java.util.List;
+
+/**
+ * 入库单Service接口
+ *
+ * @author ruoyi
+ * @date 2022-10-12
+ */
+public interface ICarInfoService {
+
+    List<CarInfoDTO> queryCarInfo();
+
+    Boolean updateCarInfo(String carNo, String x, String y);
+
+    Boolean updateCarInfo(String carNo, String battery);
+
+    Boolean updateCarInfo(String carNo, String battery, String x, String y);
+}

+ 57 - 0
warewms-ams/src/main/java/com/ruoyi/ams/agv/car/service/impl/CarInfoServiceImpl.java

@@ -0,0 +1,57 @@
+package com.ruoyi.ams.agv.car.service.impl;
+
+import cn.hutool.core.collection.CollectionUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.ruoyi.ams.agv.car.domain.CarInfo;
+import com.ruoyi.ams.agv.car.dto.CarInfoDTO;
+import com.ruoyi.ams.agv.car.mapper.CarInfoMapper;
+import com.ruoyi.ams.agv.car.service.ICarInfoService;
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.utils.ConvertUtils;
+import com.ruoyi.common.utils.StringUtils;
+import org.apache.commons.compress.utils.Lists;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 入库单Service业务层处理
+ *
+ * @author ruoyi
+ * @date 2022-10-12
+ */
+@Service
+public class CarInfoServiceImpl implements ICarInfoService {
+
+    @Autowired
+    private CarInfoMapper carInfoMapper;
+
+    @Override
+    public List<CarInfoDTO> queryCarInfo(){
+        List<CarInfo> carInfoList = carInfoMapper.selectList(Wrappers.<CarInfo>lambdaQuery().eq(CarInfo::getActiveFlag, Constants.YES));
+        return CollectionUtil.isNotEmpty(carInfoList) ? ConvertUtils.sourceToTarget(carInfoList, CarInfoDTO.class) : Lists.newArrayList();
+    }
+
+    @Override
+    public Boolean updateCarInfo(String carNo, String x, String y) {
+        return updateCarInfo(carNo, null, x, y);
+    }
+
+    @Override
+    public Boolean updateCarInfo(String carNo, String battery) {
+        return updateCarInfo(carNo, battery);
+    }
+
+    @Override
+    public Boolean updateCarInfo(String carNo, String battery, String x, String y) {
+        return carInfoMapper.update(new CarInfo(), Wrappers.<CarInfo>lambdaUpdate()
+                .set(StringUtils.isNotBlank(battery), CarInfo::getBattery, battery)
+                .set(StringUtils.isNotBlank(x), CarInfo::getX, x)
+                .set(StringUtils.isNotBlank(y), CarInfo::getY, y)
+                .eq(CarInfo::getCarNo, carNo)) > 0;
+    }
+
+
+
+}

+ 11 - 0
warewms-ams/src/main/java/com/ruoyi/ams/agv/car/vo/CarInfoVO.java

@@ -0,0 +1,11 @@
+package com.ruoyi.ams.agv.car.vo;
+
+import com.ruoyi.ams.agv.car.domain.CarInfo;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class CarInfoVO extends CarInfo {
+
+}

+ 40 - 5
warewms-ams/src/main/java/com/ruoyi/ams/agv/ndc/service/impl/SocketBufferServiceImpl.java

@@ -1,7 +1,9 @@
 package com.ruoyi.ams.agv.ndc.service.impl;
 
+import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
+import com.ruoyi.ams.agv.car.service.ICarInfoService;
 import com.ruoyi.ams.agv.ndc.common.Aci;
 import com.ruoyi.ams.agv.ndc.common.ByteUtil;
 import com.ruoyi.ams.agv.ndc.domain.AmsNdcEvent;
@@ -49,6 +51,8 @@ public class SocketBufferServiceImpl implements SocketBufferService {
     private ChargerButtProxy chargerButtProxy;
     @Autowired
     private RedisCache redisCache;
+    @Autowired
+    private ICarInfoService carInfoService;
 
     // 创建一个线程池
     private static ExecutorService executorService;
@@ -111,17 +115,29 @@ public class SocketBufferServiceImpl implements SocketBufferService {
     @Override
     public void handleMsgOrderStatus(byte[] parameters) {
         int carNo = ByteUtil.getUnsignedShort(parameters, 6);
+        if (ObjectUtil.isNull(carNo)) {
+            log.error("SocketBufferServiceImpl - handleMsgOrderStatus carNo is null");
+            return;
+        }
         switch (parameters[5]) {
             case 0x58:
                 //电池余量为千分比
-                //car.setBattery(ByteUtil.getUnsignedShort(parameters, 14) / 10);
-                //car.update();
+                int battery = ByteUtil.getUnsignedShort(parameters, 14) / 10;
+                if (ObjectUtil.isNull(battery)) {
+                    log.error("SocketBufferServiceImpl - handleMsgOrderStatus battery is null");
+                    return;
+                }
+                carInfoService.updateCarInfo(String.valueOf(carNo), String.valueOf(battery));
                 break;
             case 0x63:
                 //xy轴位置
-                //car.setX(251770 - ByteUtil.getUnsignedShort(parameters, 6) * 10);
-                //car.setY(96620 - ByteUtil.getUnsignedShort(parameters, 14) * 10);
-                //car.update();
+                int x = 251770 - ByteUtil.getUnsignedShort(parameters, 6) * 10;
+                int y = 96620 - ByteUtil.getUnsignedShort(parameters, 14) * 10;
+                if (ObjectUtil.isNull(x) || ObjectUtil.isNull(y)) {
+                    log.error("SocketBufferServiceImpl - handleMsgOrderStatus coordinate is null");
+                    return;
+                }
+                carInfoService.updateCarInfo(String.valueOf(carNo), String.valueOf(x), String.valueOf(y));
                 break;
         }
     }
@@ -378,6 +394,25 @@ public class SocketBufferServiceImpl implements SocketBufferService {
                         chargerButtProxy.theChargingSynchronizer(index202, chargingSite202, agvNo202, END);
                     });
                     break;
+                case 203://NDC eCode = 702 | 4003消息:车号
+                    Integer agvNo = Integer.parseInt(event.getLp1()); // 车号
+                    if (ObjectUtil.isNull(agvNo)) {
+                        log.error("SocketBufferServiceImpl - handleMsgEvent event 702 agvNo is null");
+                        return;
+                    }
+                    Integer battery = Integer.parseInt(event.getLp2()); // 电量
+                    if (ObjectUtil.isNull(battery)) {
+                        log.error("SocketBufferServiceImpl - handleMsgEvent event 702 battery is null");
+                        return;
+                    }
+                    Integer x = Integer.parseInt(event.getLp3()); // x坐标
+                    Integer y = Integer.parseInt(event.getLp4()); // y坐标
+                    if (ObjectUtil.isNull(x) || ObjectUtil.isNull(y)) {
+                        log.error("SocketBufferServiceImpl - handleMsgEvent event 702 coordinate is null");
+                        return;
+                    }
+                    carInfoService.updateCarInfo(String.valueOf(agvNo), String.valueOf(battery), String.valueOf(x), String.valueOf(y));
+                    break;
                 default:
                     log.info("----event:" + eventId);
                     break;

+ 4 - 4
warewms-ams/src/main/java/com/ruoyi/ams/inv/mapper/InvLotLocIdMapper.java

@@ -1,9 +1,5 @@
 package com.ruoyi.ams.inv.mapper;
 
-import java.math.BigDecimal;
-import java.util.List;
-import java.util.Map;
-
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.ruoyi.ams.config.domain.dto.LotattDTO;
 import com.ruoyi.ams.inv.domain.InvLotAtt;
@@ -14,6 +10,10 @@ import com.ruoyi.base.domain.vo.BaseLocationLotattDTO;
 import com.ruoyi.common.core.domain.AjaxResult;
 import org.apache.ibatis.annotations.Param;
 
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Map;
+
 /**
  * 库位库存信息Mapper接口
  *

+ 4 - 0
warewms-ams/src/main/java/com/ruoyi/ams/inv/service/IInvLotLocIdService.java

@@ -331,6 +331,8 @@ public interface IInvLotLocIdService {
      */
     Boolean clearTraceIdByLocationId(String locationId);
 
+    List<InvLotLocId> selectInvLocIdList();
+
     /**
      * 根据库位id关联任务id
      * @param locationId
@@ -353,4 +355,6 @@ public interface IInvLotLocIdService {
      * @return
      */
     Boolean updateInvLotLocId(String locationId, BigDecimal qtyallocated);
+
+    List<InvLotLocId> selectInvLotLocIdByTime(String beginTime, String endTime);
 }

+ 11 - 0
warewms-ams/src/main/java/com/ruoyi/ams/inv/service/impl/InvLotLocIdServiceImpl.java

@@ -775,6 +775,11 @@ public class InvLotLocIdServiceImpl implements IInvLotLocIdService {
         return operateTraceIdByLocationId(locationId, null);
     }
 
+    @Override
+    public List<InvLotLocId> selectInvLocIdList() {
+        return invLotLocIdMapper.selectList(Wrappers.emptyWrapper());
+    }
+
     /**
      * 根据库位id操作任务id
      * @param locationId
@@ -799,5 +804,11 @@ public class InvLotLocIdServiceImpl implements IInvLotLocIdService {
                 .set(InvLotLocId::getQtyallocated, qtyallocated).eq(InvLotLocId::getLocationId, locationId)) > 0;
     }
 
+    @Override
+    public List<InvLotLocId> selectInvLotLocIdByTime(String beginTime, String endTime) {
+        return invLotLocIdMapper.selectList(Wrappers.<InvLotLocId>lambdaQuery()
+                .between(InvLotLocId::getCreateTime, beginTime, endTime));
+    }
+
 
 }

+ 29 - 0
warewms-ams/src/main/java/com/ruoyi/ams/screen/dto/LargeScreenInvLotLocIdDTO.java

@@ -0,0 +1,29 @@
+package com.ruoyi.ams.screen.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+
+@Data
+public class LargeScreenInvLotLocIdDTO implements Serializable {
+
+    private static final long serialVersionUID = 4431666333888292342L;
+
+    /**
+     * 库区名
+     */
+    private String zoneName;
+
+    /**
+     * 重量(吨)
+     */
+    private BigDecimal weight;
+
+    /**
+     * 托盘数
+     */
+    private Integer palletNum;
+
+}

+ 26 - 0
warewms-ams/src/main/java/com/ruoyi/ams/screen/dto/LargeScreenWcsTaskDTO.java

@@ -0,0 +1,26 @@
+package com.ruoyi.ams.screen.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class LargeScreenWcsTaskDTO implements Serializable {
+    private static final long serialVersionUID = -900564514593492183L;
+
+    @ApiModelProperty(value = "起始点位")
+    private String locationFrom;
+
+    @ApiModelProperty(value = "终点点位")
+    private String locationTo;
+
+    @ApiModelProperty(value = "任务状态")
+    private Long state;
+
+    @ApiModelProperty(value = "任务状态备注")
+    private String stateRemark;
+
+    @ApiModelProperty(value = "AGV接收车号")
+    private String agvNo;
+}

+ 19 - 0
warewms-ams/src/main/java/com/ruoyi/ams/screen/dto/SkuLiquidLevelDTO.java

@@ -0,0 +1,19 @@
+package com.ruoyi.ams.screen.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+@Data
+public class SkuLiquidLevelDTO implements Serializable {
+
+    private static final long serialVersionUID = -4232277221785896928L;
+
+    @ApiModelProperty(value = "物料")
+    private String sku;
+
+    @ApiModelProperty(value = "液位值")
+    private BigDecimal liquidLevel;
+}

+ 19 - 0
warewms-ams/src/main/java/com/ruoyi/ams/screen/dto/SkuQtyInfoDTO.java

@@ -0,0 +1,19 @@
+package com.ruoyi.ams.screen.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+@Data
+public class SkuQtyInfoDTO implements Serializable {
+
+    private static final long serialVersionUID = 4857035237485972793L;
+
+    @ApiModelProperty(value = "时间")
+    private String time;
+
+    @ApiModelProperty(value = "数量")
+    private BigDecimal total;
+}

+ 17 - 0
warewms-ams/src/main/java/com/ruoyi/ams/screen/dto/VisualDataScreenSkuQtyDTO.java

@@ -0,0 +1,17 @@
+package com.ruoyi.ams.screen.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+public class VisualDataScreenSkuQtyDTO implements Serializable {
+
+    @ApiModelProperty(value = "物料")
+    private String sku;
+
+    private List<SkuQtyInfoDTO> skuQtyInfoDTOList;
+
+}

+ 34 - 0
warewms-ams/src/main/java/com/ruoyi/ams/screen/dto/VisualDataScreenSkuQtyReqDTO.java

@@ -0,0 +1,34 @@
+package com.ruoyi.ams.screen.dto;
+
+import com.ruoyi.common.enums.Granularity;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+public class VisualDataScreenSkuQtyReqDTO implements Serializable {
+
+    private static final long serialVersionUID = 7597316679610576711L;
+
+    @ApiModelProperty(value = "展示物料集合")
+    private List<String> skuList;
+
+    @NotBlank(message = "出入库类型不能为空!")
+    @ApiModelProperty(value = "出入库类型")
+    private String docType;
+
+    @NotBlank(message = "起始时间不能为空!")
+    @ApiModelProperty(value = "起始时间")
+    private String beginTime;
+
+    @NotBlank(message = "结束时间不能为空!")
+    @ApiModelProperty(value = "结束时间")
+    private String endTime;
+
+    @ApiModelProperty(value = "时间粒度")
+    private Granularity granularity;
+
+}

+ 20 - 0
warewms-ams/src/main/java/com/ruoyi/ams/screen/dto/WcsRgvInfoConvertDTO.java

@@ -0,0 +1,20 @@
+package com.ruoyi.ams.screen.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class WcsRgvInfoConvertDTO implements Serializable {
+    private static final long serialVersionUID = -6664089704990784912L;
+
+    @ApiModelProperty(value = "车辆编号")
+    private String id;
+
+    @ApiModelProperty(value = "电池")
+    private String battery;
+
+    @ApiModelProperty(value = "状态")
+    private String currentTask;
+}

+ 20 - 0
warewms-ams/src/main/java/com/ruoyi/ams/screen/dto/WcsRgvInfoDTO.java

@@ -0,0 +1,20 @@
+package com.ruoyi.ams.screen.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class WcsRgvInfoDTO implements Serializable {
+    private static final long serialVersionUID = 7721243160106648286L;
+
+    @ApiModelProperty(value = "车辆编号")
+    private String carNo;
+
+    @ApiModelProperty(value = "电池")
+    private String battery;
+
+    @ApiModelProperty(value = "状态")
+    private String state;
+}

+ 41 - 0
warewms-ams/src/main/java/com/ruoyi/ams/screen/service/VisualDataScreenService.java

@@ -0,0 +1,41 @@
+package com.ruoyi.ams.screen.service;
+
+import com.ruoyi.ams.screen.dto.*;
+
+import java.util.List;
+
+public interface VisualDataScreenService {
+
+    /**
+     * 获取四向车车辆信息
+     * @return
+     */
+    List<WcsRgvInfoDTO> queryWcsRgvInfo();
+
+    /**
+     * 获取搅拌槽液位值
+     * @param skuList
+     * @return
+     */
+    List<SkuLiquidLevelDTO> querySkuLiquidLevel(List<String> skuList);
+
+    /**
+     * 获取大屏任务列表
+     * @return
+     */
+    List<LargeScreenWcsTaskDTO> selectLargeScreenWcsTaskList(Integer size);
+
+    /**
+     * 查询物料时间区域内入库/出库总量 按时间粒度分割
+     * @param visualDataScreenSkuQtyReqDTO
+     * @return
+     */
+    List<VisualDataScreenSkuQtyDTO> queryVisualDataScreenSkuQtyDTOList(VisualDataScreenSkuQtyReqDTO visualDataScreenSkuQtyReqDTO);
+
+    /**
+     * 查询库位库存信息列表
+     * @param size
+     * @return
+     */
+    List<LargeScreenInvLotLocIdDTO> queryLargeScreenInvLotLocIdDTOList(Integer size);
+}

+ 234 - 0
warewms-ams/src/main/java/com/ruoyi/ams/screen/service/impl/VisualDataScreenServiceImpl.java

@@ -0,0 +1,234 @@
+package com.ruoyi.ams.screen.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.comparator.CompareUtil;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.fastjson.JSON;
+import com.ruoyi.ams.inv.domain.InvLotLocId;
+import com.ruoyi.ams.inv.service.IInvLotLocIdService;
+import com.ruoyi.ams.screen.dto.*;
+import com.ruoyi.ams.screen.service.VisualDataScreenService;
+import com.ruoyi.ams.task.domain.WcsTask;
+import com.ruoyi.ams.task.service.IWcsTaskService;
+import com.ruoyi.ams.xuankuang.domain.dto.WcsResponseDTO;
+import com.ruoyi.ams.xuankuang.service.StirringTankClientService;
+import com.ruoyi.ams.xuankuang.service.WmsToWcsApiService;
+import com.ruoyi.base.constant.Constant;
+import com.ruoyi.base.domain.BaseLocationInfo;
+import com.ruoyi.base.domain.BaseLocationZone;
+import com.ruoyi.base.service.IBaseLocationInfoService;
+import com.ruoyi.base.service.IBaseLocationZoneService;
+import com.ruoyi.base.service.IBaseSkuService;
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.enums.Granularity;
+import com.ruoyi.common.exception.base.BaseException;
+import com.ruoyi.common.utils.ConvertUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.time.SplitedTimeParam;
+import com.ruoyi.common.utils.time.TimeUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Service
+@Slf4j
+public class VisualDataScreenServiceImpl implements VisualDataScreenService {
+
+    @Autowired
+    private IInvLotLocIdService invLotLocIdService;
+
+    @Autowired
+    private IBaseSkuService baseSkuService;
+
+    @Autowired
+    private IWcsTaskService wcsTaskService;
+
+    @Autowired
+    private StirringTankClientService stirringTankClientService;
+
+    @Autowired
+    private WmsToWcsApiService wmsToWcsApiService;
+
+    @Autowired
+    private IBaseLocationInfoService baseLocationInfoService;
+
+    @Autowired
+    private IBaseLocationZoneService baseLocationZoneService;
+
+
+
+    /**
+     * 获取四向车车辆信息
+     * @return
+     */
+    @Override
+    public List<WcsRgvInfoDTO> queryWcsRgvInfo(){
+        WcsResponseDTO wcsResponseDTO = wmsToWcsApiService.queryWcsRgvInfo();
+        if (ObjectUtil.isNull(wcsResponseDTO)) throw new BaseException("WmsToWcsApiService - queryWcsRgvInfo response is null");
+        List<Object> rgvInfoList = JSON.parseArray(JSON.toJSONString(wcsResponseDTO.getData()), Object.class);
+        return rgvInfoList.stream().map(item -> {
+            WcsRgvInfoConvertDTO wcsRgvInfoConvertDTO = BeanUtil.toBean(item, WcsRgvInfoConvertDTO.class);
+            WcsRgvInfoDTO wcsRgvInfoDTO = new WcsRgvInfoDTO();
+            wcsRgvInfoDTO.setState(wcsRgvInfoConvertDTO.getCurrentTask());
+            wcsRgvInfoDTO.setCarNo(wcsRgvInfoConvertDTO.getId());
+            wcsRgvInfoDTO.setBattery(wcsRgvInfoConvertDTO.getBattery());
+            return wcsRgvInfoDTO;
+        }).collect(Collectors.toList());
+    }
+
+    /**
+     * 获取搅拌槽液位值
+     * @param skuList
+     * @return
+     */
+    @Override
+    public List<SkuLiquidLevelDTO> querySkuLiquidLevel(List<String> skuList) {
+        List<String> querySkuList = CollectionUtil.isNotEmpty(skuList) ? skuList : baseSkuService.queryBaseSkuBySkuTypeList();
+        return querySkuList.stream().map(item -> {
+            SkuLiquidLevelDTO skuLiquidLevelDTO = new SkuLiquidLevelDTO();
+            skuLiquidLevelDTO.setSku(item);
+            //todo null
+            BigDecimal skuLiquidLevel = BigDecimal.ZERO;
+            try {
+                skuLiquidLevel = stirringTankClientService.getSkuLiquidLevel(item);
+            } catch (Exception e) {
+                log.info("Exception of VisualDataScreenServiceImpl-querySkuLiquidLevel has been thrown, cause is stirringTankClientService-getSkuLiquidLevel is on error," +
+                                " sku is {}, cucrrent time is {}, Caused by {}"
+                        , item, DateUtil.now(), e);
+            }
+            skuLiquidLevelDTO.setLiquidLevel(skuLiquidLevel);
+            return skuLiquidLevelDTO;
+        }).collect(Collectors.toList());
+    }
+
+    /**
+     * 获取大屏任务列表
+     * @return
+     */
+    @Override
+    public List<LargeScreenWcsTaskDTO> selectLargeScreenWcsTaskList(@RequestParam Integer size) {
+        List<WcsTask> wcsTaskList = wcsTaskService.selectWcsTaskList();
+        List<BaseLocationInfo> baseLocationInfoList = baseLocationInfoService.queryBaseLocationInfoList();
+        Map<Long, String> locationMap = baseLocationInfoList.stream().collect(Collectors.toMap(BaseLocationInfo::getId, BaseLocationInfo::getLocationNo));
+        if (CollectionUtil.isEmpty(wcsTaskList)){
+            return new ArrayList<>();
+        }
+        List<LargeScreenWcsTaskDTO> largeScreenWcsTaskDTO = ConvertUtils.sourceToTarget(wcsTaskList.subList(0, size), LargeScreenWcsTaskDTO.class);
+        largeScreenWcsTaskDTO.forEach(item -> {
+            item.setLocationFrom(locationMap.get(Long.parseLong(item.getLocationFrom())));
+            item.setLocationTo(locationMap.get(Long.parseLong(item.getLocationTo())));
+            item.setStateRemark(Constant.TASK_STS.getRemark(Integer.valueOf(item.getState().toString())));
+        });
+        return largeScreenWcsTaskDTO;
+    }
+
+    /**
+     * 查询物料时间区域内入库/出库总量 按时间粒度分割 skuList不传即获取所有生产物料用量
+     * @param visualDataScreenSkuQtyReqDTO
+     * @return
+     */
+    @Override
+    public List<VisualDataScreenSkuQtyDTO> queryVisualDataScreenSkuQtyDTOList(VisualDataScreenSkuQtyReqDTO visualDataScreenSkuQtyReqDTO) {
+        List<String> skuList = CollectionUtil.isNotEmpty(visualDataScreenSkuQtyReqDTO.getSkuList()) ?
+                visualDataScreenSkuQtyReqDTO.getSkuList() : baseSkuService.queryBaseSkuBySkuTypeList();
+        if (ObjectUtil.isNull(visualDataScreenSkuQtyReqDTO.getGranularity())) {
+            visualDataScreenSkuQtyReqDTO.setGranularity(Granularity.DAY);
+        }
+        return queryVisualDataScreenSkuQtyDTOList(skuList, visualDataScreenSkuQtyReqDTO.getDocType(), visualDataScreenSkuQtyReqDTO.getBeginTime(),
+                visualDataScreenSkuQtyReqDTO.getEndTime(), visualDataScreenSkuQtyReqDTO.getGranularity());
+    }
+
+    /**
+     * 查询库位库存信息列表
+     * @param size
+     * @return
+     */
+    @Override
+    public List<LargeScreenInvLotLocIdDTO> queryLargeScreenInvLotLocIdDTOList(Integer size) {
+        List<InvLotLocId> invLotLocIdList = invLotLocIdService.selectInvLocIdList();
+        if (CollectionUtil.isEmpty(invLotLocIdList)) {
+            return new ArrayList<>();
+        }
+        List<BaseLocationInfo> baseLocationInfoList = baseLocationInfoService.queryBaseLocationInfoList();
+        Map<Long, List<BaseLocationInfo>> baseLocationInfoMap = baseLocationInfoList.stream().collect(Collectors.groupingBy(BaseLocationInfo::getZoneId));
+        List<BaseLocationZone> baseLocationZoneList = baseLocationZoneService.selectBaseLocationZoneList();
+        return baseLocationZoneList.stream().filter(item -> CompareUtil.compare(item.getZoneId(), Constant.CACHE_ZONE) != 0).map(item -> {
+            List<BaseLocationInfo> locationInfoList = baseLocationInfoMap.get(item.getZoneId());
+            List<InvLotLocId> invLotLocIdFilterList = invLotLocIdList.stream().filter(invLotLocId -> ObjectUtil.isNotNull(invLotLocId.getQty()) &&
+                    locationInfoList.stream().map(BaseLocationInfo::getId).collect(Collectors.toList()).contains(Long.parseLong(invLotLocId.getLocationId()))).collect(Collectors.toList());
+            LargeScreenInvLotLocIdDTO largeScreenInvLotLocIdDTO = new LargeScreenInvLotLocIdDTO();
+            largeScreenInvLotLocIdDTO.setZoneName(item.getZoneName());
+            largeScreenInvLotLocIdDTO.setWeight(invLotLocIdFilterList.stream().map(InvLotLocId::getQty).reduce(BigDecimal.ZERO, BigDecimal::add));
+            largeScreenInvLotLocIdDTO.setPalletNum(invLotLocIdFilterList.size());
+            return largeScreenInvLotLocIdDTO;
+        }).skip(Long.valueOf(BigDecimal.ZERO.toString())).limit(size).collect(Collectors.toList());
+    }
+
+    /**
+     * 查询物料时间区域内入库/出库总量 按时间粒度分割
+     * @param skuList
+     * @param docType
+     * @param beginTime
+     * @param endTime
+     * @param granularity
+     * @return
+     */
+    private List<VisualDataScreenSkuQtyDTO> queryVisualDataScreenSkuQtyDTOList(List<String> skuList, String docType, String beginTime, String endTime, Granularity granularity) {
+        List<InvLotLocId> invLotLocIdList = invLotLocIdService.selectInvLotLocIdByTime(beginTime, endTime);
+        Map<String, SplitedTimeParam> splitTimeMap = TimeUtils.getSplitedTimeGroupByTime(beginTime, endTime, granularity);
+        if (CollectionUtil.isEmpty(invLotLocIdList)){
+            return buildVisualDataScreenSkuQtyDTOList(skuList, invLotLocIdList, splitTimeMap);
+        }
+        List<Long> locationIdList = wcsTaskService.getBucketLocationIdList(Constants.BUCKET_CACHE_OUT);
+        locationIdList.add(Constant.LOC_SORTATION_CACHE);
+        List<InvLotLocId> invLotLocIdFilterList = invLotLocIdList.stream().filter(item -> (skuList.contains(item.getSku()) &&
+                StringUtils.equals(docType, Constant.DOC_TYPE.ASN.getType())) != locationIdList.contains(Long.parseLong(item.getLocationId()))).collect(Collectors.toList());
+        return buildVisualDataScreenSkuQtyDTOList(skuList, invLotLocIdFilterList, splitTimeMap);
+    }
+
+    private List<VisualDataScreenSkuQtyDTO> buildVisualDataScreenSkuQtyDTOList(List<String> skuList, List<InvLotLocId> invLotLocIdList, Map<String, SplitedTimeParam> splitTimeMap){
+        return skuList.stream().map(item -> {
+            List<SkuQtyInfoDTO> skuQtyInfoDTOList = new ArrayList<>();
+            for (Map.Entry<String, SplitedTimeParam> splitTimeParamEntry : splitTimeMap.entrySet()) {
+                SplitedTimeParam splitedTimeParam = splitTimeParamEntry.getValue();
+                SkuQtyInfoDTO skuQtyInfoDTO = buildSkuQtyInfoDTO(splitedTimeParam, CollectionUtil.isNotEmpty(invLotLocIdList) ?
+                        invLotLocIdList.stream().filter(lotLocId -> StringUtils.equals(item, lotLocId.getSku())).collect(Collectors.toList()) : invLotLocIdList);
+                skuQtyInfoDTOList.add(skuQtyInfoDTO);
+            }
+            VisualDataScreenSkuQtyDTO visualDataScreenSkuQtyDTO = new VisualDataScreenSkuQtyDTO();
+            visualDataScreenSkuQtyDTO.setSku(item);
+            visualDataScreenSkuQtyDTO.setSkuQtyInfoDTOList(skuQtyInfoDTOList);
+            return visualDataScreenSkuQtyDTO;
+        }).collect(Collectors.toList());
+    }
+
+    private SkuQtyInfoDTO buildSkuQtyInfoDTO(SplitedTimeParam splitedTimeParam, List<InvLotLocId> invLotLocIdList){
+        return buildSkuQtyInfoDTO(splitedTimeParam.getBeginTime(), splitedTimeParam.getEndTime(), invLotLocIdList);
+    }
+
+    private SkuQtyInfoDTO buildSkuQtyInfoDTO(String beginTime, String endTime, List<InvLotLocId> invLotLocIdList) {
+        SkuQtyInfoDTO skuQtyInfoDTO = new SkuQtyInfoDTO();
+        skuQtyInfoDTO.setTime(beginTime);
+        if (CollectionUtil.isEmpty(invLotLocIdList)) {
+            skuQtyInfoDTO.setTotal(BigDecimal.ZERO);
+            return skuQtyInfoDTO;
+        }
+        List<InvLotLocId> invLotLocIdBetweenTimeList = invLotLocIdList.stream().filter(item ->
+                TimeUtils.dateToTimestamp(item.getCreateTime()) >= TimeUtils.dateToTimestamp(beginTime, TimeUtils.DATE_TIME_PATTERN)
+                && TimeUtils.dateToTimestamp(item.getCreateTime()) <= TimeUtils.dateToTimestamp(endTime, TimeUtils.DATE_TIME_PATTERN)).collect(Collectors.toList());
+        BigDecimal total = invLotLocIdBetweenTimeList.stream().filter(lotLocId -> ObjectUtil.isNotEmpty(lotLocId.getQty()))
+                .map(InvLotLocId::getQty).reduce(BigDecimal.ZERO, BigDecimal::add);
+        skuQtyInfoDTO.setTotal(total);
+        return skuQtyInfoDTO;
+    }
+
+}

+ 2 - 0
warewms-ams/src/main/java/com/ruoyi/ams/task/service/IWcsTaskService.java

@@ -218,4 +218,6 @@ public interface IWcsTaskService {
      * @return
      */
     List<Long> getBucketLocationIdList(String locationSceneCode);
+
+    List<WcsTask> selectWcsTaskList();
 }

+ 5 - 1
warewms-ams/src/main/java/com/ruoyi/ams/task/service/impl/WcsTaskServiceImpl.java

@@ -2,7 +2,6 @@ package com.ruoyi.ams.task.service.impl;
 
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@@ -678,6 +677,11 @@ public class WcsTaskServiceImpl implements IWcsTaskService {
         baseLocationInfoService.updateBaseLocationInfo(baseLocationInfo);
     }
 
+    @Override
+    public List<WcsTask> selectWcsTaskList(){
+        return wcsTaskMapper.selectList(Wrappers.emptyWrapper());
+    }
+
 
     /**
      * 取消任务删除中间缓存库存

+ 14 - 0
warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/domain/dto/EmergencyOrderDTO.java

@@ -0,0 +1,14 @@
+package com.ruoyi.ams.xuankuang.domain.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class EmergencyOrderDTO implements Serializable {
+
+    private String orderNo;
+
+    private String locationId;
+
+}

+ 10 - 0
warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/domain/dto/SkuAgitatedTankAttrDTO.java

@@ -31,6 +31,16 @@ public class SkuAgitatedTankAttrDTO implements Serializable {
      */
     private StirringTankClient.STIR_TANK_COMMAND readDosageCommand;
 
+    /**
+     * 读搅拌槽所需物料剂量的指令
+     */
+    private StirringTankClient.STIR_TANK_COMMAND readLiquidLevel;
+
+    /**
+     * 是否自动注入
+     */
+    private Boolean automatic;
+
     /**
      * 无法注入药量的点位索引
      */

+ 26 - 0
warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/domain/dto/WcsResponseDTO.java

@@ -0,0 +1,26 @@
+package com.ruoyi.ams.xuankuang.domain.dto;
+
+import lombok.Data;
+
+@Data
+public class WcsResponseDTO {
+
+    /**
+     * 业务响应码,默认为200
+     * @author chenyang
+     */
+    private String code;
+
+    /**
+     * 业务提示信息
+     * @author chenyang
+     */
+    private String message;
+
+    /**
+     * 业务响应体
+     * @author chenyang
+     */
+    private Object data;
+
+}

+ 25 - 2
warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/service/StirringTankClientService.java

@@ -39,23 +39,35 @@ public class StirringTankClientService {
     //物料的换算比率映射 PS: 换算比例 Rate=20 代表一份物料20kg
     private static final  Map<String, SkuAgitatedTankAttrDTO> skuToAgitatedTankAttrMapper = new HashMap<String, SkuAgitatedTankAttrDTO>(){
         {
+            put("Na2CO3", new SkuAgitatedTankAttrDTO().setReadDosageCommand(READ_THE_STIRRING_TANK_07)
+                    .setReadLiquidLevel(READ_THE_STIRRING_TANK_01).setAutomatic(Boolean.FALSE)
+                    .setRate(25).setUnableBitIndex(5).setAbleBitIndex(5).setStartBitIndex(5)
+                    .setRunBitIndex(5).setErrorBitIndex(5).setEndBitIndex(5).setConfirmBitIndex(5));//碳酸钠
             put("C5H10OS2", new SkuAgitatedTankAttrDTO().setReadDosageCommand(READ_THE_STIRRING_TANK_08)
+                    .setReadLiquidLevel(READ_THE_STIRRING_TANK_02).setAutomatic(Boolean.TRUE)
                     .setRate(25).setUnableBitIndex(1).setAbleBitIndex(1).setStartBitIndex(1)
                     .setRunBitIndex(1).setErrorBitIndex(1).setEndBitIndex(1).setConfirmBitIndex(1));//丁黄药
+            put("C4H9O2PSSNH4", new SkuAgitatedTankAttrDTO().setReadDosageCommand(READ_THE_STIRRING_TANK_09)
+                    .setReadLiquidLevel(READ_THE_STIRRING_TANK_03).setAutomatic(Boolean.FALSE)
+                    .setRate(5).setUnableBitIndex(5).setAbleBitIndex(5).setStartBitIndex(5)
+                    .setRunBitIndex(5).setErrorBitIndex(5).setEndBitIndex(5).setConfirmBitIndex(5));//丁铵黑药
             put("(NaPO3)6", new SkuAgitatedTankAttrDTO().setReadDosageCommand(READ_THE_STIRRING_TANK_10)
+                    .setReadLiquidLevel(READ_THE_STIRRING_TANK_04).setAutomatic(Boolean.TRUE)
                     .setRate(20).setUnableBitIndex(3).setAbleBitIndex(3).setStartBitIndex(3)
                     .setRunBitIndex(3).setErrorBitIndex(3).setEndBitIndex(3).setConfirmBitIndex(3));//六偏磷酸钠
             put("(NH4)2SO4", new SkuAgitatedTankAttrDTO().setReadDosageCommand(READ_THE_STIRRING_TANK_11)
+                    .setReadLiquidLevel(READ_THE_STIRRING_TANK_05).setAutomatic(Boolean.TRUE)
                     .setRate(20).setUnableBitIndex(4).setAbleBitIndex(4).setStartBitIndex(4)
                     .setRunBitIndex(4).setErrorBitIndex(4).setEndBitIndex(4).setConfirmBitIndex(4));//硫酸铵
-            put("CH3CH2OCS2Na", new SkuAgitatedTankAttrDTO().setReadDosageCommand(READ_THE_STIRRING_TANK_06)
+            put("CH3CH2OCS2Na", new SkuAgitatedTankAttrDTO().setReadDosageCommand(READ_THE_STIRRING_TANK_12)
+                    .setReadLiquidLevel(READ_THE_STIRRING_TANK_06).setAutomatic(Boolean.TRUE)
                     .setRate(25).setUnableBitIndex(5).setAbleBitIndex(5).setStartBitIndex(5)
                     .setRunBitIndex(5).setErrorBitIndex(5).setEndBitIndex(5).setConfirmBitIndex(5));//乙黄药
         }
     };
 
     public static final List<String> getSkuList(){
-        return skuToAgitatedTankAttrMapper.keySet().stream().collect(Collectors.toList());
+        return skuToAgitatedTankAttrMapper.entrySet().stream().filter(item -> item.getValue().getAutomatic()).map(Map.Entry::getKey).collect(Collectors.toList());
     }
 
     public Boolean setTaskEnd(String skuChemicalName) {
@@ -123,6 +135,17 @@ public class StirringTankClientService {
         return NumberUtil.div(neededWeightCount, skuAgitatedTankAttrDTO.getRate(), 0);
     }
 
+    /**
+     * 读取物料搅拌槽液位值
+     * @param skuChemicalName 物料化学名称
+     * @return
+     */
+    public BigDecimal getSkuLiquidLevel(String skuChemicalName){
+        SkuAgitatedTankAttrDTO skuAgitatedTankAttrDTO = skuToAgitatedTankAttrMapper.get(skuChemicalName);
+        Number neededWeightCount = stirringTankClient.readLiquidLevel(skuAgitatedTankAttrDTO.getReadDosageCommand());
+        return NumberUtil.div(neededWeightCount, BigDecimal.ONE);
+    }
+
 
     /**
      * 对比碳酸钠库存

+ 101 - 0
warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/service/WmsDocOrderSubService.java

@@ -86,6 +86,107 @@ public class WmsDocOrderSubService {
     @Autowired
     private ISysConfigService sysConfigService;
 
+    @Transactional
+    public AjaxResult emergencyInitOrderDetails(String orderNo, String locationId) {
+
+        //  根据单号,和创建状态为00
+        WmsDocOrderDetails wmsDocOrderDetails = new WmsDocOrderDetails();
+        wmsDocOrderDetails.setOrderNo(orderNo);
+        wmsDocOrderDetails.setLineStatus(Constant.ORDER_STS.STS00.getValue());
+        List<WmsDocOrderDetails> list = iWmsDocOrderDetailsService.selectWmsDocOrderDetailsList(wmsDocOrderDetails);
+        // 查询出库单头
+        WmsDocOrderHeader wmsDocOrderHeader = iWmsDocOrderHeaderService.selectWmsDocOrderHeaderByOrderNo(orderNo);
+
+        List<BaseLocationLotattDTO> filteredLocationLotattList = baseLocationInfoService.selectAllocatingInventoryAccordingConditionsOrderBy(Long.parseLong(locationId));
+
+        boolean con = true;
+        //机械手应拆袋数
+        int allocateQuantities = 0;
+        //出库单对应袋数
+        int orderNum = list.get(0).getQtyOrdered().intValue();
+        //分配数量
+        List<OutTaskForm.Dest> destList = Lists.newArrayList();
+        for (BaseLocationLotattDTO baseLocationLotatt : filteredLocationLotattList) {
+
+
+            BaseSku baseSku = iBaseSkuService.selectBaseSkuByCustomerId(Constant.CUSTOMER_ID, list.get(0).getSku());
+            String palletNo = baseLocationLotatt.getLotattVO().getLotatt07();
+            String locationFrom = baseLocationLotatt.getLocationNo();
+            String wcsNo = "wcs" + wcsTaskSubService.generateTaskNo();//生成唯一标识wcsno
+            if(ObjectUtil.isNull(baseLocationLotatt) || ObjectUtil.isNull(baseLocationLotatt.getId())) continue;
+
+            Float qty = baseLocationLotatt.getQty();
+            //Wcs x y z
+            String Y = baseLocationLotatt.getRowNo();
+            String Z = baseLocationLotatt.getShiftNo();
+            String X = baseLocationLotatt.getRowIndex();
+            String sku = baseLocationLotatt.getSku();
+            String taskNo = IdWorker.getIdStr();
+            if (sku.equals("C4H9O2PSSNH4")) {
+                // 生成桶装料出库任务
+                addWcsOutTask(taskNo, locationFrom, Constant.DRUM_CONNECTORS.toString(), orderNo, palletNo, wcsNo, "桶装料出库任务");
+            } else {
+                // 生成四向车出库任务
+                addWcsOutTask(taskNo, locationFrom, Constant.LOC_SORTATION_CACHE.toString(), orderNo, palletNo, wcsNo, "袋装料出库任务");
+            }
+            //修改出库出库存的traceId
+            invLotLocIdService.operateTraceIdByLocationId(locationId, taskNo);
+            //调用出库任务下发接口
+            OutTaskForm outTaskForm = new OutTaskForm();
+            outTaskForm.setTaskNo(taskNo);
+            outTaskForm.setRow(Integer.parseInt(X));
+            outTaskForm.setCol(Integer.parseInt(Y));
+            outTaskForm.setFloor(Integer.parseInt(Z));
+            outTaskForm.setPackageType(Integer.valueOf(baseSku.getSkuType()));
+            outTaskForm.setMaterial(Integer.valueOf(baseSku.getDesc2()));
+            outTaskForm.setTotal(qty.intValue());
+            outTaskForm.setDocNo(orderNo);
+            if (Integer.valueOf(baseSku.getSkuType()) == 2){
+                List<OutTaskForm.Dest> dests = new ArrayList<>();
+                OutTaskForm.Dest dest = new OutTaskForm.Dest();
+                dest.setDest(Integer.parseInt(wmsDocOrderHeader.getSoReference3()));
+                if (orderNum < qty.intValue()) {
+                    allocateQuantities = orderNum;
+                    dest.setNum(allocateQuantities);
+                    invLotLocIdService.updateInvLotLocId(locationId, new BigDecimal(allocateQuantities));
+                } else {
+                    allocateQuantities = qty.intValue();
+                    orderNum = orderNum - qty.intValue();
+                    dest.setNum(allocateQuantities);
+                    invLotLocIdService.updateInvLotLocId(locationId, new BigDecimal(allocateQuantities));
+                }
+                dests.add(dest);
+                destList.add(dest);
+                outTaskForm.setDests(dests);
+            }
+
+            log.info("WmsDocOrderSubService - initOrderDetails is ready out task to Wcs ......");
+            WcsResponseVo wcsResponseVo = wmsToWcsApiService.wmsOutTask(outTaskForm);
+            if (!wcsResponseVo.isSuccess()) {
+                con = false;
+                wmsDocOrderHeader.setRemark(wcsResponseVo.getMessage());
+                iWmsDocOrderHeaderService.updateWmsDocOrderHeader(wmsDocOrderHeader);
+                continue;
+            }
+        }
+        int totalQtyAllocated = destList.stream().filter(item -> ObjectUtil.isNotNull(item.getNum()))
+                .mapToInt(OutTaskForm.Dest::getNum).sum();
+
+        if (con == true) {
+            // 修改 明细行状态为10
+            WmsDocOrderDetails wmsDocOrderDetail = list.get(0);
+            wmsDocOrderDetail.setLineStatus(Constant.ORDER_STS.STS10.getValue());
+            wmsDocOrderDetail.setQtyAllocated(new BigDecimal(totalQtyAllocated));
+            wmsDocOrderDetail.setQtyAllocatedEach(new BigDecimal(totalQtyAllocated));
+            iWmsDocOrderDetailsService.updateWmsDocOrderDetails(list.get(0));
+            // 修改 单头10
+            wmsDocOrderHeader.setRemark("");
+            wmsDocOrderHeader.setOrderStatus(Constant.ORDER_STS.STS10.getValue());
+            iWmsDocOrderHeaderService.updateWmsDocOrderHeader(wmsDocOrderHeader);
+        }
+        return AjaxResult.success("", filteredLocationLotattList);
+    }
+
 
     @Transactional
     public AjaxResult initOrderDetails(@PathVariable("orderNo") String orderNo) {

+ 30 - 1
warewms-ams/src/main/java/com/ruoyi/ams/xuankuang/service/WmsToWcsApiService.java

@@ -1,7 +1,9 @@
 package com.ruoyi.ams.xuankuang.service;
 
+import cn.hutool.core.map.MapUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
+import com.ruoyi.ams.xuankuang.domain.dto.WcsResponseDTO;
 import com.ruoyi.ams.xuankuang.domain.form.*;
 import com.ruoyi.ams.xuankuang.domain.vo.WcsResponseVo;
 import com.ruoyi.base.constant.Constant;
@@ -155,7 +157,7 @@ public class WmsToWcsApiService {
     /**
      * agv回调wcs货物取走接口
      *
-     * @param wcsId
+     * @param taskNo
      * @return
      */
     @Retryable(
@@ -201,5 +203,32 @@ public class WmsToWcsApiService {
         }
         return wcsResponseVo;
     }
+
+    /**
+     * 获取四向车信息接口
+     * @param
+     * @return
+     */
+    @Retryable(
+            maxAttempts = 4, //指定重试次数
+            //调用失败后,等待5s重试,后面重试间隔依次变为原来的2倍
+            backoff = @Backoff(delay = 5000, multiplier = 2)
+    )
+    public WcsResponseDTO queryWcsRgvInfo(){
+        //入参为json格式 typeId固定值为1
+        String json = JSON.toJSONString(MapUtil.of("typeId", 1));
+        log.info("WmsToWcsApiService - queryWcsRgvInfo request is :{}, time is :{}", json, DateUtils.getTime());
+        String r = "";
+        WcsResponseDTO wcsResponseDTO = new WcsResponseDTO();
+        try {
+            r = HttpRequest.postData(Constant.WCS_RGV_URL, json);
+            wcsResponseDTO = JSON.parseObject(r, WcsResponseDTO.class);
+            log.info("WmsToWcsApiService - queryWcsRgvInfo response is :{}, time is :{}", JSONObject.toJSONString(wcsResponseDTO), DateUtils.getTime());
+        } catch (Exception e) {
+            log.error("四向车信息获取失败", e);
+        }
+        return wcsResponseDTO;
+    }
+
 }
 

+ 8 - 0
warewms-ams/src/main/resources/mapper/ams/CarInfoMapper.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.ams.agv.car.mapper.CarInfoMapper">
+
+
+</mapper>

+ 87 - 14
warewms-base/src/main/java/com/ruoyi/base/constant/Constant.java

@@ -1,7 +1,10 @@
 package com.ruoyi.base.constant;
 
+import cn.hutool.core.comparator.CompareUtil;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 
+import java.util.Arrays;
+
 /**
  * Created by IntelliJ IDEA.
  * User: andy.qu
@@ -41,6 +44,11 @@ public class Constant {
      */
     public static final Long LOC_MIDDLE_CACHE = 99999l;
 
+    /**
+     * 缓存位集合
+     */
+    public static final Long CACHE_ZONE = 9999l;
+
 
 
     public static final Long DEFAULT_WAREHOUSE_ID = 1L;
@@ -65,6 +73,7 @@ public class Constant {
     // WCS智库 agv回调wcs取货完成
     public static final String WCS_TASK_URL6 = "http://localhost:8082/adaptor/agv/callback/outtask?taskNo=";
 
+    public static final String WCS_RGV_URL = "http://localhost:8080/engineer/device/manage/rgv/info/page";
 
     public enum TaskType{
         EMPTY_PALLET("emptyPallet"),
@@ -632,65 +641,76 @@ public class Constant {
         /**
          * 下发AMS
          */
-        TASK0(0),
+        TASK0(0, "下发AMS"),
         /**
          * 开始
          */
-        TASK1(1),
+        TASK1(1, "开始"),
         /**
          * 完成
          */
-        TASK2(2),
+        TASK2(2, "完成"),
         /**
          * 开始取货
          */
-        TASK3(3),
+        TASK3(3, "开始取货"),
         /**
          * 取货完成
          */
-        TASK4(4),
+        TASK4(4, "取货完成"),
         /**
          * 开始卸货
          */
-        TASK5(5),
+        TASK5(5, "开始卸货"),
         /**
          * 卸货完成
          */
-        TASK6(6),
+        TASK6(6, "卸货完成"),
         /**
          * 取消
          */
-        TASK_CANCEL(7),
+        TASK_CANCEL(7, "取消"),
         /**
          * 空叉取消
          */
-        TASK8(8),
+        TASK8(8, "空叉取消"),
         /**
          * 队列等待
          */
-        TASK_WAIT(9),
+        TASK_WAIT(9, "队列等待"),
         /**
          * 已下发
          */
-        TASK_PUBILSH(10),
+        TASK_PUBILSH(10, "已下发"),
         /**
          * 任务创建
          */
-        TASK_CREATE(13);
+        TASK_CREATE(13, "任务创建");
 
 
         private Integer value;
 
+        private String remark;
+
         public Integer getValue() {
             return value;
         }
-
         public Long getLongValue(){
             return ObjectUtils.isNotNull(value) ? value.longValue() : null;
         }
 
-        TASK_STS(Integer value) {
+
+        public String getRemark() {
+            return remark;
+        }
+
+        public static String getRemark(Integer value){
+            return Arrays.stream(TASK_STS.values()).filter(item -> CompareUtil.compare(item.value, value) == 0).map(TASK_STS::getRemark).findFirst().orElseGet(() -> null);
+        }
+
+        TASK_STS(Integer value, String remark) {
             this.value = value;
+            this.remark = remark;
         }
     }
 
@@ -893,4 +913,57 @@ public class Constant {
             return type;
         }
     }
+
+    /**
+     * 单据类型
+     */
+    public enum DOC_TYPE {
+        /**
+         * 入库
+         */
+        ASN("asn"),
+        /**
+         * 出库
+         */
+        ORDER("order");
+
+        private String type;
+
+        DOC_TYPE(String type){
+            this.type = type;
+        }
+
+        public String getType() {
+            return type;
+        }
+    }
+
+    public enum SKU_TYPE {
+        /**
+         * 桶装物料
+         */
+        BUCKET_SKU("1"),
+        /**
+         * 袋装物料
+         */
+        BAG_SKU("2"),
+        /**
+         * 袋装空托盘
+         */
+        EMP_TRAY_BAG("3"),
+        /**
+         * 桶装空托盘
+         */
+        EMP_TRAY_BUCKET("4");
+
+        private String type;
+
+        SKU_TYPE(String type){
+            this.type = type;
+        }
+
+        public String getType() {
+            return type;
+        }
+    }
 }

+ 1 - 1
warewms-base/src/main/java/com/ruoyi/base/mapper/BaseLocationInfoMapper.java

@@ -131,7 +131,7 @@ public interface BaseLocationInfoMapper extends BaseMapper<BaseLocationInfo> {
     List<BaseLocationLotattDTO> selectAllocatingInventoryAccordingConditionsOrderBy(@Param("zoneId") List<String> zoneId, @Param("warehouseId") Long warehouseId
             , @Param("lotatt") Map<String, String> lotatt, @Param("sku") String sku, @Param("orderByClause") String orderBy);
 
-
+    List<BaseLocationLotattDTO> selectAllocatingInventoryAccordingConditionsForEmergency(@Param("locationId") Long locationId);
     /**
      * 根据库位返回同库区同列目标占用的库位list
      * 同列是否已经存在任务

+ 9 - 0
warewms-base/src/main/java/com/ruoyi/base/service/IBaseLocationInfoService.java

@@ -81,6 +81,13 @@ public interface IBaseLocationInfoService {
             , String sku
             , String orderBy);
 
+    /**
+     * 查询指定库位信息(应急出库)
+     * @param locationId
+     * @return
+     */
+    List<BaseLocationLotattDTO> selectAllocatingInventoryAccordingConditionsOrderBy(Long locationId);
+
     /**
      * 查询库位信息列表
      *
@@ -367,6 +374,8 @@ public interface IBaseLocationInfoService {
      */
     List<BaseLocationInfo> selectLocationInfoList();
 
+    List<BaseLocationInfo> queryBaseLocationInfoList();
+
     /**
      * 查询库ID列表库位信息列表
      * @param locationIdList

+ 6 - 0
warewms-base/src/main/java/com/ruoyi/base/service/IBaseSkuService.java

@@ -88,4 +88,10 @@ public interface IBaseSkuService {
      * @return
      */
     BaseSku selectSkuByMaterialType(String materialType);
+
+    /**
+     * 查询生产物料信息
+     * @return
+     */
+    List<String> queryBaseSkuBySkuTypeList();
 }

+ 17 - 0
warewms-base/src/main/java/com/ruoyi/base/service/impl/BaseLocationInfoServiceImpl.java

@@ -183,6 +183,16 @@ public class BaseLocationInfoServiceImpl implements IBaseLocationInfoService {
                 , orderBy);
     }
 
+    /**
+     * 查询指定库位信息(应急出库)
+     * @param locationId
+     * @return
+     */
+    @Override
+    public List<BaseLocationLotattDTO> selectAllocatingInventoryAccordingConditionsOrderBy(Long locationId) {
+        return baseLocationInfoMapper.selectAllocatingInventoryAccordingConditionsForEmergency(locationId);
+    }
+
     /**
      * 查询库位信息列表
      *
@@ -574,6 +584,13 @@ public class BaseLocationInfoServiceImpl implements IBaseLocationInfoService {
         return baseLocationInfoMapper.selectList(queryWrapper);
     }
 
+    @Override
+    public List<BaseLocationInfo> queryBaseLocationInfoList() {
+        LambdaQueryWrapper<BaseLocationInfo> queryWrapper = Wrappers.<BaseLocationInfo>lambdaQuery()
+                .eq(BaseLocationInfo::getWarehouseId, Constants.DEFAULT_WAREHOUSE_ID);
+        return baseLocationInfoMapper.selectList(queryWrapper);
+    }
+
     @Override
     public List<BaseLocationInfo> selectLocationInfoList(List<Long> locationIdList) {
         LambdaQueryWrapper<BaseLocationInfo> queryWrapper = Wrappers.<BaseLocationInfo>lambdaQuery()

+ 10 - 0
warewms-base/src/main/java/com/ruoyi/base/service/impl/BaseSkuServiceImpl.java

@@ -2,6 +2,8 @@ package com.ruoyi.base.service.impl;
 
 import cn.hutool.core.collection.CollectionUtil;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.google.common.collect.Lists;
+import com.ruoyi.base.constant.Constant;
 import com.ruoyi.base.domain.BaseSku;
 import com.ruoyi.base.mapper.BaseSkuMapper;
 import com.ruoyi.base.service.IBaseSkuService;
@@ -10,6 +12,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * 物料信息Service业务层处理
@@ -122,4 +125,11 @@ public class BaseSkuServiceImpl implements IBaseSkuService
                 baseSkuMapper.selectList(Wrappers.<BaseSku>lambdaQuery().eq(BaseSku::getDesc2, materialType));
         return CollectionUtil.isNotEmpty(baseSkuList)? baseSkuList.get(0) : new BaseSku() ;
     }
+
+    @Override
+    public List<String> queryBaseSkuBySkuTypeList() {
+        List<BaseSku> baseSkuList = baseSkuMapper.selectList(Wrappers.<BaseSku>lambdaQuery().in(BaseSku::getSkuType,
+                Lists.newArrayList(Constant.SKU_TYPE.BAG_SKU.getType(), Constant.SKU_TYPE.BUCKET_SKU.getType())));
+        return CollectionUtil.isNotEmpty(baseSkuList) ? baseSkuList.stream().map(BaseSku::getSku).collect(Collectors.toList()) : Lists.newArrayList();
+    }
 }

+ 12 - 0
warewms-base/src/main/resources/mapper/base/BaseLocationInfoMapper.xml

@@ -635,6 +635,18 @@
         </if>
     </select>
 
+    <select id="selectAllocatingInventoryAccordingConditionsForEmergency" parameterType="BaseLocationInfo"
+            resultMap="BaseLocationInfoLotattResult">
+        select
+        b.*
+        , inv.sku, inv.qty
+        , att.*
+        from base_location_info b
+        left join inv_lot_loc_id inv on b.id = inv.location_id
+        left join inv_lot_att att on inv.lotnum = att.lotnum
+        where b.id = #{locationId}
+    </select>
+
     <select id="selectAllocatingInventoryAccordingConditionsOrderBy" parameterType="BaseLocationInfo"
             resultMap="BaseLocationInfoLotattResult">
         select

+ 11 - 0
warewms-hard/src/main/java/com/ruoyi/hard/xuankang/StirringTankClient.java

@@ -151,6 +151,17 @@ public class StirringTankClient {
         return NumberUtil.mul(NumberUtil.div(needInvQuantity, 100, 2), 1000);
     }
 
+    /**
+     * 读搅拌槽所需的剂量,单位是kg
+     * @param tankCommand
+     * @return
+     */
+    public Number readLiquidLevel(STIR_TANK_COMMAND tankCommand){
+        Number needInvQuantity = read1(tankCommand.getSlaveId(), tankCommand.getOffset());
+        log.info("readLiquidLevel result is {}", needInvQuantity);
+        return NumberUtil.div(needInvQuantity, 100, 2);
+    }
+
 
     public Boolean readExcuteTaskMark(int bitIndex) {
         Number number = read1(READ_THE_STIRRING_TANK_14.getSlaveId(), READ_THE_STIRRING_TANK_14.getOffset());