package com.foreverwin.mesnac.dispatch.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.foreverwin.mesnac.common.constant.Constants;
import com.foreverwin.mesnac.common.dto.SfcDispatchDto;
import com.foreverwin.mesnac.common.enums.DispatchStatusEnum;
import com.foreverwin.mesnac.common.enums.HandleEnum;
import com.foreverwin.mesnac.common.service.ProdReadyTaskService;
import com.foreverwin.mesnac.common.service.SfcDispatchCommonService;
import com.foreverwin.mesnac.common.util.DateUtil;
import com.foreverwin.mesnac.common.util.ExcelUtils;
import com.foreverwin.mesnac.common.util.StringUtil;
import com.foreverwin.mesnac.dispatch.dto.RouterDTO;
import com.foreverwin.mesnac.dispatch.dto.SfcDispatchEmployeeDto;
import com.foreverwin.mesnac.dispatch.dto.WorkCenterWorkTimeDTO;
import com.foreverwin.mesnac.dispatch.mapper.SfcDispatchMapper;
import com.foreverwin.mesnac.dispatch.model.CallItem;
import com.foreverwin.mesnac.dispatch.model.SfcDispatch;
import com.foreverwin.mesnac.dispatch.model.SfcDispatchEmployee;
import com.foreverwin.mesnac.dispatch.model.UserResource;
import com.foreverwin.mesnac.dispatch.service.*;
import com.foreverwin.mesnac.meapi.dto.WorkCenterLinkDTO;
import com.foreverwin.mesnac.meapi.model.*;
import com.foreverwin.mesnac.meapi.service.*;
import com.foreverwin.mesnac.meapi.util.StringUtils;
import com.foreverwin.modular.core.exception.BaseException;
import com.foreverwin.modular.core.exception.BusinessException;
import com.foreverwin.modular.core.util.CommonMethods;
import org.apache.commons.fileupload.FileItem;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author Leon.L
 * @since 2021-06-02
 */
@Service("sfcDispatchService")
@Transactional(rollbackFor = Exception.class)
public class SfcDispatchServiceImpl extends ServiceImpl<SfcDispatchMapper, SfcDispatch> implements SfcDispatchService, SfcDispatchCommonService {

    @Autowired
    private SfcService sfcService;
    @Autowired
    private ResrceService resrceService;
    @Autowired
    private RouterService routerService;
    @Autowired
    private NwaUserService nwaUserService;
    @Autowired
    private ResrceService resourceService;
    @Autowired
    private CallItemService callItemService;
    @Autowired
    private ShopOrderService shopOrderService;
    @Autowired
    private UserGroupService userGroupService;
    @Autowired
    private SfcDispatchMapper sfcDispatchMapper;
    @Autowired
    private UserResourceService userResourceService;
    @Autowired
    private ProdReadyTaskService prodReadyTaskService;
    @Autowired
    private ShopOrderReleaseService shopOrderReleaseService;
    @Autowired
    private WorkCenterMemberService workCenterMemberService;
    @Autowired
    private ProductionCalendarService productionCalendarService;
    @Autowired
    private SfcDispatchEmployeeService sfcDispatchEmployeeService;

    @Override
    public List<SfcDispatch> findSfcDispatch(String site, String sfc, String operation, String stepId) {
        return sfcDispatchMapper.findSfcDispatch(site, sfc, operation, stepId);
    }

    @Override
    public List<SfcDispatchDto> findSfcDispatchList(Map paramMap) {
        List<SfcDispatchDto> list = sfcDispatchMapper.findSfcDispatchList(paramMap);
        if (list == null || list.size() <= 0) {
//            List<SfcDispatchDto> sfcDispatchDtoList=new ArrayList<>();
//            for(SfcDispatchDto sfcDispatchDto:list){
//                Sfc sfcServiceById = sfcService.getById(HandleEnum.SFC.getHandle(CommonMethods.getSite(), sfcDispatchDto.getSfc()));
//                if (sfcServiceById==null){
//                    sfcDispatchDto.setDrawingsRevision(null);
//                }else {
//                    String itemBo = sfcServiceById.getItemBo();
//                    String path="/"+ StringUtil.trimHandle(itemBo)+"_"+StringUtil.trimRevision(itemBo)+"/";
//                    sfcDispatchDto.setDrawingsRevision(path);
//                }
//                sfcDispatchDtoList.add(sfcDispatchDto);
//            }
            return list;
        }

        //查询用户对应用户组
        String site = CommonMethods.getSite();
        String user = CommonMethods.getUser();
        String userBo = HandleEnum.USER.getHandle(site, user);
        List<UserGroup> userGroupList = userGroupService.getUserGroupListByUserBo(userBo);
        String role = "ADMINISTRATORS";
        if (userGroupList != null && userGroupList.size() > 0) {
            for (UserGroup userGroupModel: userGroupList) {
                String userGroup = userGroupModel.getUserGroup();
                if (Constants.USER_GROUP_ADMINISTRATOR.equals(userGroup)) {
                    role = Constants.USER_GROUP_ADMINISTRATOR;
                    break;
                } else if (Constants.USER_GROUP_WX_USER.equals(userGroup)) {
                    role = Constants.USER_GROUP_WX_USER;
                    break;
                } else if (Constants.USER_GROUP_CJDD.equals(userGroup)) {
                    role = Constants.USER_GROUP_CJDD;
                    break;
                } else if (Constants.USER_GROUP_ZJH.equals(userGroup)) {
                    role = Constants.USER_GROUP_ZJH;
                    break;
                }
            }
        }

        //赋值用户组
        for (SfcDispatchDto sfcDispatch: list) {
            sfcDispatch.setRole(role);
        }
        return list;
    }

