Compare commits

...

8 Commits

Author SHA1 Message Date
aikai
1444a079de Merge branch 'dev' of http://git.znkjfw.com/ak/zn-cloud-wcs into dev
# Conflicts:
#	yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/houselocation/HouseLocationService.java
#	yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/houselocation/HouseLocationServiceImpl.java
2025-01-16 10:35:11 +08:00
aikai
4deea77ed2 feat(system): 实现仓库点位地图节点批量操作功能
- 新增 NodeBaseDTO 类作为节点基础数据传输对象
- 实现 PositionMapItem 和 WareHouseLocation 的批量保存、编辑和删除方法
- 添加 HouseLocationStrategyImpl 类处理库位节点
- 创建 NodeProcessingContext 类协调不同类型的节点处理策略- 定义 NodeProcessingStrategy接口规范节点处理逻辑
- 更新 PositionMapItemController 支持批量操作
- 调整 PositionMapItemDO 和相关 VO 类以支持新功能
2025-01-16 10:34:04 +08:00
aikai
c593611b56 Merge branch 'dev' of http://git.znkjfw.com/ak/zn-cloud-wcs into dev 2025-01-15 16:38:28 +08:00
aikai
6bf1f7da7f 缓存配置 - xxl-job配置 - 前端AGV地图png转base64 2025-01-13 16:23:11 +08:00
aikai
edbea240f8 Merge branch 'dev' of http://git.znkjfw.com/ak/zn-cloud-wcs into aikai 2025-01-13 15:01:16 +08:00
aikai
627d5151ef 前端png文件下载改base64格式 2025-01-13 14:55:22 +08:00
aikai
e490462195 Merge branch 'dev' of http://git.znkjfw.com/ak/zn-cloud-wcs into aikai 2025-01-13 14:54:47 +08:00
aikai
eb580beee0 前端png文件下载改base64格式 2025-01-13 14:54:35 +08:00
21 changed files with 319 additions and 139 deletions

View File

@ -207,4 +207,5 @@ public interface ErrorCodeConstants {
ErrorCode AGV_FILE_UPLOAD_CONTENT_IS_EMPTY = new ErrorCode(1_002_038_002, "AGV文件上传内容为空");
ErrorCode PLEASE_UPLOAD_PNG_AND_YAML_FILES = new ErrorCode(1_002_038_003, "请上传png和yaml两个文件并且文件内容不为空");
ErrorCode AGV_MAP_NOT_FOUND = new ErrorCode(1_002_038_004, "找不到AGV地图信息");
ErrorCode AGV_IMAGE_CONVERSION_TO_BASE64_FAILED = new ErrorCode(1_002_038_005, "AGV图片转base64失败");
}

View File

