增加rfid,雷达

增加redis
修改盘点数据类型
master
LAPTOP-S9HJSOEB\昊天 1 month ago
parent cbbbfc123b
commit 681ad300e3

@ -45,7 +45,6 @@
<!-- Bpm 工作流相关 -->
<flowable.version>7.0.1</flowable.version>
<!-- 工具类相关 -->
<captcha-plus.version>2.0.3</captcha-plus.version>
<jsoup.version>1.17.2</jsoup.version>
<lombok.version>1.18.34</lombok.version>
<mapstruct.version>1.5.5.Final</mapstruct.version>
@ -511,12 +510,6 @@
<version>${jsch.version}</version>
</dependency>
<dependency>
<groupId>com.xingyuv</groupId>
<artifactId>spring-boot-starter-captcha-plus</artifactId>
<version>${captcha-plus.version}</version>
</dependency>
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>

@ -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);
}
}
}

@ -138,10 +138,7 @@
<artifactId>tencentcloud-sdk-java-sms</artifactId> <!-- 短信(腾讯云) -->
</dependency>
<dependency>
<groupId>com.xingyuv</groupId>
<artifactId>spring-boot-starter-captcha-plus</artifactId> <!-- 验证码,一般用于登录使用 -->
</dependency>
<dependency>
<groupId>org.dromara.hutool</groupId>

@ -146,10 +146,7 @@
<artifactId>tencentcloud-sdk-java-sms</artifactId> <!-- 短信(腾讯云) -->
</dependency>
<dependency>
<groupId>com.xingyuv</groupId>
<artifactId>spring-boot-starter-captcha-plus</artifactId> <!-- 验证码,一般用于登录使用 -->
</dependency>
<dependency>
<groupId>org.dromara.hutool</groupId>

@ -164,10 +164,7 @@
<artifactId>tencentcloud-sdk-java-sms</artifactId> <!-- 短信(腾讯云) -->
</dependency>
<dependency>
<groupId>com.xingyuv</groupId>
<artifactId>spring-boot-starter-captcha-plus</artifactId> <!-- 验证码,一般用于登录使用 -->
</dependency>
<dependency>
<groupId>org.dromara.hutool</groupId>