    @Override
    public Boolean saveDispatch(String site, String user, StringBuffer message, List<SfcDispatchDto> sfcDispatchList) {
        return this.sfcDispatch(site, user, DispatchStatusEnum.SAVE.getCode(), message, sfcDispatchList);
    }

    @Override
    public Boolean releaseDispatch(String site, String user, StringBuffer message, List<SfcDispatchDto> sfcDispatchList) {
        Boolean flag = this.sfcDispatch(site, user, DispatchStatusEnum.RELEASE.getCode(), message, sfcDispatchList);

        if (flag) {
            //创建产前准备任务
            prodReadyTaskService.createTask(sfcDispatchList);

            //保存叫料数据
            callItemService.sfcDispatchCallItem(site, user, sfcDispatchList);
        }
        return flag;
    }

    @Override
    public void returnToNew(String user, List<SfcDispatchDto> sfcDispatchList) {
        if (sfcDispatchList == null || sfcDispatchList.size() <= 0) {
            return;
        }

        LocalDateTime nowDate = LocalDateTime.now();
        SfcDispatch sfcDispatch = null;
        List<SfcDispatch> list = new ArrayList<>();
        for (SfcDispatchDto sfcDispatchDto : sfcDispatchList) {
            String sfcDispatchBo = sfcDispatchDto.getHandle();
            String shopOrder = sfcDispatchDto.getShopOrder();
            String dispatchNo = sfcDispatchDto.getDispatchNo();
            String status = sfcDispatchDto.getDispatchStatus();
            if (!DispatchStatusEnum.PAUSE.getCode().equals(status) && !DispatchStatusEnum.CANCEL.getCode().equals(status)) {
                throw BusinessException.build("工单[" + shopOrder + "]的派工单[" + dispatchNo + "]派工状态不是暂挂或取消状态，不能返回新建状态！");
            }

            //校验不允许存在叫料信息
            List<CallItem> callItemList = callItemService.getEffectedCallItemByDispatchBo(sfcDispatchBo);
            if (callItemList != null && callItemList.size() > 0) {
                throw BusinessException.build("工单[" + shopOrder + "]的派工单[" + dispatchNo + "]已有发料，不能返回新建！");
            }

            sfcDispatch = new SfcDispatch();
            sfcDispatch.setHandle(sfcDispatchBo);
            sfcDispatch.setDispatchStatus(DispatchStatusEnum.NEW.getCode());
            sfcDispatch.setModifyUser(user);
            sfcDispatch.setModifiedDateTime(nowDate);
            list.add(sfcDispatch);
        }

        if (list != null && list.size() > 0) {
            this.updateBatchById(list);
        }
    }

    @Override
    public void pause(String user, List<SfcDispatchDto> sfcDispatchList) {
        if (sfcDispatchList == null || sfcDispatchList.size() <= 0) {
            return;
        }

        LocalDateTime nowDate = LocalDateTime.now();
        SfcDispatch sfcDispatch = null;
        List<SfcDispatch> list = new ArrayList<>();
        for (SfcDispatchDto sfcDispatchDto : sfcDispatchList) {
            String shopOrder = sfcDispatchDto.getShopOrder();
            String dispatchNo = sfcDispatchDto.getDispatchNo();
            String status = sfcDispatchDto.getDispatchStatus();
            if (!DispatchStatusEnum.NEW.getCode().equals(status) && !DispatchStatusEnum.RELEASE.getCode().equals(status)) {
                throw BusinessException.build("工单[" + shopOrder + "]的派工单[" + dispatchNo + "]派工状态不是新建或发布状态，不能变更为暂挂！");
            }

            sfcDispatch = new SfcDispatch();
            sfcDispatch.setHandle(sfcDispatchDto.getHandle());
            sfcDispatch.setDispatchStatus(DispatchStatusEnum.PAUSE.getCode());
            sfcDispatch.setModifyUser(user);
            sfcDispatch.setModifiedDateTime(nowDate);
            list.add(sfcDispatch);
        }

        if (list != null && list.size() > 0) {
            this.updateBatchById(list);
        }
    }

