add:agv模块看板

This commit is contained in:
zhangzq
2026-01-19 18:40:06 +08:00
parent d4b4059195
commit 854b806b88
50 changed files with 2350 additions and 242 deletions

View File

@@ -0,0 +1,92 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
*
* 1.请不要删除和修改根目录下的LICENSE文件。
* 2.请不要删除和修改Snowy源码头部的版权声明。
* 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
* 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作。
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
package org.nl.agv.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.nl.agv.service.AgvCarService;
import org.nl.agv.service.entity.AgvCar;
import org.nl.agv.service.query.AgvCarQuery;
import org.nl.common.page.PageQuery;
import org.nl.common.pojo.CommonResult;
import org.nl.agv.service.dto.AgvStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
@Tag(name = "AGV模块")
@RestController()
@RequestMapping("/api/agv")
@Validated
public class AgvCarController {
static {
System.out.println("初始化AGV模块------------");
}
@Autowired
private AgvCarService agvCarService;
@GetMapping("status")
public CommonResult<List> status() {
List<AgvStatus> list = new ArrayList<>();
for (int i = 0; i < 4; i++) {
AgvStatus build = AgvStatus.builder().status(2)
.carId(String.valueOf(i + 1))
.statusInfo("运行中").type("1")
.action("请求取货")
.icon("/Users/mima0000/Desktop/car.png")
.actionInfo("申请取货")
.x(String.valueOf(new Random().nextInt(1189) + 100))
.y(String.valueOf(new Random().nextInt(889) + 100)).power("67")
.angle("180").build();
list.add(build);
}
return CommonResult.data(list);
}
/**
* agv列表
* @return
*/
@GetMapping("list")
public CommonResult list(AgvCarQuery query, PageQuery pageQuery) {
return CommonResult.data(agvCarService.page(pageQuery.build(), query.build()));
}
/**
* agv列表
* @return
*/
@GetMapping("save")
public CommonResult save(AgvCar car) {
agvCarService.save(car);
return CommonResult.ok();
}
/**
* 车俩基础信息
* @return
*/
@GetMapping("agvCar")
public CommonResult<AgvCar> agvCar(String carId) {
AgvCar car = agvCarService.getOne(new LambdaQueryWrapper<AgvCar>().eq(AgvCar::getCarId, carId));
return CommonResult.data(car);
}
}

View File

@@ -0,0 +1,11 @@
package org.nl.agv.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.nl.agv.service.entity.AgvCar;
import org.nl.agv.service.mapper.AgvCarMapper;
import org.nl.layout.service.dto.MapLayout;
import org.nl.layout.service.entity.AgvLayoutMap;
public interface AgvCarService extends IService<AgvCar> {
}

View File

