add:基础数据+IOT

This commit is contained in:
2026-02-27 17:25:21 +08:00
parent 2cbf0e063c
commit 40a310b160
74 changed files with 6073 additions and 223 deletions

View File

@@ -27,6 +27,8 @@ import org.nl.module.device.service.BaseDataDeviceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.multipart.MultipartFile;
import java.util.ArrayList;
import java.util.List;
@@ -79,10 +81,38 @@ public class BaseDataDeviceController {
*/
@Operation(summary = "删除设备信息")
@PostMapping("/delete")
public CommonResult delete(@RequestParam Integer id) {
baseDataDeviceService.removeById(id);
public CommonResult delete(@RequestBody BaseDataDevice device) {
baseDataDeviceService.removeById(device.getId());
return CommonResult.ok();
}
/**
* 批量删除设备信息
*/
@Operation(summary = "批量删除设备信息")
@PostMapping("/deleteBatch")
public CommonResult deleteBatch(@RequestBody java.util.List<Integer> ids) {
baseDataDeviceService.removeBatchByIds(ids);
return CommonResult.ok();
}
/**
* 下载导入模板
*/
@Operation(summary = "下载导入模板")
@GetMapping("/downloadImportTemplate")
public void downloadImportTemplate(HttpServletResponse response) {
baseDataDeviceService.downloadImportTemplate(response);
}
/**
* 导入设备信息
*/
@Operation(summary = "导入设备信息")
@PostMapping("/import")
public CommonResult importDevice(@RequestParam("file") MultipartFile file) {
return CommonResult.data(baseDataDeviceService.importDevice(file));
}
@Operation(summary = "设备组件列表")
@GetMapping("compentList")
@SaIgnore

View File

@@ -1,6 +1,7 @@
package org.nl.module.device.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -33,16 +34,20 @@ public class BaseDataDevice implements Serializable {
@Schema(description = "设备名称")
private String name;
@Schema(description = "类型")
private String type;
@Schema(description = "区域")
private String region;
@Schema(description = "描述")
private String description;
@Schema(description = "扩展参数")
private String editParam;
@Schema(description = "否启用")
private Boolean isUsed;
@Schema(description = "否启用")
private Boolean enabled;
@Schema(description = "图标文件ID")
private String icon;
@Schema(description = "角度")
private Integer angle;
@Schema(description = "x坐标")
private Integer x;
@@ -50,14 +55,11 @@ public class BaseDataDevice implements Serializable {
@Schema(description = "y坐标")
private Integer y;
@Schema(description = "角度")
private Integer angle;
@Schema(description = "放大比例")
private Integer size;
private Integer scale;
@Schema(description = "图标地址")
private String icon;
@Schema(description = "描述")
private String description;
@Schema(description = "图标文件ID")
private String fileId;

View File

@@ -0,0 +1,43 @@
package org.nl.module.device.param;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Getter;
import lombok.Setter;
/**
* 设备导入参数
*/
@Getter
@Setter
public class BaseDataDeviceImportParam {
@ExcelProperty("设备编码")
private String code;
@ExcelProperty("设备名称")
private String name;
@ExcelProperty("所属区域")
private String region;
@ExcelProperty("图标文件ID")
private String icon;
@ExcelProperty("X坐标")
private String x;
@ExcelProperty("Y坐标")
private String y;
@ExcelProperty("角度")
private String angle;
@ExcelProperty("放大比例")
private String scale;
@ExcelProperty("启用状态")
private String enabled;
@ExcelProperty("备注")
private String description;
}

View File

@@ -1,11 +1,23 @@
package org.nl.module.device.service;
import com.baomidou.mybatisplus.extension.service.IService;
import cn.hutool.json.JSONObject;
import jakarta.servlet.http.HttpServletResponse;
import org.nl.module.device.entity.BaseDataDevice;
import org.springframework.web.multipart.MultipartFile;
/**
* 设备信息表Service接口
*/
public interface BaseDataDeviceService extends IService<BaseDataDevice> {
/**
* 下载导入模板
*/
void downloadImportTemplate(HttpServletResponse response);
/**
* 导入设备信息
*/
JSONObject importDevice(MultipartFile file);
}

View File

@@ -1,10 +1,26 @@
package org.nl.module.device.service.impl;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import jakarta.servlet.http.HttpServletResponse;
import org.nl.common.exception.CommonException;
import org.nl.common.util.CommonDownloadUtil;
import org.nl.common.util.CommonResponseUtil;
import org.nl.module.device.entity.BaseDataDevice;
import org.nl.module.device.mapper.BaseDataDeviceMapper;
import org.nl.module.device.param.BaseDataDeviceImportParam;
import org.nl.module.device.service.BaseDataDeviceService;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
/**
* 设备信息表Service实现类
@@ -12,4 +28,99 @@ import org.springframework.stereotype.Service;
@Service
public class BaseDataDeviceServiceImpl extends ServiceImpl<BaseDataDeviceMapper, BaseDataDevice> implements BaseDataDeviceService {
@Override
public void downloadImportTemplate(HttpServletResponse response) {
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
EasyExcel.write(outputStream, BaseDataDeviceImportParam.class)
.sheet("设备模板")
.doWrite(Collections.emptyList());
CommonDownloadUtil.download("设备导入模板.xlsx", outputStream.toByteArray(), response);
} catch (Exception e) {
try {
CommonResponseUtil.renderError(response, "下载设备导入模板失败");
} catch (IOException ignored) {
// ignored
}
}
}
@Override
public JSONObject importDevice(MultipartFile file) {
try {
int successCount = 0;
int errorCount = 0;
JSONArray errorDetail = JSONUtil.createArray();
List<BaseDataDeviceImportParam> importList = EasyExcel.read(file.getInputStream())
.head(BaseDataDeviceImportParam.class)
.sheet()
.headRowNumber(1)
.doReadSync();
for (int i = 0; i < importList.size(); i++) {
JSONObject result = this.doImport(importList.get(i), i);
if (result.getBool("success")) {
successCount += 1;
} else {
errorCount += 1;
errorDetail.add(result);
}
}
return JSONUtil.createObj()
.set("totalCount", importList.size())
.set("successCount", successCount)
.set("errorCount", errorCount)
.set("errorDetail", errorDetail);
} catch (Exception e) {
throw new CommonException("设备导入失败");
}
}
private JSONObject doImport(BaseDataDeviceImportParam param, int index) {
if (ObjectUtil.hasEmpty(param.getCode(), param.getName())) {
return JSONUtil.createObj()
.set("index", index + 1)
.set("success", false)
.set("msg", "必填字段存在空值");
}
BaseDataDevice device = new BaseDataDevice();
device.setCode(param.getCode());
device.setName(param.getName());
device.setRegion(param.getRegion());
device.setIcon(param.getIcon());
device.setX(parseInteger(param.getX()));
device.setY(parseInteger(param.getY()));
device.setAngle(parseInteger(param.getAngle()));
device.setScale(parseInteger(param.getScale()));
device.setEnabled(parseBoolean(param.getEnabled(), true));
device.setDescription(param.getDescription());
this.save(device);
return JSONUtil.createObj()
.set("index", index + 1)
.set("success", true)
.set("msg", "成功");
}
private Integer parseInteger(String value) {
if (ObjectUtil.isEmpty(value)) {
return null;
}
try {
return Integer.parseInt(value.trim());
} catch (Exception e) {
return null;
}
}
private Boolean parseBoolean(String value, boolean defaultValue) {
if (ObjectUtil.isEmpty(value)) {
return defaultValue;
}
String normalized = value.trim();
if ("1".equals(normalized) || "true".equalsIgnoreCase(normalized) || "".equals(normalized) || "启用".equals(normalized)) {
return true;
}
if ("0".equals(normalized) || "false".equalsIgnoreCase(normalized) || "".equals(normalized) || "禁用".equals(normalized)) {
return false;
}
return defaultValue;
}
}

View File

@@ -1,50 +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.module.point;
import cn.dev33.satoken.annotation.SaIgnore;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.nl.common.pojo.CommonResult;
import org.nl.module.point.dto.PointStatus;
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/baseData/point")
@Validated
@SaIgnore
public class PointStatusController {
static {
System.out.println("初始化AGV模块------------");
}
@GetMapping("status")
public CommonResult<List<PointStatus>> status() {
List<PointStatus> list = new ArrayList<>();
for (int i = 0; i < new Random().nextInt(100)+10; i++) {
PointStatus build = PointStatus.builder().pointCode("A1_1" + i)
.pointName("货位" + i)
.x(new Random().nextInt(1280))
.y(new Random().nextInt(960)).status(String.valueOf(i / 2)).build();
list.add(build);
}
return CommonResult.data(list);
}
}

View File

@@ -0,0 +1,138 @@
/*
* 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.module.point.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.lang3.StringUtils;
import org.nl.common.pojo.CommonResult;
import org.nl.module.point.entity.BaseDataPoint;
import org.nl.module.point.service.BaseDataPointService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.multipart.MultipartFile;
/**
* 点位表Controller
*/
@Tag(name = "点位信息管理")
@RestController
@RequestMapping("/api/baseData/point")
@Validated
public class BaseDataPointController {
@Autowired
private BaseDataPointService baseDataPointService;
/**
* 获取点位列表
*/
@Operation(summary = "获取点位列表")
@GetMapping("/list")
public CommonResult list(@RequestParam(required = false) String searchKey,
@RequestParam(required = false) String region,
@RequestParam(required = false) Integer subDeviceId,
@RequestParam(defaultValue = "1") Integer current,
@RequestParam(defaultValue = "10") Integer size) {
LambdaQueryWrapper<BaseDataPoint> queryWrapper = new LambdaQueryWrapper<>();
// 关键词搜索(点位名称或编码)
if (StringUtils.isNotBlank(searchKey)) {
queryWrapper.and(wrapper -> wrapper
.like(BaseDataPoint::getName, searchKey)
.or()
.like(BaseDataPoint::getCode, searchKey)
);
}
// 区域搜索
if (StringUtils.isNotBlank(region)) {
queryWrapper.like(BaseDataPoint::getRegion, region);
}
// 子设备筛选
if (subDeviceId != null) {
queryWrapper.eq(BaseDataPoint::getSubDeviceId, subDeviceId);
}
// 按创建时间倒序
queryWrapper.orderByDesc(BaseDataPoint::getCreateTime);
Page<BaseDataPoint> page = new Page<>(current, size);
Page<BaseDataPoint> result = baseDataPointService.page(page, queryWrapper);
return CommonResult.data(result);
}
/**
* 新增点位信息
*/
@Operation(summary = "新增点位信息")
@PostMapping("/add")
public CommonResult add(@RequestBody BaseDataPoint point) {
baseDataPointService.save(point);
return CommonResult.ok();
}
/**
* 修改点位信息
*/
@Operation(summary = "修改点位信息")
@PostMapping("/edit")
public CommonResult edit(@RequestBody BaseDataPoint point) {
baseDataPointService.updateById(point);
return CommonResult.ok();
}
/**
* 删除点位信息
*/
@Operation(summary = "删除点位信息")
@PostMapping("/delete")
public CommonResult delete(@RequestBody BaseDataPoint point) {
baseDataPointService.removeById(point.getId());
return CommonResult.ok();
}
/**
* 批量删除点位信息
*/
@Operation(summary = "批量删除点位信息")
@PostMapping("/deleteBatch")
public CommonResult deleteBatch(@RequestBody java.util.List<Integer> ids) {
baseDataPointService.removeBatchByIds(ids);
return CommonResult.ok();
}
/**
* 下载导入模板
*/
@Operation(summary = "下载导入模板")
@GetMapping("/downloadImportTemplate")
public void downloadImportTemplate(HttpServletResponse response) {
baseDataPointService.downloadImportTemplate(response);
}
/**
* 导入点位信息
*/
@Operation(summary = "导入点位信息")
@PostMapping("/import")
public CommonResult importPoint(@RequestParam("file") MultipartFile file) {
return CommonResult.data(baseDataPointService.importPoint(file));
}
}

View File

@@ -1,33 +0,0 @@
package org.nl.module.point.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class PointStatus {
/**
* 点位编码
*/
private String pointCode;
/**
* 车辆类型
*/
private String pointName;
/**
* 坐标X
*/
private int x;
/**
* 坐标Y
*/
private int y;
/**
* 点位状态 0无货1有货
*/
private String status;
}

View File

@@ -0,0 +1,68 @@
package org.nl.module.point.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
/**
* 点位表实体类
*/
@Data
@TableName("base_data_point")
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Schema(description = "点位表")
public class BaseDataPoint implements Serializable {
@TableId(type = IdType.AUTO)
@Schema(description = "主键ID")
private Integer id;
@Schema(description = "点位编码")
private String code;
@Schema(description = "点位名称")
private String name;
@Schema(description = "点位区域")
private String region;
@Schema(description = "X坐标")
private Integer x;
@Schema(description = "Y坐标")
private Integer y;
@Schema(description = "有无货")
private Boolean isHasgoods;
@Schema(description = "关联子设备ID")
private Integer subDeviceId;
@Schema(description = "启用状态")
private Boolean enabled;
@Schema(description = "描述")
private String description;
@Schema(description = "创建时间")
private Date createTime;
@Schema(description = "创建用户")
private String createName;
@Schema(description = "修改时间")
private Date updateTime;
@Schema(description = "修改用户")
private String updateName;
}

View File

@@ -0,0 +1,13 @@
package org.nl.module.point.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.nl.module.point.entity.BaseDataPoint;
/**
* 点位表Mapper
*/
@Mapper
public interface BaseDataPointMapper extends BaseMapper<BaseDataPoint> {
}

View File

@@ -0,0 +1,40 @@
package org.nl.module.point.param;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Getter;
import lombok.Setter;
/**
* 点位导入参数
*/
@Getter
@Setter
public class BaseDataPointImportParam {
@ExcelProperty("点位编码")
private String code;
@ExcelProperty("点位名称")
private String name;
@ExcelProperty("点位区域")
private String region;
@ExcelProperty("X坐标")
private String x;
@ExcelProperty("Y坐标")
private String y;
@ExcelProperty("有无货")
private String isHasgoods;
@ExcelProperty("子设备ID")
private String subDeviceId;
@ExcelProperty("启用状态")
private String enabled;
@ExcelProperty("备注")
private String description;
}

View File

@@ -0,0 +1,23 @@
package org.nl.module.point.service;
import com.baomidou.mybatisplus.extension.service.IService;
import cn.hutool.json.JSONObject;
import jakarta.servlet.http.HttpServletResponse;
import org.nl.module.point.entity.BaseDataPoint;
import org.springframework.web.multipart.MultipartFile;
/**
* 点位表Service接口
*/
public interface BaseDataPointService extends IService<BaseDataPoint> {
/**
* 下载导入模板
*/
void downloadImportTemplate(HttpServletResponse response);
/**
* 导入点位信息
*/
JSONObject importPoint(MultipartFile file);
}

View File

@@ -0,0 +1,126 @@
package org.nl.module.point.service.impl;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import jakarta.servlet.http.HttpServletResponse;
import org.nl.common.exception.CommonException;
import org.nl.common.util.CommonDownloadUtil;
import org.nl.common.util.CommonResponseUtil;
import org.nl.module.point.entity.BaseDataPoint;
import org.nl.module.point.mapper.BaseDataPointMapper;
import org.nl.module.point.param.BaseDataPointImportParam;
import org.nl.module.point.service.BaseDataPointService;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
/**
* 点位表Service实现类
*/
@Service
public class BaseDataPointServiceImpl extends ServiceImpl<BaseDataPointMapper, BaseDataPoint> implements BaseDataPointService {
@Override
public void downloadImportTemplate(HttpServletResponse response) {
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
EasyExcel.write(outputStream, BaseDataPointImportParam.class)
.sheet("点位模板")
.doWrite(Collections.emptyList());
CommonDownloadUtil.download("点位导入模板.xlsx", outputStream.toByteArray(), response);
} catch (Exception e) {
try {
CommonResponseUtil.renderError(response, "下载点位导入模板失败");
} catch (IOException ignored) {
// ignored
}
}
}
@Override
public JSONObject importPoint(MultipartFile file) {
try {
int successCount = 0;
int errorCount = 0;
JSONArray errorDetail = JSONUtil.createArray();
List<BaseDataPointImportParam> importList = EasyExcel.read(file.getInputStream())
.head(BaseDataPointImportParam.class)
.sheet()
.headRowNumber(1)
.doReadSync();
for (int i = 0; i < importList.size(); i++) {
JSONObject result = this.doImport(importList.get(i), i);
if (result.getBool("success")) {
successCount += 1;
} else {
errorCount += 1;
errorDetail.add(result);
}
}
return JSONUtil.createObj()
.set("totalCount", importList.size())
.set("successCount", successCount)
.set("errorCount", errorCount)
.set("errorDetail", errorDetail);
} catch (Exception e) {
throw new CommonException("点位导入失败");
}
}
private JSONObject doImport(BaseDataPointImportParam param, int index) {
if (ObjectUtil.hasEmpty(param.getCode(), param.getName())) {
return JSONUtil.createObj()
.set("index", index + 1)
.set("success", false)
.set("msg", "必填字段存在空值");
}
Integer subDeviceId = parseInteger(param.getSubDeviceId());
BaseDataPoint point = new BaseDataPoint();
point.setCode(param.getCode());
point.setName(param.getName());
point.setRegion(param.getRegion());
point.setX(parseInteger(param.getX()));
point.setY(parseInteger(param.getY()));
point.setIsHasgoods(parseBoolean(param.getIsHasgoods(), false));
point.setSubDeviceId(subDeviceId);
point.setEnabled(parseBoolean(param.getEnabled(), true));
point.setDescription(param.getDescription());
this.save(point);
return JSONUtil.createObj()
.set("index", index + 1)
.set("success", true)
.set("msg", "成功");
}
private Integer parseInteger(String value) {
if (ObjectUtil.isEmpty(value)) {
return null;
}
try {
return Integer.parseInt(value.trim());
} catch (Exception e) {
return null;
}
}
private Boolean parseBoolean(String value, boolean defaultValue) {
if (ObjectUtil.isEmpty(value)) {
return defaultValue;
}
String normalized = value.trim();
if ("1".equals(normalized) || "true".equalsIgnoreCase(normalized) || "".equals(normalized) || "".equals(normalized) || "启用".equals(normalized)) {
return true;
}
if ("0".equals(normalized) || "false".equalsIgnoreCase(normalized) || "".equals(normalized) || "".equals(normalized) || "禁用".equals(normalized)) {
return false;
}
return defaultValue;
}
}