    @Override
    public void cancel(String user, List<SfcDispatchDto> sfcDispatchList) {
        if (sfcDispatchList == null || sfcDispatchList.size() <= 0) {
            return;
        }

        LocalDateTime nowDate = LocalDateTime.now();
        SfcDispatch sfcDispatch = null;
        List<SfcDispatch> list = new ArrayList<>();
        List<String> dispatchBoList = new ArrayList<>();
        for (SfcDispatchDto sfcDispatchDto : sfcDispatchList) {
            String sfcDispatchBo = sfcDispatchDto.getHandle();
            String shopOrder = sfcDispatchDto.getShopOrder();
            String dispatchNo = sfcDispatchDto.getDispatchNo();
            String status = sfcDispatchDto.getDispatchStatus();
            if (!DispatchStatusEnum.NEW.getCode().equals(status) && !DispatchStatusEnum.RELEASE.getCode().equals(status) && !DispatchStatusEnum.PAUSE.getCode().equals(status) && !DispatchStatusEnum.START.getCode().equals(status)) {
                throw BusinessException.build("工单[" + shopOrder + "]的派工单[" + dispatchNo + "]派工状态不是新建、发布、已开始或暂挂状态，不能变更为取消！");
            }

            //校验派工单领料状态为无需叫料或未叫料
            List<CallItem> callItemList = callItemService.getEffectedCallItemByDispatchBo(sfcDispatchBo);
            if (callItemList != null && callItemList.size() > 0) {
                throw BusinessException.build("工单[" + shopOrder + "]的派工单[" + dispatchNo + "]已有发料，不能取消！");
            }


            sfcDispatch = new SfcDispatch();
            sfcDispatch.setHandle(sfcDispatchBo);
            sfcDispatch.setDispatchStatus(DispatchStatusEnum.CANCEL.getCode());
            sfcDispatch.setModifyUser(user);
            sfcDispatch.setModifiedDateTime(nowDate);
            list.add(sfcDispatch);


            sfcDispatchDto.setDispatchStatus(DispatchStatusEnum.CANCEL.getCode());

            dispatchBoList.add(sfcDispatchBo);
        }

        if (list != null && list.size() > 0) {
            this.updateBatchById(list);
        }

        //取消叫料数据
        callItemService.updateCallItemStatusByDispatchBo(Constants.CALL_ITEM_STATUS_CANCELED, user, dispatchBoList);

        //取消产前准备任务
        prodReadyTaskService.createTask(sfcDispatchList);
    }

