多个bug修改

master
LAPTOP-S9HJSOEB\昊天 8 months ago
parent 0fedc117bf
commit d85fb7522d

@ -103,6 +103,13 @@ public class StockController {
EChartsOption bars = stockService.laneInventoryStatistics();
return success(bars);
}
@PostMapping("/laneInventoryStatisticsPie")
@Operation(summary = "首页巷道盘点统计")
@PreAuthorize("@ss.hasPermission('logistics:order:laneInventoryStatistics')")
public CommonResult< List<Map<String,String>> > laneInventoryStatisticsPie() {
List<Map<String,String>> bars = stockService.laneInventoryStatisticsPie();
return success(bars);
}
@Resource
private DictDataService dictDataService;

@ -16,19 +16,26 @@ 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.rfid.RfidService;
import cn.iocoder.yudao.module.camera.service.sensorgun.SensorGunService;
import cn.iocoder.yudao.module.camera.service.street.StreetService;
import cn.iocoder.yudao.module.camera.util.NetworkUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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 lombok.extern.slf4j.Slf4j;
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.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@ -37,6 +44,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@RestController
@RequestMapping("/logistics/street")
@Validated
@Slf4j
public class StreetController {
@Resource
@ -45,6 +53,7 @@ public class StreetController {
private LightSourceService lightSourceService;
@PostMapping("/create")
@Operation(summary = "创建巷道")
@PreAuthorize("@ss.hasPermission('logistics:street:create')")
@ -79,6 +88,65 @@ public class StreetController {
streetService.getCameraName(streetRespVO);
return success(streetRespVO);
}
@Resource
SensorGunService sensorGunService;
@Resource
RfidService rfidService;
@GetMapping("/linkCheck")
@Operation(summary = "巷道状态查询")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('logistics:street:linkCheck')")
public CommonResult<List<NetworkUtil> > linkCheck(@RequestParam("id") Integer id) {
// 使用try-with-resources确保线程池正确关闭
try (ExecutorService executorService = Executors.newFixedThreadPool(10)) {
List<CompletableFuture<NetworkUtil>> futures = new ArrayList<>();
StreetDO street = streetService.getById(id);
List<NetworkUtil> networkUtilList = new ArrayList<>();
// 异步检查PLC网络可达性
futures.add(CompletableFuture.supplyAsync(() ->
new NetworkUtil().isReachable(street.getPlcIp(), street.getPlcPort(), "plc"), executorService));
// 异步检查扫码枪网络可达性
List<SensorGunDO> sensorGunDOList = sensorGunService.list(new QueryWrapper<SensorGunDO>().eq("street_id", id));
for (SensorGunDO sensorGunDO : sensorGunDOList) {
futures.add(CompletableFuture.supplyAsync(() ->
new NetworkUtil().isReachable(sensorGunDO.getIp(), sensorGunDO.getPort(), "扫码枪"), executorService));
}
// 异步检查RFID网络可达性
List<RfidDO> rfidDOList = rfidService.list(new QueryWrapper<RfidDO>().eq("street_id", id));
for (RfidDO rfidDO : rfidDOList) {
futures.add(CompletableFuture.supplyAsync(() ->
new NetworkUtil().isReachable(rfidDO.getIp(), rfidDO.getPort(), "RFID"), executorService));
}
// 异步检查光源网络可达性
List<LightSourceDO> lightSourceDOList = lightSourceService.list(new QueryWrapper<LightSourceDO>().eq("street_id", id));
for (LightSourceDO lightSourceDO : lightSourceDOList) {
futures.add(CompletableFuture.supplyAsync(() ->
new NetworkUtil().isReachable(lightSourceDO.getIp(), Integer.valueOf(lightSourceDO.getPort()), "光源"), executorService));
}
// 等待所有异步任务完成并收集结果
for (CompletableFuture<NetworkUtil> future : futures) {
try {
// 设置超时时间,避免长时间等待
networkUtilList.add(future.get(5, TimeUnit.SECONDS));
} catch (InterruptedException | ExecutionException | TimeoutException e) {
log.error("网络可达性检查异常", e);
}
}
return success(networkUtilList);
} catch (Exception e) {
log.error("执行网络检查时发生错误", e);
return success(new ArrayList<>());
}
}
@GetMapping("/page")
@Operation(summary = "获得巷道分页")

@ -2,10 +2,7 @@ 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.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.*;
import lombok.*;
import org.glassfish.jaxb.core.v2.TODO;
@ -83,6 +80,8 @@ public class CheckLogDO extends BaseDO {
* {@link TODO check_status }
*/
private Integer status;
@TableField(exist = false)
private String statusName;
/**
*
*/

@ -33,6 +33,7 @@ public class OrderDO extends BaseDO {
private String cmdName ;
private String taskId ;
private String shelfCode;
private String uuid ;
private int fromSide ;
private int fromDirection ;
private int fromColumn ;

@ -9,7 +9,7 @@ import java.util.List;
public class Axis {
private String type = "value";
private boolean boundaryGap = true;
private int interval= 1; // 设置步长为 1
private int splitNumber =5;
private int minInterval= 1; // 设置步长为 1
// private int splitNumber =5;
private List<String> data = new ArrayList<>();
}

@ -16,12 +16,12 @@ import org.apache.ibatis.annotations.Mapper;
public interface CheckLogMapper extends BaseMapperX<CheckLogDO> {
default PageResult<CheckLogDO> selectPage(CheckLogPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<CheckLogDO>()
.eqIfPresent(CheckLogDO::getBatchNumber, reqVO.getBatchNumber())
.likeIfPresent(CheckLogDO::getBatchNumber, reqVO.getBatchNumber())
.eqIfPresent(CheckLogDO::getRow, reqVO.getRow())
.eqIfPresent(CheckLogDO::getColumn, reqVO.getColumn())
.eqIfPresent(CheckLogDO::getStreetId, reqVO.getStreetId())
.betweenIfPresent(CheckLogDO::getExportTime, reqVO.getExportTime())
.eqIfPresent(CheckLogDO::getTaskId, reqVO.getTaskId())
.likeIfPresent(CheckLogDO::getTaskId, reqVO.getTaskId())
.eqIfPresent(CheckLogDO::getDirection, reqVO.getDirection())
.eqIfPresent(CheckLogDO::getSide, reqVO.getSide())
.eqIfPresent(CheckLogDO::getStatus, reqVO.getStatus())

@ -19,7 +19,7 @@ public interface OrderMapper extends BaseMapperX<OrderDO> {
.betweenIfPresent(OrderDO::getStartTime, reqVO.getStartTime())
.betweenIfPresent(OrderDO::getEndTime, reqVO.getEndTime())
.eqIfPresent(OrderDO::getSrmNumber, reqVO.getSrmNumber())
.eqIfPresent(OrderDO::getTaskId, reqVO.getTaskId())
.likeIfPresent(OrderDO::getTaskId, reqVO.getTaskId())
.eqIfPresent(OrderDO::getFromDirection, reqVO.getFromDirection())
.eqIfPresent(OrderDO::getFromColumn, reqVO.getFromColumn())
.eqIfPresent(OrderDO::getFromRow, reqVO.getFromRow())

@ -100,6 +100,7 @@ public class HikFlaskApiService implements ScanService {
System.out.println("Unexpected code " + response);
String responseBody = Objects.requireNonNull(response.body()).string();
log.info("picComputeAll:{}",responseBody);
return gson.fromJson(responseBody, HikPythonEntity.class);
}catch (Exception e){
log.error("Error occurred while calling /api/picComputeAll", e);
@ -146,12 +147,19 @@ public class HikFlaskApiService implements ScanService {
try {
scanData.setCode("缺件");
HikPythonEntity hikPythonEntity = picComputeAll(stockDO.getWmsItemCode(),urlPath);
System.out.println(hikPythonEntity);
for (int i = 0; i < 4; i++){
if (hikPythonEntity.getColors()==null|| hikPythonEntity.getColors().size()==0){
hikPythonEntity = picComputeAll(stockDO.getWmsItemCode(),urlPath);
}
}
log.info("hik3d拍照结果"+hikPythonEntity.toString());
if (hikPythonEntity != null && !hikPythonEntity.getStatus().equals("ERROR")){
if (hikPythonEntity.getLack()!= null && hikPythonEntity.getLack()) {
}else {
scanData.setCode("正常");
scanData.setCode( "正常");
log.info("taskId"+stockDO.getTaskId()+" hik3d拍照结果"+hikPythonEntity.toString());
}
if (hikPythonEntity.getColors() != null && hikPythonEntity.getColors().size() > 0) {
for (String color:hikPythonEntity.getColors()){

@ -10,6 +10,8 @@ import cn.iocoder.yudao.module.camera.dal.dataobject.street.StreetDO;
import cn.iocoder.yudao.module.camera.dal.mysql.checklog.CheckLogMapper;
import cn.iocoder.yudao.module.camera.service.resources.URLResourcesService;
import cn.iocoder.yudao.module.camera.service.street.StreetService;
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
import cn.iocoder.yudao.module.system.service.dict.DictDataService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import de.danielbechler.util.Strings;
@ -81,11 +83,14 @@ public class CheckLogServiceImpl extends ServiceImpl<CheckLogMapper, CheckLogDO>
.le(Strings.hasText(endTime),"create_time",endTime));
}
@Resource
DictDataService dictDataService;
@Resource
private URLResourcesService urlResourcesService;
@Override
public PageResult<CheckLogDO> getCheckLogPage(CheckLogPageReqVO pageReqVO) {
List<StreetDO> streetDOS = streetService.list();
Map<String,DictDataDO> dict = dictDataService.getDictValueMap("check_status");
PageResult<CheckLogDO> checkLogDOPageResult = checkLogMapper.selectPage(pageReqVO);
Map<Integer,String> streetMap = streetDOS.stream().collect(Collectors.toMap(StreetDO::getId,StreetDO::getName));
@ -93,6 +98,7 @@ public class CheckLogServiceImpl extends ServiceImpl<CheckLogMapper, CheckLogDO>
for (CheckLogDO checkLogDO : checkLogDOPageResult.getList()){
List<URLResourcesDo> urlResources = urlResourcesService.list(new QueryWrapper<URLResourcesDo>().eq("uuid", checkLogDO.getPic()));
checkLogDO.setUrlResources(urlResources);
checkLogDO.setStatusName(dict.get(checkLogDO.getStatus().toString()).getLabel());
checkLogDO.setStreetName(streetMap.get(checkLogDO.getStreetId()));
}
return checkLogDOPageResult;

@ -147,10 +147,12 @@ public class OrderServiceImpl implements OrderService {
Map<String,Long> stocksMap = orderDOS.stream().collect(Collectors.groupingBy(OrderDO::getSrmNumber,Collectors.counting()));
List<Long> data = new ArrayList<>();
xAxis.setData(new ArrayList<>());
int max = 0;
// 遍历街道列表为X轴添加类别数据并收集对应的数据到数据序列中
for (StreetDO street : streets) {
xAxis.getData().add(street.getName());
data.add(stocksMap.get(street.getPlcId()));
}
series.setData(data);
seriesList.add(series);
@ -162,6 +164,7 @@ public class OrderServiceImpl implements OrderService {
// 将数据序列添加到系列列表中
eChartsOption.setSeries(seriesList);
// eChartsOption.getYAxis().setSplitNumber(eChartsOption.setsSplitNumber());
return eChartsOption;
}
@ -216,6 +219,7 @@ public class OrderServiceImpl implements OrderService {
legend.setData(legendDate);
eChartsOption.setLegend(legend);
eChartsOption.setSeries(seriesList);
// yAxis.setSplitNumber(eChartsOption.setsSplitNumber());
return eChartsOption;
}

@ -49,7 +49,6 @@ import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@ -97,10 +96,15 @@ public class PLCServiceImpl implements PLCService {
public void gyrateCameraByCode(CameraDO cameraDO, String code) {
Integer ptzId = cameraIoService.getOne(new QueryWrapper<CameraIoDO>()
CameraIoDO cameraIoDO = cameraIoService.getOne(new QueryWrapper<CameraIoDO>()
.eq("camera_Id", cameraDO.getId())
.eq("code", code)
.last(" limit 1")).getPtzId();
.last(" limit 1"));
if (cameraIoDO == null){
log.error("ptz not found in sql,code{},cameraId:{}", code, cameraDO.getId());
return;
}
Integer ptzId = cameraIoDO.getPtzId();
if (ptzId != null && ptzId >= 0) {
@ -288,6 +292,7 @@ public class PLCServiceImpl implements PLCService {
String pathSrc = PathUtil.createFileName(dataInfoData, street, picCmd, ".jpg");
pathSrc = cameraCapture(camera, true, pathSrc, dictDataService.getDictDataList("camera_conf"));
urlResourcesService.save(URLResourcesDo.builder().url(saveApiPath + pathSrc).uuid(order.getUuid()).type("1").little("球机拍照").build());
order.setPics(Strings.hasText(order.getPics()) ? order.getPics() + ";" + saveApiPath + pathSrc : saveApiPath + pathSrc);
orderMapper.updateById(order);
}
@ -301,7 +306,6 @@ public class PLCServiceImpl implements PLCService {
ScanServiceFactory scanServiceFactory;
ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
// 设置线程最大执行时间,单位为毫秒
long timeout = 5000;
@ -367,8 +371,13 @@ public class PLCServiceImpl implements PLCService {
stock.setCheckPic(uuid);
//拍照记录
String pathSrc = PathUtil.createFileName(dataInfo, street, "E1", ".jpg");
CameraDO camera = cameraService.getById(dataInfo.getFromDirection() == 1 ? street.getCamera1Id() : street.getCamera2Id());
pathSrc = cameraCapture(camera, false, pathSrc, dictDataService.getDictDataList("camera_conf"));
// 旋转预置点位
// 判断巷道有几个相机 如果只有一个,则调用一个,如果是两个,先判断是否有对拍设置决定那个相机拍摄
CameraDO camera = getCameraByLeftRight(street, stock.getDirection());
// 调用预置点位 开始则调用E1
gyrateCameraByCode(camera, "E1");
pathSrc = cameraCapture(camera, true, pathSrc, dictDataService.getDictDataList("camera_conf"));
urlResourcesService.save(URLResourcesDo.builder().url(saveApiPath + pathSrc).uuid(uuid).type("1").little("球机拍照").build());
// 先记录正常未盘点情况
@ -397,8 +406,19 @@ public class PLCServiceImpl implements PLCService {
StockDO stock = stockService.getOne(
new QueryWrapper<StockDO>()
.eq("task_id", taskId)
.last("limit 1")
);
if (stock == null) {
log.error("taskId:{}不存在", taskId);
return;
}
StreetDO street = streetService.getById(stock.getStreetId());
// 旋转预置点位
// 判断巷道有几个相机 如果只有一个,则调用一个,如果是两个,先判断是否有对拍设置决定那个相机拍摄
CameraDO camera = getCameraByLeftRight(street, stock.getDirection());
// 调用预置点位
gyrateCameraByCode(camera, cmd);
for (String scanType : scanTypes) {
DictDataDO dictDataDO = dictDataList.get(scanType);
ScanData scanData = scanServiceFactory.scan(dictDataDO.getValue(), street, stock);
@ -436,6 +456,8 @@ public class PLCServiceImpl implements PLCService {
StockDO stock = stockService.getOne(
new QueryWrapper<StockDO>()
.eq("task_id", taskId)
.orderByDesc("export_time")
.last("limit 1")
);
if (stock == null) {
log.error("taskId:{}不存在", taskId);
@ -541,6 +563,9 @@ public class PLCServiceImpl implements PLCService {
if (street != null) {
OrderDO order = new OrderDO();
String uuid = UUID.randomUUID().toString();
order.setUuid(uuid);
order.setTaskId(kescEntity.getTaskId());
order.setCreateTime(LocalDateTime.now());
@ -566,11 +591,9 @@ public class PLCServiceImpl implements PLCService {
String path = zLMediaKitService.startRecord("live", street.getCamera1Id().toString());
// String path = cameraVideo(street.getCamera1Id(), pathSrc, order.getCreateTime(), endDownLoadTime, dictDataList);
order.setVideoPath1(path);
}
if (street.getCamera2Id() != null) {
String path = zLMediaKitService.startRecord("live", street.getCamera2Id().toString());
order.setVideoPath2(path);
}
orderMapper.insert(order);
@ -611,13 +634,26 @@ public class PLCServiceImpl implements PLCService {
if (street.getCamera1Id() != null) {
for (int i = 0; i < 5; i++) {
zLMediaKitService.stopRecord("live", street.getCamera1Id().toString());
String path = zLMediaKitService.stopRecord("live", street.getCamera1Id().toString(),order.getStartTime());
if (!path.equals("")){
urlResourcesService.save(URLResourcesDo.builder().url(path).uuid(order.getUuid()).type("2").little("随行视频").build());
order.setVideoPath1(path);
break;
}
}
// String path = cameraVideo(street.getCamera1Id(), pathSrc, order.getCreateTime(), endDownLoadTime, dictDataList);
}
if (street.getCamera2Id() != null) {
zLMediaKitService.stopRecord("live", street.getCamera2Id().toString());
for (int i = 0; i < 5; i++) {
String path = zLMediaKitService.stopRecord("live", street.getCamera2Id().toString(),order.getStartTime());
if (!path.equals("")){
urlResourcesService.save(URLResourcesDo.builder().url(path).uuid(order.getUuid()).type("2").little("随行视频").build());
order.setVideoPath2(path);
break;
}
}
}

@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.camera.controller.admin.rfid.vo.RfidPageReqVO;
import cn.iocoder.yudao.module.camera.controller.admin.rfid.vo.RfidSaveReqVO;
import cn.iocoder.yudao.module.camera.dal.dataobject.rfid.RfidDO;
import com.baomidou.mybatisplus.extension.service.IService;
import jakarta.validation.Valid;
/**
@ -11,7 +12,7 @@ import jakarta.validation.Valid;
*
* @author
*/
public interface RfidService {
public interface RfidService extends IService< RfidDO> {
/**
* RFID

@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.camera.controller.admin.rfid.vo.RfidPageReqVO;
import cn.iocoder.yudao.module.camera.controller.admin.rfid.vo.RfidSaveReqVO;
import cn.iocoder.yudao.module.camera.dal.dataobject.rfid.RfidDO;
import cn.iocoder.yudao.module.camera.dal.mysql.rfid.RfidMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
@ -20,8 +21,7 @@ import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.RFID_NOT_EX
*/
@Service
@Validated
public class RfidServiceImpl implements RfidService {
public class RfidServiceImpl extends ServiceImpl<RfidMapper, RfidDO> implements RfidService {
@Resource
private RfidMapper rfidMapper;

@ -9,6 +9,9 @@ import cn.iocoder.yudao.module.camera.dal.entity.echarts.EChartsOption;
import com.baomidou.mybatisplus.extension.service.IService;
import jakarta.validation.Valid;
import java.util.List;
import java.util.Map;
/**
* Service
*
@ -57,4 +60,5 @@ public interface StockService extends IService< StockDO> {
StockStreetList getStreetList(StockStreetList stockSaveReqVO);
EChartsOption laneInventoryStatistics();
List<Map<String,String>> laneInventoryStatisticsPie();
}

@ -5,10 +5,14 @@ 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.*;
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.stock.StockMapper;
import cn.iocoder.yudao.module.camera.service.checklog.CheckLogService;
import cn.iocoder.yudao.module.camera.service.street.StreetService;
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
import cn.iocoder.yudao.module.system.service.dict.DictDataService;
@ -19,6 +23,7 @@ import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@ -98,6 +103,8 @@ public class StockServiceImpl extends ServiceImpl<StockMapper,StockDO> implement
return stockStreetList;
}
@Resource
CheckLogService checkLogService;
@Resource
private DictDataService dictDataService;
@Override
@ -106,8 +113,9 @@ public class StockServiceImpl extends ServiceImpl<StockMapper,StockDO> implement
eChartsOption.setXAxis(new Axis());
List<Series> bars = new ArrayList<>();
List<StreetDO> streets = streetService.list();
List<StockDO> stocks = list();
Map<String,Map<Integer,Long>> stocksMap = stocks.stream().collect(Collectors.groupingBy(StockDO::getStatus,Collectors.groupingBy(StockDO::getStreetId,Collectors.counting())));
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())));
Map<String, DictDataDO> dictDataMap = dictDataService.getDictDataList("check_status");
Axis yAxis = new Axis();
yAxis.setType("category");
@ -116,6 +124,7 @@ 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);
@ -127,10 +136,8 @@ public class StockServiceImpl extends ServiceImpl<StockMapper,StockDO> implement
// 盘点异常
case 1 -> bar.setColor("#ec6464");
// 盘点正确
case 2 -> bar.setColor("#94cc74");
// 人工核对正确
case 3 -> bar.setColor("#5474c4");
default -> bar.setColor("");
@ -140,14 +147,37 @@ public class StockServiceImpl extends ServiceImpl<StockMapper,StockDO> implement
if (stocksMap.get(dictDataMap.get(entry).getValue())==null){
values.add(null);
}else values.add(stocksMap.get(dictDataMap.get(entry).getValue()).get(street.getId()));
}
bar.setData(values);
bars.add(bar);
}
eChartsOption.setSeries(bars);
// eChartsOption.getXAxis().setSplitNumber(eChartsOption.setsSplitNumber());
return eChartsOption;
}
@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())));
Map<String, DictDataDO> dictDataMap = dictDataService.getDictValueMap("check_status");
List<Map<String,String>> list = new ArrayList<>();
for (String key :stocksMap.keySet()){
Map<String,String> map = new HashMap<>();
map.put("name",dictDataMap.get(key).getLabel());
map.put("value",stocksMap.get(key).toString());
list.add(map);
}
return list;
}
}

@ -1,13 +1,13 @@
package cn.iocoder.yudao.module.camera.service.streamingMedia;
import cn.iocoder.yudao.module.camera.dal.dataobject.camera.CameraDO;
import cn.iocoder.yudao.module.camera.dal.zlm.RtspSessionResponse;
import java.time.LocalDateTime;
import java.util.List;
public interface ZLMediaKitService {
String startRecord(String app, String stream);
RtspSessionResponse stopRecord(String app, String stream);
String stopRecord(String app, String stream, LocalDateTime path);
void addRtspProxy(CameraDO camera, String zlmApiUrl, String zlmApiSecret);
void pic(CameraDO camera, String zlmApiUrl);
void zlmConf( List<CameraDO> list);

@ -19,7 +19,10 @@ import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
@ -43,15 +46,17 @@ public class ZLMediaKitServiceImpl implements ZLMediaKitService{
@Override
public String
startRecord(String app, String cameraId) {
public String startRecord(String app, String cameraId) {
String zlmApiSecret = dictDataService.parseDictData("ZLMediaKit_conf", "secret").getValue();
String mp4SavePath = dictDataService.parseDictData("ZLMediaKit_conf", "mp4SavePath").getValue();
Map<String, Object> addParams = new HashMap<>();
addParams.put("secret", zlmApiSecret);
addParams.put("type", "1");//0为hls1为mp4
addParams.put("vhost", "__defaultVhost__");
addParams.put("app", "live");
addParams.put("customized_path", mp4SavePath);
addParams.put("stream","camera"+ cameraId);
// addParams.put("url", CameraChannel.getRtspUrl(camera.getIp(), camera.getRtspPort(), camera.getChannel(), camera.getUser(), camera.getPassword(),camera.getType()));
// sendHttp(addParams, "startRecord");
@ -67,7 +72,7 @@ public class ZLMediaKitServiceImpl implements ZLMediaKitService{
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Runnable task = () -> {
stopRecord(app,cameraId);
stopRecord(app,cameraId,LocalDateTime.now());
};
@ -77,6 +82,62 @@ public class ZLMediaKitServiceImpl implements ZLMediaKitService{
return path;
}
// 检查指定文件夹中最新的文件名,且文件修改时间在指定时间之后
public String getLatestFileNameAfterTime(String directoryPath, LocalDateTime afterTime) {
try {
Path directory = Paths.get(directoryPath);
// 将LocalDateTime转换为Instant用于比较
Instant afterInstant = afterTime.atZone(ZoneId.systemDefault()).toInstant();
// 获取目录下所有文件
try (Stream<Path> paths = Files.list(directory)) {
return paths
.filter(Files::isRegularFile) // 只考虑文件
.filter(path -> {
try {
// 获取文件最后修改时间
Instant lastModified = Files.getLastModifiedTime(path).toInstant();
// 筛选修改时间在指定时间之后的文件
return lastModified.isAfter(afterInstant);
} catch (IOException e) {
log.error("获取文件修改时间失败: {}", e.getMessage());
return false;
}
})
.max((path1, path2) -> {
try {
// 按最后修改时间比较
Instant time1 = Files.getLastModifiedTime(path1).toInstant();
Instant time2 = Files.getLastModifiedTime(path2).toInstant();
return time1.compareTo(time2);
} catch (IOException e) {
log.error("比较文件修改时间失败: {}", e.getMessage());
return 0;
}
})
.map(path -> path.getFileName().toString()) // 提取文件名
.orElse(""); // 如果没有符合条件的文件,返回空字符串
}
} catch (IOException e) {
log.error("读取目录失败: {}", e.getMessage());
return "";
}
}
// 检查摄像头目录中最新的文件名,且文件修改时间在指定时间之后
public String getLatestCameraFileNameAfterTime(String app, String cameraId, LocalDateTime afterTime) {
String mp4SavePath = dictDataService.parseDictData("ZLMediaKit_conf", "mp4SavePath").getValue();
String mp4SaveApi = dictDataService.parseDictData("ZLMediaKit_conf", "mp4SaveApi").getValue();
// 获取当前日期
LocalDate currentDate = LocalDate.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String formattedDate = currentDate.format(formatter);
String directoryPath = mp4SavePath + "record/" + app + "/" + cameraId + "/" + formattedDate;
String mp4SaveApiPath = mp4SaveApi + "record/" + app + "/" + cameraId + "/" + formattedDate + "/";
return mp4SaveApiPath + getLatestFileNameAfterTime(directoryPath, afterTime);
}
// 新增方法:检查指定文件夹下是否有以.为开头的文件
public String checkHiddenFilesInDirectory(String app, String cameraId) {
@ -113,6 +174,43 @@ public class ZLMediaKitServiceImpl implements ZLMediaKitService{
return "";
}
// 新增方法:检查指定文件夹下是否有以.为开头的文件
public String checkAndRenameFile(String app, String cameraId,String filePath) {
String mp4SavePath = dictDataService.parseDictData("ZLMediaKit_conf", "mp4SavePath").getValue();
// mp4SaveApi
String mp4SaveApi = dictDataService.parseDictData("ZLMediaKit_conf", "mp4SaveApi").getValue();
// 获取当前日期
LocalDate currentDate = LocalDate.now();
// 定义日期格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
// 格式化日期
String formattedDate = currentDate.format(formatter);
// 构建完整路径
String fullPath = mp4SavePath + "record/" + app + "/camera" + cameraId + "/" + formattedDate + "/." + filePath;
String renamedPath = mp4SavePath + "record/" + app + "/camera" + cameraId + "/" + formattedDate + "/" + filePath;
// 构建访问路径
String accessPath = mp4SaveApi + "record/" + app + "/camera" + cameraId + "/" + formattedDate + "/" + filePath;
try {
Path originalFilePath = Paths.get(fullPath);
// 检查带点的文件是否存在
if (Files.exists(originalFilePath)) {
// 重命名为去掉点的文件名
Path newFilePath = Paths.get(renamedPath);
Files.move(originalFilePath, newFilePath);
return accessPath;
}
} catch (IOException e) {
log.error("文件重命名失败: {}", e.getMessage());
}
return "";
}
/**
* ZLMediaKitgetSnap
*
@ -155,9 +253,6 @@ public class ZLMediaKitServiceImpl implements ZLMediaKitService{
log.info("截图保存成功: {}", savePath);
// 返回访问路径(根据你的需求调整)
String mp4SaveApi = dictDataService.parseDictData("ZLMediaKit_conf", "mp4SaveApi").getValue();
} else {
log.error("获取截图失败HTTP状态码: {}", response.code());
@ -179,7 +274,7 @@ public class ZLMediaKitServiceImpl implements ZLMediaKitService{
return input;
}
@Override
public RtspSessionResponse stopRecord(String app, String stream) {
public String stopRecord(String app, String stream ,LocalDateTime time) {
String zlmApiSecret = dictDataService.parseDictData("ZLMediaKit_conf", "secret").getValue();
Map<String, Object> addParams = new HashMap<>();
@ -190,9 +285,15 @@ public class ZLMediaKitServiceImpl implements ZLMediaKitService{
addParams.put("stream","camera"+ stream);
// addParams.put("url", CameraChannel.getRtspUrl(camera.getIp(), camera.getRtspPort(), camera.getChannel(), camera.getUser(), camera.getPassword(),camera.getType()));
RtspSessionResponse rtspSessionResponse = sendHttp(addParams, "stopRecord");
return rtspSessionResponse;
if (rtspSessionResponse!=null && rtspSessionResponse.isResult()){
String fileName = getLatestCameraFileNameAfterTime(app, "camera"+stream, time.minusSeconds(10));
return fileName;
}else {
return "";
}
}
@Override
public void zlmConf( List<CameraDO> list) {

@ -0,0 +1,248 @@
package cn.iocoder.yudao.module.camera.util;
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
import cn.iocoder.yudao.module.system.service.dict.DictDataService;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Comparator;
import java.util.Map;
@Slf4j
@Component
public class DiskSpaceManager {
// 日期格式化器
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
/**
*
* @param driveLetter
* @param diskUsageThreshold 使
* @param minFreeSpace
* @return
*/
public static boolean checkDiskSpace(String driveLetter,double diskUsageThreshold,long minFreeSpace) {
try {
// 方法2: 使用FileStore类更精确
Path path = Paths.get(driveLetter + "/");
FileStore store = Files.getFileStore(path);
long totalSpace2 = store.getTotalSpace();
long usableSpace2 = store.getUsableSpace();
long unallocatedSpace = store.getUnallocatedSpace();
minFreeSpace = minFreeSpace * 1024 * 1024 * 1024;
log.info("驱动器: " + driveLetter);
log.info("总空间: " + formatBytes(totalSpace2));
log.info("可用空间: " + formatBytes(usableSpace2));
log.info("未分配空间: " + formatBytes(unallocatedSpace));
log.info("已用空间: " + formatBytes(totalSpace2 - usableSpace2));
log.info("使用率: " + String.format("%.2f%%", (double)(totalSpace2 - usableSpace2) / totalSpace2 * 100));
if ((double)(totalSpace2 - usableSpace2)/ totalSpace2> diskUsageThreshold || minFreeSpace>unallocatedSpace) {
return true;
}else return false;
} catch (Exception e) {
System.err.println("查询磁盘空间时发生错误: " + e.getMessage());
e.printStackTrace();
}
return false;
}
/**
*
* @param bytes
* @return
*/
private static String formatBytes(long bytes) {
if (bytes < 1024) return bytes + " B";
if (bytes < 1024 * 1024) return String.format("%.2f KB", bytes / 1024.0);
if (bytes < 1024 * 1024 * 1024) return String.format("%.2f MB", bytes / (1024.0 * 1024));
if (bytes < 1024L * 1024 * 1024 * 1024) return String.format("%.2f GB", bytes / (1024.0 * 1024 * 1024));
return String.format("%.2f TB", bytes / (1024.0 * 1024 * 1024 * 1024));
}
@Resource
DictDataService dictDataService;
/**
*
*/
@Scheduled(cron = "0 3 0 * * ? " ) // 每5分钟检查一次
@PostConstruct
public void checkAndCleanSpace() {
Map<String, DictDataDO> dictDataMap = dictDataService.getDictDataList("base_conf");
// 检查是否需要清理空间
for (int i = Integer.parseInt(dictDataMap.get("max_retention_days").getValue()); i > Integer.parseInt(dictDataMap.get("min_retention_days").getValue()); i--){
deleteFoldersByDaysAgo(i,dictDataMap);
if (!(checkDiskSpace(dictDataMap.get("base_path").getValue()
,Double.parseDouble(dictDataMap.get("disk_usage_threshold").getValue())
,Long.parseLong(dictDataMap.get("min_free_space").getValue())))){
break;
}
}
}// ... existing code ...
/**
*
* @param daysAgo 3030
* @return
*/
public int deleteFoldersByDaysAgo(int daysAgo,Map<String, DictDataDO> dictDataMap) {
LocalDate targetDate = LocalDate.now().minusDays(daysAgo);
String targetDateStr = targetDate.format(DATE_FORMATTER);
String[] monitoredFolders = dictDataMap.get("monitored_folders").getValue().split(",");
log.info("开始删除 {} 天前的文件夹,日期: {}", daysAgo, targetDateStr);
int deletedCount = 0;
for (String monitoredFolder : monitoredFolders) {
try {
File parentFolder = new File(monitoredFolder);
if (!parentFolder.exists() || !parentFolder.isDirectory()) {
continue;
}
// 递归查找并删除所有匹配日期的文件夹
deletedCount += deleteFoldersRecursively(parentFolder, targetDateStr);
} catch (Exception e) {
log.error("处理监控文件夹时发生错误: {}", monitoredFolder, e);
}
}
log.info("删除 {} 天前文件夹完成,共删除 {} 个文件夹", daysAgo, deletedCount);
return deletedCount;
}
// ... existing code ...
/**
*
* @param parentFolder
* @param targetDateStr
* @return
*/
private int deleteFoldersRecursively(File parentFolder, String targetDateStr) {
int deletedCount = 0;
File[] files = parentFolder.listFiles();
if (files == null) {
return deletedCount;
}
for (File file : files) {
if (file.isDirectory()) {
// 如果文件夹名称匹配目标日期,则删除
if (file.getName().equals(targetDateStr)) {
try {
long folderSize = getFolderSize(file.getAbsolutePath());
fastDeleteFolder(file.getAbsolutePath());
deletedCount++;
log.info("快速删除文件夹: {}, 日期: {}, 释放空间: {} MB",
file.getAbsolutePath(),
targetDateStr,
folderSize / (1024.0 * 1024));
} catch (IOException e) {
log.error("快速删除文件夹失败: {}", file.getAbsolutePath(), e);
}
}
// 递归处理子目录
deletedCount += deleteFoldersRecursively(file, targetDateStr);
}
}
return deletedCount;
}
/**
*
* @param folderPath
* @throws IOException IO
*/
private void fastDeleteFolder(String folderPath) throws IOException {
Path folder = Paths.get(folderPath);
if (!Files.exists(folder)) {
return;
}
// 使用并行流加速删除过程
try (java.util.stream.Stream<Path> walk = Files.walk(folder)) {
walk.parallel()
.sorted(Comparator.reverseOrder()) // 先删除文件,再删除目录
.forEach(path -> {
try {
Files.deleteIfExists(path);
} catch (IOException e) {
log.warn("删除文件/文件夹失败: {}", path, e);
}
});
}
}
/**
*
* @param daysAgo
* @return yyyy-MM-dd
*/
public String generateDateStr(int daysAgo) {
LocalDate targetDate = LocalDate.now().minusDays(daysAgo);
return targetDate.format(DATE_FORMATTER);
}
/**
*
* @param dateStr (yyyy-MM-dd)
* @return
*/
/**
*
* @param folderPath
* @return ()
* @throws IOException IO
*/
private long getFolderSize(String folderPath) throws IOException {
Path folder = Paths.get(folderPath);
if (!Files.exists(folder)) {
return 0;
}
final long[] size = {0};
Files.walkFileTree(folder, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
size[0] += attrs.size();
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
return FileVisitResult.CONTINUE;
}
});
return size[0];
}
// ... existing code ...
}

@ -0,0 +1,99 @@
package cn.iocoder.yudao.module.camera.util;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class NetworkUtil {
private String ip;
private Integer port;
private String type;
private boolean isConnect = false;
/**
*
* @param ip IP
* @param port nullping
* @return
*/
public static NetworkUtil isReachable(String ip, Integer port,String type){
NetworkUtil networkUtil = isReachable(ip, port,2000);
networkUtil.setType(type);
return networkUtil;
}
/**
*
* @param ip IP
* @param port nullping
* @param timeout
* @return
*/
public static NetworkUtil isReachable(String ip, Integer port, int timeout) {
NetworkUtil networkUtil = new NetworkUtil();
networkUtil.ip = ip;
networkUtil.port = port;
boolean isReachable = false;
if (ip == null || ip.isEmpty()) {
isReachable = false;
}
try {
// 如果端口为空只进行ping测试
if (port == null) {
InetAddress address = InetAddress.getByName(ip);
isReachable = address.isReachable(timeout);
} else {
// 如果端口不为空,进行端口连通性测试
try (Socket socket = new Socket()) {
socket.connect(new InetSocketAddress(ip, port), timeout);
isReachable = true;
} catch (Exception e) {
isReachable = false;
}
}
} catch (Exception e) {
isReachable = false;
}
networkUtil.setConnect(isReachable);
return networkUtil;
}
/**
* IPping
* @param ip IP
* @param timeout
* @return ping
*/
public static boolean isPingable(String ip, int timeout) {
try {
InetAddress address = InetAddress.getByName(ip);
return address.isReachable(timeout);
} catch (IOException e) {
return false;
}
}
/**
*
* @param ip IP
* @param port
* @param timeout
* @return
*/
public static boolean isPortOpen(String ip, int port, int timeout) {
try (Socket socket = new Socket()) {
socket.connect(new InetSocketAddress(ip, port), timeout);
return true;
} catch (IOException e) {
return false;
}
}
}

@ -55,6 +55,14 @@ spring:
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
data:
redis:
lettuce:
pool:
max-active: 100 # 增加最大连接数
max-idle: 50 # 增加最大空闲连接数
min-idle: 10 # 增加最小空闲连接数
max-wait: 5000ms # 增加获取连接的最大等待时间
shutdown-timeout: 1000ms # 增加关闭超时时间
timeout: 5000ms # 增加连接超时时间
host: 127.0.0.1 # 地址
port: 6379 # 端口
database: 1 # 数据库索引

@ -1,5 +1,5 @@
server:
port: 48080
port: 48081
--- #################### 数据库相关配置 ####################
@ -46,8 +46,8 @@ spring:
primary: master
datasource:
master:
name: sy-logistics
url: jdbc:mysql://192.168.2.162:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
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://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 连接的示例
@ -55,7 +55,7 @@ spring:
# url: jdbc:dm://10.211.55.4:5236?schema=RUOYI_VUE_PRO # DM 连接的示例
username: root
password: Leaper@123
password: root
# username: sa
# password: JSm:g(*%lU4ZAkz06cd52KqT3)i1?H7W
# username: SYSDBA # DM 连接的示例
@ -76,6 +76,14 @@ spring:
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
data:
redis:
lettuce:
pool:
max-active: 100 # 增加最大连接数
max-idle: 50 # 增加最大空闲连接数
min-idle: 10 # 增加最小空闲连接数
max-wait: 5000ms # 增加获取连接的最大等待时间
shutdown-timeout: 1000ms # 增加关闭超时时间
timeout: 5000ms # 增加连接超时时间
host: 127.0.0.1 # 地址
port: 6379 # 端口
database: 0 # 数据库索引

Loading…
Cancel
Save