@ -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<CheckConfDO> checkConfList = checkConfService.list(new QueryWrapper<CheckConfDO>()
.ne("check_scan_type", 0)
.eq("is_Display", 1)
.eq("is_Enable", 1));
List<DictDataDO> dictDataDOS =checkConfList.stream().map(checkConfDO ->{

@ -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<String> check(@RequestBody KsecDataInfo kescEntity){
public CommonResult<Object> 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<String,Object> 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<String> singleInventoryReturn(@RequestBody BoxCountResponse scanData){
List<CheckConfDO> checkConfList = checkConfService.list(new QueryWrapper<CheckConfDO>()
List<CheckConfDO> checkConfList = checkConfService.list(new QueryWrapper<CheckConfDO>()
.ne("check_scan_type", 0)
.eq("is_Enable", 1));
plcService.singleInventoryReturn(scanData.getTaskId(),scanData.getResult(),scanData.getScanType(),checkConfList);
CheckLogDO checkLogDO = checkLogService.getOne(new QueryWrapper<CheckLogDO>()
.eq("task_id", scanData.getTaskId())
.orderByDesc("id")
.last("limit 1"));
StockDO stockDO = stockService.getOne(new QueryWrapper<StockDO>()
.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<CheckConfDO> checkConfList = checkConfService.list(new QueryWrapper<CheckConfDO>()
.ne("check_scan_type", 0)
.eq("is_Enable", 1));
boxCountResponse.setResult("NoRead");
CheckLogDO checkLogDO = checkLogService.getOne(new QueryWrapper<CheckLogDO>()
.eq("task_id", boxCountResponse.getTaskId())
.orderByDesc("id")
.last("limit 1"));
StockDO stockDO = stockService.getOne(new QueryWrapper<StockDO>()
.eq("task_id", boxCountResponse.getTaskId())
.orderByDesc("id")
.last("limit 1"));
// 增加空指针保护
List<String> 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());

@ -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<OrderStatistics> 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<String, Object> orderStat = orderMapper.selectTotalAndMonthCount(firstDayOfMonthStart);
Map<String, Object> 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')")

@ -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<Integer> createRadar(@Valid @RequestBody RadarSaveReqVO createReqVO) {
return success(radarService.createRadar(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新Radar")
@PreAuthorize("@ss.hasPermission('logistics:Radar:update')")
public CommonResult<Boolean> 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<Boolean> 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<RadarRespVO> 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<PageResult<RadarRespVO>> getRadarPage(@Valid RadarPageReqVO pageReqVO) {
PageResult<RadarDO> 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<RadarDO> list = radarService.getRadarPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "Radar.xls", "数据", RadarRespVO.class,
BeanUtils.toBean(list, RadarRespVO.class));
}
}

@ -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;
}

@ -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;
}

@ -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;
}

@ -50,4 +50,6 @@ public class SpecificationConfRespVO {
@ExcelProperty("高度单位mm")
private Integer high;
@Schema(description = "图片路径")
private String pic;
}

@ -37,4 +37,7 @@ public class SpecificationConfSaveReqVO {
@Schema(description = "高度单位mm")
private Integer id;
@Schema(description = "图片路径")
private String pic;
}

@ -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<CheckConfDO> checkConfList = checkConfService.list(new QueryWrapper<CheckConfDO>()
.ne("check_scan_type", 0)
.eq("is_Display",1)
.eq("is_Enable", 1));
Map<String, DictDataDO> 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());

@ -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<List<RadarDO>> getRadarListByStreetId(@RequestParam("streetId") Integer streetId) {
return success(streetService.getRadarListByStreetId(streetId));
}
@GetMapping("/shelfCode/list-by-street-id")
@Operation(summary = "获得货架列表")
@Parameter(name = "streetId", description = "巷道id")

@ -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<RfidDO> rfids;
@Schema(description = "扫码枪列表")
private List<RadarDO> radars;
@Schema(description = "光源列表")
private List<LightSourceDO> lightSources;

@ -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<String, String> extendInfo =new HashMap<>();
/**
* WMS 扩展信息(键值对,JSON 存储)
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private Map<String, String> wmsExtendInfo =new HashMap<>();
}

@ -52,6 +52,7 @@ public class SpecificationConfDO extends BaseDO {
* 类型
*/
private String type;
private String pic;
/**
* 高度单位mm
*/

@ -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<String, String> extendInfo =new HashMap<>();
/**
* WMS 扩展信息(键值对,JSON 存储)
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private Map<String, String> wmsExtendInfo =new HashMap<>();
}

@ -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;

@ -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<CheckLogDO> {
/**
* 动态更新最后一条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<CheckLogDO> {
*/
int updateStatusByFields(@Param("id") Integer id, @Param("fields") List<String> fields);
/**
* 按 巷道 + 状态 分组统计盘点记录数量(数据库聚合,避免全表加载到内存)
*
* @return 每行包含 street_id、status、count 三列
*/
List<Map<String, Object>> selectGroupCountByStreetIdAndStatus();
/**
* 按 状态 分组统计盘点记录数量(数据库聚合,避免全表加载到内存)
*
* @return 每行包含 status、count 两列
*/
List<Map<String, Object>> selectGroupCountByStatus();
/**
* 一次查询统计 全量总数 + 本月总数(从 monthStart 起),避免多次 COUNT(*) 扫描大表
*
* @param monthStart 本月 1 号 0 点
* @return 单行:total_count、month_count
*/
Map<String, Object> selectTotalAndMonthCount(@Param("monthStart") LocalDateTime monthStart);
}

@ -43,4 +43,12 @@ public interface OrderMapper extends BaseMapperX<OrderDO> {
List<Map<String, Object>> selectGroupCountBySrmNumberAndDate(@Param("startTime") LocalDateTime startTime);
/**
* 一次查询统计 全量总数 + 本月总数(从 startTime 起),避免多次 COUNT(*) 扫描大表
*
* @param monthStart 本月 1 号 0 点
* @return 单行:total_count、month_count
*/
Map<String, Object> selectTotalAndMonthCount(@Param("monthStart") LocalDateTime monthStart);
}

@ -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<RadarDO> {
default PageResult<RadarDO> selectPage(RadarPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<RadarDO>()
.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<RadarDO> selectListByStreetId(Integer streetId) {
return selectList(RadarDO::getStreetId, streetId);
}
default int deleteByStreetId(Integer streetId) {
return delete(RadarDO::getStreetId, streetId);
}
}

@ -52,10 +52,10 @@ public interface StockMapper extends BaseMapperX<StockDO> {
/**
* 动态更新最后一条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<StockDO> {
* @return 更新行数
*/
int updateStatusByFields(@Param("id") Long id, @Param("fields") List<String> fields);
/**
* 清空整个表(TRUNCATE)
*/
void truncate();
}

@ -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;

@ -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<String,String> extendInfo =new HashMap<>();
private Map<String,String> 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;
// }
}

@ -108,7 +108,7 @@ public class KsecDecoder extends DelimiterBasedFrameDecoder {
} else if (Cmd.E.name().equals(ksecInfo.getType())) {
//智能盘点
dataInfo.setCount("正常");
// dataInfo.setCount("正常");
// plcService.check( dataInfo);

@ -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());

@ -59,6 +59,6 @@ public interface CheckLogService extends IService<CheckLogDO> {
*
* @param taskId 任务ID
*/
void updateLastByTaskId(String taskId, String value,String column);
void updateLastByTaskId(Integer taskId, String value,String column);
}

@ -83,7 +83,7 @@ public class CheckLogServiceImpl extends ServiceImpl<CheckLogMapper, CheckLogDO>
}
@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<CheckLogMapper, CheckLogDO>
.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;