    @Override
    public Boolean importDispatch(String site, String user, String fileType, StringBuffer message, MultipartFile multipartFile) {
        InputStream inputStream = null;
        List<SfcDispatchDto> sfcDispatchList;
        try {
            sfcDispatchList = ExcelUtils.readExcel(fileType, SfcDispatchDto.class, multipartFile, null);
        } finally {
            if (inputStream != null){
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        if (sfcDispatchList == null || sfcDispatchList.size() <= 0) {
            throw BusinessException.build("上传的Excel没有数据，或者数据格式不正确！");
        }

        return this.sfcDispatch(site, user, DispatchStatusEnum.IMPORT.getCode(), message, sfcDispatchList);
    }

    @Override
    public Map<String, Object> ganttList(String site, Map paramMap) {
        Map<String, Object> map = new HashMap<>();

        //查询派工数据
        List<SfcDispatchDto> scheduleList = this.findSfcDispatchList(paramMap);
        if (scheduleList == null || scheduleList.size() <= 0) {
            return map;
        }
        map.put("schedules", scheduleList);

        Set<String> workCenterList = new TreeSet<>();
        scheduleList.forEach(s -> {
            if (s.getWorkCenter() != null) {
                workCenterList.add(StringUtils.trimHandle(s.getWorkCenter()));
            }
        });

        Date startFromDate = DateUtil.parseDate((String)paramMap.get("startFromDate"));
        Date StartToDate = DateUtil.parseDate((String)paramMap.get("StartToDate"));
        Map<String, Map<String, List<WorkCenterWorkTimeDTO>>> processedMap = this.processWorkCenterWorkTimes(site, workCenterList, startFromDate, StartToDate);
        map.put("workCenterWorkTimes", processedMap);

        return map;
    }


    public String importDispatch(FileItem fileItem, HttpServletRequest httpServletRequest) {
        String site = httpServletRequest.getParameter("site");
        String user = httpServletRequest.getParameter("user");
        String fileType = httpServletRequest.getParameter("fileType");

        InputStream inputStream = null;
        List<SfcDispatchDto> sfcDispatchList;
        try {
            sfcDispatchList = ExcelUtils.readExcel(fileType, SfcDispatchDto.class, null, fileItem);
        } finally {
            if (inputStream != null){
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        if (sfcDispatchList == null || sfcDispatchList.size() <= 0) {
            throw BusinessException.build("上传的Excel没有数据，或者数据格式不正确");
        }


        //调用业务处理逻辑
        StringBuffer message = new StringBuffer();
        this.sfcDispatch(site, user, DispatchStatusEnum.IMPORT.getCode(), message, sfcDispatchList);

        return message.toString();
    }



    /**
     * 派工数据保存
     *
     * @param site
     * @param user
     * @param type
     * @param message
     * @param sfcDispatchList
     * @return
     */
    Boolean  sfcDispatch(String site, String user, String type, StringBuffer message, List<SfcDispatchDto> sfcDispatchList) {
        if (sfcDispatchList == null || sfcDispatchList.size() <= 0) {
            throw BusinessException.build("请选择至少一笔工单数据进行操作");
        }

        //查询所有资源类型与资源关系
        List<Map<String, Object>> resourceList = resourceService.getResourceTypeResourceList(site);
        if (resourceList == null || resourceList.size() <= 0) {
            throw BusinessException.build("资源与资源类型关系主数据未维护");
        }
        Map<String, List<Map<String, Object>>> map = resourceList.stream().collect(Collectors.groupingBy(item -> (String)item.get("RESRCE")));

        //员工资源对应关系
        List<UserResource> userResourceList = userResourceService.findEnableList(site, null, null);
        if (userResourceList == null || userResourceList.size() <= 0) {
            throw BusinessException.build("员工与资源关系主数据未维护");
        }
        Map<String, List<UserResource>> usMap = userResourceList.stream().collect(Collectors.groupingBy(UserResource::getUserId));

        //派工更新清单
        List<SfcDispatch> list = new ArrayList<>();

        //如果导入-查询所有用户
        Map<String, List<NwaUser>> userMap = new HashMap<>();
        if (DispatchStatusEnum.IMPORT.getCode().equals(type)) {
            List<NwaUser> nwaUserList = nwaUserService.findAllUser(site);
            if (nwaUserList != null && nwaUserList.size() > 0) {
                userMap = nwaUserList.stream().collect(Collectors.groupingBy(NwaUser::getFullName));
            }
        }

        int seq = 0;
        List<SfcDispatchEmployeeDto> sfcDispatchEmployeeList = new ArrayList<>();
        //状态标识，表示本次派工成功或是失败
        Boolean flag = true;
        LocalDateTime nowDate = LocalDateTime.now();
        for (SfcDispatchDto sfcDispatchDto : sfcDispatchList) {
            SfcDispatch sfcDispatch = new SfcDispatch();
            sfcDispatch.setHandle(sfcDispatchDto.getHandle());
            sfcDispatch.setModifyUser(user);
            sfcDispatch.setModifiedDateTime(nowDate);

            String resource = sfcDispatchDto.getResrce();
            String dispatchNo = sfcDispatchDto.getDispatchNo();
            String resourceType = sfcDispatchDto.getResourceType();

            String [] employeeArray = null;
            //派工导入
            if (DispatchStatusEnum.IMPORT.getCode().equals(type)) {
                String handle = HandleEnum.SFC_DISPATCH.getHandle(site, dispatchNo);
                SfcDispatch sfcDispatchModel = this.getById(handle);
                if (sfcDispatchModel == null) {
                    flag = false;
                    message.append(seq++ % 3 == 0 ? "\n" : "|   |");
                    message.append("派工单[" + dispatchNo + "]不存在，请确认数据是导出的原始数据");
                    continue;
                }
                resourceType = sfcDispatchModel.getResourceType();
                String status = sfcDispatchModel.getDispatchStatus();

                //派工单已经开始或完成的不修改
                if (DispatchStatusEnum.START.equals(status) || DispatchStatusEnum.COMPLETE.equals(status)) {
                    flag = false;
                    message.append(seq++ % 3 == 0 ? "\n" : "|   |");
                    message.append("派工单[" + dispatchNo + "]已经开始/完成，不能修改派工数据！");
                    continue;
                }

                sfcDispatch.setHandle(handle);
                //是否导入
                sfcDispatch.setIsImport(Constants.BOOL_TRUE);

                //导入的是人员名称-查找人员编号，设备
                String employee = "";
                String employeeDescription = sfcDispatchDto.getEmployeeDescription();
                if (StringUtil.notBlank(employeeDescription)) {
                    String _employeeDescription;

                    String []employeeDescriptionArray = employeeDescription.split(",");
                    employeeArray = new String[employeeDescriptionArray.length];
                    for (int i = 0; i < employeeDescriptionArray.length; i++) {
                        _employeeDescription = employeeDescriptionArray[i];
                        List<NwaUser> _list = userMap.get(_employeeDescription);
                        if (_list != null && _list.size() > 0) {
                            String userName = _list.get(0).getUserName();
                            employee += (i == 0) ? userName : "," + userName;
                            employeeArray[i] = userName;
                        }
                    }


                    //查询匹配的设备
                    List<Resrce> emResourceList = resrceService.getResourceListByUT(site, resourceType, employeeArray);
                    if (emResourceList != null && emResourceList.size() > 0) {
                        resource = emResourceList.get(0).getResrce();
                    }
                }


                //派工人员赋值
                sfcDispatch.setIsDispatch("true");
                sfcDispatch.setResrce(resource);
                sfcDispatch.setEmployee(employee);
                sfcDispatch.setEmployeeDescription(employeeDescription);
                sfcDispatch.setRemark(sfcDispatchDto.getRemark());
                sfcDispatch.setBlankingSize(sfcDispatchDto.getBlankingSize());
                sfcDispatch.setPlannedStartDate(sfcDispatchDto.getPlannedStartDate());
                sfcDispatch.setPlannedCompDate(sfcDispatchDto.getPlannedCompDate());
                sfcDispatch.setEarliestStartDate(sfcDispatchDto.getEarliestStartDate());
                sfcDispatch.setLatestEndDate(sfcDispatchDto.getLatestEndDate());
                sfcDispatch.setOther2(sfcDispatchDto.getOther2());

                list.add(sfcDispatch);


                //记录派工人员
                if (employeeArray != null && employeeArray.length > 0) {
                    SfcDispatchEmployeeDto sfcDispatchEmployee = new SfcDispatchEmployeeDto();
                    sfcDispatchEmployee.setSite(site);
                    sfcDispatchEmployee.setSfcDispatchBo(handle);
                    sfcDispatchEmployee.setDispatchEmployee(employeeArray);
                    sfcDispatchEmployeeList.add(sfcDispatchEmployee);
                }

                continue;
            }

            //派工保存
            if (DispatchStatusEnum.SAVE.getCode().equals(type)) {
                //校验派工状态
                String originalStatus = sfcDispatchDto.getDispatchStatus();
                /*if (!DispatchStatusEnum.NEW.getCode().equals(originalStatus)) {
                    flag = false;
                    message.append(seq++ % 3 == 0 ? "\n" : "|   |");
                    message.append("派工单[" + dispatchNo + "]的派工状态不是新建，不允许保存");
                    continue;
                }*/

                if (DispatchStatusEnum.CANCEL.getCode().equals(originalStatus)) {
                    flag = false;
                    message.append(seq++ % 3 == 0 ? "\n" : "|   |");
                    message.append("派工单[" + dispatchNo + "]的派工状态已取消，不允许保存");
                    continue;
                }
                if (DispatchStatusEnum.COMPLETE.getCode().equals(originalStatus)) {
                    flag = false;
                    message.append(seq++ % 3 == 0 ? "\n" : "|   |");
                    message.append("派工单[" + dispatchNo + "]的派工状态已完成，不允许保存");
                    continue;
                }

                //时间
                if (Constants.USER_GROUP_ZJH.equals(sfcDispatchDto.getRole())) {
                    sfcDispatchDto.setEarliestStartDate(sfcDispatchDto.getPlannedStartDate());
                    sfcDispatchDto.setLatestEndDate(sfcDispatchDto.getPlannedCompDate());
                }
            }



            //派工发布
            String employees = sfcDispatchDto.getEmployee();
            if (DispatchStatusEnum.RELEASE.getCode().equals(type)) {
                //校验派工状态
                String originalStatus = sfcDispatchDto.getDispatchStatus();
                if (!DispatchStatusEnum.NEW.getCode().equals(originalStatus) && !DispatchStatusEnum.PAUSE.getCode().equals(originalStatus)) {
                    flag = false;
                    message.append(seq++ % 3 == 0 ? "\n" : "|   |");
                    message.append("派工单[" + dispatchNo + "]的派工状态不是新建或暂挂，不允许发布");
                    continue;
                }

                //资源、计划时间必输
                if (StringUtil.isBlank(employees)) {
                    flag = false;
                    message.append(seq++%3 == 0 ? "\n" : "|   |");
                    message.append("派工单[" + dispatchNo + "]的操作者没有维护，不允许发布");
                    continue;
                }
                if (StringUtil.isBlank(resource)) {
                    flag = false;
                    message.append(seq++%3 == 0 ? "\n" : "|   |");
                    message.append("派工单[" + dispatchNo + "]的资源没有维护，不允许发布");
                    continue;
                }
                if (sfcDispatchDto.getPlannedStartDate() == null || sfcDispatchDto.getPlannedCompDate() == null) {
                    flag = false;
                    message.append(seq++%3 == 0 ? "\n" : "|   |");
                    message.append("派工单[" + dispatchNo + "]的计划开始或完成时间没维护，不允许发布");
                    continue;
                }


                sfcDispatch.setSfcReleasedDate(nowDate);
                //发布状态更新
                sfcDispatch.setDispatchStatus(DispatchStatusEnum.RELEASE.getCode());
                sfcDispatchDto.setDispatchStatus(DispatchStatusEnum.RELEASE.getCode());
            }


            //校验资源与累心是否匹配
            if (StringUtil.notBlank(resource)) {
                List<Map<String, Object>> resourceTypeList = map.get(resource);
                if (resourceTypeList == null || resourceTypeList.size() <= 0) {
                    flag = false;
                    message.append(seq++ % 3 == 0 ? "\n" : "|   |");
                    message.append("派工单[" + dispatchNo + "]分配的资源[" + resource + "]不存在或没有维护资源类型");
                    continue;
                }
                String _resourceType = (String) resourceTypeList.get(0).get("RESOURCE_TYPE");
                if (!resourceType.equals(_resourceType)) {
                    flag = false;
                    message.append(seq++ % 3 == 0 ? "\n" : "|   |");
                    message.append("派工单[" + dispatchNo + "]分配的资源[" + resource + "]类型与需要的资源类型[" + resourceType + "]不匹配");
                    continue;
                }
            }

            //校验操作者与资源是否匹配
            if (StringUtil.notBlank(employees)) {
                //资源、计划时间必输
                if (StringUtils.isBlank(resource)) {
                    flag = false;
                    message.append(seq++%3 == 0 ? "\n" : "|   |");
                    message.append("派工单[" + dispatchNo + "]还未分配资源，请先分配资源");
                    continue;
                }

                //派工人员为多个(只要一个匹配)
                employeeArray = employees.split(",");
                Boolean isMatch = false;
                for (int m = 0; m < employeeArray.length; m++) {
                    String employee = employeeArray[m];
                    List<UserResource> singleUserResourceList = usMap.get(employee);
                    if (singleUserResourceList == null || singleUserResourceList.size() <= 0) {
                        flag = false;
                        message.append(seq++ % 3 == 0 ? "\n" : "|   |");
                        message.append("派工单[" + dispatchNo + "]分配的操作者[" + employee + "]没有维护资源关系");
                        continue;
                    }


                    for (int i = 0; i < singleUserResourceList.size(); i++) {
                        UserResource userResource = singleUserResourceList.get(i);
                        if (resource.equals(userResource.getResrce())) {
                            isMatch = true;
                            break;
                        }
                    }

                    if (isMatch) {break;}
                }


                if (!isMatch) {
                    flag = false;
                    message.append(seq++ % 3 == 0 ? "\n" : "|   |");
                    message.append("派工单[" + dispatchNo + "]分配的操作员与资源[" + resource + "]都不匹配");
                    continue;
                }
            }

            sfcDispatch.setResrce(resource);
            sfcDispatch.setEmployee(employees);
            sfcDispatch.setEmployeeDescription(sfcDispatchDto.getEmployeeDescription());
            sfcDispatch.setRemark(sfcDispatchDto.getRemark());
            sfcDispatch.setBlankingSize(sfcDispatchDto.getBlankingSize());
            sfcDispatch.setPlannedStartDate(sfcDispatchDto.getPlannedStartDate());
            sfcDispatch.setPlannedCompDate(sfcDispatchDto.getPlannedCompDate());
            sfcDispatch.setEarliestStartDate(sfcDispatchDto.getEarliestStartDate());
            sfcDispatch.setLatestEndDate(sfcDispatchDto.getLatestEndDate());
            sfcDispatch.setOther2(sfcDispatchDto.getOther2());

            //是否分配资源
            if (StringUtil.notBlank(resource)) {
                sfcDispatch.setIsDispatch("true");
            }
            list.add(sfcDispatch);

            //记录派工人员
            if (employeeArray != null && employeeArray.length > 0) {
                SfcDispatchEmployeeDto sfcDispatchEmployee = new SfcDispatchEmployeeDto();
                sfcDispatchEmployee.setSite(site);
                sfcDispatchEmployee.setSfcDispatchBo(sfcDispatchDto.getHandle());
                sfcDispatchEmployee.setDispatchEmployee(employeeArray);
                sfcDispatchEmployeeList.add(sfcDispatchEmployee);
            }
        }

        //执行更新
        if (flag && list != null && list.size() > 0) {
            this.updateBatchById(list);
        }

        //记录派工人员明细
        sfcDispatchEmployeeService.saveSfcDispatchEmployee(sfcDispatchEmployeeList);

        return flag;
    }


    @Override
    public void saveSplitSfcDispatch(String site, String user, String category, String shopOrder, String sfc, String operation, String stepId, String splitSfc, String routerBo, String stepSequence) {
        LocalDateTime nowDate = LocalDateTime.now();

        //查询工单信息
        String shopOrderBo = HandleEnum.SHOP_ORDER.getHandle(site, shopOrder);
        ShopOrder shopOrderModel = shopOrderService.getById(shopOrderBo);
        if (shopOrderModel == null) {
            return;
        }

        //查询生产批次
        String splitSfcBo = HandleEnum.SFC.getHandle(site, splitSfc);
        Sfc sfcModel = sfcService.getById(splitSfcBo);
        if (sfcModel == null) {
            return;
        }

        //拆分出来的SFC生产当前工艺路线的后续步骤派工数据
        if ("N".equals(category) || "R".equals(category)) {
            int stepIdInt = Integer.parseInt(stepId);
            List<SfcDispatch> sfcDispatchList = sfcDispatchMapper.findSplitSfcDispatch(site, sfc, stepIdInt);
            if (sfcDispatchList == null || sfcDispatchList.size() <= 0) {
                return;
            }

            List<SfcDispatch> newSfcDispatchList = new ArrayList<>();
            for (SfcDispatch sfcDispatch : sfcDispatchList) {
                String _stepId = sfcDispatch.getStepId();

                String dispatchNo = splitSfc + "-" + _stepId;
                SfcDispatch sfcDispatchModel = new SfcDispatch();
                sfcDispatchModel.setHandle(HandleEnum.SFC_DISPATCH.getHandle(site, dispatchNo));
                sfcDispatchModel.setSite(site);
                sfcDispatchModel.setShopOrder(shopOrder);
                sfcDispatchModel.setSfc(splitSfc);
                sfcDispatchModel.setDispatchSeq(sfcDispatch.getDispatchSeq() + "");
                sfcDispatchModel.setDispatchNo(dispatchNo);
                sfcDispatchModel.setDispatchStatus(Constants.STATUS_NEW);
                sfcDispatchModel.setIsLock(Constants.STATUS_N);
                sfcDispatchModel.setRouterBo(sfcDispatch.getRouterBo());
                sfcDispatchModel.setStepId(_stepId);
                sfcDispatchModel.setOperation(sfcDispatch.getOperation());
                sfcDispatchModel.setResourceType(sfcDispatch.getResourceType());
                sfcDispatchModel.setWorkCenter(sfcDispatch.getWorkCenter());
                sfcDispatchModel.setDispatchQty(sfcModel.getQty());
                sfcDispatchModel.setProdHours(sfcDispatch.getProdHours());
                sfcDispatchModel.setTurnOperation("false");
                sfcDispatchModel.setSoReleasedDate(nowDate);
                sfcDispatchModel.setIsDispatch(Constants.BOOL_FALSE);
                sfcDispatchModel.setIsImport(Constants.BOOL_FALSE);
                sfcDispatchModel.setIsFirstOperation(sfcDispatch.getIsFirstOperation());
                sfcDispatchModel.setCreateUser(user);
                sfcDispatchModel.setCreatedDateTime(nowDate);
                sfcDispatchModel.setModifyUser(user);
                sfcDispatchModel.setModifiedDateTime(nowDate);
                sfcDispatchModel.setOther1("false");
                /*自动添加操作者；资源；下料尺寸；计划开始、完成时间、最早开始、完成时间*/
                sfcDispatchModel.setEmployee(sfcDispatch.getEmployee());
                sfcDispatchModel.setEmployeeDescription(sfcDispatch.getEmployeeDescription());
                sfcDispatchModel.setResrce(sfcDispatch.getResrce());
                sfcDispatchModel.setBlankingSize(sfcDispatch.getBlankingSize());
                sfcDispatchModel.setPlannedStartDate(sfcDispatch.getPlannedStartDate());
                sfcDispatchModel.setPlannedCompDate(sfcDispatch.getPlannedCompDate());
                sfcDispatchModel.setEarliestStartDate(sfcDispatch.getEarliestStartDate());
                sfcDispatchModel.setLatestEndDate(sfcDispatch.getLatestEndDate());

                newSfcDispatchList.add(sfcDispatchModel);
            }

            if (newSfcDispatchList != null && newSfcDispatchList.size() > 0) {
                this.saveBatch(newSfcDispatchList);
            }

            //修改派工数量
            sfcDispatchMapper.updateSfcDispatchQty(site, sfc, Integer.parseInt(stepSequence), new Float(sfcModel.getQty()));
        }

        //拆出来的SFC生产返修工艺路线的派工数据
        if ("R".equals(category) || "A".equals(category)) {
            Router routerModel = routerService.getById(routerBo);
            if (routerModel == null) {
                throw new BaseException("工艺路线[" + StringUtils.trimHandle(routerBo) + "]不存在");
            }

            //查询工艺路线详细
            List<RouterDTO> routerList = shopOrderReleaseService.selectShopOrderRouter(routerBo);
            if (routerList == null || routerList.size() <= 0) {
                throw new BaseException("工艺路线[" + StringUtils.trimHandle(routerBo) + "]主数据不完整，请确认");
            }


            shopOrderReleaseService.sfcDispatch(site, user, shopOrderModel, sfcModel, routerList);
        }
    }

    @Override
    public void updateSfcDispatchStatus(String site, String user, String dispatchNo, String dispatchStatus, BigDecimal workHour) {
        LocalDateTime nowDateTime = LocalDateTime.now();
        sfcDispatchMapper.updateSfcDispatchStatus(site, dispatchNo, dispatchStatus, user, nowDateTime,workHour);
    }

    @Override
    public SfcDispatchDto findResrceAndWorkCenterBySfc(SfcDispatchDto sfcDispatch) {
        String site = CommonMethods.getSite();
        return sfcDispatchMapper.findResrceAndWorkCenterBySfc(sfcDispatch,site);
    }

    @Override
    public SfcDispatchDto findSfcDispatchBySfc(SfcDispatchDto sfcDispatch) {
        String site = CommonMethods.getSite();
        return sfcDispatchMapper.findSfcDispatchBySfc(site,sfcDispatch);
    }

    public Map<String, Map<String, List<WorkCenterWorkTimeDTO>>> processWorkCenterWorkTimes(String site, Set<String> workCenterList, Date startDate, Date endDate) {

        // 设备对应的工作中心
        List<WorkCenterLinkDTO> workCenterLinkDTOList = workCenterMemberService.listWorkCenterLink(site);
        String startDateId = DateUtil.formatDate(startDate);
        String endDateId = DateUtil.formatDate(endDate);
        List<DateTime> dateList = cn.hutool.core.date.DateUtil.rangeToList(cn.hutool.core.date.DateUtil.beginOfDay(startDate), cn.hutool.core.date.DateUtil.beginOfDay(endDate), DateField.DAY_OF_YEAR);

        List<WorkCenterWorkTimeDTO> workCenterWorkTimeDTOList = productionCalendarService.listWorkTimeByRange(site, startDateId, endDateId);
        // workCenter->dateId: List<WorkCenterWorkTimeDTO>
        Map<String, Map<String, List<WorkCenterWorkTimeDTO>>> map = new HashMap<>();
        for (WorkCenterWorkTimeDTO workCenterWorkTimeDTO : workCenterWorkTimeDTOList) {
            Map<String, List<WorkCenterWorkTimeDTO>> dateIdMap = map.get(workCenterWorkTimeDTO.getWorkCenter());
            if (dateIdMap == null) {
                dateIdMap = new HashMap<>();
                List<WorkCenterWorkTimeDTO> newList = new ArrayList<>();
                newList.add(workCenterWorkTimeDTO);
                dateIdMap.put(workCenterWorkTimeDTO.getDateId(), newList);
                map.put(workCenterWorkTimeDTO.getWorkCenter(), dateIdMap);
            } else {
                List<WorkCenterWorkTimeDTO> existsDateIdList = dateIdMap.get(workCenterWorkTimeDTO.getDateId());
                if (existsDateIdList == null) {
                    existsDateIdList = new ArrayList<>();
                    dateIdMap.put(workCenterWorkTimeDTO.getDateId(), existsDateIdList);
                }
                existsDateIdList.add(workCenterWorkTimeDTO);
            }
        }
        for (Map.Entry<String, Map<String, List<WorkCenterWorkTimeDTO>>> entry : map.entrySet()) {
            Map<String, List<WorkCenterWorkTimeDTO>> map1 = entry.getValue();
            for (Map.Entry<String, List<WorkCenterWorkTimeDTO>> entry1 : map1.entrySet()) {
                entry1.setValue(this.processWorkingTime(entry1.getValue()));
            }
        }
        // 根据设备工作中心依次向上查找父工作中心，获取设备工作中心全部的工作日历设定（子工作中心未设定的继续找父工作中心，如果有则补上）
        Map<String, Map<String, List<WorkCenterWorkTimeDTO>>> processedMap = new HashMap<>();
        for (String workCenter : workCenterList) {
            Map<String, List<WorkCenterWorkTimeDTO>> dateIdMap = map.get(workCenter);
            if (dateIdMap == null) {
                dateIdMap = new HashMap<>();
                map.put(workCenter, dateIdMap);
            }
            processedMap.put(workCenter, dateIdMap);
            while (dateIdMap.size() < dateList.size()) {
                // 查找上级工作中心
                workCenter = getParentWorkCenter(workCenter, workCenterLinkDTOList);
                if (StrUtil.isBlank(workCenter)) {
                    break;
                }
                Map<String, List<WorkCenterWorkTimeDTO>> parentDateIdMap = map.get(workCenter);
                if (parentDateIdMap != null) {
                    for (Map.Entry<String, List<WorkCenterWorkTimeDTO>> entry : parentDateIdMap.entrySet()) {
                        dateIdMap.putIfAbsent(entry.getKey(), entry.getValue());
                    }
                }
            }
        }
        return processedMap;
    }

    private String getParentWorkCenter(String workCenter, List<WorkCenterLinkDTO> workCenterLinkDTOList) {
        for (WorkCenterLinkDTO workCenterLinkDTO : workCenterLinkDTOList) {
            if (workCenterLinkDTO.getWorkCenter().equals(workCenter)) {
                return workCenterLinkDTO.getParent();
            }
        }
        return null;
    }

    /**
     * 跨天时间拆分后按开始时间排序
     *
     * @param workCenterWorkTimeDTOList
     */
    private List<WorkCenterWorkTimeDTO> processWorkingTime(List<WorkCenterWorkTimeDTO> workCenterWorkTimeDTOList) {

        List<WorkCenterWorkTimeDTO> result = new ArrayList<>();
        for (int i = 0; i < workCenterWorkTimeDTOList.size(); i++) {
            WorkCenterWorkTimeDTO workCenterWorkTimeDTO = workCenterWorkTimeDTOList.get(i);
            String startTime = workCenterWorkTimeDTO.getStartTime();
            String endTime = workCenterWorkTimeDTO.getEndTime();
            if (StrUtil.isBlank(startTime) && StrUtil.isBlank(startTime)) {
                // 认定为休息日
                result.add(new WorkCenterWorkTimeDTO());
            }
            if (!StringUtils.isBlank(startTime) && startTime.indexOf(":") > 0 && !StringUtils.isBlank(endTime) && endTime.indexOf(":") > 0) {

                int startHour = Integer.parseInt(startTime.split(":")[0]);
                int startMinute = Integer.parseInt(startTime.split(":")[1]);
                int endHour = Integer.parseInt(endTime.split(":")[0]);
                int endMinute = Integer.parseInt(endTime.split(":")[1]);
                int startTotalMinutes = startHour * 60 + startMinute;
                int endTotalMinutes = endHour * 60 + endMinute;

                if (startTotalMinutes > endTotalMinutes) {
                    // 时间拆分
                    WorkCenterWorkTimeDTO workCenterWorkTime1 = new WorkCenterWorkTimeDTO();
                    BeanUtils.copyProperties(workCenterWorkTimeDTO, workCenterWorkTime1);
                    workCenterWorkTime1.setStartMinute(startTotalMinutes);
                    workCenterWorkTime1.setEndMinute(24 * 60); // 24:00
                    workCenterWorkTime1.setEndTime("24:00");
                    result.add(workCenterWorkTime1);

                    WorkCenterWorkTimeDTO workCenterWorkTime2 = new WorkCenterWorkTimeDTO();
                    BeanUtils.copyProperties(workCenterWorkTimeDTO, workCenterWorkTime2);
                    workCenterWorkTime2.setStartMinute(0); // 00:00
                    workCenterWorkTime2.setStartTime("00:00");
                    workCenterWorkTime2.setEndMinute(endTotalMinutes);
                    result.add(workCenterWorkTime2);
                } else {
                    WorkCenterWorkTimeDTO normalWorkCenterWorkTime = new WorkCenterWorkTimeDTO();
                    BeanUtils.copyProperties(workCenterWorkTimeDTO, normalWorkCenterWorkTime);
                    normalWorkCenterWorkTime.setStartMinute(startTotalMinutes);
                    normalWorkCenterWorkTime.setEndMinute(endTotalMinutes);
                    result.add(normalWorkCenterWorkTime);
                }
                result.sort(Comparator.comparing(WorkCenterWorkTimeDTO::getStartMinute));
            }
        }
        return result;
    }


}