package com.fjhx.mes.service.production.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjhx.common.constant.SourceConstant;
import com.fjhx.common.enums.PushBusinessTypeEnum;
import com.fjhx.common.utils.Assert;
import com.fjhx.customer.entity.customer.po.Customer;
import com.fjhx.customer.service.customer.CustomerService;
import com.fjhx.file.utils.ObsFileUtil;
import com.fjhx.item.entity.product.po.ProductInfo;
import com.fjhx.item.service.product.ProductInfoService;
import com.fjhx.mes.entity.applicable.po.ApplicableProducts;
import com.fjhx.mes.entity.bom.po.BomDetail;
import com.fjhx.mes.entity.bom.vo.BomDetailVo;
import com.fjhx.mes.entity.production.dto.ProductionTaskDetailDto;
import com.fjhx.mes.entity.production.dto.ProductionTaskDetailSelectDto;
import com.fjhx.mes.entity.production.po.*;
import com.fjhx.mes.entity.production.vo.ProductionTaskDetailRecordVo;
import com.fjhx.mes.entity.production.vo.ProductionTaskDetailVo;
import com.fjhx.mes.entity.technology.po.Technology;
import com.fjhx.mes.entity.work.po.WorkOrder;
import com.fjhx.mes.entity.work.po.WorkOrderProductionProcesses;
import com.fjhx.mes.entity.work.vo.WorkOrderVo;
import com.fjhx.mes.mapper.production.ProductionTaskDetailMapper;
import com.fjhx.mes.service.applicable.ApplicableProductsService;
import com.fjhx.mes.service.production.*;
import com.fjhx.mes.service.technology.TechnologyService;
import com.fjhx.mes.service.work.WorkOrderProductionProcessesService;
import com.fjhx.mes.service.work.WorkOrderService;
import com.fjhx.socket.core.PushTypeEnum;
import com.fjhx.socket.core.WebSocketPush;
import com.fjhx.socket.core.WebSocketServer;
import com.fjhx.socket.core.event.WebSocketOnMessageEvent;
import com.fjhx.socket.core.event.WebSocketOnOpenEvent;
import com.fjhx.wms.entity.stock.emums.StockWaitType;
import com.fjhx.wms.entity.stock.po.StockWait;
import com.fjhx.wms.entity.stock.po.StockWaitDetails;
import com.fjhx.wms.service.stock.StockWaitDetailsService;
import com.fjhx.wms.service.stock.StockWaitService;
import com.ruoyi.common.annotation.TenantIgnore;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.wrapper.IWrapper;
import com.ruoyi.common.utils.wrapper.SqlField;
import com.ruoyi.system.utils.UserUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
 * <p>
 * 生产任务明细 服务实现类
 * </p>
 *
 * @author
 * @since 2023-05-18
 */
@Service
public class ProductionTaskDetailServiceImpl extends ServiceImpl<ProductionTaskDetailMapper, ProductionTaskDetail> implements ProductionTaskDetailService {
    @Autowired
    private ProductionTaskDetailRecordService productionTaskDetailRecordService;
    @Autowired
    private ProductionTaskService productionTaskService;
    @Autowired
    private ProductionPlanService productionPlanService;
    @Autowired
    private WorkOrderService workOrderService;
    @Autowired
    private WorkOrderProductionProcessesService workOrderProductionProcessesService;
    @Autowired
    private StockWaitService stockWaitService;
    @Autowired
    private StockWaitDetailsService stockWaitDetailsService;
    @Autowired
    private ProductInfoService productInfoService;
    @Autowired
    private ProductionProcessesService productionProcessesService;
    @Autowired
    private ProductionTaskProcessesDetailService productionTaskProcessesDetailService;
    @Autowired
    private ApplicableProductsService applicableProductsService;
    @Autowired
    private TechnologyService technologyService;
    @Autowired
    private CustomerService customerService;

    @Override
    public Page<ProductionTaskDetailVo> getPage(ProductionTaskDetailSelectDto dto) {
        IWrapper<ProductionTaskDetail> wrapper = getWrapper();
        return pageCom(wrapper, dto);
    }

