Browse Source

feat:工艺部分实现

tags/freeze
白凤吉 3 months ago
parent
commit
fe2194f04f
  1. 5
      src/main/java/com/iflytop/gd/app/common/enums/CraftEvents.java
  2. 5
      src/main/java/com/iflytop/gd/app/common/enums/CraftStates.java
  3. 45
      src/main/java/com/iflytop/gd/app/config/CraftsStateMachineConfig.java
  4. 110
      src/main/java/com/iflytop/gd/app/core/CraftsContext.java
  5. 8
      src/main/java/com/iflytop/gd/app/model/bo/CraftsStep.java
  6. 23
      src/main/java/com/iflytop/gd/app/model/bo/TubeSol.java
  7. 124
      src/main/java/com/iflytop/gd/app/service/CraftsStepService.java
  8. 19
      src/main/java/com/iflytop/gd/system/mapper/CraftsMapper.java
  9. 15
      src/main/java/com/iflytop/gd/system/mapper/OresMapper.java
  10. 25
      src/main/java/com/iflytop/gd/system/model/entity/Crafts.java
  11. 20
      src/main/java/com/iflytop/gd/system/model/entity/Ores.java
  12. 30
      src/main/java/com/iflytop/gd/system/model/vo/OresCraftsListVO.java
  13. 47
      src/main/java/com/iflytop/gd/system/service/CraftsService.java
  14. 98
      src/main/java/com/iflytop/gd/system/service/OresService.java

5
src/main/java/com/iflytop/gd/app/common/enums/CraftEvents.java

@ -0,0 +1,5 @@
package com.iflytop.gd.app.common.enums;
public enum CraftEvents {
START, STEP_COMPLETE, PAUSE, RESUME, STOP, ERROR_OCCUR
}

5
src/main/java/com/iflytop/gd/app/common/enums/CraftStates.java

@ -0,0 +1,5 @@
package com.iflytop.gd.app.common.enums;
public enum CraftStates {
READY, RUNNING, PAUSED, STOPPED, ERROR, FINISHED
}

45
src/main/java/com/iflytop/gd/app/config/CraftsStateMachineConfig.java

@ -0,0 +1,45 @@
package com.iflytop.gd.app.config;
import com.iflytop.gd.app.common.enums.CraftEvents;
import com.iflytop.gd.app.common.enums.CraftStates;
import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.config.EnableStateMachineFactory;
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
import java.util.EnumSet;
@Configuration
@EnableStateMachineFactory
public class CraftsStateMachineConfig
extends StateMachineConfigurerAdapter<CraftStates, CraftEvents> {
@Override
public void configure(StateMachineStateConfigurer<CraftStates, CraftEvents> states) throws Exception {
states
.withStates()
.initial(CraftStates.READY)
.states(EnumSet.allOf(CraftStates.class));
}
@Override
public void configure(StateMachineTransitionConfigurer<CraftStates, CraftEvents> trans) throws Exception {
trans
.withExternal().source(CraftStates.READY).target(CraftStates.RUNNING).event(CraftEvents.START)
.and()
.withInternal().source(CraftStates.RUNNING).event(CraftEvents.STEP_COMPLETE)
.and()
.withExternal().source(CraftStates.RUNNING).target(CraftStates.PAUSED).event(CraftEvents.PAUSE)
.and()
.withExternal().source(CraftStates.PAUSED).target(CraftStates.RUNNING).event(CraftEvents.RESUME)
.and()
.withExternal().source(CraftStates.RUNNING).target(CraftStates.STOPPED).event(CraftEvents.STOP)
.and()
.withExternal().source(CraftStates.PAUSED).target(CraftStates.STOPPED).event(CraftEvents.STOP)
.and()
.withExternal().source(CraftStates.RUNNING).target(CraftStates.ERROR).event(CraftEvents.ERROR_OCCUR)
.and()
.withExternal().source(CraftStates.RUNNING).target(CraftStates.FINISHED).event(CraftEvents.STOP);
}
}

110
src/main/java/com/iflytop/gd/app/core/CraftsContext.java

