From 681ad300e3939e55ec1105f62afbd573daa1cf8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LAPTOP-S9HJSOEB=5C=E6=98=8A=E5=A4=A9?= Date: Tue, 22 Sep 2026 15:20:43 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0rfid=EF=BC=8C=E9=9B=B7?= =?UTF-8?q?=E8=BE=BE=20=E5=A2=9E=E5=8A=A0redis=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E7=9B=98=E7=82=B9=E6=95=B0=E6=8D=AE=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-dependencies/pom.xml | 7 - .../core/handler/DefaultDBFieldHandler.java | 2 +- .../yudao-module-annotation-biz/pom.xml | 5 +- .../yudao-module-camera-biz/pom.xml | 5 +- .../yudao-module-logistics-biz/pom.xml | 5 +- .../admin/checklog/CheckLogController.java | 3 +- .../admin/kesc/StockControlController.java | 40 +- .../admin/order/OrderController.java | 39 +- .../admin/radar/RadarController.java | 93 +++++ .../admin/radar/vo/RadarPageReqVO.java | 27 ++ .../admin/radar/vo/RadarRespVO.java | 36 ++ .../admin/radar/vo/RadarSaveReqVO.java | 25 ++ .../vo/SpecificationConfRespVO.java | 2 + .../vo/SpecificationConfSaveReqVO.java | 3 + .../admin/stock/StockController.java | 42 +- .../admin/street/StreetController.java | 13 + .../admin/street/vo/StreetSaveReqVO.java | 5 + .../dal/dataobject/checklog/CheckLogDO.java | 16 +- .../SpecificationConfDO.java | 1 + .../camera/dal/dataobject/stock/StockDO.java | 20 +- .../module/camera/dal/entity/ScanData.java | 2 +- .../dal/mysql/checklog/CheckLogMapper.java | 28 +- .../camera/dal/mysql/order/OrderMapper.java | 8 + .../camera/dal/mysql/rfid/RadarMapper.java | 37 ++ .../camera/dal/mysql/stock/StockMapper.java | 9 +- .../camera/framework/light/LightFactory.java | 67 +++- .../framework/netty/ksec/KsecDataInfo.java | 123 +++--- .../framework/netty/ksec/KsecDecoder.java | 2 +- .../service/Hik3D/HikFlaskApiService.java | 18 +- .../service/checklog/CheckLogService.java | 2 +- .../service/checklog/CheckLogServiceImpl.java | 9 +- .../module/camera/service/plc/PLCService.java | 6 +- .../camera/service/plc/PLCServiceImpl.java | 170 +++++---- .../module/camera/service/radar/RadarDO.java | 49 +++ .../camera/service/radar/RadarService.java | 56 +++ .../service/radar/RadarServiceImpl.java | 69 ++++ .../camera/service/rfid/MessageTran.java | 172 +++++++++ .../camera/service/rfid/RFIDSocket.java | 361 ++++++++++++++++++ .../camera/service/rfid/RfidServiceImpl.java | 16 + .../service/scan/LxService/LxServiceApi.java | 7 +- .../service/scan/OpencvServiceImpl.java | 5 +- .../camera/service/scan/PCDServiceImpl.java | 5 +- .../service/scan/QRCodeScanServiceImpl.java | 3 +- .../service/scan/RFIDScanServiceImpl.java | 119 +++++- .../camera/service/scan/RadarRequest.java | 60 +++ .../camera/service/scan/RadarResponse.java | 50 +++ .../service/scan/RadarScanServiceImpl.java | 276 +++++++++++++ .../service/scan/ScanGunScanServiceImpl.java | 7 +- .../camera/service/scan/ScanService.java | 3 +- .../service/scan/ScanServiceFactory.java | 39 +- .../service/scan/yoloCameraApi/Pojo.java | 2 + .../scan/yoloCameraApi/YoloServiceImpl.java | 179 ++++++--- .../camera/service/stock/StockService.java | 4 +- .../service/stock/StockServiceImpl.java | 61 +-- .../camera/service/street/StreetService.java | 2 + .../service/street/StreetServiceImpl.java | 26 ++ .../admin/checkconf/vo/CheckConfRespVO.java | 6 + .../checkconf/vo/CheckConfSaveReqVO.java | 7 + .../dal/dataobject/checkconf/CheckConfDO.java | 14 +- .../src/main/resources/mapper/OrderMapper.xml | 8 + .../mapper/checklog/CheckLogMapper.xml | 58 ++- .../resources/mapper/radar/RfidMapper.xml | 12 + .../resources/mapper/stock/StockMapper.xml | 39 +- .../yudao-module-system-biz/pom.xml | 5 +- .../admin/user/UserProfileController.java | 11 + .../system/service/user/AdminUserService.java | 2 + .../service/user/AdminUserServiceImpl.java | 8 + .../yudao/module/system/util/RedisUtil.java | 21 + .../src/main/resources/application-dev.yaml | 10 +- .../src/main/resources/application-local.yaml | 2 +- .../src/main/resources/application.yaml | 23 -- 71 files changed, 2256 insertions(+), 411 deletions(-) create mode 100644 yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/radar/RadarController.java create mode 100644 yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/radar/vo/RadarPageReqVO.java create mode 100644 yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/radar/vo/RadarRespVO.java create mode 100644 yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/radar/vo/RadarSaveReqVO.java create mode 100644 yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/mysql/rfid/RadarMapper.java create mode 100644 yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/radar/RadarDO.java create mode 100644 yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/radar/RadarService.java create mode 100644 yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/radar/RadarServiceImpl.java create mode 100644 yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/rfid/MessageTran.java create mode 100644 yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/RadarRequest.java create mode 100644 yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/RadarResponse.java create mode 100644 yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/RadarScanServiceImpl.java create mode 100644 yudao-module-logistics/yudao-module-logistics-biz/src/main/resources/mapper/radar/RfidMapper.xml diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index 16d16bf..3fa3117 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -45,7 +45,6 @@ 7.0.1 - 2.0.3 1.17.2 1.18.34 1.5.5.Final @@ -511,12 +510,6 @@ ${jsch.version} - - com.xingyuv - spring-boot-starter-captcha-plus - ${captcha-plus.version} - - org.lionsoul ip2region diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/handler/DefaultDBFieldHandler.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/handler/DefaultDBFieldHandler.java index 77d2ee3..7397878 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/handler/DefaultDBFieldHandler.java +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/handler/DefaultDBFieldHandler.java @@ -56,7 +56,7 @@ public class DefaultDBFieldHandler implements MetaObjectHandler { Object modifier = getFieldValByName("updater", metaObject); Long userId = WebFrameworkUtils.getLoginUserId(); if (Objects.nonNull(userId) && Objects.isNull(modifier)) { - setFieldValByName("updater", userId.toString(), metaObject); + setFieldValByName("updater", userId, metaObject); } } } diff --git a/yudao-module-annotation/yudao-module-annotation-biz/pom.xml b/yudao-module-annotation/yudao-module-annotation-biz/pom.xml index c63635e..795cec7 100644 --- a/yudao-module-annotation/yudao-module-annotation-biz/pom.xml +++ b/yudao-module-annotation/yudao-module-annotation-biz/pom.xml @@ -138,10 +138,7 @@ tencentcloud-sdk-java-sms - - com.xingyuv - spring-boot-starter-captcha-plus - + org.dromara.hutool diff --git a/yudao-module-camera/yudao-module-camera-biz/pom.xml b/yudao-module-camera/yudao-module-camera-biz/pom.xml index 289f780..470c60e 100644 --- a/yudao-module-camera/yudao-module-camera-biz/pom.xml +++ b/yudao-module-camera/yudao-module-camera-biz/pom.xml @@ -146,10 +146,7 @@ tencentcloud-sdk-java-sms - - com.xingyuv - spring-boot-starter-captcha-plus - + org.dromara.hutool diff --git a/yudao-module-logistics/yudao-module-logistics-biz/pom.xml b/yudao-module-logistics/yudao-module-logistics-biz/pom.xml index 2b2f4b1..f1fc429 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/pom.xml +++ b/yudao-module-logistics/yudao-module-logistics-biz/pom.xml @@ -164,10 +164,7 @@ tencentcloud-sdk-java-sms - - com.xingyuv - spring-boot-starter-captcha-plus - + org.dromara.hutool diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/checklog/CheckLogController.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/checklog/CheckLogController.java index 34ef651..df9a27c 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/checklog/CheckLogController.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/checklog/CheckLogController.java @@ -74,7 +74,7 @@ public class CheckLogController { CheckLogDO checkLog = checkLogService.getCheckLog(id); return success(BeanUtils.toBean(checkLog, CheckLogRespVO.class)); } -@Resource + @Resource private DictDataService dictDataService; @Resource @@ -91,6 +91,7 @@ public class CheckLogController { List checkConfList = checkConfService.list(new QueryWrapper() .ne("check_scan_type", 0) + .eq("is_Display", 1) .eq("is_Enable", 1)); List dictDataDOS =checkConfList.stream().map(checkConfDO ->{ diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/kesc/StockControlController.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/kesc/StockControlController.java index f612b3f..2ea1a72 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/kesc/StockControlController.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/kesc/StockControlController.java @@ -2,10 +2,12 @@ package cn.iocoder.yudao.module.camera.controller.admin.kesc; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.camera.dal.dataobject.checklog.CheckLogDO; +import cn.iocoder.yudao.module.camera.dal.dataobject.stock.StockDO; import cn.iocoder.yudao.module.camera.framework.netty.ksec.KsecDataInfo; import cn.iocoder.yudao.module.camera.service.checklog.CheckLogService; import cn.iocoder.yudao.module.camera.service.plc.PLCService; import cn.iocoder.yudao.module.camera.service.scan.LxService.BoxCountResponse; +import cn.iocoder.yudao.module.camera.service.stock.StockService; import cn.iocoder.yudao.module.logistics.dal.dataobject.checkconf.CheckConfDO; import cn.iocoder.yudao.module.logistics.service.checkconf.CheckConfService; import cn.iocoder.yudao.module.system.service.sse.SseClient; @@ -19,8 +21,10 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.stream.Collectors; @@ -109,8 +113,9 @@ public class StockControlController { @Operation(summary = "盘点任务") @ResponseBody @PermitAll - public CommonResult check(@RequestBody KsecDataInfo kescEntity){ + public CommonResult check(@RequestBody KsecDataInfo kescEntity){ log.info("盘点任务:{}",kescEntity); + kescEntity.setBatchNumber(kescEntity.getLotnum()); // kescEntity = kescEntity.fromBySRMNumber(kescEntity); // 开始盘点 @@ -121,9 +126,16 @@ public class StockControlController { // plcService.check(kescEntity.getTaskId(),kescEntity.getCmdName()); }else if (kescEntity.getCmdName().contains("E2")){ // 到位盘点 - plcService.check(kescEntity.getTaskId(), kescEntity.getCmdName()); + StockDO stockDO = plcService.check(kescEntity.getTaskId(), kescEntity.getCmdName()); + stockDO = stockService.getById(stockDO.getId()); + Map data = new HashMap<>(); + data.put("taskId",stockDO.getTaskId()); + data.put("lotnum",stockDO.getBatchNumber()); + data.put("result",stockDO.getStatus()); + data.putAll(stockDO.getExtendInfo()); // plcService.check(kescEntity.getTaskId(),kescEntity.getCmdName()); + return CommonResult.success(data,"OK"); } return CommonResult.success("OK"); @@ -136,16 +148,26 @@ public class StockControlController { @ResponseBody @PermitAll public CommonResult singleInventoryReturn(@RequestBody BoxCountResponse scanData){ - List checkConfList = checkConfService.list(new QueryWrapper() + List checkConfList = checkConfService.list(new QueryWrapper() .ne("check_scan_type", 0) .eq("is_Enable", 1)); - - plcService.singleInventoryReturn(scanData.getTaskId(),scanData.getResult(),scanData.getScanType(),checkConfList); + CheckLogDO checkLogDO = checkLogService.getOne(new QueryWrapper() + .eq("task_id", scanData.getTaskId()) + .orderByDesc("id") + .last("limit 1")); + StockDO stockDO = stockService.getOne(new QueryWrapper() + .eq("task_id", scanData.getTaskId()) + .orderByDesc("id") + .last("limit 1")); + plcService.singleInventoryReturn(stockDO,checkLogDO,scanData.getTaskId(),scanData.getResult(),scanData.getScanType(),checkConfList); return CommonResult.success("OK"); } @Resource CheckLogService checkLogService; + @Resource + StockService stockService; + @PostMapping("/singleInventoryQrCodeReturn") @Operation(summary = "盘点任务") @@ -155,12 +177,15 @@ public class StockControlController { List checkConfList = checkConfService.list(new QueryWrapper() .ne("check_scan_type", 0) .eq("is_Enable", 1)); - boxCountResponse.setResult("NoRead"); CheckLogDO checkLogDO = checkLogService.getOne(new QueryWrapper() .eq("task_id", boxCountResponse.getTaskId()) .orderByDesc("id") .last("limit 1")); + StockDO stockDO = stockService.getOne(new QueryWrapper() + .eq("task_id", boxCountResponse.getTaskId()) + .orderByDesc("id") + .last("limit 1")); // 增加空指针保护 List wmsCode = List.of(checkLogDO.getWmsCode().split(",")); if (boxCountResponse.getQrCodeResults() != null && new HashSet<>(boxCountResponse.getQrCodeResults()).containsAll(wmsCode)) { @@ -170,7 +195,7 @@ public class StockControlController { .collect(Collectors.joining(",")); boxCountResponse.setResult(rest); } - plcService.singleInventoryReturn(boxCountResponse.getTaskId(),boxCountResponse.getResult(),boxCountResponse.getScanType(),checkConfList); + plcService.singleInventoryReturn(stockDO,checkLogDO,boxCountResponse.getTaskId(),boxCountResponse.getResult(),boxCountResponse.getScanType(),checkConfList); return CommonResult.success("OK"); } @@ -229,6 +254,7 @@ public class StockControlController { plcService.check(kescEntity.getTaskId(),kescEntity.getCmdName()); if (kescEntity.getCmdName().equals("E3")){ plcService.checkStop(kescEntity.getTaskId()); + } }else if (kescEntity.getCmdName().startsWith("C")){ plcService.action(kescEntity.getTaskId(),kescEntity.getCmdName()); diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/order/OrderController.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/order/OrderController.java index 2ca57ae..cce9404 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/order/OrderController.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/order/OrderController.java @@ -13,6 +13,8 @@ import cn.iocoder.yudao.module.camera.controller.admin.order.vo.OrderStatistics; import cn.iocoder.yudao.module.camera.dal.dataobject.order.OrderDO; import cn.iocoder.yudao.module.camera.dal.dataobject.street.StreetDO; import cn.iocoder.yudao.module.camera.dal.entity.echarts.EChartsOption; +import cn.iocoder.yudao.module.camera.dal.mysql.checklog.CheckLogMapper; +import cn.iocoder.yudao.module.camera.dal.mysql.order.OrderMapper; import cn.iocoder.yudao.module.camera.service.checklog.CheckLogService; import cn.iocoder.yudao.module.camera.service.order.OrderService; import cn.iocoder.yudao.module.camera.service.stock.StockService; @@ -30,7 +32,6 @@ import org.springframework.web.bind.annotation.*; import java.io.IOException; import java.time.LocalDate; import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; import java.time.temporal.TemporalAdjusters; import java.util.List; import java.util.Map; @@ -50,6 +51,11 @@ public class OrderController { @Resource private CheckLogService checkLogService; + @Resource + private OrderMapper orderMapper; + @Resource + private CheckLogMapper checkLogMapper; + @Resource private StockService stockService; @@ -64,24 +70,27 @@ public class OrderController { @Operation(summary = "首页个数统计") @PreAuthorize("@ss.hasPermission('logistics:order:statistics')") public CommonResult statistics() { - // 获取当前日期 - LocalDate today = LocalDate.now(); -// 获取本月1号 - LocalDate firstDayOfMonth = today.with(TemporalAdjusters.firstDayOfMonth()); -// 设置时间为0点0分0秒 - LocalDateTime firstDayOfMonthStart = firstDayOfMonth.atStartOfDay(); -// 定义日期格式 - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); -// 格式化日期为字符串 - String firstDayOfMonthStr = firstDayOfMonthStart.format(formatter); + // 本月 1 号 0 点 + LocalDateTime firstDayOfMonthStart = LocalDate.now() + .with(TemporalAdjusters.firstDayOfMonth()) + .atStartOfDay(); + + // 一次查询同时统计 全量 + 本月,避免多次 COUNT(*) 扫描大表 + Map orderStat = orderMapper.selectTotalAndMonthCount(firstDayOfMonthStart); + Map checkLogStat = checkLogMapper.selectTotalAndMonthCount(firstDayOfMonthStart); + OrderStatistics orderStatistics = new OrderStatistics(); - orderStatistics.setOrderCount(orderService.count(null,null)); - orderStatistics.setOrderMonthCount(orderService.count(firstDayOfMonthStr,null)); - orderStatistics.setCheckLogCount(checkLogService.count(null,null)); - orderStatistics.setCheckLogMonthCount(checkLogService.count(firstDayOfMonthStr,null)); + orderStatistics.setOrderCount(toLong(orderStat.get("total_count"))); + orderStatistics.setOrderMonthCount(toLong(orderStat.get("month_count"))); + orderStatistics.setCheckLogCount(toLong(checkLogStat.get("total_count"))); + orderStatistics.setCheckLogMonthCount(toLong(checkLogStat.get("month_count"))); return success(orderStatistics); } + private Long toLong(Object value) { + return value == null ? 0L : ((Number) value).longValue(); + } + @PostMapping("/laneInventoryStatistics") @Operation(summary = "首页巷道随行统计") @PreAuthorize("@ss.hasPermission('logistics:order:laneInventoryStatistics')") diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/radar/RadarController.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/radar/RadarController.java new file mode 100644 index 0000000..17f1cf2 --- /dev/null +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/radar/RadarController.java @@ -0,0 +1,93 @@ +package cn.iocoder.yudao.module.camera.controller.admin.radar; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.camera.controller.admin.radar.vo.RadarPageReqVO; +import cn.iocoder.yudao.module.camera.controller.admin.radar.vo.RadarRespVO; +import cn.iocoder.yudao.module.camera.controller.admin.radar.vo.RadarSaveReqVO; +import cn.iocoder.yudao.module.camera.service.radar.RadarDO; +import cn.iocoder.yudao.module.camera.service.radar.RadarService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - Radar") +@RestController +@RequestMapping("/logistics/Radar") +@Validated +public class RadarController { + + @Resource + private RadarService radarService; + + @PostMapping("/create") + @Operation(summary = "创建Radar") + @PreAuthorize("@ss.hasPermission('logistics:Radar:create')") + public CommonResult createRadar(@Valid @RequestBody RadarSaveReqVO createReqVO) { + return success(radarService.createRadar(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新Radar") + @PreAuthorize("@ss.hasPermission('logistics:Radar:update')") + public CommonResult updateRadar(@Valid @RequestBody RadarSaveReqVO updateReqVO) { + radarService.updateRadar(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除Radar") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('logistics:Radar:delete')") + public CommonResult deleteRadar(@RequestParam("id") Integer id) { + radarService.deleteRadar(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得Radar") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('logistics:Radar:query')") + public CommonResult getRadar(@RequestParam("id") Integer id) { + RadarDO Radar = radarService.getRadar(id); + return success(BeanUtils.toBean(Radar, RadarRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得Radar分页") + @PreAuthorize("@ss.hasPermission('logistics:Radar:query')") + public CommonResult> getRadarPage(@Valid RadarPageReqVO pageReqVO) { + PageResult pageResult = radarService.getRadarPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, RadarRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出Radar Excel") + @PreAuthorize("@ss.hasPermission('logistics:Radar:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportRadarExcel(@Valid RadarPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = radarService.getRadarPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "Radar.xls", "数据", RadarRespVO.class, + BeanUtils.toBean(list, RadarRespVO.class)); + } + +} \ No newline at end of file diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/radar/vo/RadarPageReqVO.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/radar/vo/RadarPageReqVO.java new file mode 100644 index 0000000..5946d55 --- /dev/null +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/radar/vo/RadarPageReqVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.camera.controller.admin.radar.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - Radar分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class RadarPageReqVO extends PageParam { + + @Schema(description = "巷道id", example = "8923") + private Integer streetId; + + @Schema(description = "方向") + private Integer direction; + + @Schema(description = "ip") + private String ip; + + @Schema(description = "端口") + private Integer port; + +} \ No newline at end of file diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/radar/vo/RadarRespVO.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/radar/vo/RadarRespVO.java new file mode 100644 index 0000000..2d0e3d6 --- /dev/null +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/radar/vo/RadarRespVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.camera.controller.admin.radar.vo; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - Radar Response VO") +@Data +@ExcelIgnoreUnannotated +public class RadarRespVO { + + @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "3186") + @ExcelProperty("id") + private Integer id; + + @Schema(description = "巷道id", example = "8923") + @ExcelProperty("巷道id") + private Integer streetId; + + @Schema(description = "方向") + @ExcelProperty(value = "方向", converter = DictConvert.class) + @DictFormat("direction") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Integer direction; + + @Schema(description = "ip") + @ExcelProperty("ip") + private String ip; + + @Schema(description = "端口") + @ExcelProperty("端口") + private Integer port; + +} \ No newline at end of file diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/radar/vo/RadarSaveReqVO.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/radar/vo/RadarSaveReqVO.java new file mode 100644 index 0000000..f9b91f8 --- /dev/null +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/radar/vo/RadarSaveReqVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.camera.controller.admin.radar.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - Radar新增/修改 Request VO") +@Data +public class RadarSaveReqVO { + + @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "3186") + private Integer id; + + @Schema(description = "巷道id", example = "8923") + private Integer streetId; + + @Schema(description = "方向") + private Integer direction; + + @Schema(description = "ip") + private String ip; + + @Schema(description = "端口") + private Integer port; + +} \ No newline at end of file diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/specificationConf/vo/SpecificationConfRespVO.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/specificationConf/vo/SpecificationConfRespVO.java index 7b5f1d3..250cc00 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/specificationConf/vo/SpecificationConfRespVO.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/specificationConf/vo/SpecificationConfRespVO.java @@ -50,4 +50,6 @@ public class SpecificationConfRespVO { @ExcelProperty("高度单位mm") private Integer high; + @Schema(description = "图片路径") + private String pic; } \ No newline at end of file diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/specificationConf/vo/SpecificationConfSaveReqVO.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/specificationConf/vo/SpecificationConfSaveReqVO.java index 72cae86..be3d236 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/specificationConf/vo/SpecificationConfSaveReqVO.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/specificationConf/vo/SpecificationConfSaveReqVO.java @@ -37,4 +37,7 @@ public class SpecificationConfSaveReqVO { @Schema(description = "高度单位mm") private Integer id; + @Schema(description = "图片路径") + private String pic; + } \ No newline at end of file diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/stock/StockController.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/stock/StockController.java index d191d17..c7c4029 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/stock/StockController.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/stock/StockController.java @@ -17,7 +17,6 @@ import cn.iocoder.yudao.module.camera.dal.entity.ScanData; import cn.iocoder.yudao.module.camera.dal.entity.ScanStatus; import cn.iocoder.yudao.module.camera.dal.entity.echarts.EChartsOption; import cn.iocoder.yudao.module.camera.service.checklog.CheckLogService; -import cn.iocoder.yudao.module.camera.service.plc.PLCServiceImpl; import cn.iocoder.yudao.module.camera.service.resources.URLResourcesService; import cn.iocoder.yudao.module.camera.service.stock.StockService; import cn.iocoder.yudao.module.logistics.dal.dataobject.checkconf.CheckConfDO; @@ -151,6 +150,7 @@ public class StockController { List checkConfList = checkConfService.list(new QueryWrapper() .ne("check_scan_type", 0) + .eq("is_Display",1) .eq("is_Enable", 1)); Map scanConfName = dictDataService.getDictValueMap("scan_conf_name"); @@ -179,39 +179,15 @@ public class StockController { ScanStatus scanStatus = new ScanStatus(); scanStatus.setLabel(v.getCheckName()); - scanStatus.setRemark(remark); - - try { - String wmsType = "wms" + PLCServiceImpl.capitalize(v.getCheckName()); - - Field dictCode = ScanStatus.class.getDeclaredField("code"); - Field dictWmsCode = ScanStatus.class.getDeclaredField("wmsCode"); - - Field scanCode = getFieldFromHierarchy(finalScan.getClass(), v.getCheckName()); - Field scanWmsCode = getFieldFromHierarchy(finalScan.getClass(), wmsType); - - if (scanCode != null && scanWmsCode != null) { - dictCode.setAccessible(true); - dictWmsCode.setAccessible(true); - scanCode.setAccessible(true); - scanWmsCode.setAccessible(true); - - dictCode.set(scanStatus, scanCode.get(finalScan)); - dictWmsCode.set(scanStatus, scanWmsCode.get(finalScan)); - - // 打印 ScanStatus 的字段值 - } else { - } - - - } catch (NoSuchFieldException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - e.printStackTrace(); - throw new RuntimeException(e); - } - scanStatuses.add(scanStatus); + scanStatus.setRemark(remark); + if (finalScan != null && finalScan.getExtendInfo() != null) { + scanStatus.setCode(finalScan.getExtendInfo().get(v.getCheckName())); } + if (finalScan != null && finalScan.getWmsExtendInfo() != null) { + scanStatus.setWmsCode(finalScan.getWmsExtendInfo().get(v.getCheckName())); + } + scanStatuses.add(scanStatus); + } if (scan != null) { scan.setScan(scanStatuses); scan.setColour(dictValueMap.get(String.valueOf(scan.getStatus())).getColorType()); diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/street/StreetController.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/street/StreetController.java index c202a3c..48ef590 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/street/StreetController.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/street/StreetController.java @@ -16,6 +16,8 @@ import cn.iocoder.yudao.module.camera.dal.dataobject.shelfCode.rfid.ShelfCodeDO; import cn.iocoder.yudao.module.camera.dal.dataobject.street.StreetDO; import cn.iocoder.yudao.module.camera.framework.light.LightFactory; import cn.iocoder.yudao.module.camera.service.lightsource.LightSourceService; +import cn.iocoder.yudao.module.camera.service.radar.RadarDO; +import cn.iocoder.yudao.module.camera.service.radar.RadarService; import cn.iocoder.yudao.module.camera.service.rfid.RfidService; import cn.iocoder.yudao.module.camera.service.sensorgun.SensorGunService; import cn.iocoder.yudao.module.camera.service.street.StreetService; @@ -93,6 +95,9 @@ public class StreetController { @Resource RfidService rfidService; + @Resource + RadarService radarService; + @GetMapping("/linkCheck") @Operation(summary = "巷道状态查询") @@ -209,6 +214,14 @@ public class StreetController { return success(streetService.getRFIDListByStreetId(streetId)); } + @GetMapping("/radar/list-by-street-id") + @Operation(summary = "获得rfid列表") + @Parameter(name = "streetId", description = "巷道id") + @PreAuthorize("@ss.hasPermission('logistics:street:query')") + public CommonResult> getRadarListByStreetId(@RequestParam("streetId") Integer streetId) { + return success(streetService.getRadarListByStreetId(streetId)); + } + @GetMapping("/shelfCode/list-by-street-id") @Operation(summary = "获得货架列表") @Parameter(name = "streetId", description = "巷道id") diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/street/vo/StreetSaveReqVO.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/street/vo/StreetSaveReqVO.java index 97a1008..ff215d7 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/street/vo/StreetSaveReqVO.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/controller/admin/street/vo/StreetSaveReqVO.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.camera.controller.admin.street.vo; import cn.iocoder.yudao.module.camera.dal.dataobject.lightsource.LightSourceDO; import cn.iocoder.yudao.module.camera.dal.dataobject.rfid.RfidDO; import cn.iocoder.yudao.module.camera.dal.dataobject.sensorgun.SensorGunDO; +import cn.iocoder.yudao.module.camera.service.radar.RadarDO; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.Data; @@ -62,6 +63,10 @@ public class StreetSaveReqVO { @Schema(description = "扫码枪列表") private List rfids; + @Schema(description = "扫码枪列表") + private List radars; + + @Schema(description = "光源列表") private List lightSources; diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/dataobject/checklog/CheckLogDO.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/dataobject/checklog/CheckLogDO.java index db7a4c3..a1122da 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/dataobject/checklog/CheckLogDO.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/dataobject/checklog/CheckLogDO.java @@ -3,18 +3,21 @@ package cn.iocoder.yudao.module.camera.dal.dataobject.checklog; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.camera.dal.dataobject.resources.URLResourcesDo; import com.baomidou.mybatisplus.annotation.*; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import lombok.*; import org.glassfish.jaxb.core.v2.TODO; import java.time.LocalDateTime; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * 盘点 DO * * @author haotianWang */ -@TableName("logistics_check_log") +@TableName(value = "logistics_check_log", autoResultMap = true) @KeySequence("logistics_check_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @EqualsAndHashCode(callSuper = true) @@ -139,4 +142,15 @@ public class CheckLogDO extends BaseDO { private String wmsItemCode; private String wmsCountNumber; + /** + * 扩展信息(键值对,JSON 存储) + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private Map extendInfo =new HashMap<>(); + + /** + * WMS 扩展信息(键值对,JSON 存储) + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private Map wmsExtendInfo =new HashMap<>(); } \ No newline at end of file diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/dataobject/specificationConf/SpecificationConfDO.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/dataobject/specificationConf/SpecificationConfDO.java index 8730fbf..f9b2294 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/dataobject/specificationConf/SpecificationConfDO.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/dataobject/specificationConf/SpecificationConfDO.java @@ -52,6 +52,7 @@ public class SpecificationConfDO extends BaseDO { * 类型 */ private String type; + private String pic; /** * 高度单位mm */ diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/dataobject/stock/StockDO.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/dataobject/stock/StockDO.java index fe8af26..a858508 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/dataobject/stock/StockDO.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/dataobject/stock/StockDO.java @@ -2,17 +2,20 @@ package cn.iocoder.yudao.module.camera.dal.dataobject.stock; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import com.baomidou.mybatisplus.annotation.*; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import lombok.*; import org.glassfish.jaxb.core.v2.TODO; import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; /** * 盘点状态 DO * * @author 芋道源码 */ -@TableName("logistics_stock") +@TableName(value = "logistics_stock", autoResultMap = true) @KeySequence("logistics_stock_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @EqualsAndHashCode(callSuper = true) @@ -24,6 +27,9 @@ public class StockDO extends BaseDO { @TableField(exist = false) private String scanType; + + @TableField(exist = false) + private String pic; /** * id */ @@ -164,4 +170,16 @@ public class StockDO extends BaseDO { private String wmsItemCode; private String wmsCountNumber; + /** + * 扩展信息(键值对,JSON 存储) + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private Map extendInfo =new HashMap<>(); + + /** + * WMS 扩展信息(键值对,JSON 存储) + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private Map wmsExtendInfo =new HashMap<>(); + } \ No newline at end of file diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/entity/ScanData.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/entity/ScanData.java index fab1119..b50da96 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/entity/ScanData.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/entity/ScanData.java @@ -14,7 +14,7 @@ public class ScanData extends StockDO { private LocalDateTime createTime; private Integer stockId; private Integer checkLogId; - private String code; + private String code ; private String trayCode; private String type; private Integer direction; diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/mysql/checklog/CheckLogMapper.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/mysql/checklog/CheckLogMapper.java index 72c00c8..3ebb4a2 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/mysql/checklog/CheckLogMapper.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/mysql/checklog/CheckLogMapper.java @@ -8,7 +8,9 @@ import cn.iocoder.yudao.module.camera.dal.dataobject.checklog.CheckLogDO; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; +import java.time.LocalDateTime; import java.util.List; +import java.util.Map; /** * 盘点 Mapper @@ -33,10 +35,10 @@ public interface CheckLogMapper extends BaseMapperX { /** * 动态更新最后一条taskId匹配的记录 - * @param taskId 任务ID + * @param id 任务ID * @return 更新行数 */ - int updateLastByTaskId(@Param("taskId") String taskId, @Param("value") String value , @Param("column")String column); + int updateLastByTaskId(@Param("id") Integer id, @Param("value") String value , @Param("column")String column); /** * 根据字段列表更新status @@ -47,4 +49,26 @@ public interface CheckLogMapper extends BaseMapperX { */ int updateStatusByFields(@Param("id") Integer id, @Param("fields") List fields); + /** + * 按 巷道 + 状态 分组统计盘点记录数量(数据库聚合,避免全表加载到内存) + * + * @return 每行包含 street_id、status、count 三列 + */ + List> selectGroupCountByStreetIdAndStatus(); + + /** + * 按 状态 分组统计盘点记录数量(数据库聚合,避免全表加载到内存) + * + * @return 每行包含 status、count 两列 + */ + List> selectGroupCountByStatus(); + + /** + * 一次查询统计 全量总数 + 本月总数(从 monthStart 起),避免多次 COUNT(*) 扫描大表 + * + * @param monthStart 本月 1 号 0 点 + * @return 单行:total_count、month_count + */ + Map selectTotalAndMonthCount(@Param("monthStart") LocalDateTime monthStart); + } \ No newline at end of file diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/mysql/order/OrderMapper.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/mysql/order/OrderMapper.java index 1c00a53..820b60e 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/mysql/order/OrderMapper.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/mysql/order/OrderMapper.java @@ -43,4 +43,12 @@ public interface OrderMapper extends BaseMapperX { List> selectGroupCountBySrmNumberAndDate(@Param("startTime") LocalDateTime startTime); + /** + * 一次查询统计 全量总数 + 本月总数(从 startTime 起),避免多次 COUNT(*) 扫描大表 + * + * @param monthStart 本月 1 号 0 点 + * @return 单行:total_count、month_count + */ + Map selectTotalAndMonthCount(@Param("monthStart") LocalDateTime monthStart); + } \ No newline at end of file diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/mysql/rfid/RadarMapper.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/mysql/rfid/RadarMapper.java new file mode 100644 index 0000000..ae1be8f --- /dev/null +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/mysql/rfid/RadarMapper.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.camera.dal.mysql.rfid; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.camera.controller.admin.radar.vo.RadarPageReqVO; +import cn.iocoder.yudao.module.camera.service.radar.RadarDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * RFID Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface RadarMapper extends BaseMapperX { + + default PageResult selectPage(RadarPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(RadarDO::getStreetId, reqVO.getStreetId()) + .eqIfPresent(RadarDO::getDirection, reqVO.getDirection()) + .eqIfPresent(RadarDO::getIp, reqVO.getIp()) + .eqIfPresent(RadarDO::getPort, reqVO.getPort()) + .orderByDesc(RadarDO::getId)); + } + + + default List selectListByStreetId(Integer streetId) { + return selectList(RadarDO::getStreetId, streetId); + } + + default int deleteByStreetId(Integer streetId) { + return delete(RadarDO::getStreetId, streetId); + } +} \ No newline at end of file diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/mysql/stock/StockMapper.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/mysql/stock/StockMapper.java index 5cc2d58..8c42237 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/mysql/stock/StockMapper.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/dal/mysql/stock/StockMapper.java @@ -52,10 +52,10 @@ public interface StockMapper extends BaseMapperX { /** * 动态更新最后一条taskId匹配的记录 - * @param taskId 任务ID + * @param id 任务ID * @return 更新行数 */ - int updateLastByTaskId(@Param("taskId") String taskId, @Param("value") String value , @Param("column")String column); + int updateLastByTaskId(@Param("id") Long id, @Param("value") String value , @Param("column")String column); /** @@ -66,4 +66,9 @@ public interface StockMapper extends BaseMapperX { * @return 更新行数 */ int updateStatusByFields(@Param("id") Long id, @Param("fields") List fields); + + /** + * 清空整个表(TRUNCATE) + */ + void truncate(); } \ No newline at end of file diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/framework/light/LightFactory.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/framework/light/LightFactory.java index 2afbb7b..52cea0c 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/framework/light/LightFactory.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/framework/light/LightFactory.java @@ -29,6 +29,8 @@ public class LightFactory { HikControlSocket.openLight(lightSourceRespVO.getIp(), Integer.parseInt( lightSourceRespVO.getPort()),1, 0); } else if (lightSourceRespVO.getType() == 3) { lightController(lightSourceRespVO.getIp(),Integer.parseInt( lightSourceRespVO.getPort()), 0); + }else if (lightSourceRespVO.getType() == 4) { + lightRelayController(lightSourceRespVO.getIp(),Integer.parseInt( lightSourceRespVO.getPort()), 0); } }else { if (lightSourceRespVO.getType() == 1) { @@ -36,14 +38,75 @@ public class LightFactory { JYDAMEquip equip = JYDamHelper.Connect(lightSourceRespVO.getIp(),Integer.parseInt( lightSourceRespVO.getPort())); JYDamHelper.openDO(equip, 1); } else if (lightSourceRespVO.getType() == 2) { - HikControlSocket.openLight(lightSourceRespVO.getIp(), Integer.parseInt( lightSourceRespVO.getPort()),1, 1); + HikControlSocket.openLight(lightSourceRespVO.getIp(), Integer.parseInt(lightSourceRespVO.getPort()),1, 1); } else if (lightSourceRespVO.getType() == 3) { - lightController(lightSourceRespVO.getIp(),Integer.parseInt( lightSourceRespVO.getPort()), 1); + lightController(lightSourceRespVO.getIp(),Integer.parseInt(lightSourceRespVO.getPort()), 1); + }else if (lightSourceRespVO.getType() == 4) { + lightRelayController(lightSourceRespVO.getIp(),Integer.parseInt( lightSourceRespVO.getPort()), 0); } } } + public static void lightRelayController(String ip, Integer port, Integer stat) { + Socket socket = new Socket(); + OutputStream os = null; + InputStream is = null; + try { + socket.connect(new InetSocketAddress(ip, port), 3000); + os = socket.getOutputStream(); + is = socket.getInputStream(); + socket.setSoTimeout(3000); + // 开灯: 01 05 00 00 FF 00 8C 3A,关灯: 01 05 00 00 FF 01 4D FA + byte[] cmd = stat != null && stat == 1 + ? new byte[]{0x01, 0x05, 0x00, 0x00, (byte) 0xFF, 0x00, (byte) 0x8C, 0x3A} + : new byte[]{0x01, 0x05, 0x00, 0x00, 0x00, 0x00, (byte)0xCD, (byte) 0xCA}; + os.write(cmd); + os.flush(); + // 读取返回,判断是否成功(返回帧通常与发送帧一致) + byte[] resp = new byte[8]; + int len = is.read(resp); + if (len > 0) { + log.info("[lightRelayController] ip={}, port={}, stat={}, 发送={}, 返回={}", + ip, port, stat, toHex(cmd), toHex(resp, len)); + } + } catch (IOException e) { + log.error("[lightRelayController] 控制失败, ip={}, port={}, stat={}", ip, port, stat, e); + } finally { + if (os != null) { + try { + os.close(); + } catch (IOException e) { + log.error("[lightRelayController] 关闭输出流失败", e); + } + } + if (is != null) { + try { + is.close(); + } catch (IOException e) { + log.error("[lightRelayController] 关闭输入流失败", e); + } + } + try { + socket.close(); + } catch (IOException e) { + log.error("[lightRelayController] 关闭socket失败", e); + } + } + } + + private static String toHex(byte[] data) { + return toHex(data, data.length); + } + + private static String toHex(byte[] data, int len) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < len; i++) { + sb.append(String.format("%02X ", data[i])); + } + return sb.toString().trim(); + } + public static void lightController(String ip ,Integer port,Integer stat){ Socket socket = new Socket(); OutputStream os = null; diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/framework/netty/ksec/KsecDataInfo.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/framework/netty/ksec/KsecDataInfo.java index d319fb5..6305ed2 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/framework/netty/ksec/KsecDataInfo.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/framework/netty/ksec/KsecDataInfo.java @@ -3,6 +3,9 @@ package cn.iocoder.yudao.module.camera.framework.netty.ksec; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; +import java.util.HashMap; +import java.util.Map; + @Data public class KsecDataInfo { @@ -38,49 +41,57 @@ public class KsecDataInfo { private Integer ackStatus; - private String code; - - private String trayCode; - - private String category; - - private String count; - -//品规码 - private String itemCode; -//货架码 - private String shelfCode; -// 托盘码 - private String pltCode; - -//数量 - private String countNumber; - - - private String wmsCode; - - private String wmsTrayCode; - - private String wmsCategory; - - private String wmsCount; - - //品规码 - private String wmsItemCode; - //货架码 - private String wmsShelfCode; - // 托盘码 - private String wmsPltCode; - - //数量 - private String wmsCountNumber; + private Map extendInfo =new HashMap<>(); + private Map wmsExtendInfo =new HashMap<>(); + +// +// private String code; +// +// private String trayCode; +// +// private String category; +// +// private String count; +// +////品规码 +// private String itemCode; +////货架码 +// private String shelfCode; +//// 托盘码 +// private String pltCode; +// +////数量 +// private String countNumber; +// +// +// private String wmsCode; +// +// private String wmsTrayCode; +// +// private String wmsCategory; +// +// private String wmsCount; +// +// //品规码 +// private String wmsItemCode; +// //货架码 +// private String wmsShelfCode; +// // 托盘码 +// private String wmsPltCode; +// +// //数量 +// private String wmsCountNumber; + /** + * 盘点批次号,之后合并到batchNumber + */ + private String lotnum; /** * 盘点批次号 */ private String batchNumber; - private ExtendInfo extendInfo; +// private ExtendInfo extendInfo; @@ -115,23 +126,23 @@ public class KsecDataInfo { return data; } - public KsecDataInfo toWMSData() { - this.wmsCode = this.code; - this.wmsTrayCode = this.trayCode; - this.wmsCategory = this.category; - this.wmsCount = this.count; - this.wmsItemCode = this.itemCode; - this.wmsShelfCode = this.shelfCode; - this.wmsPltCode = this.pltCode; - this.wmsCountNumber = this.countNumber; - this.code = null; - this.trayCode = null; - this.category = null; - this.count = null; - this.itemCode = null; - this.shelfCode = null; - this.pltCode = null; - this.countNumber = null; - return this; - } +// public KsecDataInfo toWMSData() { +// this.wmsCode = this.code; +// this.wmsTrayCode = this.trayCode; +// this.wmsCategory = this.category; +// this.wmsCount = this.count; +// this.wmsItemCode = this.itemCode; +// this.wmsShelfCode = this.shelfCode; +// this.wmsPltCode = this.pltCode; +// this.wmsCountNumber = this.countNumber; +// this.code = null; +// this.trayCode = null; +// this.category = null; +// this.count = null; +// this.itemCode = null; +// this.shelfCode = null; +// this.pltCode = null; +// this.countNumber = null; +// return this; +// } } diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/framework/netty/ksec/KsecDecoder.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/framework/netty/ksec/KsecDecoder.java index 4d9f3e8..fd87e7e 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/framework/netty/ksec/KsecDecoder.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/framework/netty/ksec/KsecDecoder.java @@ -108,7 +108,7 @@ public class KsecDecoder extends DelimiterBasedFrameDecoder { } else if (Cmd.E.name().equals(ksecInfo.getType())) { //智能盘点 - dataInfo.setCount("正常"); +// dataInfo.setCount("正常"); // plcService.check( dataInfo); diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/Hik3D/HikFlaskApiService.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/Hik3D/HikFlaskApiService.java index de4beb1..1443ebc 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/Hik3D/HikFlaskApiService.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/Hik3D/HikFlaskApiService.java @@ -8,19 +8,15 @@ import cn.iocoder.yudao.module.camera.dal.entity.HikPythonEntity; import cn.iocoder.yudao.module.camera.dal.entity.ScanData; import cn.iocoder.yudao.module.camera.service.resources.URLResourcesService; import cn.iocoder.yudao.module.camera.service.scan.ScanService; +import cn.iocoder.yudao.module.logistics.dal.dataobject.checkconf.CheckConfDO; import cn.iocoder.yudao.module.system.service.dict.DictDataService; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonPrimitive; -import com.google.gson.JsonSerializer; +import com.google.gson.*; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import okhttp3.*; import org.springframework.stereotype.Service; import java.io.IOException; -import java.lang.reflect.Type; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @@ -189,7 +185,7 @@ public class HikFlaskApiService implements ScanService { URLResourcesService urlResourcesService; // 识别结果是正常或缺件 @Override - public ScanData scan(StreetDO streetDO, StockDO stockDO) { + public ScanData scan(StreetDO streetDO, StockDO stockDO, CheckConfDO checkConfDO ) { ScanData scanData = new ScanData(); @@ -198,7 +194,7 @@ public class HikFlaskApiService implements ScanService { try { scanData.setCode("false"); - HikPythonEntity hikPythonEntity = picComputeAll(stockDO.getWmsItemCode(),urlPath); + HikPythonEntity hikPythonEntity = picComputeAll(stockDO.getWmsExtendInfo().get(checkConfDO.getCheckName()),urlPath); // for (int i = 0; i < 4; i++){ // if (hikPythonEntity == null || hikPythonEntity.getColors()==null|| hikPythonEntity.getColors().size()==0){ // hikPythonEntity = picComputeAll(stockDO.getWmsItemCode(),urlPath); @@ -231,7 +227,7 @@ public class HikFlaskApiService implements ScanService { // return null; } - public ScanData scanExist(StreetDO streetDO, StockDO stockDO) { + public ScanData scanExist(StreetDO streetDO, StockDO stockDO, CheckConfDO checkConfDO) { ScanData scanData = new ScanData(); @@ -241,10 +237,10 @@ public class HikFlaskApiService implements ScanService { scanData.setCode("有货"); - HikPythonEntity hikPythonEntity = picBitCloudy(stockDO.getWmsItemCode(),urlPath); + HikPythonEntity hikPythonEntity = picBitCloudy(stockDO.getWmsExtendInfo().get(checkConfDO.getCheckName()),urlPath); for (int i = 0; i < 4; i++){ if (hikPythonEntity.getColors()==null|| hikPythonEntity.getColors().size()==0){ - hikPythonEntity = picComputeAll(stockDO.getWmsItemCode(),urlPath); + hikPythonEntity = picComputeAll(stockDO.getWmsExtendInfo().get(checkConfDO.getCheckName()),urlPath); } } log.info("hik3d拍照结果:"+hikPythonEntity.toString()); diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/checklog/CheckLogService.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/checklog/CheckLogService.java index bea08ca..dd294c7 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/checklog/CheckLogService.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/checklog/CheckLogService.java @@ -59,6 +59,6 @@ public interface CheckLogService extends IService { * * @param taskId 任务ID */ - void updateLastByTaskId(String taskId, String value,String column); + void updateLastByTaskId(Integer taskId, String value,String column); } \ No newline at end of file diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/checklog/CheckLogServiceImpl.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/checklog/CheckLogServiceImpl.java index c31d808..4c23cbc 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/checklog/CheckLogServiceImpl.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/checklog/CheckLogServiceImpl.java @@ -83,7 +83,7 @@ public class CheckLogServiceImpl extends ServiceImpl } @Override - public void updateLastByTaskId(String taskId,String value,String column) { + public void updateLastByTaskId(Integer taskId,String value,String column) { checkLogMapper.updateLastByTaskId(taskId, value, column); } @@ -113,10 +113,13 @@ public class CheckLogServiceImpl extends ServiceImpl .collect(Collectors.groupingBy(URLResourcesDo::getUuid)); } - //记录巷道名 + //记录巷道名、状态名 for (CheckLogDO checkLogDO : checkLogDOPageResult.getList()){ checkLogDO.setUrlResources(urlResourcesMap.getOrDefault(checkLogDO.getPic(), Collections.emptyList())); - checkLogDO.setStatusName(dict.get(checkLogDO.getStatus().toString()).getLabel()); + if (checkLogDO.getStatus() != null) { + DictDataDO statusDict = dict.get(checkLogDO.getStatus().toString()); + checkLogDO.setStatusName(statusDict != null ? statusDict.getLabel() : null); + } checkLogDO.setStreetName(streetMap.get(checkLogDO.getStreetId())); } return checkLogDOPageResult; diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/plc/PLCService.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/plc/PLCService.java index 585cfe2..50dbc12 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/plc/PLCService.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/plc/PLCService.java @@ -1,5 +1,7 @@ package cn.iocoder.yudao.module.camera.service.plc; +import cn.iocoder.yudao.module.camera.dal.dataobject.checklog.CheckLogDO; +import cn.iocoder.yudao.module.camera.dal.dataobject.stock.StockDO; import cn.iocoder.yudao.module.camera.framework.netty.ksec.KsecDataInfo; import cn.iocoder.yudao.module.camera.framework.netty.streetAlgorithm.executor.AlgorithmDelayTask; import cn.iocoder.yudao.module.logistics.dal.dataobject.checkconf.CheckConfDO; @@ -16,8 +18,8 @@ public interface PLCService { void orderStart(KsecDataInfo kescEntity); void orderStop(String taskId); - void singleInventoryReturn(String taskId, String value, String type, List checkConfList); - void check(String taskId, String cmd); + Integer singleInventoryReturn(StockDO stock, CheckLogDO checkLogDO, String taskId, String value, String type, List checkConfList); + StockDO check(String taskId, String cmd); void stopCheck(String taskId, Map result); void stockSave(AlgorithmDelayTask algorithmDelayTask); diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/plc/PLCServiceImpl.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/plc/PLCServiceImpl.java index a584c86..dfc8ed6 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/plc/PLCServiceImpl.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/plc/PLCServiceImpl.java @@ -444,6 +444,16 @@ public class PLCServiceImpl implements PLCService { @Override public void checkStart(KsecDataInfo dataInfo) { +// 当lotnum不为空,并且Stock中不存在时,清空stock + if (Strings.hasText(dataInfo.getLotnum())) { + StockDO stock = stockService.getOne(new QueryWrapper() + .eq("batch_Number", dataInfo.getLotnum()) + .last("limit 1")); + if (stock == null) { +// 清空整个表 + stockService.truncate(); + } + } List checkConfList = checkConfService.list(new QueryWrapper() .ne("check_scan_type", 0) @@ -501,15 +511,18 @@ public class PLCServiceImpl implements PLCService { newStock.setRow(dataInfo.getFromRow()); newStock.setColumn(dataInfo.getFromColumn()); newStock.setTaskId(dataInfo.getTaskId()); - newStock.setWmsCode(dataInfo.getWmsCode()); - newStock.setWmsTrayCode(dataInfo.getWmsTrayCode()); + newStock.setWmsExtendInfo(dataInfo.getWmsExtendInfo()); + +// +// newStock.setWmsCode(dataInfo.getWmsCode()); +// newStock.setWmsTrayCode(dataInfo.getWmsTrayCode()); // newStock.setTrayCode(dataInfo.getTrayCode()); - newStock.setWmsCategory(dataInfo.getWmsCategory()); - newStock.setWmsCount(dataInfo.getWmsCount()); - newStock.setWmsItemCode(dataInfo.getWmsItemCode()); - newStock.setWmsShelfCode(dataInfo.getWmsShelfCode()); - newStock.setWmsPltCode(dataInfo.getWmsPltCode()); - newStock.setWmsCountNumber(dataInfo.getWmsCountNumber()); +// newStock.setWmsCategory(dataInfo.getWmsCategory()); +// newStock.setWmsCount(dataInfo.getWmsCount()); +// newStock.setWmsItemCode(dataInfo.getWmsItemCode()); +// newStock.setWmsShelfCode(dataInfo.getWmsShelfCode()); +// newStock.setWmsPltCode(dataInfo.getWmsPltCode()); +// newStock.setWmsCountNumber(dataInfo.getWmsCountNumber()); newStock.setId(stock.getId()); stock = newStock; @@ -529,7 +542,7 @@ public class PLCServiceImpl implements PLCService { CameraDO camera = getCameraByLeftRight(street, stock.getDirection()); // 调用预置点位 开始则调用E1 gyrateCameraByCode(camera, "E1"); - pathSrc = cameraCapture(camera, true, pathSrc, dictDataService.getDictDataList("camera_conf")); + pathSrc = cameraCapture(camera, false, pathSrc, dictDataService.getDictDataList("camera_conf")); urlResourcesService.save(URLResourcesDo.builder().url(saveApiPath + pathSrc).uuid(uuid).type("1").little("球机拍照").build()); // 先记录正常未盘点情况 @@ -552,9 +565,9 @@ public class PLCServiceImpl implements PLCService { return cmd.replace("inventory","").toLowerCase()+ "End"; } - public void check(String taskId, String cmd) { + public StockDO check(String taskId, String cmd) { List checkConfList = checkConfService.list(new QueryWrapper() - + .ne("check_scan_type", 0) .eq("is_Enable", 1)); //根据扫码配置 获取扫码结果 // 如果存在扫码情况,进行扫码 @@ -566,8 +579,13 @@ public class PLCServiceImpl implements PLCService { ); if (stock == null) { log.error("taskId:{}不存在", taskId); - return; + return null; } + CheckLogDO checkLogDO = checkLogService.getOne( + new QueryWrapper() + .eq("task_id", taskId) + .last("limit 1").orderByDesc("create_time") + ); StreetDO street = streetService.getById(stock.getStreetId()); // 旋转预置点位 @@ -586,45 +604,63 @@ public class PLCServiceImpl implements PLCService { // 异步执行扫码 AsyncTaskUtil.execute(() -> { try { - ScanData scanData = scanServiceFactory.scan(scanType, street, stock); - singleInventoryReturn(taskId, scanData.getCode(), checkConfDO.getCheckName(), checkConfList); + ScanData scanData = scanServiceFactory.scan(scanType, street, stock,checkConfDO); + singleInventoryReturn(stock,checkLogDO,taskId, scanData.getCode(), checkConfDO.getCheckName(), checkConfList); } catch (Exception e) { log.error("异步扫码异常, taskId: {}, scanType: {}", taskId, scanType, e); } }); }else if (checkConfDO.getCheckAsyn().equals("0")){ - ScanData scanData = scanServiceFactory.scan(scanType, street, stock); - singleInventoryReturn(taskId, scanData.getCode(), checkConfDO.getCheckName(), checkConfList); + ScanData scanData = scanServiceFactory.scan(scanType, street, stock,checkConfDO); + singleInventoryReturn(stock,checkLogDO,taskId, scanData.getCode(), checkConfDO.getCheckName(), checkConfList); }else if (checkConfDO.getCheckAsyn().equals("2")){ stock.setScanType(checkConfDO.getCheckName()); - scanServiceFactory.scan(scanType, street, stock); + scanServiceFactory.scan(scanType, street, stock,checkConfDO); } } - - + return stock; } + return null; } - public void singleInventoryReturn(String taskId, String value,String type,List< CheckConfDO> checkConfList){ + public Integer singleInventoryReturn(StockDO stock,CheckLogDO checkLogDO,String taskId, String value,String type,List< CheckConfDO> checkConfList){ - checkLogService.updateLastByTaskId(taskId,value,camelToSnake(type)); - stockService.updateLastByTaskId(taskId,value,camelToSnake(type)); - StockDO stock = stockService.getOne( - new QueryWrapper() - .eq("task_id", taskId) - .orderByDesc("create_time") - .last("limit 1") - ); - CheckLogDO checkLogDO = checkLogService.getOne(new QueryWrapper() - .eq("task_id", taskId).orderByDesc("create_time").last("limit 1")); + checkConfList = checkConfList.stream().filter(checkConfDO -> checkConfDO.getIsDisplay()).collect(Collectors.toList()); + // 按 taskId 加分布式锁,避免异步并发修改同一任务的数据(防止 JSON_SET 读改写丢失更新) + // 自旋等待锁,保证所有 key 都能写入 + String lockKey = "lock:singleInventoryReturn:" + taskId; + boolean locked = false; + try { + // 最多等待 10 秒(每次间隔 50ms),避免拿不到锁直接丢数据 + long deadline = System.currentTimeMillis() + 10_000; + while (!(locked = redisUtil.setIfAbsent(lockKey, "1", 30))) { + if (System.currentTimeMillis() > deadline) { + log.error("获取分布式锁超时,taskId: {}, type: {}", taskId, type); + break; + } + Thread.sleep(50); + } - List codes = checkConfList.stream() - .map(checkConfDO -> camelToSnake(checkConfDO.getCheckName())) - .collect(Collectors.toList()); - if(stock!=null){ - stockService.updateStatusByFields(stock.getId(),codes); - } + checkLogService.updateLastByTaskId(checkLogDO.getId(),value,(type)); - checkLogMapper.updateStatusByFields(checkLogDO.getId(),codes); + List codes = checkConfList.stream() + .map(CheckConfDO::getCheckName) + .collect(Collectors.toList()); +// .map(checkConfDO -> camelToSnake(checkConfDO.getCheckName())) + if(stock!=null){ + stockService.updateLastByTaskId(stock.getId(),value,(type)); + stockService.updateStatusByFields(stock.getId(),codes); + } + + checkLogMapper. + updateStatusByFields(checkLogDO.getId(),codes); + } catch (InterruptedException e) { + log.error("singleInventoryReturn error", e); + } finally { + if (locked) { + redisUtil.del(lockKey); + } + } + return checkLogDO.getId(); } public void stopCheck(String taskId,Map result) { log.info("taskId:{}识别完成", taskId); @@ -671,26 +707,18 @@ public class PLCServiceImpl implements PLCService { checkLog(checkLogDO); redisUtil.del("stock:task:" + taskId); } - public ScanData scanTest(KsecDataInfo dataInfo,String type) { - StreetDO street = streetService.getStreetByPlcId(dataInfo.getSRMNumber()); -// 判断巷道有几个相机 如果只有一个,则调用一个,如果是两个,先判断是否有对拍设置决定那个相机拍摄 - CameraDO camera = getCameraByLeftRight(street, dataInfo.getFromDirection()); - gyrateCameraByCode(camera, dataInfo.getCmdName()); - - String pathSrc = PathUtil.createFileName(dataInfo, street, dataInfo.getCmdName(), ".jpg"); - pathSrc = cameraCapture(camera, false, pathSrc, dictDataService.getDictDataList("camera_conf")); - StockDO stockDO = new StockDO(); - stockDO.setCheckPic(pathSrc); - return scanServiceFactory.scan(type,street,stockDO); - } public void checkStop(String taskId) { Map resultReport = new HashMap<>(); + List checkConfList = checkConfService.list(new QueryWrapper() + .ne("check_scan_type", 0) + .eq("is_Display", 1) + .eq("is_Enable", 1)); - Map csscStartList = dictDataService.getDictDataList("scan_enable"); +// Map csscStartList = dictDataService.getDictDataList("scan_enable"); StockDO stock = stockService.getOne( new QueryWrapper() .eq("task_id", taskId) @@ -706,37 +734,33 @@ public class PLCServiceImpl implements PLCService { return; } stock.setStatus("2"); - for (String key : csscStartList.keySet()) { - String[] split = csscStartList.get(key).getValue().split(","); - for (String s : split) { - String wmsType = "wms" + capitalize(s); - try { - Field stockField = StockDO.class.getDeclaredField(s); - Field wmsField = StockDO.class.getDeclaredField(wmsType); + for (CheckConfDO checkConfDO : checkConfList) { + String s = checkConfDO.getCheckName(); + String wmsType = "wms" + capitalize(s); + try { + Field stockField = StockDO.class.getDeclaredField(s); + Field wmsField = StockDO.class.getDeclaredField(wmsType); // 添加以下两行代码,设置字段可访问 - stockField.setAccessible(true); - wmsField.setAccessible(true); - resultReport.put(s, stockField.get(stock)); - result.put(s, wmsField.get(stock).toString().equals(stockField.get(stock).toString())); - - if (!wmsField.get(stock).toString().equals(stockField.get(stock).toString())) { - stock.setStatus("1"); - } - } catch (Exception e) { + stockField.setAccessible(true); + wmsField.setAccessible(true); + resultReport.put(s, stockField.get(stock)); + result.put(s, wmsField.get(stock).toString().equals(stockField.get(stock).toString())); - stock.setStatus("1"); - log.error("scan error", e); - } + if (!wmsField.get(stock).toString().equals(stockField.get(stock).toString())) { + stock.setStatus("1"); } + } catch (Exception e) { + + stock.setStatus("1"); + log.error("scan error", e); + } } + stockService.updateById(stock); checkLog(stock); - setUpdateResult(resultReport); - + setUpdateResult(resultReport); redisUtil.del("stock:task:" + taskId); - - } public static String capitalize(String str) { diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/radar/RadarDO.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/radar/RadarDO.java new file mode 100644 index 0000000..2546be2 --- /dev/null +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/radar/RadarDO.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.camera.service.radar; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; +import org.glassfish.jaxb.core.v2.TODO; + +/** + * RFID DO + * + * @author 芋道源码 + */ +@TableName("logistics_radar") +@KeySequence("logistics_radar_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RadarDO extends BaseDO { + + /** + * id + */ + @TableId + private Integer id; + /** + * 巷道id + */ + private Integer streetId; + /** + * 方向 + * + * 枚举 {@link TODO direction 对应的类} + */ + private Integer direction; + /** + * ip + */ + private String ip; + /** + * 端口 + */ + private Integer port; + +} \ No newline at end of file diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/radar/RadarService.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/radar/RadarService.java new file mode 100644 index 0000000..eb998df --- /dev/null +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/radar/RadarService.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.camera.service.radar; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.camera.controller.admin.radar.vo.RadarPageReqVO; +import cn.iocoder.yudao.module.camera.controller.admin.radar.vo.RadarSaveReqVO; +import com.baomidou.mybatisplus.extension.service.IService; +import jakarta.validation.Valid; + +/** + * RFID Service 接口 + * + * @author 芋道源码 + */ +public interface RadarService extends IService< RadarDO> { + + + /** + * 创建RFID + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Integer createRadar(@Valid RadarSaveReqVO createReqVO); + + /** + * 更新RFID + * + * @param updateReqVO 更新信息 + */ + void updateRadar(@Valid RadarSaveReqVO updateReqVO); + + /** + * 删除RFID + * + * @param id 编号 + */ + void deleteRadar(Integer id); + + /** + * 获得RFID + * + * @param id 编号 + * @return RFID + */ + RadarDO getRadar(Integer id); + + /** + * 获得RFID分页 + * + * @param pageReqVO 分页查询 + * @return RFID分页 + */ + PageResult getRadarPage(RadarPageReqVO pageReqVO); + + +} \ No newline at end of file diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/radar/RadarServiceImpl.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/radar/RadarServiceImpl.java new file mode 100644 index 0000000..df29305 --- /dev/null +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/radar/RadarServiceImpl.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.module.camera.service.radar; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.camera.controller.admin.radar.vo.RadarPageReqVO; +import cn.iocoder.yudao.module.camera.controller.admin.radar.vo.RadarSaveReqVO; +import cn.iocoder.yudao.module.camera.dal.mysql.rfid.RadarMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.RFID_NOT_EXISTS; + +/** + * RFID Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class RadarServiceImpl extends ServiceImpl implements RadarService { + + @Resource + private RadarMapper radarMapper; + @Override + public Integer createRadar(RadarSaveReqVO createReqVO) { + // 插入 + RadarDO rfid = BeanUtils.toBean(createReqVO, RadarDO.class); + radarMapper.insert(rfid); + // 返回 + return rfid.getId(); + } + + @Override + public void updateRadar(RadarSaveReqVO updateReqVO) { + // 校验存在 + validateRadarExists(updateReqVO.getId()); + // 更新 + RadarDO updateObj = BeanUtils.toBean(updateReqVO, RadarDO.class); + radarMapper.updateById(updateObj); + } + + @Override + public void deleteRadar(Integer id) { + // 校验存在 + validateRadarExists(id); + // 删除 + radarMapper.deleteById(id); + } + + private void validateRadarExists(Integer id) { + if (radarMapper.selectById(id) == null) { + throw exception(RFID_NOT_EXISTS); + } + } + + @Override + public RadarDO getRadar(Integer id) { + return radarMapper.selectById(id); + } + + @Override + public PageResult getRadarPage(RadarPageReqVO pageReqVO) { + return radarMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/rfid/MessageTran.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/rfid/MessageTran.java new file mode 100644 index 0000000..54a255f --- /dev/null +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/rfid/MessageTran.java @@ -0,0 +1,172 @@ +package cn.iocoder.yudao.module.camera.service.rfid; + +/** + * Object of describing data package; + * @author Administrator + * + */ +public class MessageTran { + private byte btPacketType; //head of data, defauld value is 0xA0 + private byte btDataLen; //Length of data package, which means the byte quantity after the "length", not including the "length" + private byte btReadId; //Address of reader + private byte btCmd; //The commend code of data package + private byte[] btAryData; //The commend specification of data package, some commends without specification + private byte btCheck; //Checksum + private byte[] btAryTranData; //Complete data package + + public final static byte HEAD = (byte) 0xA0; + /** + * MessageTran default constructor + */ + public MessageTran() { + } + + /** + * MessageTran Constructor + * @param btReadId address of reader + * @param btCmd command code of data package + * @param btAryData command parameters of data package, some commands without parameters + */ + public MessageTran(byte btReadId, byte btCmd, byte[] btAryData) { + int nLen = btAryData.length; + + this.btPacketType = HEAD; + + this.btDataLen = (byte)(nLen + 3); + this.btReadId = btReadId; + this.btCmd = btCmd; + + this.btAryData = new byte[nLen]; + System.arraycopy(btAryData, 0, this.btAryData, 0, btAryData.length); + //btAryData.CopyTo(this.btAryData, 0); + + this.btAryTranData = new byte[nLen + 5]; + this.btAryTranData[0] = this.btPacketType; + this.btAryTranData[1] = this.btDataLen; + this.btAryTranData[2] = this.btReadId; + this.btAryTranData[3] = this.btCmd; + System.arraycopy(this.btAryData, 0, this.btAryTranData, 4, this.btAryData.length); + //this.btAryData.CopyTo(this.btAryTranData, 4); + + this.btCheck = checkSum(this.btAryTranData, 0, nLen + 4); + int b = this.btCheck & 0xff; + System.out.println("check:"+b); + this.btAryTranData[nLen + 4] = this.btCheck; + } + + /** + * MessageTran Constructor + * @param btReadId address of reader + * @param btCmd read command + */ + public MessageTran(byte btReadId, byte btCmd) { + this.btPacketType = HEAD; + this.btDataLen = 0x03; + this.btReadId = btReadId; + this.btCmd = btCmd; + + this.btAryTranData = new byte[5]; + this.btAryTranData[0] = this.btPacketType; + this.btAryTranData[1] = this.btDataLen; + this.btAryTranData[2] = this.btReadId; + this.btAryTranData[3] = this.btCmd; + + this.btCheck = checkSum(this.btAryTranData, 0, 4); + this.btAryTranData[4] = this.btCheck; + } + + /** + * MessageTran constructor + * @param btAryTranData complete data package + */ + public MessageTran(byte[] btAryTranData) { + int nLen = btAryTranData.length; + + this.btAryTranData = new byte[nLen]; + System.arraycopy(btAryTranData, 0, this.btAryTranData, 0, btAryTranData.length); + //btAryTranData.CopyTo(this.btAryTranData, 0); + + + byte btCK = checkSum(this.btAryTranData, 0, this.btAryTranData.length - 1); + if (btCK != btAryTranData[nLen - 1]) { + return; + } + + this.btPacketType = btAryTranData[0]; + this.btDataLen = btAryTranData[1]; + this.btReadId = btAryTranData[2]; + this.btCmd = btAryTranData[3]; + this.btCheck = btAryTranData[nLen - 1]; + + if (nLen > 5) { + this.btAryData = new byte[nLen - 5]; + for (int nloop = 0; nloop < nLen - 5; nloop++ ) { + this.btAryData[nloop] = btAryTranData[4 + nloop]; + } + } + } + + /** + * Obtain complete data package + * @return Data package + */ + public byte[] getAryTranData() { + return this.btAryTranData; + } + + /** + * Obtain command parameters of data package, some command without parameters + * @return commends parameters + */ + public byte[] getAryData() { + return this.btAryData; + } + + /** + * Obtain address of reader + * @return Address of reader + */ + public byte getReadId() { + return this.btReadId; + } + + /** + * Obtain command of data package + * @return command + */ + public byte getCmd() { + return this.btCmd; + } + + /** + * Obain head of data, default 0xA0 + * @return head of data + */ + public byte getPacketType() { + return this.btPacketType; + } + + /** + * Check head of data + * @return Result of checking + */ + public boolean checkPacketType() { + return this.btPacketType == HEAD; + } + + /** + * Calculate checksum + * @param btAryBuffer data + * @param nStartPos start position + * @param nLen Checking length + * @return Checksum + */ + public byte checkSum(byte[] btAryBuffer, int nStartPos, int nLen) { + byte btSum = 0x00; + + for (int nloop = nStartPos; nloop < nStartPos + nLen; nloop++ ) { + btSum += btAryBuffer[nloop]; + } + return (byte)(((~btSum) + 1) & 0xFF); + } +} diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/rfid/RFIDSocket.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/rfid/RFIDSocket.java index 74ad067..aed5806 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/rfid/RFIDSocket.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/rfid/RFIDSocket.java @@ -1,11 +1,372 @@ package cn.iocoder.yudao.module.camera.service.rfid; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; +import java.io.*; +import java.lang.reflect.Array; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * sick扫码枪 + */ /** * sick扫码枪 */ @Slf4j public class RFIDSocket { + private Socket socket; + + private OutputStream os; + + private InputStream is; + + private Queue buffer; + + private boolean running; + + private int step; + + private int length; + + private String ip; + + private int port; + + private int index; + + private static File file; + + private static FileWriter fw; + + /** + * 读到的所有code标签(线程安全) + */ + private Set tags = ConcurrentHashMap.newKeySet(); + + private Map countMap = new ConcurrentHashMap<>(); + + private List byteList = new ArrayList<>(30); + + public Set getTags(){ + return tags; + } + + /** + * 单线程同步扫描:持续读取并解析标签,持续 time 秒; + * 若命中 wmsCode 则立即返回 true,否则扫描结束后返回 false。 + * 该方法会占用当前线程,适合不需要后台独立读取线程的场景。 + * + * @param wmsCode 目标标签 + * @param time 扫描时长,单位秒 + * @return 是否命中目标标签 + */ + public boolean scanAndWait(String wmsCode, int time) { + running = true; + buffer = new LinkedList<>(); + long deadline = System.currentTimeMillis() + time * 1000L; + byte[] readBuffer = new byte[512]; + try { + while (System.currentTimeMillis() < deadline) { + // 非阻塞判断当前是否有数据可读,避免一直阻塞在 read 上 + int available; + try { + available = is.available(); + } catch (IOException e) { + log.info("rfid read disconnect"); + break; + } + if (available > 0) { + int n = Math.min(available, readBuffer.length); + try { + n = is.read(readBuffer, 0, n); + } catch (IOException e) { + log.info("rfid read disconnect"); + break; + } + if (n == -1) { + break; + } + for (int k = 0; k < n; k++) { + buffer.offer(readBuffer[k]); + } + while (buffer.size() > 0) { + String code = readTag(); + if (code != null) { + tags.add(code); + countMap.merge(code, 1, Integer::sum); + if (wmsCode != null && wmsCode.equals(code)) { + return true; + } + } + } + } else { + // 无数据时短暂让出 CPU,等待读卡器回包 + try { + Thread.sleep(10); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + break; + } + } + } + } finally { + // 单线程扫描结束后自行关闭,避免连接泄漏 + close(); + } + return false; + } + + /** + * 获取rfid扫描最多的tag,不保证准确性 + * @return + */ + public String getTag(){ + if(isNotEmpty(countMap)){ + int count = 0; + String t = ""; + for (String tag : countMap.keySet()){ + if(countMap.get(tag)>count){ + count = countMap.get(tag); + t = tag; + } + } + return t; + }else return ""; + } + + + + public RFIDSocket(String ip,int port) { + this.ip = ip; + this.port = port; + socket = new Socket(); + os = null; + is = null; + try { + socket.connect(new InetSocketAddress(ip,port),3000); + os = socket.getOutputStream(); + is = socket.getInputStream(); + } catch (IOException e) { + throw new RuntimeException(e); + } + + } + + public void readData(){ + running = true; + buffer = new LinkedList<>(); + + Thread thread = new Thread(new Runnable() { + + @Override + public void run() { + byte[] readBuffer = new byte[512]; + while (running){ + int n; + try { + // 批量读取,读不到会阻塞,返回 -1 表示连接已断开 + n = is.read(readBuffer); + } catch (IOException e) { + // close() 关闭 socket 或流时会走到这里,说明连接已关闭,退出线程 + log.info("rfid read disconnect"); + break; + } + if(n == -1){ + break; + } + for(int k = 0; k < n; k++){ + buffer.offer(readBuffer[k]); + } + while (buffer.size() > 0){ + String code = readTag(); + if(code != null){ + // 命中新标签时通过 debug 打印,避免热路径 System.out 拖慢识别速度 + if(tags.add(code)){ + log.debug("rfid read tag:{}", code); + } + countMap.merge(code, 1, Integer::sum); + } + } + } + } + }); + thread.setDaemon(true); + thread.start(); + } + public static boolean isEmpty(Object o) { + if (o == null) { + return true; + } + if (o instanceof String) { + return ((String) o).isEmpty(); + } + if (o instanceof Collection) { + return ((Collection) o).isEmpty(); + } + if (o instanceof Map) { + return ((Map) o).isEmpty(); + } + if (o.getClass().isArray()) { + return Array.getLength(o) == 0; + } + return "".equals(o.toString()); + } + + public static boolean isNotEmpty(Object o) { + return !isEmpty(o); + } + + private String readTag(){ + String tag = null; + Byte b = buffer.poll(); + if(b == null){ + return tag; + } + if(step == 0){ + //判断是否表示头 + if(b == MessageTran.HEAD){ + step++; + byteList.add(b); + } + }else if(step == 1){ + //读长度 + length = b & 0xff; + step++; + byteList.add(b); + }else if(step == 2){ + byteList.add(b); + index++; + if(index == length-1){ + step++; + } + }else if(step == 3){ + byteList.add(b); + byte[]bytes = new byte[byteList.size()]; + for(int i = 0;i implements RfidService { + private static Map socketMap = new HashMap<>(); + + + public static void put(Integer streetId,RFIDSocket rfidSocket){ + socketMap.put(streetId,rfidSocket); + } + public static void remove(Integer streetId){ + socketMap.remove(streetId); + } + + public static RFIDSocket get(Integer streetId){ + return socketMap.get(streetId); + } @Resource private RfidMapper rfidMapper; diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/LxService/LxServiceApi.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/LxService/LxServiceApi.java index 0b92880..b7d8d07 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/LxService/LxServiceApi.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/LxService/LxServiceApi.java @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.camera.dal.dataobject.street.StreetDO; import cn.iocoder.yudao.module.camera.dal.entity.ScanData; import cn.iocoder.yudao.module.camera.service.resources.URLResourcesService; import cn.iocoder.yudao.module.camera.service.specificationConf.SpecificationConfService; +import cn.iocoder.yudao.module.logistics.dal.dataobject.checkconf.CheckConfDO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; @@ -53,7 +54,7 @@ public class LxServiceApi { } return boxCountResponse; } - public ScanData categoryScan(StreetDO streetDO, StockDO stockDO) { + public ScanData categoryScan(StreetDO streetDO, StockDO stockDO, CheckConfDO checkConfDO) { String url = "http://" + streetDO.getPlcIp() + ":" + streetDO.getPlcPort() + "/category/async"; BoxCountRequest request = new BoxCountRequest(); request.setCameraId(1); @@ -69,7 +70,7 @@ public class LxServiceApi { return scanData; } - public ScanData countScan(StreetDO streetDO, StockDO stockDO) { + public ScanData countScan(StreetDO streetDO, StockDO stockDO, CheckConfDO checkConfDO) { String url = "http://" + streetDO.getPlcIp() + ":" + streetDO.getPlcPort() + "/api/boxCount/async"; SpecificationConfDO specificationConfDO = specificationConfService.getOne(new LambdaQueryWrapper().eq(SpecificationConfDO::getType, stockDO.getWmsItemCode())); @@ -90,7 +91,7 @@ public class LxServiceApi { return scanData; } - public ScanData codeScan(StreetDO streetDO, StockDO stockDO) { + public ScanData codeScan(StreetDO streetDO, StockDO stockDO, CheckConfDO checkConfDO) { String url = "http://" + streetDO.getPlcIp() + ":" + streetDO.getPlcPort() + "/api/qrcode/async"; log.info("LxServiceApi codeScan:{}",url); diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/OpencvServiceImpl.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/OpencvServiceImpl.java index 32b801f..8d38529 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/OpencvServiceImpl.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/OpencvServiceImpl.java @@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.camera.dal.dataobject.stock.StockDO; import cn.iocoder.yudao.module.camera.dal.dataobject.street.StreetDO; import cn.iocoder.yudao.module.camera.dal.entity.ScanData; import cn.iocoder.yudao.module.camera.service.resources.URLResourcesService; +import cn.iocoder.yudao.module.logistics.dal.dataobject.checkconf.CheckConfDO; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpEntity; @@ -23,12 +24,12 @@ public class OpencvServiceImpl implements ScanService { URLResourcesService urlResourcesService; @Override - public ScanData scan(StreetDO streetDO, StockDO stockDO) { + public ScanData scan(StreetDO streetDO, StockDO stockDO, CheckConfDO checkConfDO ) { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); // ScanData scanData = new ScanData(); - scanData.setCode(stockDO.getCategory()); + scanData.setCode(stockDO.getWmsExtendInfo().get(checkConfDO.getCheckName())); scanData.setIp(streetDO.getPlcIp()); scanData.setPort(streetDO.getPlcPort()); scanData.setUuid(stockDO.getCheckPic()); diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/PCDServiceImpl.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/PCDServiceImpl.java index d53fc1d..330fa50 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/PCDServiceImpl.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/PCDServiceImpl.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.camera.service.scan; import cn.iocoder.yudao.module.camera.dal.dataobject.stock.StockDO; import cn.iocoder.yudao.module.camera.dal.dataobject.street.StreetDO; import cn.iocoder.yudao.module.camera.dal.entity.ScanData; +import cn.iocoder.yudao.module.logistics.dal.dataobject.checkconf.CheckConfDO; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpEntity; @@ -18,12 +19,12 @@ public class PCDServiceImpl implements ScanService{ @Resource RestTemplate restTemplate; @Override - public ScanData scan(StreetDO streetDO, StockDO stockDO) { + public ScanData scan(StreetDO streetDO, StockDO stockDO, CheckConfDO checkConfDO ) { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); // ScanData scanData = new ScanData(); - scanData.setCode(stockDO.getCategory()); + scanData.setCode(stockDO.getWmsExtendInfo().get(checkConfDO.getCheckName())); scanData.setIp(streetDO.getPlcIp()); scanData.setPort(streetDO.getPlcPort()); scanData.setUuid(stockDO.getCheckPic()); diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/QRCodeScanServiceImpl.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/QRCodeScanServiceImpl.java index 6dea456..388eabd 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/QRCodeScanServiceImpl.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/QRCodeScanServiceImpl.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.camera.service.scan; import cn.iocoder.yudao.module.camera.dal.dataobject.stock.StockDO; import cn.iocoder.yudao.module.camera.dal.dataobject.street.StreetDO; import cn.iocoder.yudao.module.camera.dal.entity.ScanData; +import cn.iocoder.yudao.module.logistics.dal.dataobject.checkconf.CheckConfDO; import com.google.zxing.*; import com.google.zxing.client.j2se.BufferedImageLuminanceSource; import com.google.zxing.common.HybridBinarizer; @@ -25,7 +26,7 @@ import static org.springframework.data.redis.connection.util.DecodeUtils.decodeM public class QRCodeScanServiceImpl implements ScanService { @Override - public ScanData scan(StreetDO streetDO, StockDO stockDO) { + public ScanData scan(StreetDO streetDO, StockDO stockDO, CheckConfDO checkConfDO ) { ScanData scanData = new ScanData(); try { // 构建图片URL路径 diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/RFIDScanServiceImpl.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/RFIDScanServiceImpl.java index 7ea08d6..e2c2436 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/RFIDScanServiceImpl.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/RFIDScanServiceImpl.java @@ -1,14 +1,129 @@ package cn.iocoder.yudao.module.camera.service.scan; +import cn.iocoder.yudao.module.camera.dal.dataobject.rfid.RfidDO; import cn.iocoder.yudao.module.camera.dal.dataobject.stock.StockDO; import cn.iocoder.yudao.module.camera.dal.dataobject.street.StreetDO; import cn.iocoder.yudao.module.camera.dal.entity.ScanData; +import cn.iocoder.yudao.module.camera.service.rfid.RFIDSocket; +import cn.iocoder.yudao.module.camera.service.rfid.RfidService; +import cn.iocoder.yudao.module.camera.service.rfid.RfidServiceImpl; +import cn.iocoder.yudao.module.logistics.dal.dataobject.checkconf.CheckConfDO; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import java.util.HashSet; +import java.util.Set; + @Service("rfidScanService") +@Slf4j public class RFIDScanServiceImpl implements ScanService{ + + @Resource + RfidService rfidService; + + + /** + * 根据信息开启rfid链接 + * @param plcCmdInfo 相关信息 + */ + public void RFIDCheck(StreetDO street,StockDO plcCmdInfo) { + if (street != null) { + //rfid不分左右,rfid使用同一ip和端口,依靠传递字符调整方向 + RfidDO rfid = rfidService.getOne(new QueryWrapper() + .eq("street_Id",street.getId()) + .eq("direction",plcCmdInfo.getDirection()).last("limit 1")); + if (rfid != null) { + + RFIDStart(rfid.getIp(), rfid.getPort(), street.getId(), plcCmdInfo.getDirection()); + + }else { + log.error("没有rfid"); + } + } + } + + public void RFIDStart(String ip, Integer port, Integer streetId, Integer direction) { + RFIDSocket rfidSocket = new RFIDSocket(ip, port); + log.info("rfid调用,ip:"+ip+";port:"+port); + rfidSocket.startCheck(direction); + rfidSocket.readData(); + RfidServiceImpl.put(streetId, rfidSocket); + } + + public Set RFIDStop(StreetDO street) { + RFIDSocket rfidSocket = RfidServiceImpl.get(street.getId()); + Set tags = new HashSet<>(); + if (rfidSocket != null) { + tags = rfidSocket.getTags(); + log.info("tags:{}", tags); + rfidSocket.close(); + RfidServiceImpl.remove(street.getId()); + } + return tags; + } + + public static void main(String[] args) { + + RFIDSocket rfidSocket = new RFIDSocket("192.168.0.178", 4001); + rfidSocket.startCheck(1); + if (rfidSocket.scanAndWait("E045EE00020051F24",3)){ + System.out.println("命中"); + }else { + System.out.println("未命中"); + } + + } + @Override - public ScanData scan(StreetDO streetDO, StockDO stockDO) { - return null; + public ScanData scan(StreetDO streetDO, StockDO stockDO, CheckConfDO checkConfDO ) { + + String wmsCode = stockDO.getWmsExtendInfo().get(checkConfDO.getCheckName()); + // 单线程同步扫描,命中 wmsCode 则返回 true + Boolean isSuccess = RFIDCheck(streetDO, stockDO, wmsCode, 3); + + ScanData scanData = new ScanData(); + if (Boolean.TRUE.equals(isSuccess)) { + scanData.setCode(wmsCode); + } else { + scanData.setCode("no read"); + } + + scanData.setDirection(stockDO.getDirection()); + return scanData; + } + + /** + * 进行rfid扫码,扫描time时间,如果有wmsCode则停止扫描返回true,没有,则扫描完成后返回false + * @param streetDO + * @param stockDO + * @param wmsCode + * @param time 单位s + * @return + */ + + private Boolean RFIDCheck(StreetDO streetDO, StockDO stockDO, String wmsCode, int time) { + if (streetDO == null) { + log.error("streetDO 为空"); + return false; + } + // 查询对应方向上的 rfid 配置 + RfidDO rfid = rfidService.getOne(new QueryWrapper() + .eq("street_Id", streetDO.getId()) + .eq("direction", stockDO.getDirection()).last("limit 1")); + if (rfid == null) { + log.error("没有rfid,streetId:{}", streetDO.getId()); + return false; + } + // 单线程同步扫描:连接、扫描、命中判断、关闭全部在当前线程内完成 + RFIDSocket rfidSocket = new RFIDSocket(rfid.getIp(), rfid.getPort()); + log.info("rfid调用,ip:{};port:{}", rfid.getIp(), rfid.getPort()); + try { + rfidSocket.startCheck(stockDO.getDirection()); + return rfidSocket.scanAndWait(wmsCode, time); + } finally { + rfidSocket.close(); + } } } diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/RadarRequest.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/RadarRequest.java new file mode 100644 index 0000000..c5b51dd --- /dev/null +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/RadarRequest.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.camera.service.scan; + +import lombok.Data; + +/** + * PAVO2 雷达 HTTP 请求体 + * + *

对应 PAVO2 HTTP 运行模式 POST 到根路径 {@code /} 的 JSON body(与 TCP 协议一致,不带结尾 '>')。

+ */ +@Data +public class RadarRequest { + + /** + * 功能:count(盘点计数)/ check(检测)/ config(重载配置)/ ConfigureSpeed(标定速度剖面) + */ + private String function; + + /** + * 扫描动作:start / stop + */ + private String scan; + + /** + * 扫描时长(秒),到时自动停止;start 不带 scanTime 时需手动 stop 拿结果 + */ + private Integer scanTime; + + /** + * 扫描范围(箱体尺寸) + */ + private Box box; + + /** + * 任务 id + */ + private String task_id; + + /** + * 箱体尺寸 + */ + @Data + public static class Box { + /** + * 长度(mm) + */ + private Integer l; + /** + * 宽度(mm) + */ + private Integer w; + /** + * 整堆高度(mm) + */ + private Integer h; + /** + * 单层个数 + */ + private Integer maxPerLayer; + } +} diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/RadarResponse.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/RadarResponse.java new file mode 100644 index 0000000..dbf1728 --- /dev/null +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/RadarResponse.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.camera.service.scan; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * PAVO2 雷达 HTTP 响应体 + * + *

响应 body 与 TCP 协议一致(不带结尾 '>')。

+ */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RadarResponse { + + /** + * 是否成功 + */ + private boolean success; + + /** + * 状态描述,如 scan not running + */ + private String status; + + /** + * 消息/错误信息 + */ + private String message; + + /** + * 结果描述,如 scan not running + */ + private String result; + + private String pic; + + /** + * 计数结果(count 功能返回) + */ + private Integer count; + + /** + * 任务 id + */ + private String task_id; +} diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/RadarScanServiceImpl.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/RadarScanServiceImpl.java new file mode 100644 index 0000000..fbc0a51 --- /dev/null +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/RadarScanServiceImpl.java @@ -0,0 +1,276 @@ +package cn.iocoder.yudao.module.camera.service.scan; + +import cn.iocoder.yudao.module.camera.dal.dataobject.resources.URLResourcesDo; +import cn.iocoder.yudao.module.camera.dal.dataobject.specificationConf.SpecificationConfDO; +import cn.iocoder.yudao.module.camera.dal.dataobject.stock.StockDO; +import cn.iocoder.yudao.module.camera.dal.dataobject.street.StreetDO; +import cn.iocoder.yudao.module.camera.dal.entity.ScanData; +import cn.iocoder.yudao.module.camera.service.radar.RadarDO; +import cn.iocoder.yudao.module.camera.service.radar.RadarService; +import cn.iocoder.yudao.module.camera.service.resources.URLResourcesService; +import cn.iocoder.yudao.module.camera.service.specificationConf.SpecificationConfService; +import cn.iocoder.yudao.module.logistics.dal.dataobject.checkconf.CheckConfDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +/** + * PAVO2 雷达 HTTP 接口实现 + * + *

PAVO2 雷达以 HTTP 运行模式对外提供接口,POST 到根路径 {@code /}, + * 请求体为与 TCP 协议完全相同的 JSON(不带结尾 '>'),响应 body 与 TCP 相同。

+ * + *

数据来源:

+ *
    + *
  • ip/端口:通过 {@link RadarService} 按巷道 id + 方向(stockDO.direction)查询 {@link RadarDO}
  • + *
  • box 尺寸:通过 {@link SpecificationConfService} 按品规(stockDO.wmsItemCode)查询 {@link SpecificationConfDO}
  • + *
+ */ +@Slf4j +@Service("RadarScanService") +public class RadarScanServiceImpl implements ScanService { + + @Resource + private RadarService radarService; + + @Resource + private SpecificationConfService specificationConfService; + + @Resource + private RestTemplate restTemplate; + + @Resource + URLResourcesService urlResourcesService; + + @Override + public ScanData scan(StreetDO streetDO, StockDO stockDO, CheckConfDO checkConfDO ) { + RadarDO radar = getRadar(streetDO, stockDO); + if (radar == null) { + log.error("[radar] 未找到雷达配置, streetId={}, direction={}", streetDO.getId(), stockDO.getDirection()); + return new ScanData(); + } + String baseUrl = "http://" + radar.getIp() + ":" + radar.getPort(); + // 默认盘点计数;若 stockDO 指定 scanType 为 check,则走检测 + String function = "check".equalsIgnoreCase(stockDO.getScanType()) ? "check" : "count"; + String taskId = stockDO.getTaskId() != null ? stockDO.getTaskId() : String.valueOf(stockDO.getId()); + + // 构建带 box 尺寸的 start 请求 + RadarRequest start = buildBoxRequest(function, "start", taskId, stockDO,checkConfDO); + RadarResponse startResp = postJson(baseUrl + "/", start); + + // stop 拿结果 + RadarRequest stop = new RadarRequest(); + stop.setFunction(function); + stop.setScan("stop"); + stop.setTask_id(taskId); + RadarResponse stopResp = postJson(baseUrl + "/", stop); + + return toScanData(stockDO, stopResp != null ? stopResp : startResp); + } + public ScanData scanCountStart(StreetDO streetDO, StockDO stockDO, CheckConfDO checkConfDO) { + RadarResponse stopResp = countStart( streetDO,stockDO,checkConfDO); + + + return toScanData(stockDO, stopResp ); + } + public ScanData scanCountStop(StreetDO streetDO, StockDO stockDO, CheckConfDO checkConfDO) { + RadarDO radar = getRadar(streetDO, stockDO); + if (radar == null) { + log.error("[radar] 未找到雷达配置, streetId={}, direction={}", streetDO.getId(), stockDO.getDirection()); + return new ScanData().setCode("Not found radar"); + } + String baseUrl = "http://" + radar.getIp() + ":" + radar.getPort(); + // 默认盘点计数;若 stockDO 指定 scanType 为 check,则走检测 + String taskId = stockDO.getTaskId() != null ? stockDO.getTaskId() : String.valueOf(stockDO.getId()); + + // 构建带 box 尺寸的 start 请求 + // stop 拿结果 + RadarRequest stop = new RadarRequest(); + stop.setFunction("count"); + stop.setScan("stop"); + stop.setTask_id(taskId); + RadarResponse stopResp = postJson(baseUrl + "/", stop); + + return toScanData(stockDO, stopResp ); + } + + + + + +// /** +// * 盘点计数:start(固定时长,到时自动停止) +// */ +// public RadarResponse countStart(StreetDO streetDO, StockDO stockDO, int scanTime) { +// RadarRequest request = buildBoxRequest("count", "start", taskId(stockDO), stockDO); +// request.setScanTime(scanTime); +// return postJson(streetDO, stockDO, request); +// } + + /** + * 盘点计数:start(手动,等 stop 拿结果) + */ + public RadarResponse countStart(StreetDO streetDO, StockDO stockDO, CheckConfDO checkConfDO) { + RadarRequest request = buildBoxRequest("count", "start", taskId(stockDO), stockDO,checkConfDO); + return postJson(streetDO, stockDO, request); + } + + /** + * 盘点计数:stop(拿结果) + */ + public RadarResponse countStop(StreetDO streetDO, StockDO stockDO) { + RadarRequest request = buildRequest("count", "stop", taskId(stockDO), stockDO); + return postJson(streetDO, stockDO, request); + } + + /** + * 检测:start(手动) + */ + public RadarResponse checkStart(StreetDO streetDO, StockDO stockDO) { + RadarRequest request = buildRequest("check", "start", taskId(stockDO), stockDO); + return postJson(streetDO, stockDO, request); + } + + /** + * 检测:stop(拿结果) + */ + public RadarResponse checkStop(StreetDO streetDO, StockDO stockDO) { + RadarRequest request = buildRequest("check", "stop", taskId(stockDO), stockDO); + return postJson(streetDO, stockDO, request); + } + + /** + * 重载 config/config + */ + public RadarResponse reloadConfig(StreetDO streetDO, StockDO stockDO) { + RadarRequest request = new RadarRequest(); + request.setFunction("config"); + return postJson(streetDO, stockDO, request); + } + + /** + * 标定速度剖面 + */ + public RadarResponse configureSpeed(StreetDO streetDO, StockDO stockDO, int scanTime) { + RadarRequest request = new RadarRequest(); + request.setFunction("ConfigureSpeed"); + request.setScanTime(scanTime); + return postJson(streetDO, stockDO, request); + } + + /** + * 构建带 box 尺寸的请求。box 数据来自品规配置(按 stockDO.wmsItemCode 匹配 type)。 + */ + private RadarRequest buildBoxRequest(String function, String scan, String taskId, StockDO stockDO, CheckConfDO checkConfDO ) { + RadarRequest request = new RadarRequest(); + request.setFunction(function); + request.setScan(scan); + request.setTask_id(taskId); + + SpecificationConfDO conf = specificationConfService.getOne( + new QueryWrapper() + .eq("type", stockDO.getWmsExtendInfo().get("category")).last("limit 1")); + if (conf != null) { + RadarRequest.Box box = new RadarRequest.Box(); + box.setL(conf.getLength()); + box.setW(conf.getWidth()); + box.setH(conf.getHeight()); + box.setMaxPerLayer(conf.getLayersNumber()); + request.setBox(box); + } + return request; + } + /** + * 构建带 box 尺寸的请求。box 数据来自品规配置(按 stockDO.wmsItemCode 匹配 type)。 + */ + private RadarRequest buildRequest(String function, String scan, String taskId , StockDO stockDO) { + RadarRequest request = new RadarRequest(); + request.setFunction(function); + request.setScan(scan); + request.setTask_id(taskId); + + + return request; + } + + /** + * 根据巷道 id + 方向查询雷达配置(ip/端口)。 + */ + private RadarDO getRadar(StreetDO streetDO, StockDO stockDO) { + return radarService.getOne(new LambdaQueryWrapper() + .eq(RadarDO::getStreetId, streetDO.getId()) + .eq(RadarDO::getDirection, stockDO.getDirection())); + } + + private String baseUrl(StreetDO streetDO, StockDO stockDO) { + RadarDO radar = getRadar(streetDO, stockDO); + if (radar == null) { + return null; + } + return "http://" + radar.getIp() + ":" + radar.getPort(); + } + + private String taskId(StockDO stockDO) { + return stockDO.getTaskId() != null ? stockDO.getTaskId() : String.valueOf(stockDO.getId()); + } + + private RadarResponse postJson(StreetDO streetDO, StockDO stockDO, RadarRequest body) { + String url = baseUrl(streetDO, stockDO); + if (url == null) { + log.error("[radar] 未找到雷达配置, streetId={}, direction={}", streetDO.getId(), stockDO.getDirection()); + return null; + } + return postJson(url + "/", body); + } + + /** + * 向雷达发送 POST JSON 请求。 + */ + private RadarResponse postJson(String url, RadarRequest body) { + try { + // 将 body 序列化为 JSON 字节,显式设置 Content-Length,避免服务端返回 411 Length Required + ObjectMapper objectMapper = new ObjectMapper(); + byte[] bodyBytes = objectMapper.writeValueAsBytes(body); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.setContentLength(bodyBytes.length); + HttpEntity request = new HttpEntity<>(bodyBytes, headers); + RadarResponse resp = restTemplate.postForObject(url, request, RadarResponse.class); + log.info("[radar] url={} body={} resp={}", url, body, resp); + return resp; + } catch (Exception e) { + RadarResponse resp = new RadarResponse(); + resp.setMessage("scan error"); + log.error("[radar] request error, url={} body={}", url, body, e); + return resp; + } + } + + /** + * 将雷达返回结果转换为 ScanData,结果放到 code 供上层与 wms 数量比对。 + */ + private ScanData toScanData(StockDO stockDO, RadarResponse resp) { + ScanData scanData = new ScanData(); + if (resp != null) { + String code = resp.getCount() != null ? String.valueOf(resp.getCount()) + : resp.getMessage(); + scanData.setCode(code); + } + scanData.setId(stockDO.getId()); + scanData.setDirection(stockDO.getDirection()); + scanData.setUuid(stockDO.getCheckPic()); + if (resp != null && resp.getPic() != null) { + urlResourcesService.save(URLResourcesDo.builder().url(resp.getPic()).uuid(stockDO.getCheckPic()).type("1").little("个数3d生成图").build()); + } + + + return scanData; + } +} diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/ScanGunScanServiceImpl.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/ScanGunScanServiceImpl.java index 5844ce6..f4c28e0 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/ScanGunScanServiceImpl.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/ScanGunScanServiceImpl.java @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.camera.dal.entity.ScanData; import cn.iocoder.yudao.module.camera.service.sensorgun.CognexSocket; import cn.iocoder.yudao.module.camera.service.sensorgun.SensorGunService; import cn.iocoder.yudao.module.camera.service.sensorgun.SickSocket; +import cn.iocoder.yudao.module.logistics.dal.dataobject.checkconf.CheckConfDO; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; @@ -81,9 +82,11 @@ public class ScanGunScanServiceImpl implements ScanService{ return bd.readLine(); } @Override - public ScanData scan(StreetDO streetDO, StockDO stockDO) { + public ScanData scan(StreetDO streetDO, StockDO stockDO, CheckConfDO checkConfDO ) { ScanData scanData = new ScanData(); - SensorGunDO sensorGun = sensorService.getOne(new QueryWrapper().eq("street_id", streetDO.getId()).eq("direction", stockDO.getDirection())); + SensorGunDO sensorGun = sensorService.getOne(new QueryWrapper() + .eq("street_id", streetDO.getId()) + .eq("direction", stockDO.getDirection())); String trayCode = ""; if (sensorGun == null) { log.error("no sensor gun config in database ,street id:{},direction:{}", streetDO.getId(), stockDO.getDirection()); diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/ScanService.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/ScanService.java index 32ea7b4..f623be4 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/ScanService.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/ScanService.java @@ -3,7 +3,8 @@ package cn.iocoder.yudao.module.camera.service.scan; import cn.iocoder.yudao.module.camera.dal.dataobject.stock.StockDO; import cn.iocoder.yudao.module.camera.dal.dataobject.street.StreetDO; import cn.iocoder.yudao.module.camera.dal.entity.ScanData; +import cn.iocoder.yudao.module.logistics.dal.dataobject.checkconf.CheckConfDO; public interface ScanService { - ScanData scan(StreetDO streetDO, StockDO stockDO); + ScanData scan(StreetDO streetDO, StockDO stockDO, CheckConfDO checkConfDO ); } diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/ScanServiceFactory.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/ScanServiceFactory.java index a22493d..cb230e2 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/ScanServiceFactory.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/ScanServiceFactory.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.camera.dal.entity.ScanData; import cn.iocoder.yudao.module.camera.service.Hik3D.HikFlaskApiService; import cn.iocoder.yudao.module.camera.service.scan.LxService.LxServiceApi; import cn.iocoder.yudao.module.camera.service.scan.yoloCameraApi.YoloServiceImpl; +import cn.iocoder.yudao.module.logistics.dal.dataobject.checkconf.CheckConfDO; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -27,6 +28,8 @@ public class ScanServiceFactory { private HikFlaskApiService hikFlaskApiService; @Resource private QRCodeScanServiceImpl qrCodeScanService; + @Resource + private RadarScanServiceImpl radarScanService; @Resource LxServiceApi lxServiceApi; @@ -35,65 +38,71 @@ public class ScanServiceFactory { // 返回的ScanData的code会将作为扫描结果,如果和wms的一致,则记录为成功 // 图片保存将在scan方法中实现 - public ScanData scan(String type, StreetDO streetDO, StockDO stockDO) { + public ScanData scan(String type, StreetDO streetDO, StockDO stockDO, CheckConfDO checkConfDO ) { try { - switch (type) { case "0": return null; // 扫码枪扫码 case "1": log.info("扫码枪扫码"); - return scanGunScanService.scan(streetDO, stockDO); + return scanGunScanService.scan(streetDO, stockDO,checkConfDO); // RFID扫码 case "2": log.info("RFID扫码"); - return rfidScanService.scan(streetDO, stockDO); + return rfidScanService.scan(streetDO, stockDO,checkConfDO); // 视觉扫码 case "3": log.info("视觉扫码-分类"); - return yoloService.scanClassify(streetDO, stockDO); + return yoloService.scanClassify(streetDO,stockDO,checkConfDO); // 3D扫码 case "4": log.info("3D扫码"); - return pcdService.scan(streetDO, stockDO); + return pcdService.scan(streetDO, stockDO,checkConfDO); // opencv扫码 case "5": log.info("opencv扫码"); - return opencvService.scan(streetDO, stockDO); + return opencvService.scan(streetDO, stockDO,checkConfDO); // hik3d识别扫码 case "6": log.info("hik3d识别扫码"); - return hikFlaskApiService.scan(streetDO, stockDO); + return hikFlaskApiService.scan(streetDO, stockDO,checkConfDO); // hik3d识别扫码存在 case "7": log.info("hik3d识别扫码存在"); - return hikFlaskApiService.scanExist(streetDO, stockDO); + return hikFlaskApiService.scanExist(streetDO,stockDO,checkConfDO); // hik3d识别扫码存在 case "8": log.info("lx识别扫码存在"); - return yoloService.scanExist(streetDO, stockDO); + return yoloService.scanExist(streetDO,stockDO,checkConfDO); // hik3d识别扫码存在 case "9": log.info("yolo识别扫码-检测"); - return yoloService.scanDetect(streetDO, stockDO); + return yoloService.scanDetect(streetDO,stockDO,checkConfDO); case "10": log.info("lx接口品规"); - return lxServiceApi.categoryScan(streetDO, stockDO);// 二维码识别 + return lxServiceApi.categoryScan(streetDO,stockDO,checkConfDO);// 二维码识别 case "11": log.info("lx接口个数"); - return lxServiceApi.countScan(streetDO, stockDO); + return lxServiceApi.countScan(streetDO,stockDO,checkConfDO); case "12": log.info("lx货物码"); - return lxServiceApi.codeScan(streetDO, stockDO); + return lxServiceApi.codeScan(streetDO,stockDO,checkConfDO); + case "13": + log.info("雷达识别开始"); + return radarScanService.scanCountStart(streetDO,stockDO,checkConfDO); + + case "14": + log.info("雷达识别结束"); + return radarScanService.scanCountStop(streetDO,stockDO,checkConfDO); // 默认情况处理 default: return new ScanData(); } } catch (Exception e) { log.error("scan error", e); - return new ScanData(); + return new ScanData().setCode("scan error"); } } diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/yoloCameraApi/Pojo.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/yoloCameraApi/Pojo.java index 4b2bd39..28b06f7 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/yoloCameraApi/Pojo.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/yoloCameraApi/Pojo.java @@ -12,6 +12,8 @@ public class Pojo { private String determinePath; //结果 private Boolean result; + private String code; + private String pic; private String type; private List detects; private String path; diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/yoloCameraApi/YoloServiceImpl.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/yoloCameraApi/YoloServiceImpl.java index 44ed450..5438926 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/yoloCameraApi/YoloServiceImpl.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/scan/yoloCameraApi/YoloServiceImpl.java @@ -6,13 +6,20 @@ import cn.iocoder.yudao.module.camera.dal.dataobject.street.StreetDO; import cn.iocoder.yudao.module.camera.dal.entity.ScanData; import cn.iocoder.yudao.module.camera.service.resources.URLResourcesService; import cn.iocoder.yudao.module.camera.service.scan.ScanService; +import cn.iocoder.yudao.module.logistics.dal.dataobject.checkconf.CheckConfDO; import cn.iocoder.yudao.module.system.service.dict.DictDataService; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.google.gson.*; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; import okhttp3.*; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; import java.io.IOException; import java.time.LocalDate; @@ -25,63 +32,66 @@ import java.util.Objects; @Slf4j public class YoloServiceImpl implements ScanService { - private static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); @Resource private OkHttpClient client; - + + @Resource + private RestTemplate restTemplate; private final Gson gson; - + public YoloServiceImpl() { // 配置 Gson 支持 Java 8 时间类型 DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - + this.gson = new GsonBuilder() - .registerTypeAdapter(LocalDate.class, (JsonSerializer) (date, type, jsonSerializationContext) -> - new JsonPrimitive(date.format(dateFormatter))) - .registerTypeAdapter(LocalDate.class, (JsonDeserializer) (json, type, jsonDeserializationContext) -> - LocalDate.parse(json.getAsString(), dateFormatter)) - .registerTypeAdapter(LocalDateTime.class, (JsonSerializer) (dateTime, type, jsonSerializationContext) -> - new JsonPrimitive(dateTime.format(dateTimeFormatter))) - .registerTypeAdapter(LocalDateTime.class, (JsonDeserializer) (json, type, jsonDeserializationContext) -> - LocalDateTime.parse(json.getAsString(), dateTimeFormatter)) + .registerTypeAdapter(LocalDate.class, (JsonSerializer) (date, type, jsonSerializationContext) -> + new JsonPrimitive(date.format(dateFormatter))) + .registerTypeAdapter(LocalDate.class, (JsonDeserializer) (json, type, jsonDeserializationContext) -> + LocalDate.parse(json.getAsString(), dateFormatter)) + .registerTypeAdapter(LocalDateTime.class, (JsonSerializer) (dateTime, type, jsonSerializationContext) -> + new JsonPrimitive(dateTime.format(dateTimeFormatter))) + .registerTypeAdapter(LocalDateTime.class, (JsonDeserializer) (json, type, jsonDeserializationContext) -> + LocalDateTime.parse(json.getAsString(), dateTimeFormatter)) .create(); } @Resource private DictDataService dictDataService; + @Override - public ScanData scan(StreetDO streetDO, StockDO stockDO) { + public ScanData scan(StreetDO streetDO, StockDO stockDO, CheckConfDO checkConfDO) { return null; } /** * 识别是否存在 + * * @param streetDO * @param stockDO * @return */ - public ScanData scanExist(StreetDO streetDO, StockDO stockDO) { + public ScanData scanExist(StreetDO streetDO, StockDO stockDO, CheckConfDO checkConfDO) { ScanData scanData = new ScanData(); - String urlPath ="http://"+streetDO.getPlcIp() + ":" + dictDataService.parseDictData("Hik3DApi", "yoloApiPort").getValue(); - String picPath ="http://"+streetDO.getPlcIp() + ":" + dictDataService.parseDictData("Hik3DApi", "picPath").getValue(); + String urlPath = "http://" + streetDO.getPlcIp() + ":" + dictDataService.parseDictData("Hik3DApi", "yoloApiPort").getValue(); + String picPath = "http://" + streetDO.getPlcIp() + ":" + dictDataService.parseDictData("Hik3DApi", "picPath").getValue(); try { scanData.setCode("有货"); Pojo pojo = new Pojo(); pojo.setStreetId(streetDO.getPlcId()); pojo.setDirection(stockDO.getDirection()); - pojo = setHttp(pojo,urlPath+"/category/exist"); + pojo = setHttp(pojo, urlPath + "/category/exist"); - log.info("lx3d拍照结果:"+pojo.toString()); + log.info("lx3d拍照结果:" + pojo.toString()); - if (pojo.getResult()!= null && pojo.getResult()) { - }else { - scanData.setCode( "无货"); - log.info("taskId:"+stockDO.getTaskId()+" lx3d拍照结果:"+pojo.toString()); - } + if (pojo.getResult() != null && pojo.getResult()) { + } else { + scanData.setCode("无货"); + log.info("taskId:" + stockDO.getTaskId() + " lx3d拍照结果:" + pojo.toString()); + } // if (hikPythonEntity.getColors() != null && hikPythonEntity.getColors().size() > 0) { // for (String color:hikPythonEntity.getColors()){ // if (color.startsWith(".")) { @@ -93,7 +103,7 @@ public class YoloServiceImpl implements ScanService { // } return scanData; } catch (IOException e) { - log.error("识别异常",e); + log.error("识别异常", e); System.out.println("识别异常"); e.printStackTrace(); throw new RuntimeException(e); @@ -106,29 +116,30 @@ public class YoloServiceImpl implements ScanService { /** * 识别是否存在 + * * @param streetDO * @param stockDO * @return */ - public ScanData scanClassify(StreetDO streetDO, StockDO stockDO) { + public ScanData scanClassify(StreetDO streetDO, StockDO stockDO, CheckConfDO checkConfDO) { ScanData scanData = new ScanData(); - String urlPath ="http://"+streetDO.getPlcIp() + ":" + dictDataService.parseDictData("Hik3DApi", "yoloApiPort").getValue(); - String picPath ="http://"+streetDO.getPlcIp() + ":" + dictDataService.parseDictData("Hik3DApi", "picPath").getValue(); + String urlPath = "http://" + streetDO.getPlcIp() + ":" + dictDataService.parseDictData("Hik3DApi", "yoloApiPort").getValue(); + String picPath = "http://" + streetDO.getPlcIp() + ":" + dictDataService.parseDictData("Hik3DApi", "picPath").getValue(); try { // scanData.setCode("有货"); Pojo pojo = new Pojo(); pojo.setStreetId(streetDO.getPlcId()); pojo.setDirection(stockDO.getDirection()); - pojo = setHttp(pojo,urlPath+"/yolo/classify"); + pojo = setHttp(pojo, urlPath + "/yolo/classify"); - log.info("lx3d拍照结果:"+pojo.toString()); + log.info("lx3d拍照结果:" + pojo.toString()); scanData.setCode(pojo.getType()); - urlResourcesService.save(URLResourcesDo.builder().url(picPath+pojo.getPath()).uuid( stockDO.getCheckPic()).type("1").little("有无拍照").build()); + urlResourcesService.save(URLResourcesDo.builder().url(picPath + pojo.getPath()).uuid(stockDO.getCheckPic()).type("1").little("有无拍照").build()); return scanData; } catch (IOException e) { - log.error("识别异常",e); + log.error("识别异常", e); System.out.println("识别异常"); e.printStackTrace(); throw new RuntimeException(e); @@ -138,27 +149,71 @@ public class YoloServiceImpl implements ScanService { /** * 识别是否存在 + * * @param streetDO * @param stockDO * @return */ - public ScanData scanDetect(StreetDO streetDO, StockDO stockDO) { + public ScanData scanDetect(StreetDO streetDO, StockDO stockDO, CheckConfDO checkConfDO) { ScanData scanData = new ScanData(); - String urlPath ="http://"+streetDO.getPlcIp() + ":" + dictDataService.parseDictData("Hik3DApi", "yoloApiPort").getValue(); - String picPath ="http://"+streetDO.getPlcIp() + ":" + dictDataService.parseDictData("Hik3DApi", "picPath").getValue(); - try { + + String saveApiPath = dictDataService.parseDictData("base_conf", "data_api_path").getValue(); + + String savePath = dictDataService.parseDictData("camera_conf", "media_path").getValue(); + String urlPath = "http://127.0.0.1:8097"; + try { // scanData.setCode("有货"); - Pojo pojo = new Pojo(); - pojo.setStreetId(streetDO.getPlcId()); - pojo.setDirection(stockDO.getDirection()); - pojo = setHttp(pojo,urlPath+"/yolo/detect"); + Pojo pojo = new Pojo(); + + URLResourcesDo urlResourcesDo = urlResourcesService.getOne( + new QueryWrapper() + .eq("uuid",stockDO.getCheckPic()) + .eq("type",1) + .eq("little","球机拍照").last("limit 1")); + + pojo.setPic(urlResourcesDo.getUrl().replace(saveApiPath,savePath)); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(org.springframework.http.MediaType.APPLICATION_JSON); + HttpEntity entity = new HttpEntity<>(pojo, headers); + ResponseEntity response = restTemplate.exchange( + urlPath + "/yolo/detect", // 替换为你的 API 地址 + HttpMethod.POST, + entity, + Pojo.class + ); + + log.info("盘点结果:" + pojo.toString()); + if (response.getBody() != null) { + scanData.setCode(response.getBody().getCode()); +// 后端加.jpg 先写死就行 + urlResourcesService.save(URLResourcesDo.builder().url(pojo.getPic().replace(savePath ,saveApiPath)+".jpg").uuid(stockDO.getCheckPic()).type("1").little("识别拍照").build()); + } + return scanData; + } catch (Exception e) { + log.error("识别异常", e); + System.out.println("识别异常"); + e.printStackTrace(); + throw new RuntimeException(e); + } +// return null; + } - log.info("lx3d拍照结果:"+pojo.toString()); - scanData.setCode(pojo.getType()); - urlResourcesService.save(URLResourcesDo.builder().url(picPath+pojo.getPath()).uuid( stockDO.getCheckPic()).type("1").little("有无拍照").build()); - return scanData; + public ScanData scanPicDetect(StreetDO streetDO, StockDO stockDO, CheckConfDO checkConfDO) { + ScanData scanData = new ScanData(); + String urlPath = "http://" + streetDO.getPlcIp() + ":" + dictDataService.parseDictData("Hik3DApi", "yoloApiPort").getValue(); + String picPath = "http://" + streetDO.getPlcIp() + ":" + dictDataService.parseDictData("Hik3DApi", "picPath").getValue(); + try { +// scanData.setCode("有货"); + Pojo pojo = new Pojo(); + pojo = setHttp(pojo, urlPath + "/yolo/detect"); + + log.info("lx3d拍照结果:" + pojo.toString()); + scanData.setCode(pojo.getType()); + urlResourcesService.save(URLResourcesDo.builder().url(picPath + pojo.getPath()).uuid(stockDO.getCheckPic()).type("1").little("有无拍照").build()); + return scanData; } catch (IOException e) { - log.error("识别异常",e); + log.error("识别异常", e); System.out.println("识别异常"); e.printStackTrace(); throw new RuntimeException(e); @@ -166,28 +221,30 @@ public class YoloServiceImpl implements ScanService { // return null; } + /** * 识别是否存在 + * * @param streetDO * @param stockDO * @return */ public ScanData scanningLxApiYolo(StreetDO streetDO, StockDO stockDO) { ScanData scanData = new ScanData(); - String urlPath ="http://127.0.0.1:8097/judge/scan"; + String urlPath = "http://127.0.0.1:8097/judge/scan"; try { // scanData.setCode("有货"); Pojo pojo = new Pojo(); pojo.setStreetId(streetDO.getPlcId()); pojo.setDirection(stockDO.getDirection()); - pojo = setHttp(pojo,urlPath+"/yolo/detect"); + pojo = setHttp(pojo, urlPath + "/yolo/detect"); - log.info("lx3d拍照结果:"+pojo.toString()); + log.info("lx3d拍照结果:" + pojo.toString()); scanData.setCode(pojo.getType()); - urlResourcesService.save(URLResourcesDo.builder().url(pojo.getPath()).uuid( stockDO.getCheckPic()).type("1").little("有无拍照").build()); + urlResourcesService.save(URLResourcesDo.builder().url(pojo.getPath()).uuid(stockDO.getCheckPic()).type("1").little("有无拍照").build()); return scanData; } catch (IOException e) { - log.error("识别异常",e); + log.error("识别异常", e); System.out.println("识别异常"); e.printStackTrace(); throw new RuntimeException(e); @@ -196,18 +253,17 @@ public class YoloServiceImpl implements ScanService { } - - /** * 识别是否存在 + * * @param streetDO * @param stockDO * @return */ public ScanData scanCameraDetect(StreetDO streetDO, StockDO stockDO) { ScanData scanData = new ScanData(); - String urlPath ="http://"+streetDO.getPlcIp() + ":" + dictDataService.parseDictData("Hik3DApi", "yoloApiPort").getValue(); - String picPath ="http://"+streetDO.getPlcIp() + ":" + dictDataService.parseDictData("Hik3DApi", "picPath").getValue(); + String urlPath = "http://" + streetDO.getPlcIp() + ":" + dictDataService.parseDictData("Hik3DApi", "yoloApiPort").getValue(); + String picPath = "http://" + streetDO.getPlcIp() + ":" + dictDataService.parseDictData("Hik3DApi", "picPath").getValue(); String realPath = dictDataService.getDictDataList("camera_conf").get("media_path").getValue(); @@ -215,28 +271,30 @@ public class YoloServiceImpl implements ScanService { try { // scanData.setCode("有货"); List urls = urlResourcesService.list(new LambdaQueryWrapper().eq(URLResourcesDo::getUuid, stockDO.getCheckPic())); - for (URLResourcesDo url:urls) { + for (URLResourcesDo url : urls) { Pojo pojo = new Pojo(); pojo.setStreetId(streetDO.getPlcId()); - pojo.setPath(realPath+url.getUrl().replace(saveApiPath,"")); + pojo.setPath(realPath + url.getUrl().replace(saveApiPath, "")); pojo.setDirection(stockDO.getDirection()); pojo = setHttp(pojo, urlPath + "/yolo/detect"); log.info("lx3d拍照结果:" + pojo.toString()); - if (pojo.getType()!= null && !pojo.getType().equals("")){ + if (pojo.getType() != null && !pojo.getType().equals("")) { scanData.setCode(pojo.getType()); } } // urlResourcesService.save(URLResourcesDo.builder().url(picPath+pojo.getPath()).uuid( stockDO.getCheckPic()).type("1").little("有无拍照").build()); return scanData; } catch (IOException e) { - log.error("识别异常",e); + log.error("识别异常", e); System.out.println("识别异常"); e.printStackTrace(); throw new RuntimeException(e); } // return null; } + + private static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); /** * 调用 /api/picComputeAll 接口,批量处理所有设备图片 */ @@ -244,6 +302,7 @@ public class YoloServiceImpl implements ScanService { String json = gson.toJson(pojo); + RequestBody body = RequestBody.create(json, JSON); Request request = new Request.Builder() @@ -256,10 +315,10 @@ public class YoloServiceImpl implements ScanService { System.out.println("Unexpected code " + response); String responseBody = Objects.requireNonNull(response.body()).string(); - log.info("picComputeAll:{}",responseBody); + log.info("picComputeAll:{}", responseBody); return gson.fromJson(responseBody, Pojo.class); - }catch (Exception e){ - log.error("Error occurred while calling "+baseUrl, e); + } catch (Exception e) { + log.error("Error occurred while calling " + baseUrl, e); return null; } } diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/stock/StockService.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/stock/StockService.java index 47d4271..49d8b50 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/stock/StockService.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/stock/StockService.java @@ -24,7 +24,7 @@ public interface StockService extends IService< StockDO> { * * @param taskId 任务ID= */ - void updateLastByTaskId(String taskId, String value,String column); + void updateLastByTaskId(Long taskId, String value,String column); void updateStatusByFields(Long taskId, List value); /** * 创建盘点状态 @@ -68,4 +68,6 @@ public interface StockService extends IService< StockDO> { EChartsOption laneInventoryStatistics(); List> laneInventoryStatisticsPie(); + + void truncate(); } \ No newline at end of file diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/stock/StockServiceImpl.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/stock/StockServiceImpl.java index 7429021..01b152f 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/stock/StockServiceImpl.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/stock/StockServiceImpl.java @@ -5,12 +5,12 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.camera.controller.admin.stock.vo.StockPageReqVO; import cn.iocoder.yudao.module.camera.controller.admin.stock.vo.StockSaveReqVO; import cn.iocoder.yudao.module.camera.controller.admin.stock.vo.StockStreetList; -import cn.iocoder.yudao.module.camera.dal.dataobject.checklog.CheckLogDO; import cn.iocoder.yudao.module.camera.dal.dataobject.stock.StockDO; import cn.iocoder.yudao.module.camera.dal.dataobject.street.StreetDO; import cn.iocoder.yudao.module.camera.dal.entity.echarts.Axis; import cn.iocoder.yudao.module.camera.dal.entity.echarts.EChartsOption; import cn.iocoder.yudao.module.camera.dal.entity.echarts.Series; +import cn.iocoder.yudao.module.camera.dal.mysql.checklog.CheckLogMapper; import cn.iocoder.yudao.module.camera.dal.mysql.stock.StockMapper; import cn.iocoder.yudao.module.camera.service.checklog.CheckLogService; import cn.iocoder.yudao.module.camera.service.street.StreetService; @@ -26,7 +26,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.STOCK_NOT_EXISTS; @@ -55,8 +54,8 @@ public class StockServiceImpl extends ServiceImpl implement } @Override - public void updateLastByTaskId(String taskId, String value,String column) { - stockMapper.updateLastByTaskId(taskId, value,column); + public void updateLastByTaskId(Long id, String value,String column) { + stockMapper.updateLastByTaskId(id, value,column); } @Override @@ -117,6 +116,8 @@ public class StockServiceImpl extends ServiceImpl implement @Resource CheckLogService checkLogService; @Resource + private CheckLogMapper checkLogMapper; + @Resource private DictDataService dictDataService; @Override public EChartsOption laneInventoryStatistics() { @@ -124,9 +125,18 @@ public class StockServiceImpl extends ServiceImpl implement eChartsOption.setXAxis(new Axis()); List bars = new ArrayList<>(); List streets = streetService.list(); - List stocks = checkLogService.list(); - Map> stocksMap = stocks.stream() - .collect(Collectors.groupingBy(k ->k.getStatus().toString(),Collectors.groupingBy(CheckLogDO::getStreetId,Collectors.counting()))); + + // 数据库聚合统计:按 巷道 + 状态 分组,避免全表加载到内存 + List> groupList = checkLogMapper.selectGroupCountByStreetIdAndStatus(); + // 结构:status -> (streetId -> count) + Map> stocksMap = new HashMap<>(); + for (Map row : groupList) { + Integer status = ((Number) row.get("status")).intValue(); + Integer streetId = ((Number) row.get("street_id")).intValue(); + Long count = ((Number) row.get("count")).longValue(); + stocksMap.computeIfAbsent(status, k -> new HashMap<>()).put(streetId, count); + } + Map dictDataMap = dictDataService.getDictDataList("check_status"); Axis yAxis = new Axis(); yAxis.setType("category"); @@ -135,7 +145,6 @@ public class StockServiceImpl extends ServiceImpl implement yAxis.getData().add(street.getName()); } eChartsOption.setYAxis(yAxis); - int max = 0; for (String entry : dictDataMap.keySet()) { Series bar = new Series(); bar.setName(entry); @@ -153,12 +162,11 @@ public class StockServiceImpl extends ServiceImpl implement case 3 -> bar.setColor("#5474c4"); default -> bar.setColor(""); } + Integer statusKey = Integer.parseInt(dictDataMap.get(entry).getValue()); + Map statusMap = stocksMap.get(statusKey); List values = new ArrayList<>(); for (StreetDO street : streets) { - if (stocksMap.get(dictDataMap.get(entry).getValue())==null){ - values.add(null); - }else values.add(stocksMap.get(dictDataMap.get(entry).getValue()).get(street.getId())); - + values.add(statusMap == null ? null : statusMap.get(street.getId())); } bar.setData(values); bars.add(bar); @@ -172,23 +180,32 @@ public class StockServiceImpl extends ServiceImpl implement } @Override public List> laneInventoryStatisticsPie() { - EChartsOption eChartsOption = new EChartsOption(); - eChartsOption.setXAxis(new Axis()); - List bars = new ArrayList<>(); - List streets = streetService.list(); - List stocks = checkLogService.list(); - Map stocksMap = stocks.stream() - .collect(Collectors.groupingBy(k ->k.getStatus().toString(),(Collectors.counting()))); + // 数据库聚合统计:按 状态 分组,避免全表加载到内存 + List> groupList = checkLogMapper.selectGroupCountByStatus(); + // 结构:status -> count + Map stocksMap = new HashMap<>(); + for (Map row : groupList) { + Integer status = ((Number) row.get("status")).intValue(); + Long count = ((Number) row.get("count")).longValue(); + stocksMap.put(status, count); + } + Map dictDataMap = dictDataService.getDictValueMap("check_status"); List> list = new ArrayList<>(); - for (String key :stocksMap.keySet()){ + for (Map.Entry entry : stocksMap.entrySet()) { Map map = new HashMap<>(); - map.put("name",dictDataMap.get(key).getLabel()); - map.put("value",stocksMap.get(key).toString()); + DictDataDO dictDataDO = dictDataMap.get(String.valueOf(entry.getKey())); + map.put("name", dictDataDO != null ? dictDataDO.getLabel() : String.valueOf(entry.getKey())); + map.put("value", entry.getValue().toString()); list.add(map); } return list; } + @Override + public void truncate() { + stockMapper.truncate(); + } + } \ No newline at end of file diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/street/StreetService.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/street/StreetService.java index 14e7b87..ba920e4 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/street/StreetService.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/street/StreetService.java @@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.camera.dal.dataobject.rfid.RfidDO; import cn.iocoder.yudao.module.camera.dal.dataobject.sensorgun.SensorGunDO; import cn.iocoder.yudao.module.camera.dal.dataobject.shelfCode.rfid.ShelfCodeDO; import cn.iocoder.yudao.module.camera.dal.dataobject.street.StreetDO; +import cn.iocoder.yudao.module.camera.service.radar.RadarDO; import com.baomidou.mybatisplus.extension.service.IService; import jakarta.validation.Valid; @@ -85,6 +86,7 @@ public interface StreetService extends IService { List getLightSourceListByStreetId(Integer streetId); List getRFIDListByStreetId(Integer streetId); + List getRadarListByStreetId(Integer streetId); List getShelfCodeListByStreetId(Integer streetId); diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/street/StreetServiceImpl.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/street/StreetServiceImpl.java index 9e03ead..3707188 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/street/StreetServiceImpl.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/camera/service/street/StreetServiceImpl.java @@ -12,11 +12,13 @@ import cn.iocoder.yudao.module.camera.dal.dataobject.sensorgun.SensorGunDO; import cn.iocoder.yudao.module.camera.dal.dataobject.shelfCode.rfid.ShelfCodeDO; import cn.iocoder.yudao.module.camera.dal.dataobject.street.StreetDO; import cn.iocoder.yudao.module.camera.dal.mysql.lightsource.LightSourceMapper; +import cn.iocoder.yudao.module.camera.dal.mysql.rfid.RadarMapper; import cn.iocoder.yudao.module.camera.dal.mysql.rfid.RfidMapper; import cn.iocoder.yudao.module.camera.dal.mysql.sensorgun.SensorGunMapper; import cn.iocoder.yudao.module.camera.dal.mysql.shelfCode.ShelfCodeMapper; import cn.iocoder.yudao.module.camera.dal.mysql.street.StreetMapper; import cn.iocoder.yudao.module.camera.service.camera.CameraService; +import cn.iocoder.yudao.module.camera.service.radar.RadarDO; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import jakarta.annotation.Resource; @@ -48,6 +50,8 @@ public class StreetServiceImpl extends ServiceImpl imple private LightSourceMapper lightSourceMapper; @Resource private RfidMapper rfidMapper; + @Resource + private RadarMapper radarMapper; @Resource private ShelfCodeMapper shelfCodeMapper; @@ -69,6 +73,7 @@ public class StreetServiceImpl extends ServiceImpl imple createSensorGunList(street.getId(), createReqVO.getSensorGuns()); createLightSourceList(street.getId(), createReqVO.getLightSources()); createRfidList(street.getId(), createReqVO.getRfids()); + createRfidList(street.getId(), createReqVO.getRfids()); // 返回 return street.getId(); } @@ -86,6 +91,7 @@ public class StreetServiceImpl extends ServiceImpl imple updateSensorGunList(updateReqVO.getId(), updateReqVO.getSensorGuns()); updateRfidList(updateReqVO.getId(), updateReqVO.getRfids()); updateLightSourceList(updateReqVO.getId(), updateReqVO.getLightSources()); + updateRadarList(updateReqVO.getId(), updateReqVO.getRadars()); } @Override @@ -100,6 +106,7 @@ public class StreetServiceImpl extends ServiceImpl imple deleteSensorGunByStreetId(id); deleteLightSourceByStreetId(id); deleteRfidByStreetId(id); + deleteRadarByStreetId(id); } private void validateStreetExists(Integer id) { @@ -181,6 +188,11 @@ public class StreetServiceImpl extends ServiceImpl imple return rfidMapper.selectListByStreetId(streetId); } + @Override + public List getRadarListByStreetId(Integer streetId){ + + return radarMapper.selectListByStreetId(streetId); + } @Override public List getShelfCodeListByStreetId(Integer streetId) { @@ -197,12 +209,23 @@ public class StreetServiceImpl extends ServiceImpl imple rfidMapper.insertBatch(list); } + private void createRadarList(Integer streetId, List list) { + list.forEach(o -> o.setStreetId(streetId)); + radarMapper.insertBatch(list); + } + private void updateRfidList(Integer streetId, List list) { deleteRfidByStreetId(streetId); list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下:1)id 冲突;2)updateTime 不更新 createRfidList(streetId, list); } + private void updateRadarList(Integer streetId, List list) { + deleteRadarByStreetId(streetId); + list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下:1)id 冲突;2)updateTime 不更新 + createRadarList(streetId, list); + } + private void updateLightSourceList(Integer streetId, List list) { deleteLightSourceByStreetId(streetId); list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下:1)id 冲突;2)updateTime 不更新 @@ -215,5 +238,8 @@ public class StreetServiceImpl extends ServiceImpl imple private void deleteRfidByStreetId(Integer streetId) { rfidMapper.deleteByStreetId(streetId); } + private void deleteRadarByStreetId(Integer streetId) { + radarMapper.deleteByStreetId(streetId); + } } \ No newline at end of file diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/logistics/controller/admin/checkconf/vo/CheckConfRespVO.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/logistics/controller/admin/checkconf/vo/CheckConfRespVO.java index 8c52da7..ca04778 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/logistics/controller/admin/checkconf/vo/CheckConfRespVO.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/logistics/controller/admin/checkconf/vo/CheckConfRespVO.java @@ -41,6 +41,12 @@ public class CheckConfRespVO { @ExcelProperty("是否启用") private Boolean isEnable; + + @Schema(description = "是否显示") + @ExcelProperty("是否显示") + private Boolean isDisplay; + + @Schema(description = "上位状态码", example = "1") @ExcelProperty(value = "上位状态码", converter = DictConvert.class) @DictFormat("cssc_code") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/logistics/controller/admin/checkconf/vo/CheckConfSaveReqVO.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/logistics/controller/admin/checkconf/vo/CheckConfSaveReqVO.java index 60fd342..a60cc51 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/logistics/controller/admin/checkconf/vo/CheckConfSaveReqVO.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/logistics/controller/admin/checkconf/vo/CheckConfSaveReqVO.java @@ -29,6 +29,13 @@ public class CheckConfSaveReqVO { @Schema(description = "是否启用") private Boolean isEnable; + + /** + * 是否显示 + */ + @Schema(description = "是否显示") + private Boolean isDisplay; + @Schema(description = "上位状态码", example = "1") private String checkType; diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/logistics/dal/dataobject/checkconf/CheckConfDO.java b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/logistics/dal/dataobject/checkconf/CheckConfDO.java index 9d5e341..bb56b02 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/logistics/dal/dataobject/checkconf/CheckConfDO.java +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/java/cn/iocoder/yudao/module/logistics/dal/dataobject/checkconf/CheckConfDO.java @@ -1,11 +1,11 @@ package cn.iocoder.yudao.module.logistics.dal.dataobject.checkconf; -import lombok.*; -import java.util.*; -import java.time.LocalDateTime; -import java.time.LocalDateTime; -import com.baomidou.mybatisplus.annotation.*; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; +import org.glassfish.jaxb.core.v2.TODO; /** * 盘点配置 DO @@ -53,6 +53,10 @@ public class CheckConfDO extends BaseDO { * 是否启用 */ private Boolean isEnable; + /** + * 是否显示 + */ + private Boolean isDisplay; /** * 上位状态码 * diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/resources/mapper/OrderMapper.xml b/yudao-module-logistics/yudao-module-logistics-biz/src/main/resources/mapper/OrderMapper.xml index 3bb89cd..c48ee49 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/resources/mapper/OrderMapper.xml +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/resources/mapper/OrderMapper.xml @@ -22,4 +22,12 @@ GROUP BY srm_number, DATE(create_time) + + + \ No newline at end of file diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/resources/mapper/checklog/CheckLogMapper.xml b/yudao-module-logistics/yudao-module-logistics-biz/src/main/resources/mapper/checklog/CheckLogMapper.xml index 34c55d1..32a7a70 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/resources/mapper/checklog/CheckLogMapper.xml +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/resources/mapper/checklog/CheckLogMapper.xml @@ -2,13 +2,16 @@ - + UPDATE logistics_check_log - - ${column} = #{value} - - WHERE id = (SELECT id FROM (SELECT id FROM logistics_check_log WHERE task_id = #{taskId} ORDER BY id DESC LIMIT 1) AS tmp) + SET extend_info = JSON_SET( + extend_info, + CONCAT('$.', #{column}), + #{value} + ) + WHERE id = #{id}; + @@ -16,19 +19,42 @@ UPDATE logistics_check_log SET status = CASE - WHEN - - ${field} IS NULL OR ${field} = '' - - THEN 0 - WHEN - - ${field} = wms_${field} - - THEN 2 - ELSE 1 + WHEN + + JSON_EXTRACT(extend_info, CONCAT('$.', #{field})) IS NULL + OR JSON_EXTRACT(extend_info, CONCAT('$.', #{field})) = '' + + THEN 0 + WHEN + + JSON_EXTRACT(extend_info, CONCAT('$.', #{field})) = JSON_EXTRACT(wms_extend_info, CONCAT('$.', #{field})) + + THEN 2 + ELSE 1 END WHERE id = #{id} + + + + + + + + + \ No newline at end of file diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/resources/mapper/radar/RfidMapper.xml b/yudao-module-logistics/yudao-module-logistics-biz/src/main/resources/mapper/radar/RfidMapper.xml new file mode 100644 index 0000000..59bd0fb --- /dev/null +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/resources/mapper/radar/RfidMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/yudao-module-logistics/yudao-module-logistics-biz/src/main/resources/mapper/stock/StockMapper.xml b/yudao-module-logistics/yudao-module-logistics-biz/src/main/resources/mapper/stock/StockMapper.xml index eb7138a..fd2fad5 100644 --- a/yudao-module-logistics/yudao-module-logistics-biz/src/main/resources/mapper/stock/StockMapper.xml +++ b/yudao-module-logistics/yudao-module-logistics-biz/src/main/resources/mapper/stock/StockMapper.xml @@ -4,11 +4,14 @@ + UPDATE logistics_stock - - ${column} = #{value} - - WHERE id = (SELECT id FROM (SELECT id FROM logistics_stock WHERE task_id = #{taskId} ORDER BY id DESC LIMIT 1) AS tmp) + SET extend_info = JSON_SET( + extend_info, + CONCAT('$.', #{column}), + #{value} + ) + WHERE id = #{id}; @@ -17,19 +20,25 @@ UPDATE logistics_stock SET status = CASE - WHEN - - ${field} IS NULL OR ${field} = '' - - THEN 0 - WHEN - - ${field} = wms_${field} - - THEN 2 - ELSE 1 + WHEN + + JSON_EXTRACT(extend_info, CONCAT('$.', #{field})) IS NULL + OR JSON_EXTRACT(extend_info, CONCAT('$.', #{field})) = '' + + THEN 0 + WHEN + + JSON_EXTRACT(extend_info, CONCAT('$.', #{field})) = JSON_EXTRACT(wms_extend_info, CONCAT('$.', #{field})) + + THEN 2 + ELSE 1 END WHERE id = #{id} + + + TRUNCATE TABLE logistics_stock + + \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/pom.xml b/yudao-module-system/yudao-module-system-biz/pom.xml index 3b0e421..2bc4e7d 100644 --- a/yudao-module-system/yudao-module-system-biz/pom.xml +++ b/yudao-module-system/yudao-module-system-biz/pom.xml @@ -133,10 +133,7 @@ - - - - + org.dromara.hutool diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserProfileController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserProfileController.java index c88707c..94aeb8b 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserProfileController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserProfileController.java @@ -94,4 +94,15 @@ public class UserProfileController { return success(avatar); } + @RequestMapping(value = "/updateFile", + method = {RequestMethod.POST, RequestMethod.PUT}) // 解决 uni-app 不支持 Put 上传文件的问题 + @Operation(summary = "上传图像") + public CommonResult updateFileAvatar(@RequestParam("avatarFile") MultipartFile file) throws Exception { + if (file.isEmpty()) { + throw exception(FILE_IS_EMPTY); + } + String avatar = userService.updateFileAvatar( file.getInputStream()); + return success(avatar); + } + } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java index 6345e22..7f5914b 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java @@ -66,6 +66,8 @@ public interface AdminUserService { */ String updateUserAvatar(Long id, InputStream avatarFile) throws Exception; + String updateFileAvatar(InputStream avatarFile) throws Exception; + /** * 修改密码 * diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java index efae327..f7c1c0c 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java @@ -188,6 +188,14 @@ public class AdminUserServiceImpl implements AdminUserService { return avatar; } + @Override + public String updateFileAvatar(InputStream avatarFile) { + // 存储文件 + String avatar = fileApi.createFile(IoUtil.readBytes(avatarFile)); + // 更新路径 + return avatar; + } + @Override @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_UPDATE_PASSWORD_SUB_TYPE, bizNo = "{{#id}}", success = SYSTEM_USER_UPDATE_PASSWORD_SUCCESS) diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/util/RedisUtil.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/util/RedisUtil.java index f3361fa..8d40a60 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/util/RedisUtil.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/util/RedisUtil.java @@ -160,6 +160,27 @@ public class RedisUtil { } } + /** + * 原子设置值(仅当 key 不存在时),常用于分布式锁 + * + * @param key 键 + * @param value 值 + * @param time 过期时间(秒),大于 0 才设置过期 + * @return true 设置成功(拿到锁),false 已存在(未拿到锁) + */ + public boolean setIfAbsent(String key, Object value, long time) { + try { + Boolean success = redisTemplate.opsForValue().setIfAbsent(key, value); + if (Boolean.TRUE.equals(success) && time > 0) { + redisTemplate.expire(key, time, TimeUnit.SECONDS); + } + return Boolean.TRUE.equals(success); + } catch (Exception e) { + log.error(key, e); + return false; + } + } + /** * 递增 适用场景: https://blog.csdn.net/y_y_y_k_k_k_k/article/details/79218254 高并发生成订单号,秒杀类的业务逻辑等。。 * diff --git a/yudao-server/src/main/resources/application-dev.yaml b/yudao-server/src/main/resources/application-dev.yaml index 37a3f2e..3f44da7 100644 --- a/yudao-server/src/main/resources/application-dev.yaml +++ b/yudao-server/src/main/resources/application-dev.yaml @@ -46,11 +46,13 @@ spring: primary: master datasource: master: - name: sy - url: jdbc:mysql://192.168.100.99:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例 + name: sy-primary + url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&allowMultiQueries=true # MySQL Connector/J 8.X 连接的示例 username: root - password: Leaper@123 + password: root +# password: Leaper@123 + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 data: @@ -63,7 +65,7 @@ spring: max-wait: 5000ms # 增加获取连接的最大等待时间 shutdown-timeout: 1000ms # 增加关闭超时时间 timeout: 5000ms # 增加连接超时时间 - host: 192.168.100.99 # 地址 + host: 192.168.1.21 # 地址 port: 6379 # 端口 database: 0 # 数据库索引 # password: dev # 密码,建议生产环境开启 diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index 32d0321..98b4dbc 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -47,7 +47,7 @@ spring: datasource: master: name: sy - url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例 + url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&allowMultiQueries=true # MySQL Connector/J 8.X 连接的示例 # url: jdbc:mysql://192.168.2.162:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT # MySQL Connector/J 5.X 连接的示例 # url: jdbc:postgresql://127.0.0.1:5432/${spring.datasource.dynamic.datasource.master.name} # PostgreSQL 连接的示例 # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例 diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml index 72ef5b2..4dfd628 100644 --- a/yudao-server/src/main/resources/application.yaml +++ b/yudao-server/src/main/resources/application.yaml @@ -5,10 +5,6 @@ spring: profiles: active: dev - autoconfigure: - exclude: - - com.xingyuv.captcha.config.AjCaptchaServiceAutoConfiguration - main: allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。 @@ -102,25 +98,6 @@ easy-trans: is-enable-global: true # 启用全局翻译(拦截所有 SpringMVC ResponseBody 进行自动翻译 )。如果对于性能要求很高可关闭此配置,或通过 @IgnoreTrans 忽略某个接口 is-enable-cloud: false # 禁用 TransType.RPC 微服务模式 ---- #################### 验证码相关配置 #################### - -aj: - captcha: - jigsaw: classpath:images/jigsaw # 滑动验证,底图路径,不配置将使用默认图片;以 classpath: 开头,取 resource 目录下路径 - pic-click: classpath:images/pic-click # 滑动验证,底图路径,不配置将使用默认图片;以 classpath: 开头,取 resource 目录下路径 - cache-type: redis # 缓存 local/redis... - cache-number: 1000 # local 缓存的阈值,达到这个值,清除缓存 - timing-clear: 180 # local定时清除过期缓存(单位秒),设置为0代表不执行 - type: blockPuzzle # 验证码类型 default两种都实例化。 blockPuzzle 滑块拼图 clickWord 文字点选 - water-mark: 芋道源码 # 右下角水印文字(我的水印),可使用 https://tool.chinaz.com/tools/unicode.aspx 中文转 Unicode,Linux 可能需要转 unicode - interference-options: 0 # 滑动干扰项(0/1/2) - req-frequency-limit-enable: false # 接口请求次数一分钟限制是否开启 true|false - req-get-lock-limit: 5 # 验证失败 5 次,get接口锁定 - req-get-lock-seconds: 10 # 验证失败后,锁定时间间隔 - req-get-minute-limit: 30 # get 接口一分钟内请求数限制 - req-check-minute-limit: 60 # check 接口一分钟内请求数限制 - req-verify-minute-limit: 60 # verify 接口一分钟内请求数限制 - --- #################### 消息队列相关 #################### # rocketmq 配置项,对应 RocketMQProperties 配置类