@ -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<CheckConfDO> checkConfList);
void check(String taskId, String cmd);
Integer singleInventoryReturn(StockDO stock, CheckLogDO checkLogDO, String taskId, String value, String type, List<CheckConfDO> checkConfList);
StockDO check(String taskId, String cmd);
void stopCheck(String taskId, Map<String,String> result);
void stockSave(AlgorithmDelayTask algorithmDelayTask);

@ -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<StockDO>()
.eq("batch_Number", dataInfo.getLotnum())
.last("limit 1"));
if (stock == null) {
// 清空整个表
stockService.truncate();
}
}
List<CheckConfDO> checkConfList = checkConfService.list(new QueryWrapper<CheckConfDO>()
.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<CheckConfDO> checkConfList = checkConfService.list(new QueryWrapper<CheckConfDO>()
.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<CheckLogDO>()
.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<StockDO>()
.eq("task_id", taskId)
.orderByDesc("create_time")
.last("limit 1")
);
CheckLogDO checkLogDO = checkLogService.getOne(new QueryWrapper<CheckLogDO>()
.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<String> 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<String> 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<String,String> 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<String,Object> resultReport = new HashMap<>();
List<CheckConfDO> checkConfList = checkConfService.list(new QueryWrapper<CheckConfDO>()
.ne("check_scan_type", 0)
.eq("is_Display", 1)
.eq("is_Enable", 1));
Map<String, DictDataDO> csscStartList = dictDataService.getDictDataList("scan_enable");
// Map<String, DictDataDO> csscStartList = dictDataService.getDictDataList("scan_enable");
StockDO stock = stockService.getOne(
new QueryWrapper<StockDO>()
.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) {

@ -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;
}

@ -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<RadarDO> getRadarPage(RadarPageReqVO pageReqVO);
}

@ -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<RadarMapper, RadarDO> 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<RadarDO> getRadarPage(RadarPageReqVO pageReqVO) {
return radarMapper.selectPage(pageReqVO);
}
}

@ -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);
}
}