    @Override
    public Page<ProductionTaskDetailVo> circulationPage(ProductionTaskDetailSelectDto dto) {
        IWrapper<ProductionTaskDetail> wrapper = getWrapper();
        //过滤负责人为自己的任务
        wrapper.eq("ptd", ProductionTaskDetail::getPersonLiableId, SecurityUtils.getUserId());
        //过滤未在流转的记录
        wrapper.eq("ptd", ProductionTaskDetail::getCirculationStatus, 0);
        //过滤未完成的记录
        wrapper.eq("ptd", ProductionTaskDetail::getFinishStatus, 0);
        return pageCom(wrapper, dto);
    }

    /**
     * 分页公共方法
     */
    Page<ProductionTaskDetailVo> pageCom(IWrapper<ProductionTaskDetail> wrapper, ProductionTaskDetailSelectDto dto) {
        //关键字搜索
        if (ObjectUtil.isNotEmpty(dto.getKeyword())) {
            List<Long> productIds = productInfoService.listObject(ProductInfo::getId, q -> q.like(ProductInfo::getName, dto.getKeyword()));
            wrapper.and(q -> q.in("ptd", ProductionTaskDetail::getProductId, productIds).or().like("ptd", ProductionTaskDetail::getProductSn, dto.getKeyword()));
        }

        wrapper.orderByDesc("ptd", ProductionTaskDetail::getId);
        wrapper.groupBy("ptd.id");
        Page<ProductionTaskDetailVo> page = this.baseMapper.getPage(dto.getPage(), wrapper);
        List<ProductionTaskDetailVo> records = page.getRecords();
        if (ObjectUtil.isEmpty(records)) {
            return new Page<>();
        }
        //赋值流转人名称
        UserUtil.assignmentNickName(records, ProductionTaskDetailVo::getCirculationUserId, ProductionTaskDetailVo::setCirculationUserName);

        //赋值产品名
        productInfoService.attributeAssign(records, ProductionTaskDetailVo::getProductId, (item, productInfo) -> {
            item.setProductName(productInfo.getName());
            item.setProductSpec(productInfo.getSpec());
        });
        //赋值当前工序名 目标工序名
        List<Long> productionTaskIds = records.stream().map(ProductionTaskDetail::getProductionTaskId).collect(Collectors.toList());
        IWrapper<ProductionTaskDetail> wrapper1 = IWrapper.getWrapper();
        wrapper1.in("pt", ProductionTaskDetail::getId, productionTaskIds);
//        wrapper1.groupBy("wo.id");
        List<WorkOrderVo> workOrderByProductionTask = baseMapper.getWorkOrderByProductionTask(wrapper1);
        Map<Long, WorkOrderVo> WorkOrderMap = workOrderByProductionTask.stream().collect(Collectors.toMap(WorkOrderVo::getProductionTaskId, Function.identity()));
        List<Long> workIds = workOrderByProductionTask.stream().map(WorkOrderVo::getId).collect(Collectors.toList());

        //获取工序id列表
        List<Long> productionProcessesIds = records.stream().map(ProductionTaskDetail::getProductionProcessesId).collect(Collectors.toList());
        productionProcessesIds.addAll(records.stream().map(ProductionTaskDetail::getNextProductionProcessesId).collect(Collectors.toList()));
        productionProcessesIds.addAll(records.stream().map(ProductionTaskDetail::getPreviousProcessesId).collect(Collectors.toList()));
        //获取基本工序map
        Map<Long, String> stringMap = productionProcessesService.mapKV(ProductionProcesses::getId, ProductionProcesses::getName,
                q -> q.in(ProductionProcesses::getId, productionProcessesIds));
        //获取定制工序map
        Map<Long, String> workOrderProductionPMap = workOrderProductionProcessesService.mapKV(WorkOrderProductionProcesses::getId,
                WorkOrderProductionProcesses::getName, q -> q.in(WorkOrderProductionProcesses::getWorkOrderId, workIds));

        for (ProductionTaskDetailVo record : records) {
            WorkOrderVo workOrderVo = WorkOrderMap.get(record.getProductionTaskId());
            if ("1".equals(workOrderVo.getIsCustomized())) {
                //如果是定制
                String name = workOrderProductionPMap.get(record.getProductionProcessesId());
                String nextName = workOrderProductionPMap.get(record.getNextProductionProcessesId());
                String previousName = workOrderProductionPMap.get(record.getPreviousProcessesId());
                record.setProductionProcessesName(name);
                record.setNextProductionProcessesName(nextName);
                record.setPreviousProcessesName(previousName);
            } else {
                //不是定制
                String name = stringMap.get(record.getProductionProcessesId());
                String nextName = stringMap.get(record.getNextProductionProcessesId());
                String previousName = stringMap.get(record.getPreviousProcessesId());
                record.setProductionProcessesName(name);
                record.setNextProductionProcessesName(nextName);
                record.setPreviousProcessesName(previousName);
            }
        }

        //赋值客户名称
        customerService.attributeAssign(records, ProductionTaskDetailVo::getCustomerId, (item, customer) -> {
            item.setCustomerName(customer.getName());
        });
        return page;
    }