@ -0,0 +1,110 @@
package com.iflytop.gd.app.core;
import cn.hutool.json.JSONUtil;
import com.iflytop.gd.app.common.constant.WebSocketMessageType;
import com.iflytop.gd.app.common.enums.CraftEvents;
import com.iflytop.gd.app.common.enums.CraftStates;
import com.iflytop.gd.app.model.bo.CraftsStep;
import com.iflytop.gd.app.service.CraftsStepService;
import com.iflytop.gd.system.model.entity.Crafts;
import com.iflytop.gd.system.service.WebSocketService;
import lombok.Getter;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.config.StateMachineFactory;
import org.springframework.statemachine.listener.StateMachineListenerAdapter;
import org.springframework.statemachine.state.State;
import reactor.core.publisher.Mono;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Getter
public class CraftsContext implements Runnable {
private final String heatId;
private final List<CraftsStep> craftsStepList;
private final StateMachine<CraftStates, CraftEvents> sm;
private final WebSocketService ws;
private final CraftsStepService craftsStepService;
private int currentIndex = 0;
public CraftsContext(String heatId, Crafts craft, StateMachineFactory<CraftStates, CraftEvents> factory, CraftsStepService craftsStepService, WebSocketService ws) {
this.heatId = heatId;
this.craftsStepList = JSONUtil.parseArray(craft.getSteps()).toList(CraftsStep.class);
this.craftsStepService = craftsStepService;
this.ws = ws;
this.sm = factory.getStateMachine(heatId);
Mono.from(sm.startReactively()).block(); // READY -> RUNNING
Message<CraftEvents> startMsg = MessageBuilder.withPayload(CraftEvents.START).build();
Mono.from(sm.sendEvent(Mono.just(startMsg))).block();
sm.addStateListener(new StateMachineListenerAdapter<>() {
@Override
public void stateChanged(State<CraftStates, CraftEvents> from, State<CraftStates, CraftEvents> to) {
Map<String, Object> dataMap = new HashMap<>();
dataMap.put("heatId", heatId);
dataMap.put("event", to.getId());
dataMap.put("index", currentIndex);
ws.push(WebSocketMessageType.CRAFTS, dataMap);
}
});
}
@Override
public void run() {
try {
for (; currentIndex < craftsStepList.size(); currentIndex++) {
if (sm.getState().getId() == CraftStates.STOPPED) break; // 如果收到 STOP 事件直接退出
CraftsStep step = craftsStepList.get(currentIndex);
boolean ok = executeStep(step);
if (!ok) {
Message<CraftEvents> errorMsg = MessageBuilder.withPayload(CraftEvents.ERROR_OCCUR).build();
Mono.from(sm.sendEvent(Mono.just(errorMsg))).block();
break;
}
Message<CraftEvents> completeMsg = MessageBuilder.withPayload(CraftEvents.STEP_COMPLETE).build();
Mono.from(sm.sendEvent(Mono.just(completeMsg))).block();
synchronized (this) {
while (sm.getState().getId() == CraftStates.PAUSED) {
this.wait();
}
}
}
if (sm.getState().getId() == CraftStates.RUNNING) {
Message<CraftEvents> stopMsg = MessageBuilder.withPayload(CraftEvents.STOP).build();
Mono.from(sm.sendEvent(Mono.just(stopMsg))).block();
}
} catch (InterruptedException e) {
Message<CraftEvents> stopMsg = MessageBuilder.withPayload(CraftEvents.STOP).build();
Mono.from(sm.sendEvent(Mono.just(stopMsg))).block();
}
}
private boolean executeStep(CraftsStep step) {
// TODO: 调用 craftsStepService device 服务执行具体命令
return true;
}
public void pause() {
Message<CraftEvents> pauseMsg = MessageBuilder.withPayload(CraftEvents.PAUSE).build();
Mono.from(sm.sendEvent(Mono.just(pauseMsg))).block();
}
public void resume() {
Message<CraftEvents> resumeMsg = MessageBuilder.withPayload(CraftEvents.RESUME).build();
Mono.from(sm.sendEvent(Mono.just(resumeMsg))).block();
synchronized (this) {
this.notify();
}
}
public void stop() {
Message<CraftEvents> stopMsg = MessageBuilder.withPayload(CraftEvents.STOP).build();
Mono.from(sm.sendEvent(Mono.just(stopMsg))).block();
synchronized (this) {
this.notify();
}
}
}

8
src/main/java/com/iflytop/gd/app/model/bo/CraftsStep.java

@ -0,0 +1,8 @@
package com.iflytop.gd.app.model.bo;
import cn.hutool.json.JSONObject;
public class CraftsStep {
String name;
JSONObject params;
}