@ -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<Byte> 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<String> tags = ConcurrentHashMap.newKeySet();
private Map<String, Integer> countMap = new ConcurrentHashMap<>();
private List<Byte> byteList = new ArrayList<>(30);
public Set<String> 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<byteList.size();i++){
bytes[i] = byteList.get(i);
}
MessageTran messageTran = new MessageTran(bytes);
byte[] aryData = messageTran.getAryData();
if(aryData != null && aryData.length == 9){
//只能根据长度判断返回的包是标签内容还是其他
//9个字节,第一个字节是指哪个天线,暂时不用管,只需关注什么标签
StringBuffer sb = new StringBuffer();
log.debug("antId:{}",String.format("%02X",aryData[0]));
for(int i = 1;i<aryData.length;i++){
sb.append(String.format("%02X",aryData[i]));
}
tag = sb.toString();
}
clear();
}
return tag;
}
private void clear(){
byteList.clear();
step = 0;
length = 0;
index = 0;
}
public void close() {
running = false;
// 先关闭 socket,让阻塞在 is.read() 的线程抛出 IOException 从而退出
try {
if (socket != null) {
socket.close();
}
} catch (IOException e) {
log.warn("close socket error:{}", e);
}
try {
if (is != null) {
is.close();
}
} catch (IOException e) {
log.warn("close input stream error:{}", e);
}
try {
if (os != null) {
os.close();
}
} catch (IOException e) {
log.warn("close output stream error:{}", e);
}
}
public void startCheck(Integer direction){
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
while (running){
byte []antChanges = new byte[6];
antChanges[0] = (byte)0xa0;
antChanges[1] = (byte)0x04;
antChanges[2] = (byte)0x01;
antChanges[3] = (byte)0x74;
log.info("rfid天线1 ip:"+ip);
antChanges[4] = (byte)0x00;
antChanges[5] = (byte)0xe7;
//切换天线 使用天线1
// if(1 == direction ){
// //切换天线 使用天线0
// log.info("rfid左 ip:"+ip);
// }else {
//
// antChanges[4] = (byte)0x01;
// antChanges[5] = (byte)0xe6;
// }
try {
os.write(antChanges);
Thread.sleep(10);
} catch (InterruptedException | IOException e) {
log.error("send cmd error:{}",e);
}
byte[]bytes = new byte[5];
bytes[0] = (byte)0xa0;
bytes[1] = (byte)0x03;
bytes[2] = (byte)0x01;
bytes[3] = (byte)0xb0;
bytes[4] = (byte)0xac;
try {
os.write(bytes);
Thread.sleep(70);
} catch (InterruptedException | IOException e) {
log.warn("send rfid cmd error:{}",e);
}
}
}
});
thread.setDaemon(true);
thread.start();
}
public static void main(String[] args) throws IOException, InterruptedException {
RFIDSocket rfid = new RFIDSocket("10.43.26.128",4001);
file = new File("D:\\code.txt");
file.createNewFile();
fw = new FileWriter(file, true);
fw.write("\n");
rfid.startCheck(1);
rfid.readData();
Thread.sleep(1000*30000);
rfid.close();
System.out.println(rfid.getTags());
// fw.write("\n");
// fw.flush();
// for(String tag : rfid.getTags())
// {
// fw.write(tag+"\n");
// fw.flush();
// }
fw.close();
}
}

@ -11,6 +11,9 @@ import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.util.HashMap;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.RFID_NOT_EXISTS;
@ -22,7 +25,20 @@ import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.RFID_NOT_EX
@Service
@Validated
public class RfidServiceImpl extends ServiceImpl<RfidMapper, RfidDO> implements RfidService {
private static Map<Integer,RFIDSocket> 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;

@ -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<SpecificationConfDO>().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);

@ -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());

@ -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());

@ -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路径

@ -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<RfidDO>()
.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<String> RFIDStop(StreetDO street) {
RFIDSocket rfidSocket = RfidServiceImpl.get(street.getId());
Set<String> 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<RfidDO>()
.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();
}
}
}

@ -0,0 +1,60 @@
package cn.iocoder.yudao.module.camera.service.scan;
import lombok.Data;
/**
* PAVO2 雷达 HTTP 请求体
*
* <p>对应 PAVO2 HTTP 运行模式 POST 到根路径 {@code /} 的 JSON body(与 TCP 协议一致,不带结尾 '>')。</p>
*/
@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;
}
}

@ -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 响应体
*
* <p>响应 body 与 TCP 协议一致(不带结尾 '>')。</p>
*/
@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;
}

@ -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 接口实现
*
* <p>PAVO2 雷达以 HTTP 运行模式对外提供接口,POST 到根路径 {@code /},
* 请求体为与 TCP 协议完全相同的 JSON(不带结尾 '>'),响应 body 与 TCP 相同。</p>
*
* <p>数据来源:</p>
* <ul>
* <li>ip/端口:通过 {@link RadarService} 按巷道 id + 方向(stockDO.direction)查询 {@link RadarDO}</li>
* <li>box 尺寸:通过 {@link SpecificationConfService} 按品规(stockDO.wmsItemCode)查询 {@link SpecificationConfDO}</li>
* </ul>
*/
@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<SpecificationConfDO>()
.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<RadarDO>()
.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<byte[]> 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;
}
}

@ -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<SensorGunDO>().eq("street_id", streetDO.getId()).eq("direction", stockDO.getDirection()));
SensorGunDO sensorGun = sensorService.getOne(new QueryWrapper<SensorGunDO>()
.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());