    /**
     * 任务流转
     */
    @Override
    @DSTransactional
    public synchronized void circulation(ProductionTaskDetailDto dto) {
        ProductionTaskDetail productionTaskDetail = this.getById(dto.getId());

        if (Objects.equals(productionTaskDetail.getCirculationStatus(), 1)) {
            throw new ServiceException("该任务已被提交，请重试或刷新！");
        }

        //创建任务明细记录
        ProductionTaskDetailRecord productionTaskDetailRecord = new ProductionTaskDetailRecord();
        productionTaskDetailRecord.setProductionTaskDetailId(productionTaskDetail.getId());
        productionTaskDetailRecord.setProductionProcessesId(productionTaskDetail.getProductionProcessesId());
        productionTaskDetailRecord.setPersonLiableId(SecurityUtils.getUserId());
        productionTaskDetailRecord.setReceivedTime(productionTaskDetail.getReceivedTime());
        productionTaskDetailRecordService.save(productionTaskDetailRecord);

        //修改流转状态
        productionTaskDetail.setCirculationStatus(1);
        //赋值流转人id
        productionTaskDetail.setCirculationUserId(SecurityUtils.getUserId());

        //赋值上一道工序 为当前工序
        productionTaskDetail.setPreviousProcessesId(productionTaskDetail.getProductionProcessesId());

        //将下一工序赋值到当前工序
        productionTaskDetail.setProductionProcessesId(productionTaskDetail.getNextProductionProcessesId());
        //清空下一工序
        productionTaskDetail.setNextProductionProcessesId(-1l);
        //查找下一工序相关信息 如果有则赋值
        ProductionTask productionTask = productionTaskService.getById(productionTaskDetail.getProductionTaskId());
        ProductionPlan productionPlan = productionPlanService.getById(productionTask.getProductionPlanId());
        WorkOrder workOrder = workOrderService.getById(productionPlan.getWorkOrderId());
        List<WorkOrderProductionProcesses> productionProcessesList = workOrderService.getProductionProcessesList(workOrder);
        //赋值下一工序id
        for (int i = 0; i < productionProcessesList.size(); i++) {
            WorkOrderProductionProcesses wopp = productionProcessesList.get(i);
            if (wopp.getId().equals(productionTaskDetail.getProductionProcessesId())) {
                //默认赋值空 如果有下一节点赋值下一节点id
                if ((i + 1) < productionProcessesList.size()) {
                    WorkOrderProductionProcesses nextProductionProcesses = productionProcessesList.get(i + 1);
                    productionTaskDetail.setNextProductionProcessesId(nextProductionProcesses.getId());
                    break;
                }
            }
        }

        //设置当前工序状态未开始
        productionTaskDetail.setProcessesStatus(0);
        //清空负责人
        productionTaskDetail.setPersonLiableId(-1L);

        this.updateById(productionTaskDetail);

        //保存附件
        ObsFileUtil.saveFile(dto.getFileList(), productionTaskDetailRecord.getId());

        //推送消息给下一工序的用户有单可以抢了
        Long nextProductionProcessesId = productionTaskDetail.getNextProductionProcessesId();
        List<Long> userIds = productionTaskProcessesDetailService.listObject(ProductionTaskProcessesDetail::getUserId, q -> q
                .eq(ProductionTaskProcessesDetail::getProductionProcessesId, nextProductionProcessesId)
                .eq(ProductionTaskProcessesDetail::getProductionTaskId, productionTaskDetail.getProductionTaskId())
        );
        WebSocketPush.byUsers(PushTypeEnum.MESSAGE, userIds, "您有新的任务可接收！", PushBusinessTypeEnum.NEW_TASK.getType());
    }