@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.system;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Configuration;
/**
* 项目的启动类
@ -13,6 +15,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
* @author 芋道源码
*/
@SpringBootApplication
@EnableCaching
public class SystemServerApplication {
public static void main(String[] args) {

View File

@ -1,65 +0,0 @@
package cn.iocoder.yudao.module.system.config;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @ClassName XxlJobConfig
* @Description: xxl-job依赖配置
* @author
* @date 2022年12月07日 08:37
* @version 1.0
*/
@Configuration //是否开启xxl-job定时任务注释掉 //@Configuration 则不开启定时任务
@Data
@Slf4j
public class XxlJobConfig {
@Value("${xxl.job.admin.addresses}")
private String adminAddresses;
@Value("${xxl.job.accessToken}")
private String accessToken;
@Value("${xxl.job.executor.appname}")
private String appname;
@Value("${xxl.job.executor.address}")
private String address;
@Value("${xxl.job.executor.ip}")
private String ip;
@Value("${xxl.job.executor.port}")
private int port;
@Value("${xxl.job.executor.logpath}")
private String logPath;
@Value("${xxl.job.executor.logretentiondays}")
private int logRetentionDays;
@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
XxlJobHelper.log(">>>>>>>>>>> xxl-job config init.>>>>>>>>>>>");
System.out.println("=============== xxl-job config init.===============");
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
xxlJobSpringExecutor.setAppname(appname);
xxlJobSpringExecutor.setAddress(address);
xxlJobSpringExecutor.setIp(ip);
xxlJobSpringExecutor.setPort(port);
xxlJobSpringExecutor.setAccessToken(accessToken);
xxlJobSpringExecutor.setLogPath(logPath);
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
return xxlJobSpringExecutor;
}
}

View File

@ -81,11 +81,12 @@ public class PositionMapController {
return CommonResult.success(true);
}
@GetMapping("/downloadPng")
@GetMapping("/downloadPngBase64")
@Operation(summary = "下载png文件")
@PermitAll
public void downloadPng(@RequestParam Integer floor, @RequestParam String area, HttpServletResponse response) throws IOException {
positionMapService.downloadPng(floor, area, response);
public CommonResult<String> downloadPngBase64(@RequestParam Integer floor, @RequestParam String area) {
String base64 = positionMapService.downloadPngBase64(floor, area);
return CommonResult.success(base64);
}
@GetMapping("/download")

View File

@ -1,15 +1,17 @@
package cn.iocoder.yudao.module.system.controller.admin.positionmap;
import cn.hutool.core.collection.CollectionUtil;
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.system.controller.admin.positionmap.dto.NodeBaseDTO;
import cn.iocoder.yudao.module.system.controller.admin.positionmap.vo.PositionMapItemPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.positionmap.vo.PositionMapItemRespVO;
import cn.iocoder.yudao.module.system.controller.admin.positionmap.vo.PositionMapItemSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.positionmap.PositionMapItemDO;
import cn.iocoder.yudao.module.system.handler.mapnode.NodeProcessingContext;
import cn.iocoder.yudao.module.system.service.positionmap.PositionMapItemService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
@ -22,7 +24,10 @@ import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@ -35,28 +40,22 @@ public class PositionMapItemController {
@Resource
private PositionMapItemService positionMapItemService;
@PostMapping("/create")
@Operation(summary = "创建仓库点位地图子表")
@PreAuthorize("@ss.hasPermission('system:position-map-item:create')")
public CommonResult<Long> createPositionMapItem(@Valid @RequestBody PositionMapItemSaveReqVO createReqVO) {
return success(positionMapItemService.createPositionMapItem(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新仓库点位地图子表")
@PreAuthorize("@ss.hasPermission('system:position-map-item:update')")
public CommonResult<Boolean> updatePositionMapItem(@Valid @RequestBody PositionMapItemSaveReqVO updateReqVO) {
positionMapItemService.updatePositionMapItem(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除仓库点位地图子表")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('system:position-map-item:delete')")
public CommonResult<Boolean> deletePositionMapItem(@RequestParam("id") Long id) {
positionMapItemService.deletePositionMapItem(id);
@Resource
private NodeProcessingContext nodeProcessingContext;
// -- 前端给所有的节点信息 -
@PostMapping("/batchSaveOrEdit")
@Operation(summary = "批量新增编辑节点")
public CommonResult batchSaveOrEdit(@RequestParam Long positionMapId, @Valid @RequestBody List<NodeBaseDTO> nodeBaseDTOS) {
// -- 这里使用策略模式 - 根据各个类型区分 - 如果需要新增类型新增策略实现类即可 - 如果不需要关联存储具体的表直接将json存储到dataJson字段即可
Map<Integer, List<NodeBaseDTO>> map = nodeBaseDTOS.stream().collect(Collectors.groupingBy(NodeBaseDTO::getType));
// -- 获取到对应地图的所有点位
List<PositionMapItemDO> oldList = positionMapItemService.getByMapId(positionMapId);
Map<Integer, List<PositionMapItemDO>> oldMap = oldList.stream().collect(Collectors.groupingBy(PositionMapItemDO::getType));
for (Map.Entry<Integer, List<NodeBaseDTO>> entry : map.entrySet()) {
int key = entry.getKey();
List<PositionMapItemDO> oldItemList = CollectionUtil.isEmpty(oldMap.get(key)) ? Collections.emptyList() : oldMap.get(key);
nodeProcessingContext.processNodesByStrategy(positionMapId, oldItemList, key, entry.getValue());
}
return success(true);
}

View File

@ -0,0 +1,35 @@
package cn.iocoder.yudao.module.system.controller.admin.positionmap.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.ToString;
@Schema(description = "管理后台 - 仓库点位地图子表 - 节点基础属性")
@Data
@ToString(callSuper = true)
public class NodeBaseDTO {
@Schema(description = "id")
private Long id;
@Schema(description = "仓库点位地图表id")
private Long positionMapId;
@Schema(description = "库区id(自定义)")
private Long areaId;
@Schema(description = "巷道id(自定义)")
private Long laneId;
@Schema(description = "坐标x轴")
private String locationX;
@Schema(description = "坐标y轴")
private String locationY;
@Schema(description = "类型 1.路径点位 2.库位点 3.充电桩 4.停车点 5.区域变更点 6.等待点 --- 后续补充", example = "1")
private Integer type;
@Schema(description = "对应各个类型的独有属性Json格式 例如({库位长度:1,库位宽度:2,库位方向:单向}", example = "1")
private String dataJson;
}

View File

@ -31,10 +31,13 @@ public class PositionMapItemPageReqVO extends PageParam {
@Schema(description = "坐标y轴")
private String locationY;
@Schema(description = "类型 1.行走点位 2.库位 3.充电桩 --- 后续补充", example = "1")
@Schema(description = "类型 1.路径点位 2.库位点 3.充电桩 4.停车点 5.区域变更点 6.等待点 --- 后续补充", example = "1")
private Integer type;
@Schema(description = "类型所对应表id", example = "15418")
@Schema(description = "对应各个类型的独有属性Json格式 例如({库位长度:1,库位宽度:2,库位方向:单向}", example = "1")
private String dataJson;
@Schema(description = "类型所对应表id可空 - 不需要绑定具体表的话 存json即可", example = "15418")
private Long objectId;
@Schema(description = "创建时间")

View File

@ -36,12 +36,15 @@ public class PositionMapItemRespVO {
@ExcelProperty("坐标y轴")
private String locationY;
@Schema(description = "类型 1.行走点位 2.库位 3.充电桩 --- 后续补充", example = "1")
@ExcelProperty("类型 1.行走点位 2.库位 3.充电桩 --- 后续补充")
@Schema(description = "类型 1.路径点位 2.库位点 3.充电桩 4.停车点 5.区域变更点 6.等待点 --- 后续补充", example = "1")
@ExcelProperty("类型 1.路径点位 2.库位点 3.充电桩 4.停车点 5.区域变更点 6.等待点 --- 后续补充")
private Integer type;
@Schema(description = "类型所对应表id", example = "15418")
@ExcelProperty("类型所对应表id")
@Schema(description = "对应各个类型的独有属性Json格式 例如({库位长度:1,库位宽度:2,库位方向:单向}", example = "1")
private String dataJson;
@Schema(description = "类型所对应表id可空 - 不需要绑定具体表的话 存json即可", example = "15418")
@ExcelProperty("类型所对应表id可空 - 不需要绑定具体表的话 存json即可")
private Long objectId;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)

View File

@ -27,10 +27,13 @@ public class PositionMapItemSaveReqVO {
@Schema(description = "坐标y轴")
private String locationY;
@Schema(description = "类型 1.行走点位 2.库位 3.充电桩 --- 后续补充", example = "1")
@Schema(description = "类型 1.路径点位 2.库位点 3.充电桩 4.停车点 5.区域变更点 6.等待点 --- 后续补充", example = "1")
private Integer type;
@Schema(description = "类型所对应表id", example = "15418")
@Schema(description = "对应各个类型的独有属性Json格式 例如({库位长度:1,库位宽度:2,库位方向:单向}", example = "1")
private String dataJson;
@Schema(description = "类型所对应表id可空 - 不需要绑定具体表的话 存json即可", example = "15418")
private Long objectId;
}

View File

@ -146,4 +146,8 @@ public class WareHouseLocationDO extends BaseDO {
* ware_position_map的id
*/
private Long mapId;
}
/**
* ware_position_map_item的id
*/
private Long mapItemId;
}

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.system.dal.dataobject.positionmap;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import java.time.LocalDateTime;
@ -25,7 +26,7 @@ public class PositionMapItemDO extends BaseDO {
/**
* 主键ID
*/
@TableId
@TableId(type = IdType.ASSIGN_ID)
private Long id;
/**
* 仓库点位地图表id
@ -48,11 +49,15 @@ public class PositionMapItemDO extends BaseDO {
*/
private String locationY;
/**
* 类型 1.行走点位 2.库位 3.充电桩 --- 后续补充
* 类型 1.路径点位 2.库位点 3.充电桩 4.停车点 5.区域变更点 6.等待点 --- 后续补充
*/
private Integer type;
/**
* 类型所对应表id
* 对应各个类型的独有属性Json格式 例如{库位长度:1,库位宽度:2,库位方向:单向}
*/
private String dataJson;
/**
* 类型所对应表id可空 - 不需要绑定具体表的话 存json即可
*/
private Long objectId;

View File

@ -0,0 +1,59 @@
package cn.iocoder.yudao.module.system.handler.mapnode;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.system.controller.admin.positionmap.dto.NodeBaseDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.positionmap.PositionMapItemDO;
import cn.iocoder.yudao.module.system.handler.mapnode.strategy.HouseLocationStrategyImpl;
import cn.iocoder.yudao.module.system.handler.mapnode.strategy.NodeProcessingStrategy;
import cn.iocoder.yudao.module.system.service.positionmap.PositionMapItemService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.baomidou.mybatisplus.core.toolkit.IdWorker.getId;
@Component
public class NodeProcessingContext {
private final Map<Integer, NodeProcessingStrategy> strategyMap = new HashMap<>();
@Autowired
private HouseLocationStrategyImpl houseLocationStrategyImpl;
@Autowired
private PositionMapItemService positionMapItemService;
/**
* 项目启动时 初始化策略
*/
@PostConstruct
public void init() {
// 节点
// strategyMap.put(1, positionMapItemStrategyImpl);
// 库位
strategyMap.put(2, houseLocationStrategyImpl);
// todo 可以继续添加更多的策略
}
public void processNodesByStrategy(Long positionMapId, List<PositionMapItemDO> oldItemList, int key, List<NodeBaseDTO> nodeBaseDTOS) {
// -- 这里处理节点 - 因为所有的类型都要建立在节点之上 - 把所有新增没有节点id的先分配id下 - 后续其他类型的需要绑定该id
nodeBaseDTOS.forEach(a->{if (a.getId() == null) {a.setId(getId());}});
List<PositionMapItemDO> newList = BeanUtil.copyToList(nodeBaseDTOS, PositionMapItemDO.class);
List<List<PositionMapItemDO>> list = CollectionUtils.diffList(oldItemList, newList,
(oldVal, newVal) -> ObjectUtil.equal(oldVal.getId(), newVal.getId()));
positionMapItemService.batchSaveOrEditOrDel(positionMapId, list);
// -- 获取对应的策略 - 如果没有对应的直接 return
NodeProcessingStrategy strategy = strategyMap.get(key);
if (strategy == null) {
return;
}
strategy.processNodes(positionMapId, nodeBaseDTOS);
}
}

View File

@ -0,0 +1,38 @@
package cn.iocoder.yudao.module.system.handler.mapnode.strategy;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.system.controller.admin.positionmap.dto.NodeBaseDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.houselocation.WareHouseLocationDO;
import cn.iocoder.yudao.module.system.service.houselocation.HouseLocationService;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
@Component
public class HouseLocationStrategyImpl implements NodeProcessingStrategy {
@Resource
private HouseLocationService houseLocationService;
@Override
public void processNodes(Long positionMapId, List<NodeBaseDTO> nodeBaseDTOS) {
// -- 策略1 处理库位点
// -- 将data里面的json 数据转为实体类 - 再对比节点id - 然后做新增删除修改操作
List<WareHouseLocationDO> newList = new ArrayList<>();
for (NodeBaseDTO nodeBaseDTO : nodeBaseDTOS) {
WareHouseLocationDO wareHouseLocationDO = JSONUtil.toBean(nodeBaseDTO.getDataJson(), WareHouseLocationDO.class);
wareHouseLocationDO.setMapId(positionMapId);
wareHouseLocationDO.setMapItemId(nodeBaseDTO.getId());
newList.add(wareHouseLocationDO);
}
List<WareHouseLocationDO> oldList = houseLocationService.getByMapId(positionMapId);
List<List<WareHouseLocationDO>> list = CollectionUtils.diffList(oldList, newList,
(oldVal, newVal) -> ObjectUtil.equal(oldVal.getId(), newVal.getId()));
houseLocationService.batchSaveOrEditOrDel(positionMapId, list);
}
}

View File

@ -0,0 +1,10 @@
package cn.iocoder.yudao.module.system.handler.mapnode.strategy;
import cn.iocoder.yudao.module.system.controller.admin.positionmap.dto.NodeBaseDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.positionmap.PositionMapItemDO;
import java.util.List;
public interface NodeProcessingStrategy {
void processNodes(Long positionMapId, List<NodeBaseDTO> nodeBaseDTOS);
}

View File

@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.system.service.houselocation;
import javax.validation.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.houselocation.vo.WareHouseLocationPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.houselocation.vo.WareHouseLocationRespVO;
@ -8,6 +7,7 @@ import cn.iocoder.yudao.module.system.controller.admin.houselocation.vo.WareHous
import cn.iocoder.yudao.module.system.controller.admin.houselocation.vo.WareHouseLocationVO;
import cn.iocoder.yudao.module.system.dal.dataobject.houselocation.WareHouseLocationDO;
import javax.validation.Valid;
import java.util.List;
/**
@ -55,10 +55,25 @@ public interface HouseLocationService {
*/
PageResult<WareHouseLocationDO> getHouseLocationPage(WareHouseLocationPageReqVO pageReqVO);
/**
* 库位批量保存或修改或删除
*
* @param positionMapId
* @param list
*/
void batchSaveOrEditOrDel(Long positionMapId, List<List<WareHouseLocationDO>> list);
/**
* 根据地图查询库位
*
* @param positionMapId
* @return
*/
List<WareHouseLocationDO> getByMapId(Long positionMapId);
/**
*
* @param requestVO
* @return
*/
List<WareHouseLocationRespVO> getLocationByName(WareHouseLocationVO requestVO);
}
}

View File

@ -1,23 +1,23 @@
package cn.iocoder.yudao.module.system.service.houselocation;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.controller.admin.houselocation.vo.WareHouseLocationPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.houselocation.vo.WareHouseLocationRespVO;
import cn.iocoder.yudao.module.system.controller.admin.houselocation.vo.WareHouseLocationSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.houselocation.vo.WareHouseLocationVO;
import cn.iocoder.yudao.module.system.dal.dataobject.houselocation.WareHouseLocationDO;
import cn.iocoder.yudao.module.system.dal.mysql.houselocation.WareHouseLocationMapper;
import cn.iocoder.yudao.module.system.enums.robot.ReleaseTakeEnum;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import javax.annotation.Resource;
import java.util.List;
import static cn.hutool.core.collection.CollUtil.isNotEmpty;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.HOUSE_LOCATION_NOT_EXISTS;
/**
@ -79,4 +79,24 @@ public class HouseLocationServiceImpl implements HouseLocationService {
return houseLocationMapper.getLocationByName(requestVO);
}
}
@Override
public void batchSaveOrEditOrDel(Long positionMapId, List<List<WareHouseLocationDO>> list) {
//批量添加修改删除
if (isNotEmpty(list.get(0))) {
houseLocationMapper.insertBatch(list.get(0));
}
if (isNotEmpty(list.get(1))) {
houseLocationMapper.updateBatch(list.get(1));
}
if (isNotEmpty(list.get(2))) {
houseLocationMapper.deleteByIds(convertList(list.get(2), WareHouseLocationDO::getId));
}
}
@Override
public List<WareHouseLocationDO> getByMapId(Long positionMapId) {
return houseLocationMapper.selectList(new LambdaQueryWrapperX<WareHouseLocationDO>()
.eq(WareHouseLocationDO::getMapId, positionMapId));
}
}

View File

@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.system.controller.admin.positionmap.vo.PositionMa
import cn.iocoder.yudao.module.system.dal.dataobject.positionmap.PositionMapItemDO;
import javax.validation.Valid;
import java.util.List;
/**
* 仓库点位地图子表 Service 接口
@ -52,4 +53,18 @@ public interface PositionMapItemService {
*/
PageResult<PositionMapItemDO> getPositionMapItemPage(PositionMapItemPageReqVO pageReqVO);
/**
* 获取到对应地图的所有点位信息
*
* @param positionMapId
* @return
*/
List<PositionMapItemDO> getByMapId(Long positionMapId);
/**
* 批量新增编辑操作删除操作
*
* @param list
*/
void batchSaveOrEditOrDel(Long positionMapId, List<List<PositionMapItemDO>> list);
}

View File

@ -2,14 +2,20 @@ package cn.iocoder.yudao.module.system.service.positionmap;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.controller.admin.positionmap.vo.PositionMapItemPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.positionmap.vo.PositionMapItemSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.positionmap.PositionMapItemDO;
import cn.iocoder.yudao.module.system.dal.mysql.positionmap.PositionMapItemMapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.List;
import static cn.hutool.core.collection.CollUtil.isNotEmpty;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
/**
* 仓库点位地图子表 Service 实现类
@ -55,4 +61,24 @@ public class PositionMapItemServiceImpl implements PositionMapItemService {
return positionMapItemMapper.selectPage(pageReqVO);
}
@Override
public List<PositionMapItemDO> getByMapId(Long positionMapId) {
return positionMapItemMapper.selectList(new LambdaQueryWrapperX<PositionMapItemDO>()
.eq(PositionMapItemDO::getPositionMapId, positionMapId));
}
@Override
public void batchSaveOrEditOrDel(Long positionMapId, List<List<PositionMapItemDO>> list) {
//批量添加修改删除
if (isNotEmpty(list.get(0))) {
list.get(0).forEach(item -> item.setPositionMapId(positionMapId));
positionMapItemMapper.insertBatch(list.get(0));
}
if (isNotEmpty(list.get(1))) {
positionMapItemMapper.updateBatch(list.get(1));
}
if (isNotEmpty(list.get(2))) {
positionMapItemMapper.deleteByIds(convertList(list.get(2), PositionMapItemDO::getId));
}
}
}

View File

@ -85,7 +85,6 @@ public interface PositionMapService extends IService<PositionMapDO> {
*
* @param floor
* @param area
* @param response
*/
void downloadPng(Integer floor, String area, HttpServletResponse response) throws IOException;
String downloadPngBase64(Integer floor, String area);
}

View File

@ -10,9 +10,11 @@ import cn.iocoder.yudao.module.system.dal.dataobject.positionmap.PositionMapDO;
import cn.iocoder.yudao.module.system.dal.mysql.positionmap.PositionMapMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
@ -20,6 +22,7 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.multipart.MultipartFile;
import org.yaml.snakeyaml.Yaml;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
@ -41,12 +44,15 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
*/
@Service
@Validated
@Slf4j
public class PositionMapServiceImpl extends ServiceImpl<PositionMapMapper, PositionMapDO> implements PositionMapService {
@Autowired
@Resource
private PositionMapMapper positionMapMapper;
@Value("${map.file.upload-path}")
private String UPLOAD_DIR;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Override
public Long createPositionMap(PositionMapSaveReqVO createReqVO) {
@ -253,13 +259,14 @@ public class PositionMapServiceImpl extends ServiceImpl<PositionMapMapper, Posit
@Override
public void downloadPng(Integer floor, String area, HttpServletResponse response) throws IOException {
@Cacheable(value = "pngBase64", key = "#floor + '_' + #area")
public String downloadPngBase64(Integer floor, String area) {
// 根据楼层和区域查找对应的PNG文件路径
String basePath = UPLOAD_DIR + floor + "/" + area + "/";
File directory = new File(basePath);
if (!directory.exists() || !directory.isDirectory()) {
response.sendError(HttpStatus.NOT_FOUND.value(), "Directory not found for the given floor and area.");
return;
log.error("Directory not found for floor: {}, area: {}", floor, area);
throw exception(AGV_MAP_NOT_FOUND);
}
// 查找PNG文件
@ -270,18 +277,23 @@ public class PositionMapServiceImpl extends ServiceImpl<PositionMapMapper, Posit
}
if (pngFile == null || !pngFile.exists()) {
response.sendError(HttpStatus.NOT_FOUND.value(), "PNG file not found for the given floor and area.");
return;
log.error("PNG file not found for floor: {}, area: {}", floor, area);
throw exception(AGV_MAP_NOT_FOUND);
}
// 设置响应头以指示浏览器下载文件
response.setContentType("image/png");
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + pngFile.getName() + "\"");
// 将PNG文件写入HTTP响应输出流
try (FileInputStream fis = new FileInputStream(pngFile)) {
IOUtils.copy(fis, response.getOutputStream());
String encodedString = null;
try {
// 读取文件内容
byte[] fileContent = Files.readAllBytes(pngFile.toPath());
// 将文件内容转换为Base64字符串
encodedString = Base64.getEncoder().encodeToString(fileContent);
// 添加MIME类型前缀
encodedString = "data:image/png;base64," + encodedString;
} catch (IOException e) {
log.error("Failed to convert PNG to Base64 for floor: {}, area: {}", floor, area, e);
throw exception(AGV_IMAGE_CONVERSION_TO_BASE64_FAILED);
}
return encodedString;
}
}

View File

@ -14,7 +14,8 @@ spring:
config: # 【注册中心】配置项
namespace: dev # 命名空间。这里使用 dev 开发环境
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
cache:
type: redis
--- #################### 数据库相关配置 ####################
spring:
# 数据源配置项
@ -103,16 +104,9 @@ spring:
xxl:
job:
enabled: true # 是否开启调度中心,默认为 true 开启
admin:
addresses: http://127.0.0.1:8080/xxl-job-admin
accessToken: default_token
executor:
appname: xxl-job-executor
address:
ip:
port: 9999
logpath: /data/applogs/xxl-job/jobhandler
logretentiondays: 30
addresses: http://127.0.0.1:9999/xxl-job-admin # 调度中心部署跟地址
--- #################### 服务保障相关配置 ####################