@ -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 );
}

@ -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");
}
}

@ -12,6 +12,8 @@ public class Pojo {
private String determinePath;
//结果
private Boolean result;
private String code;
private String pic;
private String type;
private List<BoundingBox> detects;
private String path;

@ -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<LocalDate>) (date, type, jsonSerializationContext) ->
new JsonPrimitive(date.format(dateFormatter)))
.registerTypeAdapter(LocalDate.class, (JsonDeserializer<LocalDate>) (json, type, jsonDeserializationContext) ->
LocalDate.parse(json.getAsString(), dateFormatter))
.registerTypeAdapter(LocalDateTime.class, (JsonSerializer<LocalDateTime>) (dateTime, type, jsonSerializationContext) ->
new JsonPrimitive(dateTime.format(dateTimeFormatter)))
.registerTypeAdapter(LocalDateTime.class, (JsonDeserializer<LocalDateTime>) (json, type, jsonDeserializationContext) ->
LocalDateTime.parse(json.getAsString(), dateTimeFormatter))
.registerTypeAdapter(LocalDate.class, (JsonSerializer<LocalDate>) (date, type, jsonSerializationContext) ->
new JsonPrimitive(date.format(dateFormatter)))
.registerTypeAdapter(LocalDate.class, (JsonDeserializer<LocalDate>) (json, type, jsonDeserializationContext) ->
LocalDate.parse(json.getAsString(), dateFormatter))
.registerTypeAdapter(LocalDateTime.class, (JsonSerializer<LocalDateTime>) (dateTime, type, jsonSerializationContext) ->
new JsonPrimitive(dateTime.format(dateTimeFormatter)))
.registerTypeAdapter(LocalDateTime.class, (JsonDeserializer<LocalDateTime>) (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<URLResourcesDo>()
.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<Pojo> entity = new HttpEntity<>(pojo, headers);
ResponseEntity<Pojo> 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<URLResourcesDo> urls = urlResourcesService.list(new LambdaQueryWrapper<URLResourcesDo>().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;
}
}

@ -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<String> value);
/**
* 创建盘点状态
@ -68,4 +68,6 @@ public interface StockService extends IService< StockDO> {
EChartsOption laneInventoryStatistics();
List<Map<String,String>> laneInventoryStatisticsPie();
void truncate();
}

@ -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<StockMapper,StockDO> 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<StockMapper,StockDO> 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<StockMapper,StockDO> implement
eChartsOption.setXAxis(new Axis());
List<Series> bars = new ArrayList<>();
List<StreetDO> streets = streetService.list();
List<CheckLogDO> stocks = checkLogService.list();
Map<String,Map<Integer,Long>> stocksMap = stocks.stream()
.collect(Collectors.groupingBy(k ->k.getStatus().toString(),Collectors.groupingBy(CheckLogDO::getStreetId,Collectors.counting())));
// 数据库聚合统计:按 巷道 + 状态 分组,避免全表加载到内存
List<Map<String, Object>> groupList = checkLogMapper.selectGroupCountByStreetIdAndStatus();
// 结构:status -> (streetId -> count)
Map<Integer, Map<Integer, Long>> stocksMap = new HashMap<>();
for (Map<String, Object> 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<String, DictDataDO> dictDataMap = dictDataService.getDictDataList("check_status");
Axis yAxis = new Axis();
yAxis.setType("category");
@ -135,7 +145,6 @@ public class StockServiceImpl extends ServiceImpl<StockMapper,StockDO> 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<StockMapper,StockDO> implement
case 3 -> bar.setColor("#5474c4");
default -> bar.setColor("");
}
Integer statusKey = Integer.parseInt(dictDataMap.get(entry).getValue());
Map<Integer, Long> statusMap = stocksMap.get(statusKey);
List<Long> 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<StockMapper,StockDO> implement
}
@Override
public List<Map<String,String>> laneInventoryStatisticsPie() {
EChartsOption eChartsOption = new EChartsOption();
eChartsOption.setXAxis(new Axis());
List<Series> bars = new ArrayList<>();
List<StreetDO> streets = streetService.list();
List<CheckLogDO> stocks = checkLogService.list();
Map<String,Long> stocksMap = stocks.stream()
.collect(Collectors.groupingBy(k ->k.getStatus().toString(),(Collectors.counting())));
// 数据库聚合统计:按 状态 分组,避免全表加载到内存
List<Map<String, Object>> groupList = checkLogMapper.selectGroupCountByStatus();
// 结构:status -> count
Map<Integer, Long> stocksMap = new HashMap<>();
for (Map<String, Object> row : groupList) {
Integer status = ((Number) row.get("status")).intValue();
Long count = ((Number) row.get("count")).longValue();
stocksMap.put(status, count);
}
Map<String, DictDataDO> dictDataMap = dictDataService.getDictValueMap("check_status");
List<Map<String,String>> list = new ArrayList<>();
for (String key :stocksMap.keySet()){
for (Map.Entry<Integer, Long> entry : stocksMap.entrySet()) {
Map<String,String> 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();
}
}

@ -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<StreetDO> {
List<LightSourceDO> getLightSourceListByStreetId(Integer streetId);
List<RfidDO> getRFIDListByStreetId(Integer streetId);
List<RadarDO> getRadarListByStreetId(Integer streetId);
List<ShelfCodeDO> getShelfCodeListByStreetId(Integer streetId);

@ -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<StreetMapper, StreetDO> 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<StreetMapper, StreetDO> 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<StreetMapper, StreetDO> 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<StreetMapper, StreetDO> imple
deleteSensorGunByStreetId(id);
deleteLightSourceByStreetId(id);
deleteRfidByStreetId(id);
deleteRadarByStreetId(id);
}
private void validateStreetExists(Integer id) {
@ -181,6 +188,11 @@ public class StreetServiceImpl extends ServiceImpl<StreetMapper, StreetDO> imple
return rfidMapper.selectListByStreetId(streetId);
}
@Override
public List<RadarDO> getRadarListByStreetId(Integer streetId){
return radarMapper.selectListByStreetId(streetId);
}
@Override
public List<ShelfCodeDO> getShelfCodeListByStreetId(Integer streetId) {
@ -197,12 +209,23 @@ public class StreetServiceImpl extends ServiceImpl<StreetMapper, StreetDO> imple
rfidMapper.insertBatch(list);
}
private void createRadarList(Integer streetId, List<RadarDO> list) {
list.forEach(o -> o.setStreetId(streetId));
radarMapper.insertBatch(list);
}
private void updateRfidList(Integer streetId, List<RfidDO> 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<RadarDO> 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<LightSourceDO> 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<StreetMapper, StreetDO> imple
private void deleteRfidByStreetId(Integer streetId) {
rfidMapper.deleteByStreetId(streetId);
}
private void deleteRadarByStreetId(Integer streetId) {
radarMapper.deleteByStreetId(streetId);
}
}

@ -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 枚举类中

@ -29,6 +29,13 @@ public class CheckConfSaveReqVO {
@Schema(description = "是否启用")
private Boolean isEnable;
/**
* 是否显示
*/
@Schema(description = "是否显示")
private Boolean isDisplay;
@Schema(description = "上位状态码", example = "1")
private String checkType;