    /**
     * 完工入库
     */
    @Override
    @DSTransactional
    public synchronized void productStorage(ProductionTaskDetailDto productionTaskDetailDto) {
        ProductionTaskDetail productionTaskDetail = getById(productionTaskDetailDto.getId());
        if (ObjectUtil.isEmpty(productionTaskDetail)) {
            throw new ServiceException("未查询到任务明细信息");
        }

        if (Objects.equals(productionTaskDetail.getFinishStatus(), 1)) {
            throw new ServiceException("该任务已完工入库，请重试或刷新！");
        }

        //创建任务明细记录
        ProductionTaskDetailRecord productionTaskDetailRecord = new ProductionTaskDetailRecord();
        productionTaskDetailRecord.setProductionTaskDetailId(productionTaskDetail.getId());
        productionTaskDetailRecord.setProductionProcessesId(productionTaskDetail.getProductionProcessesId());
        productionTaskDetailRecord.setPersonLiableId(SecurityUtils.getUserId());
        productionTaskDetailRecord.setReceivedTime(productionTaskDetail.getReceivedTime());
        productionTaskDetailRecordService.save(productionTaskDetailRecord);

        productionTaskDetail.setFinishStatus(1);//标记为完成
        productionTaskDetail.setFinishTime(new Date());//记录完成时间

        //设置当前工序状态完成
        productionTaskDetail.setProcessesStatus(3);
        this.updateById(productionTaskDetail);

        //保存附件
        ObsFileUtil.saveFile(productionTaskDetailDto.getFileList(), productionTaskDetailRecord.getId());

        StockWait stockWait = new StockWait();
        stockWait.setType(1);//入库
        stockWait.setStatus(0);//待入库
        stockWait.setBusinessType(StockWaitType.COMPLETION_IN.getDetailType());//
        stockWait.setBusinessId(productionTaskDetail.getId());//生产任务明细id

        ProductionTask productionTask = productionTaskService.getById(productionTaskDetail.getProductionTaskId());
        ProductionPlan productionPlan = productionPlanService.getById(productionTask.getProductionPlanId());
        WorkOrder workOrder = workOrderService.getById(productionPlan.getWorkOrderId());
        stockWait.setBusinessCode(workOrder.getCode());

        stockWaitService.save(stockWait);
        StockWaitDetails stockWaitDetails = new StockWaitDetails();
        stockWaitDetails.setBusinessDetailsId(productionTaskDetail.getId());
        stockWaitDetails.setStockWaitId(stockWait.getId());
        stockWaitDetails.setProductId(productionTaskDetail.getProductId());
        stockWaitDetails.setQuantity(BigDecimal.ONE);//生产任务明细入库 数量默认只有1
        stockWaitDetailsService.save(stockWaitDetails);
    }

    /**
     * 任务接收分页
     */
    @Override
    public Page<ProductionTaskDetailVo> receivePage(ProductionTaskDetailSelectDto dto) {
        IWrapper<ProductionTaskDetail> wrapper = getWrapper();

        //过滤工序用户列表里有自己的数据
        wrapper.eq("ptpd.user_id", SecurityUtils.getUserId());
        //过滤正在流转中的数据
        wrapper.eq("ptd", ProductionTaskDetail::getCirculationStatus, 1);
        //过滤未完工的数据
        wrapper.eq("ptd", ProductionTaskDetail::getFinishStatus, 0);

        return pageCom(wrapper, dto);
    }

    /**
     * 任务接收
     */
    @Override
    @DSTransactional
    public void receive(ProductionTaskDetailDto dto) {
        ProductionTaskDetail productionTaskDetail = getById(dto.getId());

        if (Objects.equals(0, productionTaskDetail.getCirculationStatus())) {
            throw new ServiceException("该任务已被他人接收，接收失败");
        }

        //修改流转状态
        productionTaskDetail.setCirculationStatus(0);
        //将负责人赋值为自己
        productionTaskDetail.setPersonLiableId(SecurityUtils.getUserId());
        //赋值接收时间
        productionTaskDetail.setReceivedTime(new Date());

        //设置当前工序状态进行中
        productionTaskDetail.setProcessesStatus(1);

        this.updateById(productionTaskDetail);
    }

    /**
     * 任务接收拒绝
     */
    @Override
    @DSTransactional
    public void rejection(ProductionTaskDetailDto productionTaskDetailDto) {
        ProductionTaskDetail productionTaskDetail = this.getById(productionTaskDetailDto.getId());
        //取消流转状态
        productionTaskDetail.setCirculationStatus(0);

        //回滚工序信息
        productionTaskDetail.setNextProductionProcessesId(productionTaskDetail.getProductionProcessesId());
        productionTaskDetail.setProductionProcessesId(productionTaskDetail.getPreviousProcessesId());

        //清空上一工序
        productionTaskDetail.setPreviousProcessesId(-1l);
        //查找下一工序相关信息 如果有则赋值
        ProductionTask productionTask = productionTaskService.getById(productionTaskDetail.getProductionTaskId());
        ProductionPlan productionPlan = productionPlanService.getById(productionTask.getProductionPlanId());
        WorkOrder workOrder = workOrderService.getById(productionPlan.getWorkOrderId());
        List<WorkOrderProductionProcesses> productionProcessesList = workOrderService.getProductionProcessesList(workOrder);
        //赋值上一工序id
        for (int i = 0; i < productionProcessesList.size(); i++) {
            WorkOrderProductionProcesses wopp = productionProcessesList.get(i);
            if (wopp.getId().equals(productionTaskDetail.getProductionProcessesId())) {
                //默认赋值空 如果有下一节点赋值下一节点id
                if ((i - 1) >= 0) {
                    WorkOrderProductionProcesses nextProductionProcesses = productionProcessesList.get(i - 1);
                    productionTaskDetail.setPreviousProcessesId(nextProductionProcesses.getId());
                    break;
                }
            }
        }

        //设置当前工序状态驳回
        productionTaskDetail.setProcessesStatus(2);

        //回滚负责人信息
        productionTaskDetail.setPersonLiableId(productionTaskDetail.getCirculationUserId());

        this.updateById(productionTaskDetail);
    }


    @Override
    public ProductionTaskDetailVo snInfo(String sn) {
        Assert.notEmpty(sn, "sn不能为空");
        ProductionTaskDetailVo result = baseMapper.snInfo(sn);
        Assert.notEmpty(result, "查询不到sn信息");

        //赋值产品信息
        ProductInfo productInfo = productInfoService.getById(result.getProductId());
        if (ObjectUtil.isNotEmpty(productInfo)) {
            result.setProductName(productInfo.getName());
            result.setProductSpec(productInfo.getSpec());
        }

        //赋值客户信息
        Customer customer = customerService.getById(result.getCustomerId());
        if (ObjectUtil.isNotEmpty(customer)) {
            result.setCustomerName(customer.getName());
        }

        //赋值工序列表
        WorkOrder workOrder = workOrderService.getById(result.getWorkOrderId());
        List<WorkOrderProductionProcesses> productionProcessesList = workOrderService.getProductionProcessesList(workOrder);

        result.setProductionProcessesList(productionProcessesList);

        Map<Long, String> productionProcessesMap = productionProcessesList.stream().collect(Collectors.toMap(WorkOrderProductionProcesses::getId, WorkOrderProductionProcesses::getName));


        //赋值工序提交记录
        List<ProductionTaskDetailRecord> productionTaskDetailRecordList = productionTaskDetailRecordService.list(q -> q
                .eq(ProductionTaskDetailRecord::getProductionTaskDetailId, result.getId())
                .orderByAsc(ProductionTaskDetailRecord::getCreateTime)
        );
        List<ProductionTaskDetailRecordVo> productionTaskDetailRecordVos = BeanUtil.copyToList(productionTaskDetailRecordList, ProductionTaskDetailRecordVo.class);
        //赋值工序名称
        for (ProductionTaskDetailRecordVo productionTaskDetailRecordVo : productionTaskDetailRecordVos) {
            Long productionProcessesId = productionTaskDetailRecordVo.getProductionProcessesId();
            String productionProcessesName = productionProcessesMap.get(productionProcessesId);
            productionTaskDetailRecordVo.setProductionProcessesName(productionProcessesName);
        }
        //赋值负责人名称
        UserUtil.assignmentNickName(productionTaskDetailRecordVos, ProductionTaskDetailRecordVo::getPersonLiableId, ProductionTaskDetailRecordVo::setPersonLiableName);

        result.setProductionTaskDetailRecordList(productionTaskDetailRecordVos);

        //获取BOM信息
        List<BomDetail> bomInfo = workOrderService.getBomInfo(workOrder);
        List<BomDetailVo> bomDetailVos = BeanUtil.copyToList(bomInfo, BomDetailVo.class);
        //赋值物料信息
        productInfoService.attributeAssign(bomDetailVos, BomDetailVo::getProductId, (item, productInfo1) -> {
            item.setProductCode(productInfo1.getCode());
            item.setProductName(productInfo1.getName());
            item.setProductSpec(productInfo1.getSpec());
            item.setProductUnit(productInfo1.getUnit());
        });
        result.setBomDetailList(bomDetailVos);

        return result;
    }

    /**
     * 获取当前用户某一工序还在进行中的任务数
     */
    @Override
    public Long haveTaskCount(ProductionTaskDetailDto dto) {
        //获取负责人为当前用户 工序为某一工序 未在流转（进行中） 未完成 的任务计数
        return this.count(q -> q
                .eq(ProductionTaskDetail::getPersonLiableId, SecurityUtils.getUserId())
                .eq(ObjectUtil.isNotEmpty(dto.getProductionProcessesId()), ProductionTaskDetail::getProductionProcessesId, dto.getProductionProcessesId())
                .eq(ProductionTaskDetail::getCirculationStatus, 0)
                .eq(ProductionTaskDetail::getFinishStatus, 0)
        );
    }

    /**
     * 退回任务（任务回到任务列表可供别人接取）
     */
    @Override
    @DSTransactional
    public void revokeTask(ProductionTaskDetailDto dto) {
        ProductionTaskDetail productionTaskDetail = getById(dto.getId());
        Assert.notEmpty(productionTaskDetail, "查询不到该任务信息");

        //修改流转状态
        productionTaskDetail.setCirculationStatus(1);
        //将负责人清空
        productionTaskDetail.setPersonLiableId(-1L);

        //设置当前工序状态驳回
        productionTaskDetail.setProcessesStatus(0);

        this.updateById(productionTaskDetail);
    }

    /**
     * 生产进度
     */
    @Override
    public Page<ProductionTaskDetailVo> taskProgressPage(ProductionTaskDetailSelectDto dto) {
        IWrapper<ProductionTaskDetail> wrapper = IWrapper.getWrapper();
        wrapper.keyword(dto.getKeyword(),
                new SqlField("t1.contractCode"),
                new SqlField("t1.workOrderCode"),
                new SqlField("t1.productionPlanCode"),
                new SqlField("t1.productionTaskCode"),
                new SqlField("t1.productCode"),
                new SqlField("t1.productName"),
                new SqlField("t1", ProductionTaskDetail::getProductSn),
                new SqlField("t1.due_date"),
                new SqlField("t1.productionProcessesName"),
                new SqlField("t1.personLiableName"),
                new SqlField("t1", ProductionTaskDetail::getFinishTime)
        );
        //高级检索
        wrapper.like("t1.contractCode", dto.getContractCode());
        wrapper.like("t1.workOrderCode", dto.getWorkOrderCode());
        wrapper.like("t1.productionPlanCode", dto.getProductionPlanCode());
        wrapper.like("t1.productionTaskCode", dto.getProductionTaskCode());
        wrapper.like("t1.productCode", dto.getProductCode());
        wrapper.like("t1.productName", dto.getProductName());
        wrapper.like("t1", ProductionTaskDetail::getProductSn, dto.getProductSn());
        wrapper.eq("t1.due_date", dto.getDueDate());
        wrapper.like("t1.productionProcessesName", dto.getProductionProcessesName());
        wrapper.like("t1.personLiableName", dto.getPersonLiableName());
        wrapper.eq("t1", ProductionTaskDetail::getFinishStatus, dto.getGetFinishStatus());
//        wrapper.eq("t1",ProductionTaskDetail::getFinishTime,dto.getGetFinishTime());

        //完成时间包含时分秒需要将时间特殊处理
        if (ObjectUtil.isNotEmpty(dto.getGetFinishTime())) {
            Date beginTime = DateUtil.beginOfDay(DateUtil.parse(dto.getGetFinishTime()));
            Date endTime = DateUtil.endOfDay(DateUtil.parse(dto.getGetFinishTime()));
            wrapper.between("t1", ProductionTaskDetail::getFinishTime, beginTime, endTime);
        }


        wrapper.orderByDesc("t1", ProductionTaskDetail::getId);

        Page<ProductionTaskDetailVo> page = baseMapper.taskProgressPage(dto.getPage(), wrapper);

        //处理工序
        Map<Long, Long> applicableProductsMap = new HashMap<>();
        Map<Long, String> technologyMap = new HashMap<>();
        Map<Long, String> productionProcessesMap = new HashMap<>();


        List<ProductionTaskDetailVo> records = page.getRecords();
        List<Long> productIds = records.stream().map(ProductionTaskDetail::getProductId).distinct().collect(Collectors.toList());
        List<ApplicableProducts> applicableProducts = applicableProductsService.list(q -> q.in(ApplicableProducts::getProductId, productIds));
        if (ObjectUtil.isNotEmpty(applicableProducts)) {
            applicableProductsMap = applicableProducts.stream().collect(Collectors.toMap(ApplicableProducts::getProductId, ApplicableProducts::getTechnologyId));

            List<Long> technologyIds = applicableProducts.stream().map(ApplicableProducts::getTechnologyId).collect(Collectors.toList());
            List<Technology> technologys = technologyService.list(q -> q.in(Technology::getId, technologyIds));
            if (ObjectUtil.isNotEmpty(technologys)) {
                technologyMap = technologys.stream().collect(Collectors.toMap(Technology::getId, Technology::getProcessRoute));

                List<Long> ppIds = new ArrayList<>();
                for (Technology technology : technologys) {
                    String processRoute = technology.getProcessRoute();
                    String[] split = processRoute.split(",");
                    for (String s : split) {
                        ppIds.add(Long.parseLong(s));
                    }
                }
                if (ObjectUtil.isNotEmpty(ppIds)) {
                    productionProcessesMap = productionProcessesService.mapKV(ProductionProcesses::getId, ProductionProcesses::getName, q -> q.in(ProductionProcesses::getId, ppIds));
                }
            }
        }


        for (ProductionTaskDetailVo record : records) {
            //赋值非定制工序列表
            if ("0".equals(record.getIsCustomized())) {
                Long technologyId = applicableProductsMap.getOrDefault(record.getProductId(), -1L);
                String processRoute = technologyMap.getOrDefault(technologyId, "");
                String[] split = processRoute.split(",");
                List<String> arr = new ArrayList<>();
                for (String s : split) {
                    if (ObjectUtil.isEmpty(s)) {
                        continue;
                    }
                    String ppName = productionProcessesMap.getOrDefault(Long.parseLong(s), "");
                    arr.add(ppName);
                }

                String collect = arr.stream().collect(Collectors.joining("->"));
                record.setProductionProcessesNames(collect);
            }
        }

        return page;
    }