23
src/main/java/com/iflytop/gd/app/model/bo/TubeSol.java

@ -0,0 +1,23 @@
package com.iflytop.gd.app.model.bo;
import lombok.Data;
/**
* 试管添加溶液
*/
@Data
public class TubeSol {
/**
* 需要添加溶液的试管编号
*/
private Integer tubeNum;
/**
* 溶液id
*/
private Long solId;
/**
* 加液量
*/
private Integer volume;
}

124
src/main/java/com/iflytop/gd/app/service/CraftsStepService.java

@ -0,0 +1,124 @@
package com.iflytop.gd.app.service;
import com.iflytop.gd.app.model.bo.TubeSol;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 设备步骤操作
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class CraftsStepService {
/**
* 抬起托盘
*
* @param heatId 加热区id
*/
public boolean upTray(String heatId) {
return true;
}
/**
* 降下托盘
*
* @param heatId 加热区id
*/
public boolean downTray(String heatId) {
return true;
}
/**
* 添加溶液
*
* @param tubeSolList 需要添加溶液的试管与溶液
*/
public boolean addLiquid(List<TubeSol> tubeSolList) {
return true;
}
/**
* 将指定加热区的托盘移至加液区
*
* @param heatId 加热区id
*/
public boolean moveToSol(String heatId) {
return true;
}
/**
* 移至加热
*
* @param heatId 加热区id
*/
public boolean moveToHeat(String heatId) {
return true;
}
/**
* 摇匀
*
* @param second 摇匀时间
*/
public boolean shaking(int second) {
return true;
}
/**
* 开始加热
*
* @param heatId 加热区id
* @param temperature 目标温度
*/
public boolean startHeating(String heatId, double temperature) {
return true;
}
/**
* 停止加热
*
* @param heatId 加热区id
*/
public boolean stopHeating(String heatId) {
return true;
}
/**
* 停止加热
*/
public boolean takePhoto() {
return true;
}
//移至异常
public boolean moveToExc() {
return true;
}
//移除异常
public boolean moveOutToExc() {
return true;
}
/**
* 等待
*
* @param second
*/
public boolean delay(int second) {
try {
Thread.sleep(second * 1000L);
return true;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return false;
}
}

19
src/main/java/com/iflytop/gd/system/mapper/CraftsMapper.java

@ -0,0 +1,19 @@
package com.iflytop.gd.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.iflytop.gd.system.model.entity.Crafts;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 工艺持久层接口
*/
@Mapper
public interface CraftsMapper extends BaseMapper<Crafts> {
List<Crafts> selectAllByOresId(Long oresId);
Crafts findByName(String name);
}

15
src/main/java/com/iflytop/gd/system/mapper/OresMapper.java

@ -0,0 +1,15 @@
package com.iflytop.gd.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.iflytop.gd.system.model.entity.Ores;
import org.apache.ibatis.annotations.Mapper;
/**
* 矿石持久层接口
*/
@Mapper
public interface OresMapper extends BaseMapper<Ores> {
Ores findByName(String name);
}

25
src/main/java/com/iflytop/gd/system/model/entity/Crafts.java

@ -0,0 +1,25 @@
package com.iflytop.gd.system.model.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.iflytop.gd.system.common.base.BaseEntity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Schema(description = "工艺")
@TableName("crafts")
@Data
public class Crafts extends BaseEntity {
@NotBlank
@Schema(description = "工艺名称")
private String name;
@Schema(description = "工艺步骤")
private String steps;
@Schema(description = "矿石ID")
private Long oresId;
}

20
src/main/java/com/iflytop/gd/system/model/entity/Ores.java

@ -0,0 +1,20 @@
package com.iflytop.gd.system.model.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.iflytop.gd.system.common.base.BaseEntity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Schema(description = "矿石")
@TableName("ores")
@Data
public class Ores extends BaseEntity {
@NotBlank()
@Schema(description = "矿石名称")
private String name;
}

30
src/main/java/com/iflytop/gd/system/model/vo/OresCraftsListVO.java

@ -0,0 +1,30 @@
package com.iflytop.gd.system.model.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.iflytop.gd.system.model.entity.Crafts;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
@Schema(description = "矿石工艺视图")
@Data
public class OresCraftsListVO {
@Schema(description = "矿石id")
private Long id;
@Schema(description = "矿石名称")
private String oresName;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
@Schema(description = "该矿石下工艺列表")
private List<Crafts> craftsList;
}

47
src/main/java/com/iflytop/gd/system/service/CraftsService.java

@ -0,0 +1,47 @@
package com.iflytop.gd.system.service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.iflytop.gd.system.mapper.CraftsMapper;
import com.iflytop.gd.system.model.entity.Crafts;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* 工艺
*/
@Service
@RequiredArgsConstructor
public class CraftsService extends ServiceImpl<CraftsMapper, Crafts>{
public List<Crafts> selectAllByOresId(Long oresId) {
return this.baseMapper.selectAllByOresId(oresId);
}
public Crafts findByName(String name) {
return this.baseMapper.findByName(name);
}
public boolean addCrafts(Crafts crafts) {
return this.baseMapper.insert(crafts) > 0;
}
public boolean updateCrafts(Crafts crafts) {
return this.baseMapper.updateById(crafts) > 0;
}
public boolean deleteCrafts(String idsStr) {
List<Long> ids = Arrays.stream(idsStr.split(","))
.map(Long::parseLong)
.collect(Collectors.toList());
return this.removeByIds(ids);
}
public Crafts findCraftsById(Long id) {
return this.baseMapper.selectById(id);
}
}

98
src/main/java/com/iflytop/gd/system/service/OresService.java

@ -0,0 +1,98 @@
package com.iflytop.gd.system.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.iflytop.gd.system.common.base.BasePageQuery;
import com.iflytop.gd.system.mapper.CraftsMapper;
import com.iflytop.gd.system.mapper.OresMapper;
import com.iflytop.gd.system.model.entity.Crafts;
import com.iflytop.gd.system.model.entity.Ores;
import com.iflytop.gd.system.model.vo.OresCraftsListVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 矿石业务实现类
*/
@Service
@RequiredArgsConstructor
public class OresService extends ServiceImpl<OresMapper, Ores> {
private final CraftsMapper craftsMapper;
public IPage<OresCraftsListVO> getPage(BasePageQuery pageQuery) {
// 构建分页对象
Page<Ores> oresPage = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
// 分页查询矿石数据
IPage<Ores> oresIPage = this.baseMapper.selectPage(oresPage, new QueryWrapper<Ores>());
// 获取矿石ID列表
List<Long> oresIds = oresIPage.getRecords().stream()
.map(Ores::getId)
.collect(Collectors.toList());
// 查询对应的工艺数据
QueryWrapper<Crafts> craftsQueryWrapper = new QueryWrapper<>();
craftsQueryWrapper.in("ores_id", oresIds);
List<Crafts> craftsList = craftsMapper.selectList(craftsQueryWrapper);
// 将工艺数据按矿石ID分组
Map<Long, List<Crafts>> craftsMap = craftsList.stream()
.collect(Collectors.groupingBy(Crafts::getOresId));
// 转换成 OresCraftsListVO
List<OresCraftsListVO> oresCraftsList = oresIPage.getRecords().stream().map(ores -> {
OresCraftsListVO oresCraftsListVO = new OresCraftsListVO();
oresCraftsListVO.setId(ores.getId());
oresCraftsListVO.setOresName(ores.getName());
oresCraftsListVO.setCreateTime(ores.getCreateTime());
oresCraftsListVO.setUpdateTime(ores.getUpdateTime());
// 设置该矿石的工艺列表
List<Crafts> crafts = craftsMap.get(ores.getId());
oresCraftsListVO.setCraftsList(crafts);
return oresCraftsListVO;
}).collect(Collectors.toList());
// 将转换后的分页数据放入新的分页对象
Page<OresCraftsListVO> resultPage = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
resultPage.setTotal(oresIPage.getTotal());
resultPage.setRecords(oresCraftsList);
return resultPage;
}
public Ores findByName(String name) {
return this.baseMapper.findByName(name);
}
public boolean addOres(Ores ores) {
return this.baseMapper.insert(ores) > 0;
}
public boolean updateOres(Ores ores) {
return this.baseMapper.updateById(ores) > 0;
}
public boolean deleteOres(String idsStr) {
List<Long> ids = Arrays.stream(idsStr.split(","))
.map(Long::parseLong)
.collect(Collectors.toList());
return this.removeByIds(ids);
}
}
Loading…
Cancel
Save