6 changed files with 417 additions and 306 deletions
-
16src/main/java/com/qyft/ms/app/controller/SprayTaskController.java
-
296src/main/java/com/qyft/ms/app/front/cmd/business/MatrixSprayStart.java
-
365src/main/java/com/qyft/ms/app/front/cmd/business/MatrixSprayStart_bak.java
-
18src/main/java/com/qyft/ms/app/model/bo/SprayTaskParams.java
-
14src/main/java/com/qyft/ms/app/model/dto/SetSprayTaskParamsDTO.java
-
14src/main/java/com/qyft/ms/app/model/vo/GetSprayTaskParamsVO.java
@ -0,0 +1,365 @@ |
|||
package com.qyft.ms.app.front.cmd.business; |
|||
|
|||
import cn.hutool.json.JSONUtil; |
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.qyft.ms.app.common.generator.PathGenerator; |
|||
import com.qyft.ms.app.device.spray.SprayTaskExecutor; |
|||
import com.qyft.ms.app.device.status.DeviceStatus; |
|||
import com.qyft.ms.app.device.status.SprayTask; |
|||
import com.qyft.ms.app.model.bo.SprayTaskStep; |
|||
import com.qyft.ms.app.model.entity.OperationLog; |
|||
import com.qyft.ms.app.model.entity.Position; |
|||
import com.qyft.ms.app.service.OperationLogService; |
|||
import com.qyft.ms.app.service.PositionService; |
|||
import com.qyft.ms.system.common.annotation.CommandMapping; |
|||
import com.qyft.ms.system.common.constant.CommandStatus; |
|||
import com.qyft.ms.system.common.device.command.CommandFuture; |
|||
import com.qyft.ms.system.common.device.command.DeviceCommandGenerator; |
|||
import com.qyft.ms.system.common.device.command.FrontResponseGenerator; |
|||
import com.qyft.ms.system.common.utils.CheckedRunnable; |
|||
import com.qyft.ms.system.common.utils.LambdaUtil; |
|||
import com.qyft.ms.system.core.handler.BaseCommandHandler; |
|||
import com.qyft.ms.system.model.bo.DeviceCommand; |
|||
import com.qyft.ms.system.model.form.FrontCmdControlForm; |
|||
import com.qyft.ms.system.service.WebSocketService; |
|||
import com.qyft.ms.system.service.device.DeviceCommandService; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import java.text.DecimalFormat; |
|||
import java.util.*; |
|||
import java.util.concurrent.CompletableFuture; |
|||
import java.util.concurrent.ExecutorService; |
|||
import java.util.concurrent.Executors; |
|||
|
|||
/** |
|||
* 喷涂_基质喷涂开始 |
|||
*/ |
|||
@Slf4j |
|||
@Component |
|||
@RequiredArgsConstructor |
|||
@CommandMapping("matrix_spray_start_bak")//业务指令注解 |
|||
public class MatrixSprayStart_bak extends BaseCommandHandler { |
|||
private static final ExecutorService singleExecutor = Executors.newSingleThreadExecutor(); |
|||
|
|||
private final SprayTaskExecutor sprayTaskExecutor; |
|||
private final PositionService positionService; |
|||
private final DeviceStatus deviceStatus; |
|||
private final OperationLogService operationLogService; |
|||
private final WebSocketService webSocketService; |
|||
private final DeviceCommandService deviceCommandService; |
|||
|
|||
private void nonNullCheck(String cmdId, String cmdCode, |
|||
String matrixPathType, |
|||
Double motorZHeight, |
|||
Double gasPressure, |
|||
Double volume, |
|||
Boolean highVoltage, |
|||
Double spacing, |
|||
Double movingSpeed, |
|||
Double times, |
|||
Object position) { |
|||
|
|||
Map<String, Object> paramMap = new LinkedHashMap<>(); |
|||
paramMap.put("matrix_path_type", matrixPathType); |
|||
paramMap.put("motor_z_height", motorZHeight); |
|||
paramMap.put("gas_pressure", gasPressure); |
|||
paramMap.put("volume", volume); |
|||
paramMap.put("high_voltage", highVoltage); |
|||
paramMap.put("spacing", spacing); |
|||
paramMap.put("moving_speed", movingSpeed); |
|||
paramMap.put("times", times); |
|||
paramMap.put("position", position); |
|||
|
|||
// 遍历 Map 检查是否为 null |
|||
for (Map.Entry<String, Object> entry : paramMap.entrySet()) { |
|||
if (entry.getValue() == null) { |
|||
String errorMsg = "参数 " + entry.getKey() + " 必填"; |
|||
webSocketService.pushDebugMsg(FrontResponseGenerator.generateJson(cmdId, cmdCode, CommandStatus.DEVICE_ERROR, errorMsg)); |
|||
throw new RuntimeException(errorMsg); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 使用单线程执行器保证线程安全,防止喷涂指令被多次调用 |
|||
*/ |
|||
@Override |
|||
protected CompletableFuture<Void> runAsync(CheckedRunnable task) { |
|||
return CompletableFuture.runAsync(LambdaUtil.unchecked(task), singleExecutor); |
|||
} |
|||
|
|||
/** |
|||
* { |
|||
* cmdName:'matrix_spray_start' |
|||
* cmdId:'', |
|||
* param:{ |
|||
* matrix_path_type:horizontal | vertical | grid;//喷涂路径类型 |
|||
* motor_z_height:;//高度 Z轴距离玻片的高度 |
|||
* gas_pressure://Mpa兆帕 不处理 |
|||
* volume:20;//单位uL微升 基质流速(控制注射泵速度) |
|||
* high_voltage:true/false;//是否打开高压 |
|||
* high_voltage_value:4000;//高压值 |
|||
* spacing:''//毫米 间距 |
|||
* moving_speed:8mm/s;//移动速度 轴速度 |
|||
* times:;//喷涂遍数 |
|||
* position:[{x1,y1,x2,y2,index}] |
|||
* } |
|||
* } |
|||
*/ |
|||
@Override |
|||
public CompletableFuture<Void> handle(FrontCmdControlForm form) { |
|||
SprayTask sprayTask = SprayTask.getInstance(); |
|||
if (sprayTask.isSpraying()) {//判断设备是否正在喷涂 |
|||
webSocketService.pushDebugMsg(FrontResponseGenerator.generateJson(form.getCmdId(), form.getCmdCode(), CommandStatus.DEVICE_ERROR, "设备正在喷涂,请先停止喷涂")); |
|||
throw new RuntimeException("设备正在喷涂,请先停止喷涂"); |
|||
} |
|||
sprayTask.setCmdId(form.getCmdId()); |
|||
sprayTask.setCmdCode(form.getCmdCode()); |
|||
sprayTask.setSpraying(true);//正在进行喷涂 |
|||
deviceStatus.setSpraying(true); |
|||
|
|||
// 1. 参数校验 |
|||
String matrixPathType = form.getStringParam("matrixPathType"); |
|||
Double motorZHeight = form.getDoubleParam("motorZHeight"); |
|||
Double gasPressure = form.getDoubleParam("gasPressure"); |
|||
Double volume = form.getDoubleParam("volume"); |
|||
Boolean highVoltage = form.getBooleanParam("highVoltage"); |
|||
Double highVoltageValue = form.getDoubleParam("highVoltageValue"); |
|||
Double spacing = form.getDoubleParam("spacing"); |
|||
Double movingSpeed = form.getDoubleParam("movingSpeed"); |
|||
Double times = form.getDoubleParam("times"); |
|||
@SuppressWarnings("unchecked") |
|||
List<Map<String, Object>> positionList = (List<Map<String, Object>>) form.getParams().get("position"); |
|||
|
|||
nonNullCheck(matrixPathType, form.getCmdId(), form.getCmdCode(), motorZHeight, gasPressure, volume, highVoltage, spacing, movingSpeed, times, positionList); |
|||
if (highVoltageValue != null && highVoltageValue > 6000) { |
|||
webSocketService.pushCMDResponseMsg(FrontResponseGenerator.generateJson(form.getCmdId(), form.getCmdCode(), CommandStatus.DEVICE_ERROR, "电压不能大于6000V")); |
|||
throw new RuntimeException("电压不能大于6000V"); |
|||
} |
|||
if (positionList.isEmpty()) { |
|||
webSocketService.pushCMDResponseMsg(FrontResponseGenerator.generateJson(form.getCmdId(), form.getCmdCode(), CommandStatus.DEVICE_ERROR, "喷涂区域不能为空")); |
|||
throw new RuntimeException("喷涂区域不能为空"); |
|||
} |
|||
// 3. 设定喷涂参数 |
|||
sprayTask.setSprayParam(matrixPathType, motorZHeight, gasPressure, volume, highVoltage, highVoltageValue, spacing, movingSpeed, times, positionList); |
|||
sprayTask.setCacheParams(form.getParams()); |
|||
|
|||
OperationLog operationLog = new OperationLog(); |
|||
Long matrixCraftId = Long.valueOf(Optional.ofNullable(sprayTask.getCacheParams().get("matrixCraftId")) |
|||
.filter(Number.class::isInstance) |
|||
.map(Number.class::cast) |
|||
.map(Number::intValue) |
|||
.orElse(0)); |
|||
operationLog.setMatrixId(matrixCraftId); |
|||
operationLog.setMatrixInfo(JSONUtil.toJsonStr(sprayTask.getCacheParams())); |
|||
operationLogService.add(operationLog); |
|||
|
|||
// 7.循环喷涂区域 |
|||
Position slidePosition1 = positionService.getOne(new LambdaQueryWrapper<Position>().eq(Position::getPointCode, "slide_position1")); |
|||
Position slidePosition2 = positionService.getOne(new LambdaQueryWrapper<Position>().eq(Position::getPointCode, "slide_position2")); |
|||
Position slidePosition3 = positionService.getOne(new LambdaQueryWrapper<Position>().eq(Position::getPointCode, "slide_position3")); |
|||
Position slidePosition4 = positionService.getOne(new LambdaQueryWrapper<Position>().eq(Position::getPointCode, "slide_position4")); |
|||
Double[][] slideArr = { |
|||
{slidePosition1.getX(), slidePosition1.getY()}, |
|||
{slidePosition2.getX(), slidePosition2.getY()}, |
|||
{slidePosition3.getX(), slidePosition3.getY()}, |
|||
{slidePosition4.getX(), slidePosition4.getY()} |
|||
}; |
|||
for (Map<String, Object> position : positionList) { |
|||
int index = (int) position.get("index"); //index 第几个玻片 |
|||
Double[] upperLeft = {((Number) position.get("x1")).doubleValue(), ((Number) position.get("y1")).doubleValue()}; //范围左上角 x1,y1 |
|||
Double[] lowerRight = {((Number) position.get("x2")).doubleValue(), ((Number) position.get("y2")).doubleValue()}; //范围右下角 x2,y2 |
|||
Double[] slide = slideArr[index];//获取玻片的坐标 |
|||
//规划路线坐标 |
|||
DecimalFormat df = new DecimalFormat("#.##"); |
|||
double left = Double.parseDouble(df.format(slide[0] + upperLeft[0])); |
|||
double right = Double.parseDouble(df.format(slide[0] + lowerRight[0])); |
|||
double top = Double.parseDouble(df.format(slide[1] + upperLeft[1])); |
|||
double bottom = Double.parseDouble(df.format(slide[1] + lowerRight[1])); |
|||
if ("horizontal".equals(matrixPathType)) {//喷涂路径类型 horizontal 横向 | vertical 纵向 | grid 网格先横向后纵向 |
|||
for (int i = 1; i <= times; i++) { |
|||
double topReal = top; |
|||
double bottomReal = bottom; |
|||
double leftReal = left; |
|||
double rightReal = right; |
|||
if (i % 2 == 0) {//双数喷涂,插空移动边界 |
|||
double halfSpacing = spacing / 2; |
|||
topReal = top + halfSpacing; |
|||
bottomReal = bottomReal - halfSpacing; |
|||
leftReal = left + halfSpacing; |
|||
rightReal = right - halfSpacing; |
|||
} |
|||
List<PathGenerator.Points> pathList = PathGenerator.generatePathPoints( |
|||
leftReal, rightReal, topReal, bottomReal, |
|||
spacing, |
|||
PathGenerator.MoveMode.HORIZONTAL_ZIGZAG_TOP_DOWN |
|||
); |
|||
List<List<DeviceCommand>> deviceCommandList = new ArrayList<>(); |
|||
|
|||
for (int j = 0; j < pathList.size(); j++) { |
|||
PathGenerator.Points p = pathList.get(j); |
|||
List<DeviceCommand> deviceCommands = new ArrayList<>(); |
|||
if (j == pathList.size() - 1) { |
|||
deviceCommands.add(DeviceCommandGenerator.motorXPositionSet(p.getX()));//移动x轴 |
|||
deviceCommands.add(DeviceCommandGenerator.motorYPositionSet(75.5 - p.getY()));//移动y轴 |
|||
} else { |
|||
deviceCommands.add(DeviceCommandGenerator.motorXPositionSet(p.getX(), movingSpeed));//移动x轴 |
|||
deviceCommands.add(DeviceCommandGenerator.motorYPositionSet(75.5 - p.getY()));//移动y轴 |
|||
} |
|||
deviceCommandList.add(deviceCommands); |
|||
} |
|||
|
|||
SprayTaskStep sprayTaskStep = new SprayTaskStep(); |
|||
sprayTaskStep.setIndex(index); |
|||
sprayTaskStep.setSpraySteps(deviceCommandList); |
|||
sprayTask.getSprayTaskStepList().add(sprayTaskStep); |
|||
} |
|||
} else if ("vertical".equals(matrixPathType)) { |
|||
for (int i = 1; i <= times; i++) { |
|||
double topReal = top; |
|||
double bottomReal = bottom; |
|||
double leftReal = left; |
|||
double rightReal = right; |
|||
if (i % 2 == 0) {//双数喷涂,插空移动边界 |
|||
double halfSpacing = spacing / 2; |
|||
topReal = top + halfSpacing; |
|||
bottomReal = bottomReal - halfSpacing; |
|||
leftReal = left + halfSpacing; |
|||
rightReal = right - halfSpacing; |
|||
} |
|||
List<PathGenerator.Points> pathList = PathGenerator.generatePathPoints( |
|||
leftReal, rightReal, topReal, bottomReal, |
|||
spacing, |
|||
PathGenerator.MoveMode.VERTICAL_ZIGZAG_LEFT_RIGHT |
|||
); |
|||
List<List<DeviceCommand>> deviceCommandList = new ArrayList<>(); |
|||
for (int j = 0; j < pathList.size(); j++) { |
|||
PathGenerator.Points p = pathList.get(j); |
|||
List<DeviceCommand> deviceCommands = new ArrayList<>(); |
|||
if (j == pathList.size() - 1) { |
|||
deviceCommands.add(DeviceCommandGenerator.motorXPositionSet(p.getX()));//移动x轴 |
|||
deviceCommands.add(DeviceCommandGenerator.motorYPositionSet(75.5 - p.getY()));//移动y轴 |
|||
} else { |
|||
deviceCommands.add(DeviceCommandGenerator.motorXPositionSet(p.getX()));//移动x轴 |
|||
deviceCommands.add(DeviceCommandGenerator.motorYPositionSet(75.5 - p.getY()));//移动y轴 |
|||
} |
|||
deviceCommandList.add(deviceCommands); |
|||
} |
|||
SprayTaskStep sprayTaskStep = new SprayTaskStep(); |
|||
sprayTaskStep.setIndex(index); |
|||
sprayTaskStep.setSpraySteps(deviceCommandList); |
|||
sprayTask.getSprayTaskStepList().add(sprayTaskStep); |
|||
} |
|||
} else if ("grid".equals(matrixPathType)) { |
|||
for (int i = 1; i <= times; i++) { |
|||
double topReal = top; |
|||
double bottomReal = bottom; |
|||
double leftReal = left; |
|||
double rightReal = right; |
|||
double halfSpacing = spacing / 2; |
|||
if (i % 2 == 0) {//双数喷涂,插空移动边界 |
|||
topReal = top + halfSpacing; |
|||
bottomReal = bottomReal - halfSpacing; |
|||
leftReal = left + halfSpacing; |
|||
rightReal = right - halfSpacing; |
|||
} |
|||
List<PathGenerator.Points> pathList = PathGenerator.generatePathPoints( |
|||
leftReal, rightReal, topReal, bottomReal, |
|||
spacing, |
|||
PathGenerator.MoveMode.HORIZONTAL_ZIGZAG_TOP_DOWN |
|||
); |
|||
List<List<DeviceCommand>> deviceCommandList = new ArrayList<>(); |
|||
for (int j = 0; j < pathList.size(); j++) { |
|||
PathGenerator.Points p = pathList.get(j); |
|||
List<DeviceCommand> deviceCommands = new ArrayList<>(); |
|||
if (j == pathList.size() - 1) { |
|||
deviceCommands.add(DeviceCommandGenerator.motorXPositionSet(p.getX()));//移动x轴 |
|||
deviceCommands.add(DeviceCommandGenerator.motorYPositionSet(75.5 - p.getY()));//移动y轴 |
|||
} else { |
|||
deviceCommands.add(DeviceCommandGenerator.motorXPositionSet(p.getX()));//移动x轴 |
|||
deviceCommands.add(DeviceCommandGenerator.motorYPositionSet(75.5 - p.getY()));//移动y轴 |
|||
} |
|||
deviceCommandList.add(deviceCommands); |
|||
} |
|||
SprayTaskStep sprayTaskStep = new SprayTaskStep(); |
|||
sprayTaskStep.setIndex(index); |
|||
sprayTaskStep.setSpraySteps(deviceCommandList); |
|||
sprayTask.getSprayTaskStepList().add(sprayTaskStep); |
|||
|
|||
pathList = PathGenerator.generatePathPoints( |
|||
leftReal, rightReal, topReal, bottomReal, |
|||
spacing, |
|||
PathGenerator.MoveMode.VERTICAL_ZIGZAG_LEFT_RIGHT |
|||
); |
|||
deviceCommandList = new ArrayList<>(); |
|||
for (int j = 0; j < pathList.size(); j++) { |
|||
PathGenerator.Points p = pathList.get(j); |
|||
List<DeviceCommand> deviceCommands = new ArrayList<>(); |
|||
if (j == pathList.size() - 1) { |
|||
deviceCommands.add(DeviceCommandGenerator.motorXPositionSet(p.getX()));//移动x轴 |
|||
deviceCommands.add(DeviceCommandGenerator.motorYPositionSet(75.5 - p.getY()));//移动y轴 |
|||
} else { |
|||
deviceCommands.add(DeviceCommandGenerator.motorXPositionSet(p.getX()));//移动x轴 |
|||
deviceCommands.add(DeviceCommandGenerator.motorYPositionSet(75.5 - p.getY()));//移动y轴 |
|||
} |
|||
deviceCommandList.add(deviceCommands); |
|||
} |
|||
SprayTaskStep sprayTaskStep2 = new SprayTaskStep(); |
|||
sprayTaskStep2.setIndex(index); |
|||
sprayTaskStep2.setSpraySteps(deviceCommandList); |
|||
sprayTask.getSprayTaskStepList().add(sprayTaskStep2); |
|||
} |
|||
} |
|||
} |
|||
return runAsync(() -> { |
|||
DeviceCommand overallDeviceStatusGetCommand = DeviceCommandGenerator.overallDeviceStatusGet(); |
|||
CommandFuture overallDeviceStatusGetCommandFuture = deviceCommandService.sendCommand(form.getCmdId(), form.getCmdCode(), overallDeviceStatusGetCommand); |
|||
commandWait(overallDeviceStatusGetCommandFuture); |
|||
|
|||
CommandFuture motorXOriginCommandFuture; |
|||
CommandFuture motorYOriginCommandFuture; |
|||
CommandFuture motorZOriginCommandFuture; |
|||
|
|||
List<CommandFuture> futureList = new ArrayList<>(); |
|||
if (!overallDeviceStatusGetCommandFuture.getResponseResult().getJSONObject("data").getBool("xAxisAtOrigin")) { |
|||
DeviceCommand motorXOriginCommand = DeviceCommandGenerator.motorXOrigin(); // x轴回原点 |
|||
motorXOriginCommandFuture = deviceCommandService.sendCommand(form.getCmdId(), form.getCmdCode(), motorXOriginCommand); |
|||
futureList.add(motorXOriginCommandFuture); |
|||
} |
|||
if (!overallDeviceStatusGetCommandFuture.getResponseResult().getJSONObject("data").getBool("yAxisAtOrigin")) { |
|||
DeviceCommand motorYOriginCommand = DeviceCommandGenerator.motorYOrigin();//y轴回原点 |
|||
motorYOriginCommandFuture = deviceCommandService.sendCommand(form.getCmdId(), form.getCmdCode(), motorYOriginCommand); |
|||
futureList.add(motorYOriginCommandFuture); |
|||
} |
|||
if (!overallDeviceStatusGetCommandFuture.getResponseResult().getJSONObject("data").getBool("zAxisAtOrigin")) { |
|||
DeviceCommand motorZOriginCommand = DeviceCommandGenerator.motorZOrigin();//z轴回原点 |
|||
motorZOriginCommandFuture = deviceCommandService.sendCommand(form.getCmdId(), form.getCmdCode(), motorZOriginCommand); |
|||
futureList.add(motorZOriginCommandFuture); |
|||
} |
|||
CommandFuture[] commandFutureArray = futureList.toArray(new CommandFuture[0]); |
|||
commandWait(commandFutureArray); |
|||
|
|||
DeviceCommand threeWayValveOpenSyringePipelineCommand = DeviceCommandGenerator.threeWayValveOpenNozzlePipeline();//打开三通阀注射器管路 |
|||
CommandFuture threeWayValveOpenSyringePipelineCommandFuture = deviceCommandService.sendCommand(form.getCmdId(), form.getCmdCode(), threeWayValveOpenSyringePipelineCommand); |
|||
commandWait(threeWayValveOpenSyringePipelineCommandFuture); |
|||
|
|||
if (sprayTask.getSprayParams().getHighVoltage()) {//加电 |
|||
DeviceCommand highVoltageOpenCommand = DeviceCommandGenerator.highVoltageOpen(highVoltageValue);//开启高压 |
|||
CommandFuture highVoltageOpenCommandFuture = deviceCommandService.sendCommand(sprayTask.getCmdId(), sprayTask.getCmdCode(), highVoltageOpenCommand); |
|||
commandWait(highVoltageOpenCommandFuture); |
|||
} |
|||
|
|||
DeviceCommand nozzleValveOpenCommand = DeviceCommandGenerator.nozzleValveOpen();//开启喷嘴阀 |
|||
CommandFuture nozzleValveOpenCommandFuture = deviceCommandService.sendCommand(sprayTask.getCmdId(), sprayTask.getCmdCode(), nozzleValveOpenCommand); |
|||
commandWait(nozzleValveOpenCommandFuture); |
|||
|
|||
// 10. 启动喷涂线程,开始喷涂 |
|||
sprayTaskExecutor.startTask(); |
|||
webSocketService.pushDebugMsg(FrontResponseGenerator.generateJson(form.getCmdId(), form.getCmdCode(), CommandStatus.SEND, "已开启喷涂线程")); |
|||
}); |
|||
} |
|||
|
|||
|
|||
} |
@ -0,0 +1,18 @@ |
|||
package com.qyft.ms.app.model.bo; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
|
|||
import java.util.List; |
|||
|
|||
@Data |
|||
@Schema(description = "多次喷涂每次喷涂的参数") |
|||
public class SprayTaskParams { |
|||
|
|||
private Integer index; |
|||
|
|||
private Long matrixId; |
|||
|
|||
private List<SprayTimes> times; |
|||
|
|||
} |
@ -0,0 +1,14 @@ |
|||
package com.qyft.ms.app.model.dto; |
|||
|
|||
import com.qyft.ms.app.model.bo.SprayTaskParams; |
|||
import com.qyft.ms.app.model.bo.SprayTimes; |
|||
import lombok.Data; |
|||
|
|||
import java.util.List; |
|||
|
|||
@Data |
|||
public class SetSprayTaskParamsDTO { |
|||
|
|||
private List<SprayTaskParams> sprayTaskParams; |
|||
|
|||
} |
@ -0,0 +1,14 @@ |
|||
package com.qyft.ms.app.model.vo; |
|||
|
|||
import com.qyft.ms.app.model.bo.SprayTaskParams; |
|||
import com.qyft.ms.app.model.bo.SprayTimes; |
|||
import lombok.Data; |
|||
|
|||
import java.util.List; |
|||
|
|||
@Data |
|||
public class GetSprayTaskParamsVO { |
|||
|
|||
private List<SprayTaskParams> sprayTaskParams; |
|||
|
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue