石墨消解仪后端服务
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

191 lines
6.7 KiB

package com.iflytop.gd.app.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.iflytop.gd.app.core.CraftsContext;
import com.iflytop.gd.app.mapper.CraftsMapper;
import com.iflytop.gd.app.model.entity.Crafts;
import com.iflytop.gd.app.model.entity.Ores;
import com.iflytop.gd.app.model.vo.CraftStatusVO;
import com.iflytop.gd.app.model.vo.SetCraftsVO;
import com.iflytop.gd.common.enums.automaton.CraftEvents;
import com.iflytop.gd.common.enums.automaton.CraftStates;
import com.iflytop.gd.common.exception.AppException;
import com.iflytop.gd.common.result.ResultCode;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import org.springframework.statemachine.config.StateMachineFactory;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
/**
* 工艺执行管理服务
*/
@Service
@RequiredArgsConstructor
public class CraftsService extends ServiceImpl<CraftsMapper, Crafts> {
private final StateMachineFactory<CraftStates, CraftEvents> stateMachineFactory;
private final WebSocketService webSocketService;
private final CraftsStepService craftsStepService;
private final OresService oresService;
private final ConcurrentHashMap<String, CraftsContext> contextMap = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, Future<?>> futureMap = new ConcurrentHashMap<>();
private ExecutorService executor;
@PostConstruct
public void init() {
this.executor = Executors.newCachedThreadPool();
}
/**
* 配置工艺
*/
public synchronized SetCraftsVO setCraft(Long craftId, String heatId) {
// 校验已有上下文状态,仅允许在 READY、STOPPED 或 FINISHED 状态下重置
CraftsContext existing = contextMap.get(heatId);
if (existing != null) {
CraftStates state = existing.getSm().getState().getId();
if (state == CraftStates.RUNNING || state == CraftStates.PAUSED) {
throw new AppException(ResultCode.CRAFT_RUNNING);
}
clearCraftContext(heatId);
}
Crafts craft = this.getById(craftId);
Ores ores = oresService.getById(craft.getOresId());
CraftsContext ctx = new CraftsContext(
heatId,
ores,
craft,
stateMachineFactory,
webSocketService,
craftsStepService
);
contextMap.put(heatId, ctx);
SetCraftsVO setCraftsVO = new SetCraftsVO();
setCraftsVO.setHeatId(heatId);
setCraftsVO.setCraftsName(craft.getName());
setCraftsVO.setCraftsId(craft.getId());
setCraftsVO.setOresName(ores.getName());
setCraftsVO.setOresId(ores.getId());
return setCraftsVO;
}
/**
* 启动执行工艺(需先调用 setCraft)
*/
public synchronized void startCrafts(String heatId) {
CraftsContext ctx = contextMap.get(heatId);
if (ctx == null) {
throw new AppException(ResultCode.CRAFT_CONTEXT_NULL);
}
if (futureMap.containsKey(heatId)) {
throw new AppException(ResultCode.CRAFT_RUNNING);
}
Future<?> future = executor.submit(ctx);
futureMap.put(heatId, future);
}
/**
* 暂停执行工艺
*/
public synchronized void pauseCrafts(String heatId) {
CraftsContext ctx = contextMap.get(heatId);
if (ctx == null) {
throw new AppException(ResultCode.CRAFT_CONTEXT_NULL);
}
ctx.pause();
}
/**
* 恢复执行工艺
*/
public synchronized void resumeCrafts(String heatId) {
CraftsContext ctx = contextMap.get(heatId);
if (ctx == null) {
throw new AppException(ResultCode.CRAFT_CONTEXT_NULL);
}
ctx.resume();
}
/**
* 停止执行工艺,不清除上下文
*/
public synchronized void stopCrafts(String heatId) {
CraftsContext ctx = contextMap.get(heatId);
Future<?> future = futureMap.remove(heatId);
if (ctx == null || future == null) {
throw new AppException(ResultCode.CRAFT_CONTEXT_NULL);
}
ctx.stop();
future.cancel(true);
}
/**
* 清理指定 heatId 的执行上下文和 Future
*/
public synchronized void clearCraftContext(String heatId) {
contextMap.remove(heatId);
Future<?> future = futureMap.remove(heatId);
if (future != null) future.cancel(true);
}
/**
* 查询指定 heatId 的执行状态
*/
public CraftStatusVO getStatus(String heatId) {
CraftsContext ctx = contextMap.get(heatId);
if (ctx == null) {
return null;
}
CraftStatusVO vo = new CraftStatusVO();
vo.setHeatId(heatId);
vo.setOresId(ctx.getOres().getId());
vo.setOresName(ctx.getOres().getName());
vo.setCraftsId(ctx.getCraft().getId());
vo.setCraftsName(ctx.getCraft().getName());
vo.setState(ctx.getSm().getState().getId());
vo.setCurrentIndex(ctx.getCurrentIndex());
vo.setSteps(ctx.getCraftsStepList());
return vo;
}
/**
* 查询所有正在执行的工艺状态
*/
public List<CraftStatusVO> getAllStatuses() {
return contextMap.entrySet().stream().map(entry -> {
String heatIdKey = entry.getKey();
CraftsContext ctx = entry.getValue();
CraftStatusVO vo = new CraftStatusVO();
vo.setHeatId(heatIdKey);
vo.setOresId(ctx.getOres().getId());
vo.setOresName(ctx.getOres().getName());
vo.setCraftsId(ctx.getCraft().getId());
vo.setCraftsName(ctx.getCraft().getName());
vo.setState(ctx.getSm().getState().getId());
vo.setCurrentIndex(ctx.getCurrentIndex());
vo.setSteps(ctx.getCraftsStepList());
return vo;
}).collect(Collectors.toList());
}
public List<Crafts> selectAllByOresId(Long oresId) {
return this.baseMapper.selectAllByOresId(oresId);
}
public Crafts findByName(String name) {
return this.getOne(new LambdaQueryWrapper<>(new Crafts()).eq(Crafts::getName, name));
}
public boolean deleteCrafts(String idsStr) {
List<Long> ids = Arrays.stream(idsStr.split(",")).map(Long::parseLong).collect(Collectors.toList());
return this.removeByIds(ids);
}
}