@ -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;
/**
* 上位状态码
*

@ -22,4 +22,12 @@
GROUP BY srm_number, DATE(create_time)
</select>
<!-- 一次统计 全量 + 本月 数量,避免多次 COUNT(*) -->
<select id="selectTotalAndMonthCount" resultType="java.util.HashMap">
SELECT
COUNT(*) AS total_count,
SUM(CASE WHEN create_time &gt;= #{monthStart} THEN 1 ELSE 0 END) AS month_count
FROM logistics_order
</select>
</mapper>

@ -2,13 +2,16 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.yudao.module.camera.dal.mysql.checklog.CheckLogMapper">
<!-- 动态更新最后一条taskId匹配的记录 -->
<!-- 同步更新 logistics_check_log 和 logistics_stock 最后一条 taskId 匹配记录的 wms_extend_info JSON 字段中的某个 key -->
<update id="updateLastByTaskId">
UPDATE logistics_check_log
<set>
${column} = #{value}
</set>
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};
</update>
<!-- 根据字段列表更新status -->
@ -16,19 +19,42 @@
<update id="updateStatusByFields">
UPDATE logistics_check_log
SET status = CASE
WHEN
<foreach collection="fields" item="field" separator=" OR ">
${field} IS NULL OR ${field} = ''
</foreach>
THEN 0
WHEN
<foreach collection="fields" item="field" separator=" AND ">
${field} = wms_${field}
</foreach>
THEN 2
ELSE 1
WHEN
<foreach collection="fields" item="field" separator=" OR ">
JSON_EXTRACT(extend_info, CONCAT('$.', #{field})) IS NULL
OR JSON_EXTRACT(extend_info, CONCAT('$.', #{field})) = ''
</foreach>
THEN 0
WHEN
<foreach collection="fields" item="field" separator=" AND ">
JSON_EXTRACT(extend_info, CONCAT('$.', #{field})) = JSON_EXTRACT(wms_extend_info, CONCAT('$.', #{field}))
</foreach>
THEN 2
ELSE 1
END
WHERE id = #{id}
</update>
<!-- 按 巷道 + 状态 分组统计(用于首页巷道盘点柱状图) -->
<select id="selectGroupCountByStreetIdAndStatus" resultType="java.util.HashMap">
SELECT street_id AS street_id, status AS status, COUNT(*) AS count
FROM logistics_check_log
GROUP BY street_id, status
</select>
<!-- 按 状态 分组统计(用于首页巷道盘点饼图) -->
<select id="selectGroupCountByStatus" resultType="java.util.HashMap">
SELECT status AS status, COUNT(*) AS count
FROM logistics_check_log
GROUP BY status
</select>
<!-- 一次统计 全量 + 本月 数量,避免多次 COUNT(*) -->
<select id="selectTotalAndMonthCount" resultType="java.util.HashMap">
SELECT
COUNT(*) AS total_count,
SUM(CASE WHEN create_time &gt;= #{monthStart} THEN 1 ELSE 0 END) AS month_count
FROM logistics_check_log
</select>
</mapper>

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.yudao.module.logistics.dal.mysql.radar.RfidMapper">
<!--
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
-->
</mapper>

@ -4,11 +4,14 @@
<!-- 动态更新最后一条taskId匹配的记录 -->
<update id="updateLastByTaskId">
UPDATE logistics_stock
<set>
${column} = #{value}
</set>
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};
</update>
<!-- 根据字段列表更新status -->
@ -17,19 +20,25 @@
<update id="updateStatusByFields">
UPDATE logistics_stock
SET status = CASE
WHEN
<foreach collection="fields" item="field" separator=" OR ">
${field} IS NULL OR ${field} = ''
</foreach>
THEN 0
WHEN
<foreach collection="fields" item="field" separator=" AND ">
${field} = wms_${field}
</foreach>
THEN 2
ELSE 1
WHEN
<foreach collection="fields" item="field" separator=" OR ">
JSON_EXTRACT(extend_info, CONCAT('$.', #{field})) IS NULL
OR JSON_EXTRACT(extend_info, CONCAT('$.', #{field})) = ''
</foreach>
THEN 0
WHEN
<foreach collection="fields" item="field" separator=" AND ">
JSON_EXTRACT(extend_info, CONCAT('$.', #{field})) = JSON_EXTRACT(wms_extend_info, CONCAT('$.', #{field}))
</foreach>
THEN 2
ELSE 1
END
WHERE id = #{id}
</update>
<!-- 清空整个表 -->
<update id="truncate">
TRUNCATE TABLE logistics_stock
</update>
</mapper>

@ -133,10 +133,7 @@
<!-- <artifactId>tencentcloud-sdk-java-sms</artifactId> &lt;!&ndash; 短信(腾讯云) &ndash;&gt;-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>com.xingyuv</groupId>-->
<!-- <artifactId>spring-boot-starter-captcha-plus</artifactId> &lt;!&ndash; 验证码,一般用于登录使用 &ndash;&gt;-->
<!-- </dependency>-->
<dependency>
<groupId>org.dromara.hutool</groupId>

@ -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<String> updateFileAvatar(@RequestParam("avatarFile") MultipartFile file) throws Exception {
if (file.isEmpty()) {
throw exception(FILE_IS_EMPTY);
}
String avatar = userService.updateFileAvatar( file.getInputStream());
return success(avatar);
}
}

@ -66,6 +66,8 @@ public interface AdminUserService {
*/
String updateUserAvatar(Long id, InputStream avatarFile) throws Exception;
String updateFileAvatar(InputStream avatarFile) throws Exception;
/**
* 修改密码
*

@ -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)

@ -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 高并发生成订单号,秒杀类的业务逻辑等。。
*

@ -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 # 密码,建议生产环境开启

@ -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 连接的示例

@ -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 配置类

Loading…
Cancel
Save