@@ -1,18 +1,27 @@
package org.nl.server.dto;
package org.nl.agv.service.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class AgvStatus {
/**
* 车辆ID
*/
private String agvId;
private String carId;
/**
* 车辆类型
*/
private String type;
/**
* 图标
* 图标地址
*/
private String icon;
private String icon="/Users/mima0000/Desktop/car.png";
/**
* 电量
*/
@@ -28,7 +37,7 @@ public class AgvStatus {
* 故障中
* 低电量
*/
private String statusType;
private String statusInfo;
/**
* 状态类型1.休息 2.正常运行 3.异常
*/
@@ -40,7 +49,7 @@ public class AgvStatus {
/**
* 动作交互信息
*/
private String actionMsg;
private String actionInfo;
/**
* 任务号
*/

View File

@@ -0,0 +1,35 @@
package org.nl.agv.service.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@TableName("agv_car")
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class AgvCar implements Serializable {
@TableId(type = IdType.AUTO)
private Long id;
/**
* 车辆ID项目初始化的时创建
*/
private String carId;
/**
* 车辆类型:ps车 NT车...
*/
private String type;
/**
* 车辆图片
*/
private String icon;
}

View File

@@ -0,0 +1,28 @@
package org.nl.agv.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.nl.agv.service.AgvCarService;
import org.nl.agv.service.entity.AgvCar;
import org.nl.agv.service.mapper.AgvCarMapper;
import org.nl.common.localStorage.service.LocalStorageService;
import org.nl.common.localStorage.service.entity.LocalStorage;
import org.nl.layout.service.AgvLayoutService;
import org.nl.layout.service.dto.DeviceLayout;
import org.nl.layout.service.dto.MapLayout;
import org.nl.layout.service.entity.AgvLayoutDevice;
import org.nl.layout.service.entity.AgvLayoutMap;
import org.nl.layout.service.mapper.AgvLayoutDeviceMapper;
import org.nl.layout.service.mapper.AgvLayoutMapMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.List;
@Service
public class AgvCarServiceImpl extends ServiceImpl<AgvCarMapper, AgvCar> implements AgvCarService {
}

View File

@@ -0,0 +1,11 @@
package org.nl.agv.service.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.nl.agv.service.entity.AgvCar;
@Mapper
public interface AgvCarMapper extends BaseMapper<AgvCar> {
}

View File

@@ -0,0 +1,8 @@
package org.nl.agv.service.query;
import org.nl.agv.service.entity.AgvCar;
import org.nl.common.page.BaseQuery;
import org.nl.layout.service.entity.AgvLayoutMap;
public class AgvCarQuery extends BaseQuery<AgvCar> {
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
*
* 1.请不要删除和修改根目录下的LICENSE文件。
* 2.请不要删除和修改Snowy源码头部的版权声明。
* 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
* 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作。
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
package org.nl.controller;
import com.alibaba.fastjson.JSONObject;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.nl.common.pojo.CommonResult;
import org.nl.language.LangBehavior;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
@Tag(name = "AGV模块")
@RestController()
@RequestMapping("/api/agv")
@Validated
public class AgvStatusController {
static {
System.out.println("初始化AGV模块------------");
}
@GetMapping("status")
public CommonResult<JSONObject> status() {
ArrayList<Object> list = new ArrayList<>();
return CommonResult.ok();
}
}

View File

@@ -0,0 +1,124 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
*
* 1.请不要删除和修改根目录下的LICENSE文件。
* 2.请不要删除和修改Snowy源码头部的版权声明。
* 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
* 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作。
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
package org.nl.layout.controller;
import cn.dev33.satoken.annotation.SaIgnore;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.nl.agv.service.AgvCarService;
import org.nl.common.exception.CommonException;
import org.nl.common.page.PageQuery;
import org.nl.common.pojo.CommonResult;
import org.nl.agv.service.dto.AgvStatus;
import org.nl.layout.service.AgvLayoutService;
import org.nl.layout.service.dto.MapLayout;
import org.nl.layout.service.entity.AgvLayoutMap;
import org.nl.layout.service.query.MapLayoutQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
@Tag(name = "AGV模块")
@RestController()
@RequestMapping("/api/agv/map")
@Validated
@SaIgnore
public class AgvLayoutController {
static {
System.out.println("初始化AGV模块------------");
}
@Autowired
private AgvLayoutService agvLayoutService;
@GetMapping("status")
public CommonResult<List> status() {
List<AgvStatus> list = new ArrayList<>();
for (int i = 0; i < 4; i++) {
AgvStatus build = AgvStatus.builder().status(2)
.carId(String.valueOf(i + 1))
.statusInfo("运行中").type("1")
.action("请求取货")
.actionInfo("申请取货")
.x(String.valueOf(new Random().nextInt(1189) + 100))
.y(String.valueOf(new Random().nextInt(889) + 100)).power("67")
.angle("180").build();
list.add(build);
}
return CommonResult.data(list);
}
/**
* 地图列表
* @param query
* @param pageQuery
* @return
*/
@GetMapping("list")
public CommonResult queruList(MapLayoutQuery query, PageQuery pageQuery) {
Page<AgvLayoutMap> page = agvLayoutService.page(pageQuery.build(), query.build());
return CommonResult.data(page);
}
/**
* 保存地图
* @param mapLayout
* @return
*/
@PostMapping("save")
public CommonResult save(@RequestBody MapLayout mapLayout) {
agvLayoutService.saveLayout(mapLayout);
return CommonResult.ok();
}
/**
* 启用地图
* @param id
* @return
*/
@GetMapping("enable")
public CommonResult queruList(Long id) {
agvLayoutService.update(new LambdaUpdateWrapper<AgvLayoutMap>()
.set(AgvLayoutMap::getEnable,false));
agvLayoutService.update(new LambdaUpdateWrapper<AgvLayoutMap>()
.set(AgvLayoutMap::getEnable,true).eq(AgvLayoutMap::getId,id));
return CommonResult.ok();
}
/**
* 初始化地图数据没传ID
* @param id
* @return
*/
@GetMapping("initLayout")
public CommonResult initLayout(Long id) {
if (id==null){
//如果没有传则返回最新版本
AgvLayoutMap one = agvLayoutService.getOne(new LambdaQueryWrapper<AgvLayoutMap>()
.orderByDesc(AgvLayoutMap::getVersion)
.eq(AgvLayoutMap::getEnable, Boolean.TRUE).last("limit 1"));
if (one == null){
throw new CommonException("地图未启用");
}
id = one.getId();
}
MapLayout mapLayout = agvLayoutService.initLayoutMap(id);
return CommonResult.data(mapLayout);
}
}

View File

@@ -0,0 +1,16 @@
package org.nl.layout.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.nl.layout.service.dto.MapLayout;
import org.nl.layout.service.entity.AgvLayoutMap;
public interface AgvLayoutService extends IService<AgvLayoutMap> {
void saveLayout(MapLayout layout);
/**
* 初始化地图获取布局信息
*/
MapLayout initLayoutMap(Long id);
}

View File

@@ -0,0 +1,16 @@
package org.nl.layout.service.dto;
import lombok.Data;
@Data
public class DeviceLayout {
private Long id;
private String code;
private String name;
private String type;
private String icon;
private Integer x;
private Integer y;
private Integer angle;
private Integer size;
}

View File

@@ -0,0 +1,15 @@
package org.nl.layout.service.dto;
import lombok.Data;
import java.util.List;
@Data
public class MapLayout {
private Long mapId;
private Integer width;
private Integer height;
private MapOrigin origin;
private String url;
private List<DeviceLayout> devices;
}

View File

@@ -0,0 +1,9 @@
package org.nl.layout.service.dto;
import lombok.Data;
@Data
public class MapOrigin {
private Integer x;
private Integer y;
}

View File

@@ -0,0 +1,35 @@
package org.nl.layout.service.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
@Data
@TableName("agv_layout_device")
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class AgvLayoutDevice implements Serializable {
@TableId(type = IdType.AUTO)
private Long id;
private Long mapLayoutId;
private Long deviceId;
private String code;
private String name;
private String type;
private Integer x;
private Integer y;
private Integer angle;
private String icon;
private Integer size;
}

View File

@@ -0,0 +1,36 @@
package org.nl.layout.service.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@TableName("agv_layout_map")
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class AgvLayoutMap implements Serializable {
@TableId(type = IdType.AUTO)
private Long Id;
private Long mapId;
private String mapName;
/**
* 通过触发器实现
*/
private Integer version;
private String url;
private Integer height;
private Integer width;
private Integer x;
private Integer y;
private Boolean enable;
}

View File

@@ -0,0 +1,74 @@
package org.nl.layout.service.impl;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.nl.common.exception.CommonException;
import org.nl.common.localStorage.service.LocalStorageService;
import org.nl.common.localStorage.service.mapper.LocalStorageMapper;
import org.nl.common.localStorage.service.entity.LocalStorage;
import org.nl.common.util.FileProperties;
import org.nl.common.util.FileUtil;
import org.nl.layout.service.AgvLayoutService;
import org.nl.layout.service.dto.DeviceLayout;
import org.nl.layout.service.dto.MapLayout;
import org.nl.layout.service.entity.AgvLayoutDevice;
import org.nl.layout.service.entity.AgvLayoutMap;
import org.nl.layout.service.mapper.AgvLayoutDeviceMapper;
import org.nl.layout.service.mapper.AgvLayoutMapMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@Service
public class AgvLayoutServiceImpl extends ServiceImpl<AgvLayoutMapMapper, AgvLayoutMap> implements AgvLayoutService {
@Autowired
private LocalStorageService localStorageService;
@Resource
private AgvLayoutDeviceMapper agvLayoutDeviceMapper;
@Override
@Transactional
public void saveLayout(MapLayout layout) {
LocalStorage storage = localStorageService.getById(layout.getMapId());
AgvLayoutMap layoutMap = AgvLayoutMap.builder()
.mapId(layout.getMapId())
.mapName(storage.getName())
.url(storage.getPath())
.width(layout.getWidth())
.height(layout.getHeight())
.x(layout.getOrigin().getX())
.y(layout.getOrigin().getY()).build();
this.baseMapper.insertUseGeneratedKeys(layoutMap);
List<DeviceLayout> deviceLayout = layout.getDevices();
if (!CollectionUtils.isEmpty(deviceLayout)){
for (DeviceLayout device : deviceLayout) {
AgvLayoutDevice layoutDevice = AgvLayoutDevice.builder()
.deviceId(device.getId())
.mapLayoutId(layoutMap.getId())
.name(device.getName())
.code(device.getCode())
.type(device.getType())
.angle(device.getAngle())
.x(device.getX())
.y(device.getY())
.size(device.getSize())
.icon(device.getIcon()).build();
agvLayoutDeviceMapper.insert(layoutDevice);
}
}
}
@Override
public MapLayout initLayoutMap(Long id) {
return this.baseMapper.initLayoutMap(id);
}
}

View File

@@ -0,0 +1,14 @@
package org.nl.layout.service.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Options;
import org.nl.common.localStorage.service.entity.LocalStorage;
import org.nl.layout.service.entity.AgvLayoutDevice;
@Mapper
public interface AgvLayoutDeviceMapper extends BaseMapper<AgvLayoutDevice> {
}

View File

@@ -0,0 +1,19 @@
package org.nl.layout.service.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Options;
import org.nl.common.localStorage.service.entity.LocalStorage;
import org.nl.layout.service.dto.MapLayout;
import org.nl.layout.service.entity.AgvLayoutMap;
@Mapper
public interface AgvLayoutMapMapper extends BaseMapper<AgvLayoutMap> {
@Insert("INSERT INTO agv_layout_map (mapId, url, height, width, x, y) VALUES (#{mapId}, #{url}, #{height}, #{width}, #{x}, #{y})")
@Options(useGeneratedKeys = true, keyProperty = "id")
void insertUseGeneratedKeys(AgvLayoutMap map);
MapLayout initLayoutMap(Long id);
}

View File

@@ -0,0 +1,50 @@
<?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="org.nl.layout.service.mapper.AgvLayoutMapMapper">
<resultMap id="mapLayoutResultMap" type="org.nl.layout.service.dto.MapLayout">
<result property="mapId" column="mapId"/>
<result property="width" column="width"/>
<result property="height" column="height"/>
<result property="url" column="url"/>
<!-- 映射origin对象 -->
<association property="origin" javaType="org.nl.layout.service.dto.MapOrigin">
<result property="x" column="origin_x"/>
<result property="y" column="origin_y"/>
</association>
<!-- 映射设备列表 -->
<collection property="devices" ofType="org.nl.layout.service.dto.DeviceLayout">
<id property="id" column="device_id"/>
<result property="code" column="device_code"/>
<result property="name" column="device_name"/>
<result property="type" column="device_type"/>
<result property="icon" column="device_icon"/>
<result property="x" column="device_x"/>
<result property="y" column="device_y"/>
<result property="angle" column="device_angle"/>
<result property="size" column="device_size"/>
</collection>
</resultMap>
<select id="initLayoutMap" resultMap="mapLayoutResultMap">
SELECT
m.map_id as mapId,
m.width,
m.height,
m.url,
m.x AS origin_x,
m.y AS origin_y,
d.id AS device_id,
d.code AS device_code,
d.name AS device_name,
d.type AS device_type,
d.icon AS device_icon,
d.x AS device_x,
d.y AS device_y,
d.angle AS device_angle,
d.size AS device_size
FROM agv_layout_map m
LEFT JOIN agv_layout_device d ON m.id = d.map_layout_id
WHERE m.id = #{id}
</select>
</mapper>

View File

@@ -0,0 +1,7 @@
package org.nl.layout.service.query;
import org.nl.common.page.BaseQuery;
import org.nl.layout.service.entity.AgvLayoutMap;
public class MapLayoutQuery extends BaseQuery<AgvLayoutMap> {
}