package com.chinaztt.mes.aps.service.impl;
|
|
import cn.hutool.core.collection.CollectionUtil;
|
import com.alibaba.fastjson.JSONObject;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.chinaztt.mes.aps.core.domain.OperationBo;
|
import com.chinaztt.mes.aps.core.domain.Order;
|
import com.chinaztt.mes.aps.entity.Resource;
|
import com.chinaztt.mes.aps.entity.ResourceDuration;
|
import com.chinaztt.mes.aps.entity.SceneTask;
|
import com.chinaztt.mes.aps.mapper.ApsCoreMapper;
|
import com.chinaztt.mes.aps.mapper.ResourceDurationMapper;
|
import com.chinaztt.mes.aps.mapper.ResourceMapper;
|
import com.chinaztt.mes.aps.mapper.SceneTaskMapper;
|
import com.chinaztt.mes.aps.service.ApsCoreService;
|
import com.chinaztt.mes.aps.vo.GanttTaskVo;
|
import com.chinaztt.mes.aps.vo.ResourceVo;
|
import com.chinaztt.mes.basic.entity.Workstation;
|
import com.chinaztt.mes.basic.mapper.WorkstationMapper;
|
import com.chinaztt.mes.plan.entity.MoStructureComponent;
|
import com.chinaztt.mes.plan.mapper.MoStructureComponentMapper;
|
import com.chinaztt.mes.production.dto.OperationTaskDTO;
|
import com.chinaztt.mes.production.entity.OperationTask;
|
import com.chinaztt.mes.production.entity.OperationTaskMaterial;
|
import com.chinaztt.mes.production.entity.OperationTaskSupply;
|
import com.chinaztt.mes.production.mapper.OperationTaskMapper;
|
import com.chinaztt.mes.production.mapper.OperationTaskMaterialMapper;
|
import com.chinaztt.mes.production.mapper.OperationTaskSupplyMapper;
|
import com.chinaztt.mes.production.state.operationtask.constant.OperationTaskStateStringValues;
|
import com.chinaztt.ztt.common.core.util.R;
|
import com.chinaztt.ztt.common.sequence.sequence.Sequence;
|
import lombok.AllArgsConstructor;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import java.math.BigDecimal;
|
import java.math.RoundingMode;
|
import java.time.LocalDate;
|
import java.time.LocalDateTime;
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
/**
|
* @Author: zhangxy
|
* @Date: 2020-10-09 10:35
|
*/
|
@Service
|
@AllArgsConstructor
|
public class ApsCoreServiceImpl implements ApsCoreService {
|
|
private Sequence opTaskSequence;
|
private ApsCoreMapper apsCoreMapper;
|
private ResourceMapper resourceMapper;
|
private ResourceDurationMapper resourceDurationMapper;
|
private SceneTaskMapper sceneTaskMapper;
|
private OperationTaskMapper operationTaskMapper;
|
private OperationTaskSupplyMapper operationTaskSupplyMapper;
|
private MoStructureComponentMapper moStructureComponentMapper;
|
private OperationTaskMaterialMapper operationTaskMaterialMapper;
|
private WorkstationMapper workstationMapper;
|
|
|
@Override
|
public void saveSceneTask(SceneTask task) {
|
sceneTaskMapper.insert(task);
|
}
|
|
@Override
|
public OperationBo queryOperation(Long operationId) {
|
return apsCoreMapper.queryOperation(operationId);
|
}
|
|
@Override
|
public JSONObject query(Long sceneId, Long groupId, LocalDate start, LocalDate end) {
|
List<ResourceVo> resources;
|
if (groupId == null || groupId == 0) {
|
resources = apsCoreMapper.getAllResourceVo();
|
} else {
|
resources = apsCoreMapper.queryResourceByGroupId(groupId);
|
}
|
Set<Long> resourceIds = resources.stream().map(r -> r.getId()).collect(Collectors.toSet());
|
JSONObject obj = new JSONObject();
|
obj.put("resources", resources);
|
if (sceneId != null && sceneId > 0) {
|
obj.put("sceneTasks", apsCoreMapper.querySceneTaskByTimeRange(sceneId, start, end, resourceIds));
|
}
|
obj.put("operationTasks", apsCoreMapper.queryOperationTaskByTimeRange(start, end, resourceIds));
|
return obj;
|
}
|
|
@Override
|
public JSONObject loadGantt(Long sceneId, List<Long> workStationList, String workCenter, LocalDate start, LocalDate end, List<String> stateList) {
|
List<ResourceVo> resources = apsCoreMapper.queryResourceByGroupIdGantt(workStationList, workCenter);
|
Set<Long> workstationIds = resources.stream().map(r -> r.getId()).collect(Collectors.toSet());
|
JSONObject obj = new JSONObject();
|
obj.put("resources", resources);
|
if (sceneId != null && sceneId > 0) {
|
obj.put("sceneTasks", apsCoreMapper.querySceneTaskByTimeRange(sceneId, start, end, workstationIds));
|
}
|
obj.put("operationTasks", apsCoreMapper.queryOperationTaskByTimeRangeGantt(start, end, workstationIds, stateList));
|
return obj;
|
}
|
|
/**
|
* 根据工作站零件数量计算机台时间
|
*
|
* @param workstationId
|
* @param partId
|
* @param qty
|
* @return
|
*/
|
@Override
|
public OperationTaskDTO calOperationTaskTime(Long workstationId, Long partId, BigDecimal qty) {
|
OperationTaskDTO operationTask = new OperationTaskDTO();
|
//根据工作站查询资源
|
Resource resource = resourceMapper.selectOne(Wrappers.<Resource>lambdaQuery()
|
.eq(Resource::getWorkstationId, workstationId));
|
if (resource != null) {
|
//根据资源id和零件id 查询资源产能
|
List<ResourceDuration> resourceDurationList = resourceDurationMapper.selectList(Wrappers.<ResourceDuration>lambdaQuery()
|
.orderByDesc(ResourceDuration::getId)
|
.eq(ResourceDuration::getPartId, partId)
|
.eq(ResourceDuration::getResourceId, resource.getId()));
|
if (CollectionUtil.isNotEmpty(resourceDurationList)) {
|
ResourceDuration resourceDuration = resourceDurationList.get(0);
|
//工单时间 = (计划数量 / 机台速率) + 前置时间 + 后置时间 单位是分钟
|
BigDecimal machnieTime = qty.divide(resourceDuration.getProductionRate(), 0, BigDecimal.ROUND_UP)
|
.add(resourceDuration.getPostProcessing())
|
.add(resourceDuration.getSetupTime());
|
//查询未完成的工单的最大的计划完成时间 如果没有就获取当前时间
|
LocalDateTime localDateTime = apsCoreMapper.getOperatioTaskMaxPlanEndTime(workstationId);
|
if (localDateTime == null) {
|
localDateTime = LocalDateTime.now();
|
}
|
operationTask.setTaskTheoreticalTime(machnieTime);
|
operationTask.setPlannedStartDate(localDateTime.plusMinutes(1));
|
operationTask.setPlannedFinishDate(operationTask.getPlannedStartDate().plusMinutes(machnieTime.longValue()));
|
}
|
}
|
return operationTask;
|
}
|
|
|
/**
|
* 根据零件数量 自动选择机台
|
*
|
* @param partId
|
* @param qty
|
* @return
|
*/
|
@Override
|
public OperationTaskDTO autoSetTime(String workCenter, Long partId, BigDecimal qty) {
|
OperationTaskDTO returnOp = new OperationTaskDTO();
|
//查询当前工作中心下面配置了 资源能力的 工作站
|
List<Long> workstationIds = apsCoreMapper.getWorkstationIdByWorkcenter(workCenter, partId);
|
if (CollectionUtil.isNotEmpty(workstationIds)) {
|
// 在这些工作站 中查找 未完成的工单 并且根据 计划完成时间 正序排序
|
List<OperationTask> operationTaskList = operationTaskMapper.selectList(Wrappers.<OperationTask>lambdaQuery()
|
.orderByAsc(OperationTask::getPlannedFinishDate)
|
.isNotNull(OperationTask::getPlannedFinishDate)
|
.in(OperationTask::getState, Arrays.asList("07unsubmit", "01pending", "02inProgress", "03interrupted"))
|
.in(OperationTask::getWorkstationId, workstationIds));
|
//设置默认时间为当前
|
LocalDateTime planStartDate = LocalDateTime.now();
|
//如果工单存 就先看看有没有不存在工单的机台 如果都有工单机台就选取第一个 工单的机台 时间根据最早时间计算 如果不存在工单就 工作站 选取第一个 时间获取当前
|
if (CollectionUtil.isNotEmpty(operationTaskList)) {
|
//将工单根据工作站进行分组
|
Map<Long, List<OperationTask>> mapWorkstationIdOps = operationTaskList.stream().collect(Collectors.groupingBy(OperationTask::getWorkstationId));
|
//过滤出在产工作台
|
List<Long> optaskStationIdList = new ArrayList<>(mapWorkstationIdOps.keySet());
|
//过滤出空闲工作台
|
List<Long> noOptaskStationIdList = workstationIds.stream().filter(item -> optaskStationIdList.stream().allMatch(each -> !item.equals(each))).collect(Collectors.toList());
|
//如果 空闲工作台 是空的
|
if (CollectionUtil.isEmpty(noOptaskStationIdList)) {
|
OperationTask firstFirstFinished = operationTaskList.get(0);
|
returnOp.setWorkstationId(firstFirstFinished.getWorkstationId());
|
//如果最早的结束时间在当前时间之后 开始时间就是当前时间 + 1min
|
if (firstFirstFinished.getPlannedFinishDate().isAfter(LocalDateTime.now())) {
|
planStartDate = firstFirstFinished.getPlannedFinishDate().plusMinutes(1);
|
}
|
} else {
|
returnOp.setWorkstationId(noOptaskStationIdList.get(0));
|
}
|
} else {
|
returnOp.setWorkstationId(workstationIds.get(0));
|
}
|
returnOp.setPlannedStartDate(planStartDate);
|
//查询资源
|
Resource resource = resourceMapper.selectOne(Wrappers.<Resource>lambdaQuery()
|
.eq(Resource::getWorkstationId, returnOp.getWorkstationId()));
|
//查询能力
|
ResourceDuration resourceDuration = resourceDurationMapper.selectOne(Wrappers.<ResourceDuration>lambdaQuery()
|
.orderByDesc(ResourceDuration::getId)
|
.eq(ResourceDuration::getPartId, partId)
|
.eq(ResourceDuration::getResourceId, resource.getId())
|
.last("limit 1"));
|
//计算工单需要完成时间
|
BigDecimal machnieTime = qty.divide(resourceDuration.getProductionRate(), 0, BigDecimal.ROUND_UP)
|
.add(resourceDuration.getPostProcessing())
|
.add(resourceDuration.getSetupTime());
|
//结束时间 + 完成时间
|
returnOp.setPlannedFinishDate(returnOp.getPlannedStartDate().plusMinutes(machnieTime.longValue()));
|
returnOp.setTaskTheoreticalTime(machnieTime);
|
Workstation workstation = workstationMapper.selectById(returnOp.getWorkstationId());
|
returnOp.setWorkstationNo(workstation.getWorkstationNo());
|
returnOp.setWorkstationName(workstation.getName());
|
}
|
return returnOp;
|
}
|
|
@Override
|
public Boolean updateTaskById(GanttTaskVo taskVo) {
|
SceneTask task = sceneTaskMapper.selectById(Long.valueOf(taskVo.getId()));
|
task.setStartTime(taskVo.getStartDate());
|
task.setEndTime(taskVo.getEndDate());
|
task.setResourceId(Long.valueOf(taskVo.getParent()));
|
sceneTaskMapper.updateById(task);
|
return Boolean.TRUE;
|
}
|
|
@Override
|
public Boolean removeSceneTask(Long id) {
|
sceneTaskMapper.deleteById(id);
|
return Boolean.TRUE;
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
@Override
|
public synchronized R<Boolean> applyToReality(Long sceneId) {
|
List<SceneTask> taskList = sceneTaskMapper.selectList(Wrappers.<SceneTask>lambdaQuery().eq(SceneTask::getSceneId, sceneId).eq(SceneTask::getApplied, false));
|
if (CollectionUtil.isEmpty(taskList)) {
|
return R.failed("该场景下没有未应用的内容");
|
}
|
for (SceneTask sceneTask : taskList) {
|
OperationTask optask = new OperationTask();
|
String number = opTaskSequence.nextNo();
|
optask.setOptaskNo(number);
|
optask.setRoutingId(sceneTask.getRoutingId());
|
optask.setRoutingOperationId(sceneTask.getRoutingOperationId());
|
optask.setState(OperationTaskStateStringValues.PENDING);
|
optask.setPlannedQuantity(sceneTask.getQuantity());
|
optask.setPlannedStartDate(sceneTask.getStartTime());
|
optask.setPlannedFinishDate(sceneTask.getEndTime());
|
optask.setPartId(sceneTask.getPartId());
|
|
Resource resource = resourceMapper.selectById(sceneTask.getResourceId());
|
optask.setWorkstationId(resource.getWorkstationId());
|
optask.setResourceId(resource.getId());
|
|
operationTaskMapper.insert(optask);
|
|
createMaterial(optask);
|
createSupply(optask, sceneTask);
|
|
sceneTask.setApplied(true);
|
sceneTaskMapper.updateById(sceneTask);
|
}
|
|
return R.ok();
|
}
|
|
|
/**
|
* 工单供应表 暂定1:1
|
* todo 拆分或者合并订单
|
*
|
* @param optask
|
* @param sceneTask
|
*/
|
private void createSupply(OperationTask optask, SceneTask sceneTask) {
|
OperationTaskSupply supply = new OperationTaskSupply();
|
supply.setMoId(sceneTask.getOrderId());
|
supply.setOperationTaskId(optask.getId());
|
supply.setQuantitySupply(sceneTask.getQuantity());
|
operationTaskSupplyMapper.insert(supply);
|
}
|
|
private void createMaterial(OperationTask optask) {
|
LambdaQueryWrapper wrapper = Wrappers.<MoStructureComponent>lambdaQuery().eq(MoStructureComponent::getRoutingOperationId, optask.getRoutingOperationId());
|
List<MoStructureComponent> list = moStructureComponentMapper.selectList(wrapper);
|
if (CollectionUtil.isNotEmpty(list)) {
|
for (MoStructureComponent s : list) {
|
OperationTaskMaterial material = new OperationTaskMaterial();
|
material.setOperationTaskId(optask.getId());
|
material.setPartId(s.getPartId());
|
material.setQpa(s.getQpa());
|
material.setQuantityRequired(s.getQpa().multiply(optask.getPlannedQuantity()));
|
operationTaskMaterialMapper.insert(material);
|
}
|
}
|
}
|
|
|
}
|