    /**
     * 生产任务明细
     */
    @Override
    public ProductionTaskDetailVo detail(Long id) {
        ProductionTaskDetailVo productionTaskDetailVo = baseMapper.getDetail(IWrapper.<ProductionTaskDetail>getWrapper()
                .eq("ptd", ProductionTaskDetail::getId, id)
        );
//        ProductionTaskDetail productionTaskDetail = this.getById(id);
        ProductionTask productionTask = productionTaskService.getById(productionTaskDetailVo.getProductionTaskId());
        ProductionPlan productionPlan = productionPlanService.getById(productionTask.getProductionPlanId());
        WorkOrder workOrder = workOrderService.getById(productionPlan.getWorkOrderId());

        List<Long> processesIds = Arrays.asList(productionTaskDetailVo.getPreviousProcessesId(),
                productionTaskDetailVo.getProductionProcessesId(),
                productionTaskDetailVo.getNextProductionProcessesId()
        );

        //获取工序列表
        List<WorkOrderProductionProcesses> productionProcessesList = workOrderService.getProductionProcessesList(workOrder);
        Map<Long, String> productionProcessesMap = productionProcessesList.stream().collect(Collectors.toMap(WorkOrderProductionProcesses::getId, WorkOrderProductionProcesses::getName));


        //赋值产品名称
        ProductInfo productInfo = productInfoService.getById(productionTaskDetailVo.getProductId());
        if (ObjectUtil.isNotEmpty(productInfo)) {
            productionTaskDetailVo.setProductName(productInfo.getName());
            productionTaskDetailVo.setProductSpec(productInfo.getSpec());
        }

        productionTaskDetailVo.setProductionProcessesName(productionProcessesMap.get(productionTaskDetailVo.getProductionProcessesId()));
        productionTaskDetailVo.setNextProductionProcessesName(productionProcessesMap.get(productionTaskDetailVo.getNextProductionProcessesId()));
        productionTaskDetailVo.setPreviousProcessesName(productionProcessesMap.get(productionTaskDetailVo.getPreviousProcessesId()));

        //赋值工序提交记录
        List<ProductionTaskDetailRecord> productionTaskDetailRecordList = productionTaskDetailRecordService.list(q -> q
                .eq(ProductionTaskDetailRecord::getProductionTaskDetailId, id)
                .orderByAsc(ProductionTaskDetailRecord::getCreateTime)
        );
        List<ProductionTaskDetailRecordVo> productionTaskDetailRecordVos = BeanUtil.copyToList(productionTaskDetailRecordList, ProductionTaskDetailRecordVo.class);
        //赋值工序名称
        for (ProductionTaskDetailRecordVo productionTaskDetailRecordVo : productionTaskDetailRecordVos) {
            Long productionProcessesId = productionTaskDetailRecordVo.getProductionProcessesId();
            String productionProcessesName = productionProcessesMap.get(productionProcessesId);
            productionTaskDetailRecordVo.setProductionProcessesName(productionProcessesName);
        }
        //赋值负责人名称
        UserUtil.assignmentNickName(productionTaskDetailRecordVos, ProductionTaskDetailRecordVo::getPersonLiableId, ProductionTaskDetailRecordVo::setPersonLiableName);

        productionTaskDetailVo.setProductionTaskDetailRecordList(productionTaskDetailRecordVos);


        //赋值上一工序流转记录Id
        List<Long> previousProcessesRecordIds = productionTaskDetailRecordService.listObject(ProductionTaskDetailRecord::getId, q -> q
                .eq(ProductionTaskDetailRecord::getProductionTaskDetailId, id)
                .eq(ProductionTaskDetailRecord::getProductionProcessesId, productionTaskDetailVo.getPreviousProcessesId())
                .orderByDesc(ProductionTaskDetailRecord::getCreateTime)
        );
        if (ObjectUtil.isNotEmpty(previousProcessesRecordIds)) {
            productionTaskDetailVo.setPreviousProcessesRecordId(previousProcessesRecordIds.get(0));
        }


        return productionTaskDetailVo;
    }


    /**
     * 用户连接websock监听
     */
    @EventListener
    @TenantIgnore
    public void webSocketOnOpenEvent(WebSocketOnOpenEvent webSocketOnOpenEvent) {
        WebSocketServer webSocketServer = webSocketOnOpenEvent.getWebSocketServer();
        sendTaskCount(webSocketServer);
    }

    /**
     * 用户收到websock消息监听
     */
    @EventListener
    @TenantIgnore
    public void webSocketOnMessageEvent(WebSocketOnMessageEvent webSocketOnMessageEvent) {
        WebSocketServer webSocketServer = webSocketOnMessageEvent.getWebSocketServer();
        String message = webSocketOnMessageEvent.getMessage();
        JSONObject json = JSONObject.parseObject(message);
        if (ObjectUtil.isNotEmpty(json.get("getTaskCount"))) {
            sendTaskCount(webSocketServer);
        }
    }

    /**
     * 发送用户任务数
     */
    void sendTaskCount(WebSocketServer webSocketServer) {
        Long userId = webSocketServer.getUserId();

        IWrapper<ProductionTaskDetail> wrapper = IWrapper.getWrapper();
        wrapper.eq("ptpd.user_id", userId);
        wrapper.eq("ptd.finish_status", 0);

        DynamicDataSourceContextHolder.push(SourceConstant.MES);
        Long userTaskCount = baseMapper.getUserTaskCount(wrapper);
        DynamicDataSourceContextHolder.clear();

        JSONObject msg = new JSONObject();
        msg.put("taskCount", userTaskCount);
        try {
            webSocketServer.getSession().getBasicRemote().sendText(msg.toJSONString(JSONWriter.Feature.WriteLongAsString));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}
