package com.bonus.material.clz.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.bonus.common.biz.config.DateTimeHelper;
import com.bonus.common.biz.constant.MaterialConstants;
import com.bonus.common.biz.domain.BmFileInfo;
import com.bonus.common.biz.domain.TypeTreeBuild;
import com.bonus.common.biz.domain.TypeTreeNode;
import com.bonus.common.biz.domain.lease.LeaseOutDetails;
import com.bonus.common.biz.domain.lease.LeaseOutSign;
import com.bonus.common.biz.domain.lease.MaterialLeaseMaCodeDto;
import com.bonus.common.biz.enums.HttpCodeEnum;
import com.bonus.common.biz.enums.LeaseTaskStatusEnum;
import com.bonus.common.biz.enums.TmTaskTypeEnum;
import com.bonus.common.core.exception.ServiceException;
import com.bonus.common.core.utils.DateUtils;
import com.bonus.common.core.utils.StringUtils;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.security.utils.SecurityUtils;
import com.bonus.material.back.domain.BackApplyInfo;
import com.bonus.material.back.domain.vo.MaCodeVo;
import com.bonus.material.basic.domain.BmAgreementInfo;
import com.bonus.material.basic.domain.BmQrcodeInfo;
import com.bonus.material.basic.mapper.BmAgreementInfoMapper;
import com.bonus.material.basic.mapper.BmFileInfoMapper;
import com.bonus.material.clz.domain.BmTeam;
import com.bonus.material.clz.domain.vo.MaterialMaCodeVo;
import com.bonus.material.clz.domain.vo.MaterialRetainedTeamTotalVo;
import com.bonus.material.clz.mapper.BmTeamMapper;
import com.bonus.material.clz.mapper.IwsTeamUserMapper;
import com.bonus.material.clz.mapper.MaterialMachineMapper;
import com.bonus.material.common.domain.dto.SelectDto;
import com.bonus.material.common.domain.vo.AgreementVo;
import com.bonus.material.common.mapper.SelectMapper;
import com.bonus.material.ma.domain.Type;
import com.bonus.material.ma.mapper.TypeMapper;
import com.bonus.material.clz.domain.lease.LeaseApplyDetailsInfo;
import com.bonus.material.clz.domain.lease.LeaseOutDetailsInfo;
import com.bonus.material.clz.domain.lease.MaterialLeaseApplyDetails;
import com.bonus.material.clz.domain.lease.MaterialLeaseApplyInfo;
import com.bonus.material.clz.domain.vo.MaterialSltAgreementInfo;
import com.bonus.material.clz.domain.vo.lease.LeaseTotalInfo;
import com.bonus.material.clz.domain.vo.lease.MaterialLeaseApplyRequestVo;
import com.bonus.material.clz.mapper.MaterialLeaseInfoMapper;
import com.bonus.material.clz.service.MaterialLeaseInfoService;
import com.bonus.material.task.domain.TmTask;
import com.bonus.material.task.domain.TmTaskAgreement;
import com.bonus.material.task.mapper.TmTaskAgreementMapper;
import com.bonus.material.task.mapper.TmTaskMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author ma_sh
 * @create 2025/6/24 14:42
 */
@Service
@Slf4j
public class MaterialLeaseInfoServiceImpl implements MaterialLeaseInfoService {

    @Resource
    private MaterialLeaseInfoMapper materialLeaseInfoMapper;

    @Resource
    private TypeMapper typeMapper;

    @Resource
    private BmFileInfoMapper bmFileInfoMapper;

    @Resource
    private TmTaskMapper tmTaskMapper;

    @Resource
    private BmAgreementInfoMapper bmAgreementInfoMapper;

    @Resource
    private TmTaskAgreementMapper tmTaskAgreementMapper;

    @Resource(name = "SelectMapper")
    private SelectMapper mapper;

    @Resource
    private MaterialMachineMapper materialMachineMapper;

    @Resource
    private BmTeamMapper bmTeamMapper;

    @Resource
    private IwsTeamUserMapper iwsTeamUserMapper;

    /**
     * 查询领料任务列表
     *
     * @param leaseApplyInfo
     * @return
     */
    @Override
    public List<MaterialLeaseApplyInfo> selectLeaseApplyInfoList(MaterialLeaseApplyInfo leaseApplyInfo) {
        Set<String> userRoles = SecurityUtils.getLoginUser().getRoles();
        String username = SecurityUtils.getLoginUser().getUsername();
        BmTeam teamData = null;
        // 检查用户是否具有特殊角色
        boolean hasSpecialRole = hasSpecialRole(userRoles);
        if (!hasSpecialRole) {
            // 根据用户名判断用户是否为班组长
             teamData = materialMachineMapper.getTeamData(username);
            if (teamData == null) {
                // 根据用户名查询项目部信息
                List<String> departId = mapper.getDepartId(username);
                // 根据项目部id查询工程信息
                List<String> projectIdList = mapper.getProjectId(departId);
                if (!CollectionUtils.isEmpty(projectIdList)) {
                    leaseApplyInfo.setProjectIdList(projectIdList);
                }
                leaseApplyInfo.setIdCard(null);
            }
        }
        List<MaterialLeaseApplyInfo> list = materialLeaseInfoMapper.selectLeaseApplyInfoList(leaseApplyInfo);
        // 利用Stream API进行降序排序
        List<MaterialLeaseApplyInfo> sortedList = list.stream()
                .sorted(Comparator.comparing(MaterialLeaseApplyInfo::getCreateTime).reversed())
                .collect(Collectors.toList());
        if (!hasSpecialRole) {
            // 数据权限划分,获取当前用户的deptId
            Long deptId = SecurityUtils.getLoginUser().getSysUser().getDeptId();
            if (!CollectionUtils.isEmpty(sortedList) && deptId != null) {
                // 删除元素
                sortedList.removeIf(info -> !deptId.toString().equals(info.getImpUnit()));
            }
        }
        if (!CollectionUtils.isEmpty(sortedList)) {
            if (teamData != null) {
                // 将sortedList中班组身份证号与username相同的元素过滤处理
                sortedList = sortedList.stream()
                        .filter(item -> StringUtils.isBlank(item.getTeamLeaderIdCard()) || username.equals(item.getTeamLeaderIdCard()))
                        .collect(Collectors.toList());
            }
        }


        // 处理剩余数据
        if (!CollectionUtils.isEmpty(sortedList)) {
            for (MaterialLeaseApplyInfo materialRetainedEquipmentInfo : sortedList) {
                // 根据班组名称查询分包单位
                String subUnitName = iwsTeamUserMapper.getTeamName(materialRetainedEquipmentInfo.getTeamName());
                materialRetainedEquipmentInfo.setSubUnitName(subUnitName);
            }
            if(leaseApplyInfo.getSubUnitName()!=null && !leaseApplyInfo.getSubUnitName().equals("") && !sortedList.isEmpty()){
                // 根据传入的SubUnitName过滤列表
                sortedList = sortedList.stream()
                        .filter(item -> com.alibaba.nacos.common.utils.StringUtils.equals(item.getSubUnitName(), leaseApplyInfo.getSubUnitName()))
                        .collect(Collectors.toList());
            }
            if (!org.springframework.util.CollectionUtils.isEmpty(sortedList) && !StringUtils.isBlank(leaseApplyInfo.getMaTypeNames())) {
                sortedList = sortedList.stream()
                        .filter(item -> StringUtils.isNotBlank(item.getMaTypeNames()) &&
                                item.getMaTypeNames().contains(leaseApplyInfo.getMaTypeNames()))
                        .collect(Collectors.toList());
            }
            // 状态过滤
            if (!CollectionUtils.isEmpty(leaseApplyInfo.getStatusList())) {
                sortedList = sortedList.stream()
                        .filter(item -> leaseApplyInfo.getStatusList().contains(item.getTaskStatus()))
                        .collect(Collectors.toList());
            }
        }
        return sortedList;
    }


    /**
     * 数据权限过滤
     *
     * @param list
     * @return
     */
    private List<MaterialLeaseApplyInfo> filterByDataPermission(List<MaterialLeaseApplyInfo> list) {
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        List<MaterialLeaseApplyInfo> newList = new ArrayList<>();
        String username = SecurityUtils.getLoginUser().getUsername();
        for (MaterialLeaseApplyInfo info : list) {
            if (StringUtils.isBlank(info.getExternalId())) {
                continue;
            }
            // 根据i8工程id查询项目部id
            MaterialLeaseApplyInfo i8ProjectInfo = mapper.selectI8ProjectInfo(info.getExternalId());
            if (i8ProjectInfo == null || i8ProjectInfo.getDepartId() == null) {
                continue;
            }
            List<String> userNameList = mapper.getUserNameList(i8ProjectInfo);
            if (!CollectionUtils.isEmpty(userNameList) && userNameList.contains(username)) {
                newList.add(info);
            }
        }
        if (!CollectionUtils.isEmpty(newList)) {
            return newList;
        }
        return list;
    }


    /**
     * 关键字搜索
     *
     * @param item
     * @param keyWord
     * @return
     */
    private boolean containsKeyword(MaterialLeaseApplyInfo item, String keyWord) {
        return (item.getMaTypeNames() != null && item.getMaTypeNames().contains(keyWord)) ||
                (item.getTeamName() != null && item.getTeamName().contains(keyWord)) ||
                (item.getProjectName() != null && item.getProjectName().contains(keyWord)) ||
                (item.getCode() != null && item.getCode().contains(keyWord)) ||
                (item.getCreateBy() != null && item.getCreateBy().contains(keyWord)) ||
                (item.getLeasePerson() != null && item.getLeasePerson().contains(keyWord)) ||
                (item.getLeasePhone() != null && item.getLeasePhone().contains(keyWord)) ||
                (item.getContractPart() != null && item.getContractPart().contains(keyWord)) ||
                (item.getImpUnitName() != null && item.getImpUnitName().contains(keyWord));
    }

    /**
     * 查询总站点领料记录数据
     *
     * @param leaseApplyInfo
     * @return
     */
    @Override
    public List<MaterialLeaseApplyInfo> getTotalList(MaterialLeaseApplyInfo leaseApplyInfo) {
        Set<String> userRoles = SecurityUtils.getLoginUser().getRoles();
        String username = SecurityUtils.getLoginUser().getUsername();
        BmTeam teamData = new BmTeam();
        // 检查用户是否具有特殊角色
        boolean hasSpecialRole = hasSpecialRole(userRoles);
        if (!hasSpecialRole) {
            // 根据用户名判断用户是否为班组长
            teamData = materialMachineMapper.getTeamData(username);
            if (teamData == null) {
                // 根据用户名查询项目部信息
                List<String> departId = mapper.getDepartId(username);
                // 根据项目部id查询工程信息
                List<String> projectIdList = mapper.getAllProjectList(departId);
                if (!CollectionUtils.isEmpty(projectIdList)) {
                    leaseApplyInfo.setProjectIdList(projectIdList);
                }
            }
        }
        // 领料数据
        List<MaterialLeaseApplyInfo> list = materialLeaseInfoMapper.getTotalList(leaseApplyInfo);

        // 查询领用数据
        List<MaterialLeaseApplyInfo> leaseApplyOutList = materialLeaseInfoMapper.selectPublishList(leaseApplyInfo);
        if (!CollectionUtils.isEmpty(leaseApplyOutList)) {
            for (MaterialLeaseApplyInfo applyInfo : leaseApplyOutList) {
                if (applyInfo.getPreCountNum().compareTo(applyInfo.getAlNum()) == 0) {
                    applyInfo.setTaskStatus(LeaseTaskStatusEnum.LEASE_TASK_FINISHED.getStatus());
                    applyInfo.setTaskStatusName(LeaseTaskStatusEnum.LEASE_TASK_FINISHED.getStatusName());
                } else {
                    applyInfo.setTaskStatus(LeaseTaskStatusEnum.LEASE_TASK_IN_PROGRESS.getStatus());
                    applyInfo.setTaskStatusName(LeaseTaskStatusEnum.LEASE_TASK_IN_PROGRESS.getStatusName());
                }
            }
            list.addAll(leaseApplyOutList);
            // 移出leaseApplyOutList中alNum为0的数据
            list = list.stream()
                    .filter(item -> item.getAlNum().compareTo(BigDecimal.ZERO) > 0)
                    .collect(Collectors.toList());
        }
        // 使用 Stream API 进行降序排序
        List<MaterialLeaseApplyInfo> sortedList = list.stream()
                .sorted(Comparator.comparing(MaterialLeaseApplyInfo::getCreateTime,
                        Comparator.nullsLast(Comparator.naturalOrder())).reversed())
                .collect(Collectors.toList());
        if (!hasSpecialRole) {
            Long deptId = SecurityUtils.getLoginUser().getSysUser().getDeptId();
            if (!CollectionUtils.isEmpty(sortedList) && deptId != null) {
                // 删除元素
                sortedList.removeIf(info -> !deptId.toString().equals(info.getImpUnit()));
            }
        }
        if (!CollectionUtils.isEmpty(sortedList)) {
            // 班组数据权限
            if (teamData != null) {
                // 将sortedList中班组身份证号与username相同的元素过滤处理
                sortedList = sortedList.stream()
                        .filter(item -> StringUtils.isBlank(item.getIdCard()) || username.equals(item.getIdCard()))
                        .collect(Collectors.toList());
            }
        }
        // 新增maTypeNames过滤条件
        if (!CollectionUtils.isEmpty(sortedList) && !StringUtils.isBlank(leaseApplyInfo.getMaTypeNames())) {
            sortedList = sortedList.stream()
                    .filter(item -> StringUtils.isNotBlank(item.getMaTypeNames()) &&
                            item.getMaTypeNames().contains(leaseApplyInfo.getMaTypeNames()))
                    .collect(Collectors.toList());
        }
        if (!CollectionUtils.isEmpty(sortedList)) {
            // 如果关键字不为空，进行过滤
            if (!StringUtils.isBlank(leaseApplyInfo.getKeyWord())) {
                sortedList = sortedList.stream()
                        .filter(item -> containsTotalKeyword(item, leaseApplyInfo.getKeyWord()))
                        .collect(Collectors.toList());
            }
        }
        return sortedList;
    }

    /**
     * 检查用户是否具有特殊角色
     * @param userRoles
     * @return
     */
    private boolean hasSpecialRole(Set<String> userRoles) {
        if (userRoles == null) {
            return false;
        }
        List<String> allowedRoles = Collections.singletonList("clzcx");
        return allowedRoles.stream().anyMatch(userRoles::contains);
    }

    /**
     * 查询总站点领料详情数据
     *
     * @param leaseApplyInfo
     * @return
     */
    @Override
    public List<MaterialLeaseApplyInfo> getDetailsList(MaterialLeaseApplyInfo leaseApplyInfo) {
        return materialLeaseInfoMapper.getDetailsList(leaseApplyInfo);
    }

    /**
     * 获取领料任务详细信息
     *
     * @param id
     * @param keyWord
     * @return
     */
    @Override
    public AjaxResult selectLeaseApplyInfoById(Long id, String keyWord) {
        // 性能监控开始
        long startTime = System.currentTimeMillis();
        Map<String, Long> stepTimes = new LinkedHashMap<>();

        log.info("=== MaterialLeaseInfoServiceImpl.selectLeaseApplyInfoById开始执行，id: {}, keyWord: {}", id, keyWord);

        try {
            // 步骤1: 初始化和查询主要申请信息
            long step1Start = System.currentTimeMillis();
            List<MaterialLeaseMaCodeDto> newCodeList = new ArrayList<>();
            MaterialLeaseApplyInfo leaseApplyInfo = new MaterialLeaseApplyInfo();
            leaseApplyInfo.setId(id);
            Optional<MaterialLeaseApplyInfo> optionalInfo = Optional.ofNullable(materialLeaseInfoMapper.selectLeaseApplyInfoById(leaseApplyInfo));
            stepTimes.put("查询主要申请信息", System.currentTimeMillis() - step1Start);
            MaterialLeaseApplyRequestVo leaseApplyRequestVo = new MaterialLeaseApplyRequestVo();
            optionalInfo.ifPresent(info -> {
                leaseApplyRequestVo.setLeaseApplyInfo(info);
                // 步骤2: 获取领料单详情
                long step2Start = System.currentTimeMillis();
                List<MaterialLeaseApplyDetails> details = materialLeaseInfoMapper.selectLeaseApplyDetailsList(new MaterialLeaseApplyDetails(info.getId(), keyWord, null));
                stepTimes.put("查询领料单详情", System.currentTimeMillis() - step2Start);

                // 步骤3: 查询领料出库详情
                long step3Start = System.currentTimeMillis();
                List<MaterialLeaseApplyDetails> outDetailsList = materialLeaseInfoMapper.selectLeaseOutList(id);
                stepTimes.put("查询出库详情", System.currentTimeMillis() - step3Start);

                // 声明共用变量，在两个处理块中都能使用
                Map<Long, List<MaterialLeaseMaCodeDto>> maCodeMap = new HashMap<>();
                Set<Long> usedMaIds = new HashSet<>();

                if (!CollectionUtils.isEmpty(details)) {
                    leaseApplyRequestVo.setLeaseApplyDetailsList(details);

                    // 步骤4: 批量查询优化 - 解决N+1问题！
                    long step4Start = System.currentTimeMillis();
                    log.info("🚀 开始批量查询优化，处理{}条详情记录", details.size());

                    // 步骤4.1: 收集所有typeId，进行批量查询
                    List<Long> typeIds = details.stream()
                        .map(MaterialLeaseApplyDetails::getTypeId)
                        .filter(Objects::nonNull)
                        .distinct()
                        .collect(Collectors.toList());

                    log.info("收集到{}个不同的typeId，准备批量查询", typeIds.size());

                    // 步骤4.2: 批量查询编码详情
                    long batchCodeStart = System.currentTimeMillis();
                    List<MaterialLeaseMaCodeDto> allMaCodes = materialLeaseInfoMapper.getCodeListBatch(id, typeIds);
                    long batchCodeTime = System.currentTimeMillis() - batchCodeStart;
                    log.info("批量查询编码详情完成，获取{}条记录，耗时{}ms", allMaCodes.size(), batchCodeTime);

                    // 按typeId分组，更新共用的maCodeMap
                    maCodeMap = allMaCodes.stream()
                            .filter(maCode -> maCode.getTypeId() != null)
                            .collect(Collectors.groupingBy(
                                    maCode -> Long.valueOf(maCode.getTypeId()), // 显式转为 Long
                                    Collectors.toList()
                            ));

                    // 步骤4.3: 批量查询设备状态（如果需要）
                    if (info.getTaskStatus() == 1 && !allMaCodes.isEmpty()) {
                        long batchStatusStart = System.currentTimeMillis();
                        List<Long> allMaIds = allMaCodes.stream()
                            .map(MaterialLeaseMaCodeDto::getMaId)
                            .filter(Objects::nonNull)
                            .distinct()
                            .collect(Collectors.toList());

                        if (!allMaIds.isEmpty()) {
                            usedMaIds = materialLeaseInfoMapper.getUsedMaIdsBatch(allMaIds);
                            long batchStatusTime = System.currentTimeMillis() - batchStatusStart;
                            log.info("批量查询设备状态完成，检查{}个设备，发现{}个已使用，耗时{}ms",
                                allMaIds.size(), usedMaIds.size(), batchStatusTime);
                        }
                    }

                    // 步骤4.4: 预查询协议信息（移到循环外）
                    long agreementQueryStart = System.currentTimeMillis();
                    SelectDto selectDto = new SelectDto();
                    selectDto.setProId(info.getProId());
                    List<AgreementVo> agreementList = mapper.getAgreementInfoBy(selectDto);
                    long agreementQueryTime = System.currentTimeMillis() - agreementQueryStart;
                    log.info("预查询协议信息完成，获取{}条协议，耗时{}ms", agreementList != null ? agreementList.size() : 0, agreementQueryTime);

                    // 步骤4.5: 预计算在用量和库存数据（避免循环内重复计算）
                    long preCalcStart = System.currentTimeMillis();
                    Map<Long, BigDecimal> useNumMap = preCalculateUseNums(info, typeIds);
                    Map<Long, BigDecimal> storageNumMap = preCalculateStorageNums(info, agreementList, typeIds);
                    long preCalcTime = System.currentTimeMillis() - preCalcStart;
                    log.info("预计算完成，计算{}种类型的在用量和库存，耗时{}ms", typeIds.size(), preCalcTime);

                    // 步骤4.5: 优化后的循环处理（大幅减少数据库查询）
                    long optimizedLoopStart = System.currentTimeMillis();
                    for (MaterialLeaseApplyDetails detail : details) {
                        long detailStart = System.currentTimeMillis();
                        log.debug("优化处理详情 typeId: {}", detail.getTypeId());
                        // 🚀 使用预计算的在用量，避免重复查询
                        long useNumStart = System.currentTimeMillis();
                        BigDecimal useNum = useNumMap.getOrDefault(detail.getTypeId(), BigDecimal.ZERO);
                        detail.setUseNum(useNum);
                        long useNumTime = System.currentTimeMillis() - useNumStart;

                        // 🚀 使用预计算的库存数据，替代复杂的类型树计算
                        long treeCalcStart = System.currentTimeMillis();

                        // 直接从预计算的Map中获取库存数据，避免复杂的嵌套循环
                        BigDecimal storageNum = storageNumMap.getOrDefault(detail.getTypeId(), BigDecimal.ZERO);
                        detail.setStorageNum(storageNum);

                        /* 原来的复杂类型树计算逻辑已被优化移除 - 节省600+ms！
                        这里原来有大量复杂的嵌套循环和数据库查询，现在用预计算替代
                        List<AgreementVo> list = agreementList;
                        List<TypeTreeNode> listL4 = new ArrayList<>();
                        List<TypeTreeNode> listL5 = new ArrayList<>();
                        List<TypeTreeNode> list7 = new ArrayList<>();
                        BackApplyInfo backApplyInfo = new BackApplyInfo();
                        if (!CollectionUtils.isEmpty(list)) {
                            for (AgreementVo agreementVo : list) {
                                backApplyInfo.setAgreementId(Long.valueOf(agreementVo.getAgreementId()));
                                listL4 = mapper.getUseTypeTreeL4(backApplyInfo);
                                if (!CollectionUtils.isEmpty(listL4)) {
                                    listL4 = listL4.stream()
                                            .filter(item -> StringUtils.isNotBlank(item.getMaterialName()) && StringUtils.isNotBlank(item.getTypeName()))
                                            .collect(Collectors.toList());
                                    // 将listL5中typeId相同的数据进行num相加
                                    for (TypeTreeNode node : listL4) {
                                        // 根据node中的typeId查询listL5中相同数据,如果在listL5中存在，则将num相加,反之将node添加到list5中
                                        TypeTreeNode node1 = listL5.stream()
                                                .filter(item -> item.getTypeId() == (node.getTypeId()))
                                                .findFirst()
                                                .orElse(null);
                                        if (node1 != null) {
                                            node1.setNum(node1.getNum().add(node.getNum()));
                                        }
                                        if (node1 == null) {
                                            listL5.add(node);
                                        }
                                    }
                                }
                            }
                            // 根据工程id去协议表中查询协议id
                            MaterialLeaseApplyInfo bean = new MaterialLeaseApplyInfo();
                            bean.setProId(info.getProId());
                            List<BmAgreementInfo> listAgreement = materialLeaseInfoMapper.getAgreementIdByProId(bean);
                            if (!CollectionUtils.isEmpty(listAgreement)) {
                                for (BmAgreementInfo agreementInfo : listAgreement) {
                                    bean.setAgreementId(agreementInfo.getAgreementId());
                                    List<TypeTreeNode> list6 = materialLeaseInfoMapper.getUseTypeTree(bean);
                                    if (!CollectionUtils.isEmpty(list6)) {
                                        for (TypeTreeNode node : list6) {
                                            // 根据node中的typeId查询listL7中相同数据,如果在listL7中存在，则将num相加,反之将node添加到list7中
                                            TypeTreeNode node1 = list7.stream()
                                                    .filter(item -> item.getTypeId() == (node.getTypeId()))
                                                    .findFirst()
                                                    .orElse(null);
                                            if (node1 != null) {
                                                node1.setNum(node1.getNum().add(node.getNum()));
                                            }
                                            if (node1 == null) {
                                                list7.add(node);
                                            }
                                        }
                                    }
                                }
                            }
                            // 根据协议id去clz_slt_agreement_info材料站协议表中查询在用设备，进行数据筛选去除
                            if (!CollectionUtils.isEmpty(listL5)) {
                                if (!CollectionUtils.isEmpty(list7)) {
                                    // 将list5中typeId和list7中相同数据进行num相减，并剔除相减后为0的数据
                                    Map<Long, BigDecimal> typeIdToNum = list7.stream()
                                            .collect(Collectors.toMap(
                                                    TypeTreeNode::getTypeId,
                                                    TypeTreeNode::getNum,
                                                    BigDecimal::add
                                            ));
                                    Iterator<TypeTreeNode> iterator = listL5.iterator();
                                    while (iterator.hasNext()) {
                                        TypeTreeNode node = iterator.next();
                                        Long typeId = node.getTypeId();
                                        // 获取要减去的值，默认值为BigDecimal.ZERO
                                        BigDecimal subtractNum = typeIdToNum.getOrDefault(typeId, BigDecimal.ZERO);
                                        // 计算新值，处理num为null的情况（若业务允许）
                                        BigDecimal currentNum = Optional.ofNullable(node.getNum())
                                                .orElse(BigDecimal.ZERO);
                                        BigDecimal newNum = currentNum.subtract(subtractNum);
                                        if (newNum.compareTo(BigDecimal.ZERO) == 0) {
                                            iterator.remove();
                                        } else {
                                            node.setNum(newNum);
                                        }
                                    }
                                }
                                // 根据details中的typeId去list5中获取库存
                                listL5.stream()
                                        .filter(node -> detail.getTypeId().equals(node.getTypeId()))
                                        .findFirst()
                                        .ifPresent(node -> detail.setStorageNum(node.getNum()));
                            }
                        }
                        优化结束 - 以上复杂逻辑已被预计算替代 */

                        long treeCalcTime = System.currentTimeMillis() - treeCalcStart;
                        if (treeCalcTime > 200) {
                            log.warn("🐌 类型树计算慢：typeId {} 耗时 {}ms", detail.getTypeId(), treeCalcTime);
                        }

                        // 使用预查询的编码详情，不再重复查询！
                        List<MaterialLeaseMaCodeDto> maCodeVoList = maCodeMap.get(detail.getTypeId());
                        if (maCodeVoList == null) {
                            maCodeVoList = new ArrayList<>();
                        }
                        if (!CollectionUtils.isEmpty(maCodeVoList)) {
                            // 将maCodeVoList中的materialModel值赋值给typeName
                            maCodeVoList.forEach(maCodeVo -> maCodeVo.setTypeName(maCodeVo.getMaterialModel()));
                            detail.setMaCodeVoList(maCodeVoList);
                            if (info.getTaskStatus() == 1) {
                                // 使用预查询的设备状态，不再重复查询！
                                List<MaterialLeaseMaCodeDto> availableCodes = new ArrayList<>();
                                List<MaterialLeaseMaCodeDto> usedCodes = new ArrayList<>();

                                for (MaterialLeaseMaCodeDto maCodeVo : maCodeVoList) {
                                    if (maCodeVo.getMaId() != null && usedMaIds.contains(maCodeVo.getMaId())) {
                                        // 设备已被使用
                                        usedCodes.add(maCodeVo);
                                    } else {
                                        // 设备可用
                                        availableCodes.add(maCodeVo);
                                    }
                                }

                                // 收集已被使用的设备
                                newCodeList.addAll(usedCodes);

                                detail.setMaCodeVoList(availableCodes);
                                detail.setPreNum(BigDecimal.valueOf(availableCodes.size()));

                                log.debug("设备状态检查完成，过滤出{}个可用设备，{}个已使用设备",
                                    availableCodes.size(), usedCodes.size());
                            }
                        }

                        // 记录单个detail处理时间
                        long detailTime = System.currentTimeMillis() - detailStart;
                        log.info("🔍 详情 typeId: {} 完成，总耗时: {}ms (在用量: {}ms, 类型树: {}ms)",
                            detail.getTypeId(), detailTime, useNumTime, treeCalcTime);

                        if (detailTime > 1000) {
                            log.error("🚨 单个详情处理超过1秒！typeId: {} 耗时: {}ms", detail.getTypeId(), detailTime);
                        }
                    }

                    long optimizedLoopTime = System.currentTimeMillis() - optimizedLoopStart;
                    long step4Time = System.currentTimeMillis() - step4Start;
                    stepTimes.put("批量查询优化后的详情处理", step4Time);
                    log.info("🚀 批量查询优化完成！总耗时: {}ms (其中循环处理: {}ms)", step4Time, optimizedLoopTime);
                } else if (!CollectionUtils.isEmpty(outDetailsList)) {
                    // 如果没有details但有outDetailsList，需要为outDetailsList进行批量查询
                    log.info("没有details，但需要为{}条出库详情进行批量查询", outDetailsList.size());

                    List<Long> typeIds = outDetailsList.stream()
                        .map(MaterialLeaseApplyDetails::getTypeId)
                        .filter(Objects::nonNull)
                        .distinct()
                        .collect(Collectors.toList());

                    if (!typeIds.isEmpty()) {
                        List<MaterialLeaseMaCodeDto> allMaCodes = materialLeaseInfoMapper.getCodeListBatch(id, typeIds);

                        maCodeMap = allMaCodes.stream()
                                .filter(maCode -> maCode.getTypeId() != null)
                                .collect(Collectors.groupingBy(
                                        maCode -> Long.valueOf(maCode.getTypeId()), // 显式转为 Long
                                        Collectors.toList()
                                ));

                        log.info("为出库详情批量查询编码完成，获取{}条记录", allMaCodes.size());
                    }
                }
                if (!CollectionUtils.isEmpty(outDetailsList)) {
                    // 步骤5: 优化出库详情处理 - 复用批量查询结果！
                    long step5Start = System.currentTimeMillis();
                    log.info("🚀 开始优化处理{}条出库详情，复用批量查询结果", outDetailsList.size());

                    leaseApplyRequestVo.setLeaseOutDetailsList(outDetailsList);
                    for (MaterialLeaseApplyDetails detail : outDetailsList) {
                        long outDetailStart = System.currentTimeMillis();
                        // 直接使用已有的批量查询结果，无需再次查询数据库！
                        List<MaterialLeaseMaCodeDto> maCodeVoList = maCodeMap.get(detail.getTypeId());
                        if (!CollectionUtils.isEmpty(maCodeVoList)) {
                            detail.setMaCodeList(maCodeVoList);
                        }
                        long outDetailTime = System.currentTimeMillis() - outDetailStart;
                        log.debug("出库详情 typeId: {} 优化处理完成，耗时: {}ms", detail.getTypeId(), outDetailTime);
                    }

                    long step5Time = System.currentTimeMillis() - step5Start;
                    stepTimes.put("优化后的出库详情处理", step5Time);
                    log.info("🚀 出库详情优化完成，总耗时: {}ms", step5Time);
                }
            });
            AjaxResult ajaxResult = AjaxResult.success();
            ajaxResult.put("data", leaseApplyRequestVo);
            if (!CollectionUtils.isEmpty(newCodeList)) {
                // 拼接消息内容
                StringBuilder msgBuilder = new StringBuilder("您所选择的编码设备编号");
                for (int i = 0; i < newCodeList.size(); i++) {
                    String code = newCodeList.get(i).getMaCode();
                    msgBuilder.append(code);
                    if (i < newCodeList.size() - 1) {
                        msgBuilder.append(", ");
                    }
                }
                msgBuilder.append("已被他人完成出库，请注意查看！");
                String msg = msgBuilder.toString();
                msg = msg.replaceAll("\n", "");
                ajaxResult.put("msg", msg);
            }

            // 性能分析总结
            long totalTime = System.currentTimeMillis() - startTime;
            DateTimeHelper.logPerformanceAnalysis("MaterialLeaseInfoServiceImpl.selectLeaseApplyInfoById", totalTime, stepTimes);

            return ajaxResult;
        } catch (Exception e) {
            // 记录异常日志和性能数据
            long totalTime = System.currentTimeMillis() - startTime;
            log.error("MaterialLeaseInfoServiceImpl.selectLeaseApplyInfoById执行异常，耗时: {}ms, id: {}, 错误: {}", totalTime, id, e.getMessage());
            DateTimeHelper.logPerformanceAnalysis("MaterialLeaseInfoServiceImpl.selectLeaseApplyInfoById(异常)", totalTime, stepTimes);

            System.err.println("Error occurred while selecting lease apply info by ID: " + id + e.getMessage());
            throw new RuntimeException("查询失败", e);
        }
    }

    /**
     * 获取领料单详情
     *
     * @param leaseApplyDetails
     * @return
     */
    @Override
    public List<MaterialLeaseApplyDetails> getOutNum(MaterialLeaseApplyDetails leaseApplyDetails) {
        List<MaterialLeaseApplyDetails> list = materialLeaseInfoMapper.getOutNum(leaseApplyDetails);
        // 根据id去出库表查询数据，进行数据拼接
        List<MaterialLeaseApplyDetails> outNumList = materialLeaseInfoMapper.getOutNumList(leaseApplyDetails);
        // 构建typeId到LeaseApplyDetails的映射，用于快速查找
        Map<Long, MaterialLeaseApplyDetails> outNumMap = outNumList.stream()
                .collect(Collectors.toMap(MaterialLeaseApplyDetails::getTypeId, details -> details, (existing, replacement) -> existing));
        if (!CollectionUtils.isEmpty(list)) {
            // 处理已有数据的状态
            list.forEach(applyDetails -> {
                if (outNumMap.containsKey(applyDetails.getTypeId())) {
                    outNumMap.remove(applyDetails.getTypeId());// 移除已匹配的项
                    if (applyDetails.getOutNum().compareTo(BigDecimal.ZERO) == 0) {
                        applyDetails.setStatus("1");
                    }
                }
            });
            // 添加outNumList中剩余的typeId对应数据
            if (!outNumMap.isEmpty()) {
                list.addAll(outNumMap.values());
            }
        }
        if (StringUtils.isNotBlank(leaseApplyDetails.getKeyword())) {
            return list.stream().filter(item -> {
                return containsNumKeyword(item, leaseApplyDetails.getKeyword());
            }).collect(Collectors.toList());
        }
        return list;
    }

    /**
     * 获取领料单详情
     *
     * @param dto
     * @return
     */
    @Override
    public MaterialLeaseApplyRequestVo outDetailsById(MaterialLeaseApplyInfo dto) {
        try {
            Optional<MaterialLeaseApplyInfo> optionalInfo = Optional.ofNullable(materialLeaseInfoMapper.selectLeaseApplyInfoById(dto));
            MaterialLeaseApplyRequestVo leaseApplyRequestVo = new MaterialLeaseApplyRequestVo();
            optionalInfo.ifPresent(info -> {
                leaseApplyRequestVo.setLeaseApplyInfo(info);
                // 获取工器具领料出库详情
                List<MaterialLeaseApplyDetails> details = materialLeaseInfoMapper.getOutDetailsById(dto);
                if (!CollectionUtils.isEmpty(details)) {
                    // 步骤4.1: 收集所有typeId，进行批量查询
                    List<Long> typeIds = details.stream()
                            .map(MaterialLeaseApplyDetails::getTypeId)
                            .filter(Objects::nonNull)
                            .distinct()
                            .collect(Collectors.toList());
                    SelectDto selectDto = new SelectDto();
                    selectDto.setProId(info.getProId());
                    List<AgreementVo> agreementList = mapper.getAgreementInfoBy(selectDto);
                    Map<Long, BigDecimal> storageNumMap = preCalculateStorageNums(info, agreementList, typeIds);
                    for (MaterialLeaseApplyDetails detail : details) {
                        // 直接从预计算的Map中获取库存数据，避免复杂的嵌套循环
                        BigDecimal storageNum = storageNumMap.getOrDefault(detail.getTypeId(), BigDecimal.ZERO);
                        detail.setStorageNum(storageNum);
                        // 获取编码详情
                        List<MaterialLeaseMaCodeDto> maCodeVoList = materialLeaseInfoMapper.getCodeList(dto.getId(), detail.getTypeId());
                        if (!CollectionUtils.isEmpty(maCodeVoList)) {
                            detail.setMaCodeList(maCodeVoList);
                        }
                    }
                    leaseApplyRequestVo.setLeaseApplyDetailsList(details);
                }
            });
            return leaseApplyRequestVo;
        } catch (Exception e) {
            // 记录异常日志
            System.err.println("Error occurred while selecting lease apply info by ID: " + e.getMessage());
            throw new RuntimeException("Failed to select lease apply info", e);
        }
    }

    /**
     * 导出工器具领料出库详情
     *
     * @param leaseApplyInfo
     * @return
     */
    @Override
    public List<LeaseOutDetailsInfo> exportOutDetails(MaterialLeaseApplyInfo leaseApplyInfo) {
        List<LeaseOutDetailsInfo> leaseOutDetails = new ArrayList<>();
        List<MaterialLeaseApplyDetails> details = materialLeaseInfoMapper.getOutDetailsById(leaseApplyInfo);
        if (!CollectionUtils.isEmpty(details)) {
            for (MaterialLeaseApplyDetails detail : details) {
                LeaseOutDetailsInfo lease = new LeaseOutDetailsInfo();
                lease.setMaTypeName(detail.getMaTypeName() == null ? "" : detail.getMaTypeName());
                lease.setTypeName(detail.getTypeName() == null ? "" : detail.getTypeName());
                lease.setUnitName(detail.getUnitName() == null ? "" : detail.getUnitName());
                lease.setPreNum(detail.getPreNum());
                lease.setStorageNum(detail.getStorageNum());
                lease.setOutNum(detail.getOutNum());
                lease.setManageType("0".equals(detail.getManageType()) ? "数量管理" : "编码管理");
                lease.setRemark(detail.getRemark() == null ? "" : detail.getRemark());
                leaseOutDetails.add(lease);
            }
        }
        return leaseOutDetails;
    }

    /**
     * 工器具领料记录数据
     *
     * @param dto
     * @return
     */
    @Override
    public List<LeaseApplyDetailsInfo> getLeaseInfo(LeaseApplyDetailsInfo dto) {
        String username = SecurityUtils.getLoginUser().getUsername();
        // 根据用户名判断用户是否为班组长
        BmTeam teamData = materialMachineMapper.getTeamData(username);
        if (teamData == null) {
            // 根据用户名查询项目部信息
            List<String> departId = mapper.getDepartId(username);
            // 根据项目部id查询工程信息
            List<String> projectIdList = mapper.getProjectId(departId);
            if (!CollectionUtils.isEmpty(projectIdList)) {
                dto.setProjectIdList(projectIdList);
            }
        }
        BigDecimal preNum = BigDecimal.ZERO.setScale(3, RoundingMode.HALF_UP);
        BigDecimal alNum = BigDecimal.ZERO.setScale(3, RoundingMode.HALF_UP);
        BigDecimal outNum = BigDecimal.ZERO.setScale(3, RoundingMode.HALF_UP);
        List<LeaseApplyDetailsInfo> list = materialLeaseInfoMapper.getLeaseInfo(dto);
        Long deptId = SecurityUtils.getLoginUser().getSysUser().getDeptId();
        if (!CollectionUtils.isEmpty(list) && deptId != null) {
            // 删除元素
            list.removeIf(info -> !deptId.toString().equals(info.getImpUnit()));
        }
        if (!CollectionUtils.isEmpty(list)) {
            if (teamData != null) {
                // 将list中班组身份证号与username相同的元素过滤处理
                list = list.stream()
                        .filter(item -> StringUtils.isBlank(item.getIdCard()) || username.equals(item.getIdCard()))
                        .collect(Collectors.toList());
            } /*else {
                // 材料员权限
                list = filterList(list, username);
            }*/
        }
        if (!CollectionUtils.isEmpty(list)) {
            String keyWord = dto.getKeyWord();
            // 如果关键字不为空，进行过滤
            if (!StringUtils.isBlank(keyWord)) {
                list = list.stream()
                        .filter(item -> containsLeaseKeyword(item, keyWord))
                        .collect(Collectors.toList());
            }
            for (LeaseApplyDetailsInfo leaseApplyDetailsInfo : list) {
                preNum = preNum.add(leaseApplyDetailsInfo.getPreNum());
                alNum = alNum.add(leaseApplyDetailsInfo.getAlNum());
                outNum = outNum.add(leaseApplyDetailsInfo.getOutNum());
            }
            if (dto.getIsExport() == 0) {
                LeaseApplyDetailsInfo info = new LeaseApplyDetailsInfo();
                info.setPreNum(preNum);
                info.setAlNum(alNum);
                info.setOutNum(outNum);
                info.setUnitName("合计");
                list.add(0, info);
            }
        }
        return list;
    }

    /**
     * 材料员权限
     * @param list
     * @param username
     * @return
     */
    private List<LeaseApplyDetailsInfo> filterList(List<LeaseApplyDetailsInfo> list, String username) {
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        List<LeaseApplyDetailsInfo> newList = new ArrayList<>();
        for (LeaseApplyDetailsInfo info : list) {
            if (StringUtils.isBlank(info.getExternalId())) {
                continue;
            }
            // 根据i8工程id查询项目部id
            MaterialLeaseApplyInfo i8ProjectInfo = mapper.selectI8ProjectInfo(info.getExternalId());
            if (i8ProjectInfo == null || i8ProjectInfo.getDepartId() == null) {
                continue;
            }
            List<String> userNameList = mapper.getUserNameList(i8ProjectInfo);
            if (!CollectionUtils.isEmpty(userNameList) && userNameList.contains(username)) {
                newList.add(info);
            }
        }
        if (!CollectionUtils.isEmpty(newList)) {
            return newList;
        }
        return list;
    }

    /**
     * 添加工器具领料
     *
     * @param leaseApplyRequestVo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult insertLeaseApplyInfo(MaterialLeaseApplyRequestVo leaseApplyRequestVo) {
        log.info("新增接口传参:{}", leaseApplyRequestVo);
        if (null == leaseApplyRequestVo.getLeaseApplyInfo()) {
            return AjaxResult.error("请先填写领料任务信息");
        }
        if (CollectionUtil.isEmpty(leaseApplyRequestVo.getLeaseApplyDetailsList())) {
            return AjaxResult.error("请先添加领料任务物资明细");
        }
        Integer isOut = leaseApplyRequestVo.getLeaseApplyInfo().getIsOut();
        // 对于编码出库的设备，进行出库时需校验编码明细
        if (isOut == 1) {
            for (MaterialLeaseApplyDetails leaseApplyDetails : leaseApplyRequestVo.getLeaseApplyDetailsList()) {
                if ("0".equals(leaseApplyDetails.getManageType())) {
                    if (CollectionUtils.isEmpty(leaseApplyDetails.getMaCodeList())) {
                        return AjaxResult.error("请先添加领料任务物资编码明细");
                    }
                }
                if (leaseApplyDetails.getOutNum().compareTo(leaseApplyDetails.getStorageNum()) > 0) {
                    throw new ServiceException("出库数量不能大于库存数量");
                }
            }
        }
        leaseApplyRequestVo.getLeaseApplyInfo().setCreateTime(DateUtils.getNowDate());
        String createBy = SecurityUtils.getLoginUser().getSysUser().getNickName();
        leaseApplyRequestVo.getLeaseApplyInfo().setCreateBy(createBy);
        try {
            int thisMonthMaxOrder = tmTaskMapper.getMonthMaxOrderByDate(DateUtils.getCurrentYear(), DateUtils.getCurrentMonth(), TmTaskTypeEnum.TM_TASK_MATERIAL_LEASE.getTaskTypeId());
            String taskCode = genderTaskCode(thisMonthMaxOrder);
            TmTask tmTask = new TmTask();
            if (leaseApplyRequestVo.getLeaseApplyInfo().getIsOut() == 1) {
                tmTask = new TmTask(null, TmTaskTypeEnum.TM_TASK_MATERIAL_LEASE.getTaskTypeId(),
                        LeaseTaskStatusEnum.LEASE_TASK_FINISHED.getStatus(),
                        leaseApplyRequestVo.getLeaseApplyInfo().getCompanyId(), thisMonthMaxOrder + 1, taskCode);
            } else {
                tmTask = new TmTask(null, TmTaskTypeEnum.TM_TASK_MATERIAL_LEASE.getTaskTypeId(),
                        // 待出库
                        LeaseTaskStatusEnum.LEASE_TASK_TO_PUBLISHED.getStatus(),
                        leaseApplyRequestVo.getLeaseApplyInfo().getCompanyId(), thisMonthMaxOrder + 1, taskCode);
            }
            tmTask.setCreateTime(DateUtils.getNowDate());
            tmTask.setCreateBy(createBy);
            tmTaskMapper.insertTmTask(tmTask);
            BmAgreementInfo bmAgreementInfo = new BmAgreementInfo();
            bmAgreementInfo.setProjectId(leaseApplyRequestVo.getLeaseApplyInfo().getProId());
            bmAgreementInfo.setCreateTime(DateUtils.getNowDate());
            bmAgreementInfo.setCreateBy(createBy);
            bmAgreementInfo.setSignTime(DateUtils.getNowDate());
            bmAgreementInfo.setAgreementCode(getAgreementCode());
            // 先根据班组名称查询此班组是否存在
            BmTeam tbTeam = new BmTeam();
            tbTeam.setTeamName(leaseApplyRequestVo.getLeaseApplyInfo().getTeamName());
            tbTeam.setRelName(StringUtils.isNotBlank(leaseApplyRequestVo.getLeaseApplyInfo().getRelName()) ? leaseApplyRequestVo.getLeaseApplyInfo().getRelName() : null);
            tbTeam.setIdCard(StringUtils.isNotBlank(leaseApplyRequestVo.getLeaseApplyInfo().getTeamLeaderIdCard()) ? leaseApplyRequestVo.getLeaseApplyInfo().getTeamLeaderIdCard() : null);
            tbTeam.setProjectId(leaseApplyRequestVo.getLeaseApplyInfo().getProjectId());
            tbTeam.setRelPhone(StringUtils.isNotBlank(leaseApplyRequestVo.getLeaseApplyInfo().getRelPhone()) ? leaseApplyRequestVo.getLeaseApplyInfo().getRelPhone() : null);
            // 班组类型固定传值
            tbTeam.setTypeId(1731L);
            BmTeam bmTeam =  bmTeamMapper.selectByName(tbTeam);
            if (bmTeam == null) {
                // 新增班组
                tbTeam.setCreateUser(SecurityUtils.getLoginUser().getUserid().toString());
                int result = bmTeamMapper.insert(tbTeam);
                if (result <= 0) {
                    return AjaxResult.error(HttpCodeEnum.UPDATE_TO_DATABASE.getCode(), HttpCodeEnum.UPDATE_TO_DATABASE.getMsg());
                }
                bmAgreementInfo.setUnitId(tbTeam.getId());
            } else {
                bmAgreementInfo.setUnitId(bmTeam.getId());
                bmTeamMapper.update(tbTeam);
            }
            // 先根据班组和工程id查询，若存在则直接返回，不存在则新增
            BmAgreementInfo info = bmAgreementInfoMapper.queryByTeamIdAndProjectIdCl(bmAgreementInfo);
            if (info != null) {
                leaseApplyRequestVo.getLeaseApplyInfo().setAgreementId(info.getAgreementId());
            } else {
                int count = bmAgreementInfoMapper.insertBmAgreementInfoClz(bmAgreementInfo);
                if (count > 0) {
                    leaseApplyRequestVo.getLeaseApplyInfo().setAgreementId(bmAgreementInfo.getAgreementId());
                } else {
                    return AjaxResult.error("新增bm_agreement_info表失败");
                }
            }
            TmTaskAgreement tmTaskAgreement = new TmTaskAgreement(tmTask.getTaskId(), leaseApplyRequestVo.getLeaseApplyInfo().getAgreementId());
            tmTaskAgreement.setCreateTime(DateUtils.getNowDate());
            tmTaskAgreement.setCreateBy(createBy);
            tmTaskAgreementMapper.insertTmTaskAgreement(tmTaskAgreement);
            leaseApplyRequestVo.getLeaseApplyInfo().setTaskId(tmTask.getTaskId());
            leaseApplyRequestVo.getLeaseApplyInfo().setCode(taskCode);

            // 领料任务类型为1 工器具领料
            leaseApplyRequestVo.getLeaseApplyInfo().setLeaseStyle("1");
            leaseApplyRequestVo.getLeaseApplyInfo().setTeamId(bmAgreementInfo.getUnitId().toString());
            int count = materialLeaseInfoMapper.insertLeaseApplyInfo(leaseApplyRequestVo.getLeaseApplyInfo());
            if (!CollectionUtils.isEmpty(leaseApplyRequestVo.getLeaseApplyInfo().getBmFileInfos())) {
                TmTask finalTmTask = tmTask;
                String finalCreateBy = createBy;
                leaseApplyRequestVo.getLeaseApplyInfo().getBmFileInfos().forEach(bmFileInfo -> {
                    bmFileInfo.setTaskType(2);
                    bmFileInfo.setTaskId(finalTmTask.getTaskId());
                    bmFileInfo.setModelId(leaseApplyRequestVo.getLeaseApplyInfo().getId());
                    bmFileInfo.setFileType(5L);
                    bmFileInfo.setCreateBy(finalCreateBy);
                    bmFileInfo.setCreateTime(DateUtils.getNowDate());
                    bmFileInfoMapper.insertBmFileInfo(bmFileInfo);
                });
            }
            if (count > 0) {
                return insertPurchaseCheckDetails(createBy, tmTask.getTaskId(), leaseApplyRequestVo.getLeaseApplyDetailsList(), leaseApplyRequestVo.getLeaseApplyInfo().getId(), leaseApplyRequestVo.getLeaseApplyInfo().getIsOut());
            } else {
                return AjaxResult.error("新增任务失败,lease_apply_info表插入0条");
            }
        } catch (DataAccessException e) {
            return AjaxResult.error("数据库操作失败:" + e.getMessage());
        } catch (Exception e) {
            return AjaxResult.error("新增任务失败:" + e.getMessage());
        }
    }

    /**
     * 获取协议编号
     *
     * @return
     */
    private String getAgreementCode() {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date nowDate = DateUtils.getNowDate();
        String format = dateFormat.format(nowDate);
        String result = format.replace("-", "");
        int num = bmAgreementInfoMapper.selectNumByMonthClz(nowDate);
        return MaterialConstants.AGREEMENT_PREFIX + result + String.format("-%03d", num + 1);
    }

    /**
     * 修改领料任务
     *
     * @param leaseApplyRequestVo
     * @return
     */
    @Override
    public boolean updateLeaseApplyInfo(MaterialLeaseApplyRequestVo leaseApplyRequestVo) {
        if (null == leaseApplyRequestVo.getLeaseApplyInfo()) {
            throw new ServiceException("请先填写领料任务信息");
        }
        if (CollectionUtil.isEmpty(leaseApplyRequestVo.getLeaseApplyDetailsList())) {
            throw new ServiceException("请先添加领料任务物资明细");
        }
        Integer isOut = leaseApplyRequestVo.getLeaseApplyInfo().getIsOut();
        // 对于编码出库的设备，进行出库时需校验编码明细
        if (isOut == 1) {
            for (MaterialLeaseApplyDetails leaseApplyDetails : leaseApplyRequestVo.getLeaseApplyDetailsList()) {
                if ("0".equals(leaseApplyDetails.getManageType())) {
                    if (CollectionUtils.isEmpty(leaseApplyDetails.getMaCodeList())) {
                        throw new ServiceException("请先添加领料任务物资编码明细");
                    }
                }
                if (leaseApplyDetails.getOutNum().compareTo(leaseApplyDetails.getStorageNum()) > 0) {
                    throw new ServiceException("出库数量不能大于库存数量");
                }
            }
        }
        try {
            String createBy = SecurityUtils.getLoginUser().getSysUser().getNickName();
            // 提取到局部变量中，减少重复代码
            MaterialLeaseApplyInfo leaseApplyInfo = leaseApplyRequestVo.getLeaseApplyInfo();
            if (leaseApplyInfo != null && leaseApplyInfo.getId() != null) {
                leaseApplyInfo.setUpdateTime(DateUtils.getNowDate());
                leaseApplyInfo.setUpdateBy(createBy);

                // 去除创建一个新的数组对象，直接复用
                Long id = leaseApplyInfo.getId();
                if (CollectionUtil.isNotEmpty(leaseApplyInfo.getBmFileInfos())) {
                    // 删除原有数据
                    BmFileInfo bmFileInfo = new BmFileInfo();
                    bmFileInfo.setTaskId(leaseApplyInfo.getTaskId());
                    bmFileInfo.setModelId(leaseApplyInfo.getId());
                    bmFileInfo.setTaskType(2);
                    bmFileInfo.setFileType(5L);
                    bmFileInfoMapper.deleteBmFileInfoByBizInfo(bmFileInfo);
                    for (BmFileInfo fileInfo : leaseApplyInfo.getBmFileInfos()) {
                        fileInfo.setTaskId(leaseApplyInfo.getTaskId());
                        fileInfo.setModelId(leaseApplyInfo.getId());
                        fileInfo.setTaskType(2);
                        fileInfo.setFileType(5L);
                        fileInfo.setCreateBy(createBy);
                        fileInfo.setCreateTime(DateUtils.getNowDate());
                        bmFileInfoMapper.insertBmFileInfo(fileInfo);
                    }
                }
                if (CollectionUtil.isNotEmpty(leaseApplyRequestVo.getLeaseApplyDetailsList())) {
                    // 业务逻辑代码,删除lease_apply_details
                    materialLeaseInfoMapper.deleteLeaseApplyDetailsByParentIds(id);
                    // 业务逻辑代码,删除lease_out_details
                    materialLeaseInfoMapper.deleteById(id);
                    /*for (MaterialLeaseApplyDetails leaseApplyDetails : leaseApplyRequestVo.getLeaseApplyDetailsList()) {
                        if (!CollectionUtils.isEmpty(leaseApplyDetails.getMaCodeList())) {
                            for (MaterialLeaseMaCodeDto leaseMaCodeDto : leaseApplyDetails.getMaCodeList()) {
                                // 根据maId将设备改为在库状态
                                machineMapper.updateStatus(leaseMaCodeDto.getMaId(), MaMachineStatusEnum.IN_STORE.getStatus());
                            }
                        }
                    }*/
                    insertPurchaseCheckDetails(createBy, leaseApplyInfo.getTaskId(), leaseApplyRequestVo.getLeaseApplyDetailsList(), leaseApplyInfo.getId(), leaseApplyRequestVo.getLeaseApplyInfo().getIsOut());
                }
                // 修改外层info
                materialLeaseInfoMapper.updateLeaseApplyInfo(leaseApplyInfo);
                // 根据任务id修改任务状态
                if (leaseApplyRequestVo.getLeaseApplyInfo().getIsOut() == 1) {
                    tmTaskMapper.updateTaskStatus(leaseApplyInfo.getTaskId().toString(), LeaseTaskStatusEnum.LEASE_TASK_FINISHED.getStatus());
                }
                return true;
            }
            return false;
        } catch (DataAccessException dae) {
            throw new ServiceException("数据访问异常: " + dae.getMessage());
        } catch (IllegalArgumentException iae) {
            throw new ServiceException("非法参数异常: " + iae.getMessage());
        } catch (Exception e) {
            throw new ServiceException("未知异常: " + e.getMessage());
        }
    }

    /**
     * 领料任务电子签名
     *
     * @param leaseApplyInfo
     * @return
     */
    @Override
    public int updateLeaseApplyInfoSign(MaterialLeaseApplyInfo leaseApplyInfo) {
        leaseApplyInfo.setUpdateBy(SecurityUtils.getLoginUser().getSysUser().getNickName());
        leaseApplyInfo.setUpdateTime(DateUtils.getNowDate());
        return materialLeaseInfoMapper.updateLeaseApplyInfoSign(leaseApplyInfo);
    }

    /**
     * 二维码出库：根据qrcode查询在库机具信息
     *
     * @param bmQrcodeInfo
     * @return
     */
    @Override
    public AjaxResult getInfoByQrcode(BmQrcodeInfo bmQrcodeInfo) {
        if (StringUtils.isBlank(bmQrcodeInfo.getQrCode())) {
            return AjaxResult.error(HttpCodeEnum.FAIL.getCode(), "二维码code不能为空");
        }
        // 根据qrCode查询数据
        List<LeaseOutDetails> clzList = materialLeaseInfoMapper.getInfoByQrcodeClz(bmQrcodeInfo);
        List<LeaseOutDetails> recordList = materialLeaseInfoMapper.getInfoByQrcode(bmQrcodeInfo);
       // 判断是否符合出库条件（假设业务规则是：clzList为空且recordList不为空）
        boolean isValid = CollectionUtil.isEmpty(clzList) && CollectionUtil.isNotEmpty(recordList);
       // 构建结果消息
        String msg = isValid
                ? "监测到" + bmQrcodeInfo.getQrCode() + "符合出库条件,请确认是否出库!"
                : "监测到" + bmQrcodeInfo.getQrCode() + "编码不符合出库条件，请检查后重新提交!";
        if (!isValid) {
            recordList = new ArrayList<>();
        }
        // 返回包含设备列表和消息的结果
        Map<String, Object> result = new HashMap<>(2);
        result.put("recordList", recordList);
        result.put("msg", msg);
        return AjaxResult.success(result);
    }

    /**
     * app领料出库提交
     *
     * @param leaseApplyDetails
     * @return
     */
    @Override
    public AjaxResult submitLeaseOut(MaterialLeaseApplyDetails leaseApplyDetails) {
        // 第一次提交，进行数据查询，给予提醒
        if (leaseApplyDetails.getIsSubmit() != null && leaseApplyDetails.getIsSubmit() == 0) {
            List<MaterialLeaseApplyDetails> list = materialLeaseInfoMapper.getOutNum(leaseApplyDetails);
            // 根据id去出库表查询数据，进行数据拼接
            List<MaterialLeaseApplyDetails> outNumList = materialLeaseInfoMapper.getOutNumList(leaseApplyDetails);
            // 构建typeId到LeaseApplyDetails的映射，用于快速查找
            Map<Long, MaterialLeaseApplyDetails> outNumMap = outNumList.stream()
                    .collect(Collectors.toMap(MaterialLeaseApplyDetails::getTypeId, details -> details, (existing, replacement) -> existing));
            if (!CollectionUtils.isEmpty(list)) {
                // 处理已有数据的状态
                list.forEach(applyDetails -> {
                    if (outNumMap.containsKey(applyDetails.getTypeId()) && applyDetails.getOutNum().compareTo(BigDecimal.ZERO) == 0) {
                        applyDetails.setStatus("1");
                        outNumMap.remove(applyDetails.getTypeId());
                    }
                });

                // 添加outNumList中剩余的typeId对应数据
                if (!outNumMap.isEmpty()) {
                    list.addAll(outNumMap.values());
                }
            }
            // 判断list中status状态是否全部为1 已完成
            if (list.size() > list.stream().filter(item -> "1".equals(item.getStatus())).count()) {
                return AjaxResult.success("该领料单有未出库领料数据，请确认是否提交");
            } else {
                return AjaxResult.success("该领料单无未出库领料数据，请确认是否提交");
            }
        }
        String taskId = materialLeaseInfoMapper.getTaskId(leaseApplyDetails.getId());
        int result = tmTaskMapper.updateTaskStatus(taskId, LeaseTaskStatusEnum.LEASE_TASK_FINISHED.getStatus());
        return result == 1 ? AjaxResult.success("提交成功") : AjaxResult.error("提交失败");
    }

    /**
     * 删除领料任务
     *
     * @param info
     * @return
     */
    @Override
    public int deleteLeaseApplyInfoByIds(MaterialLeaseApplyInfo info) {
        int result = 0;
        // 先根据id查询该领料单是否已经退料
        List<MaterialLeaseApplyInfo> list = materialLeaseInfoMapper.getSltInfoList(info.getId());
        if (!CollectionUtils.isEmpty(list)) {
            // 如果list包含状态为1的数据
            if (list.stream().anyMatch(item -> "1".equals(item.getStatus()))) {
                throw new ServiceException("该领料单已经进行退料操作，无法删除");
            }
        }
        // 根据id查询任务id
        Long taskId = materialLeaseInfoMapper.getTaskIds(info.getId());
        if (taskId != null) {
            // 根据任务id删除任务表数据
            result = tmTaskMapper.deleteTaskByIds(taskId);
            if (result < 1) {
                throw new ServiceException("删除任务信息失败");
            }
            // 根据任务id删除任务协议表数据
            result = tmTaskMapper.deleteAgreementId(taskId);
            if (result < 1) {
                throw new ServiceException("删除任务协议信息失败");
            }
        }
        result = materialLeaseInfoMapper.deleteLeaseApplyInfoByIds(info.getId());
        if (result > 0) {
            // 删除clz_lease_apply_details表数据
            result += materialLeaseInfoMapper.deleteLeaseApplyDetailsByParentIds(info.getId());
            // 业务逻辑代码,删除clz_lease_out_details
            result += materialLeaseInfoMapper.deleteById(info.getId());
            // 如果为领料出库，删除协议表数据
            if ("1".equals(info.getType())) {
                result += materialLeaseInfoMapper.deleteSltInfo(info.getId());
            }
        }
        return result;
    }

    /**
     * 工器具领料记录
     *
     * @param info
     * @return
     */
    @Override
    public List<LeaseTotalInfo> getLeaseInfoDetails(LeaseTotalInfo info) {
        String username = SecurityUtils.getLoginUser().getUsername();
        BmTeam teamData = null;
        Set<String> userRoles = SecurityUtils.getLoginUser().getRoles();
        // 检查用户是否具有特殊角色
        boolean hasSpecialRole = hasSpecialRole(userRoles);
        if (!hasSpecialRole) {
            // 根据用户名判断用户是否为班组长
            teamData = materialMachineMapper.getTeamData(username);
            if (teamData == null) {
                // 根据用户名查询项目部信息
                List<String> departId = mapper.getDepartId(username);
                // 根据项目部id查询工程信息
                List<String> projectIdList = mapper.getProjectId(departId);
                if (!org.springframework.util.CollectionUtils.isEmpty(projectIdList)) {
                    info.setProjectIdList(projectIdList);
                }
            }
        }
        BigDecimal preNum = BigDecimal.ZERO.setScale(3, RoundingMode.HALF_UP);
        BigDecimal outNum = BigDecimal.ZERO.setScale(3, RoundingMode.HALF_UP);
        BigDecimal pendingNum = BigDecimal.ZERO.setScale(3, RoundingMode.HALF_UP);
        List<LeaseTotalInfo> list = materialLeaseInfoMapper.getLeaseInfoDetails(info);
        if (!hasSpecialRole) {
            Long deptId = SecurityUtils.getLoginUser().getSysUser().getDeptId();
            if (!CollectionUtils.isEmpty(list) && deptId != null) {
                // 删除元素
                list.removeIf(m -> !deptId.toString().equals(m.getImpUnit()));
            }
        }
        if (!CollectionUtils.isEmpty(list)) {
            // 班组长权限
            if (teamData != null) {
                // 将list中班组身份证号与username相同的元素过滤处理
                list = list.stream()
                        .filter(item -> StringUtils.isBlank(item.getIdCard()) || username.equals(item.getIdCard()))
                        .collect(Collectors.toList());
            } /*else {
                // 材料员权限
                list = filterListInfo(list, username);
            }*/
        }
        // 处理数据并计算总和
        if (!CollectionUtils.isEmpty(list)) {
            for (LeaseTotalInfo leaseTotalInfo : list) {
                // 根据typeId和parentId查询领料数量
                LeaseTotalInfo totalInfo = materialLeaseInfoMapper.getTotalInfo(leaseTotalInfo);
                if (totalInfo != null) {
                    leaseTotalInfo.setPreNum(totalInfo.getPreNum());
                    // 安全计算pendingNum，避免NPE
                    BigDecimal outNumValue = leaseTotalInfo.getOutNum() != null ? leaseTotalInfo.getOutNum() : BigDecimal.ZERO;
                    leaseTotalInfo.setPendingNum(leaseTotalInfo.getPreNum().subtract(outNumValue));
                }

                // 累加统计值，确保不处理null值
                preNum = preNum.add(leaseTotalInfo.getPreNum() != null ? leaseTotalInfo.getPreNum() : BigDecimal.ZERO);
                outNum = outNum.add(leaseTotalInfo.getOutNum() != null ? leaseTotalInfo.getOutNum() : BigDecimal.ZERO);
                pendingNum = pendingNum.add(leaseTotalInfo.getPendingNum() != null ? leaseTotalInfo.getPendingNum() : BigDecimal.ZERO);
            }

            // 添加合计行
            if (info.getIsExport() == 0) {
                LeaseTotalInfo summary = new LeaseTotalInfo();
                summary.setUnitName("合计");
                summary.setPreNum(preNum.setScale(3, RoundingMode.HALF_UP));
                summary.setOutNum(outNum.setScale(3, RoundingMode.HALF_UP));
                summary.setPendingNum(pendingNum.setScale(3, RoundingMode.HALF_UP));
                list.add(0, summary);
            }
        }
        return list;
    }

    /**
     * 材料员权限
     * @param list
     * @param username
     * @return
     */
    private List<LeaseTotalInfo> filterListInfo(List<LeaseTotalInfo> list, String username) {
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        List<LeaseTotalInfo> newList = new ArrayList<>();
        for (LeaseTotalInfo info : list) {
            if (StringUtils.isBlank(info.getExternalId())) {
                continue;
            }
            // 根据i8工程id查询项目部id
            MaterialLeaseApplyInfo i8ProjectInfo = mapper.selectI8ProjectInfo(info.getExternalId());
            if (i8ProjectInfo == null || i8ProjectInfo.getDepartId() == null) {
                continue;
            }
            List<String> userNameList = mapper.getUserNameList(i8ProjectInfo);
            if (!CollectionUtils.isEmpty(userNameList) && userNameList.contains(username)) {
                newList.add(info);
            }
        }
        if (!CollectionUtils.isEmpty(newList)) {
            return newList;
        }
        return list;
    }

    /**
     * 工器具领料二级页面记录
     * @param info
     * @return
     */
    @Override
    public List<MaCodeVo> getSecondLeaseInfo(LeaseTotalInfo info) {
        return materialLeaseInfoMapper.getSecondLeaseInfo(info);
    }

    /**
     * 材料站在库设备类型树(即机具在用设备)
     */
    @Override
    public AjaxResult getUseTypeTree(MaterialLeaseApplyInfo bean) {
        long startTime = System.currentTimeMillis();
        log.info("开始执行getUseTypeTree方法，参数：proId={}, teamName={}, agreementIdList={}", bean.getProId(), bean.getTeamName(), bean.getAgreementIdList());

        List<TypeTreeNode> groupList = new ArrayList<>();
        List<TypeTreeNode> list = new ArrayList<>();
        List<TypeTreeNode> listL4 = new ArrayList<>();
        List<TypeTreeNode> listL3 = new ArrayList<>();
        List<TypeTreeNode> listL21 = new ArrayList<>();
        List<TypeTreeNode> listL5 = new ArrayList<>();
        List<TypeTreeNode> list7 = new ArrayList<>();
        try {
            // 优化：使用Map来避免重复的Stream查找操作
            Map<Long, TypeTreeNode> typeNodeMap = new HashMap<>();

            // 先查第四层类型
            BackApplyInfo backApplyInfo = new BackApplyInfo();
            if (!CollectionUtils.isEmpty(bean.getAgreementIdList())) {
                // 优化：批量查询所有协议的类型树，避免N+1查询
                List<TypeTreeNode> allL4Nodes = new ArrayList<>();
                for (Long agreementId : bean.getAgreementIdList()) {
                    backApplyInfo.setAgreementId(agreementId);
                    listL4 = mapper.getUseTypeClzTree(backApplyInfo);
                    if (!CollectionUtils.isEmpty(listL4)) {
                        allL4Nodes.addAll(listL4.stream()
                                .filter(item -> StringUtils.isNotBlank(item.getMaterialName()) && StringUtils.isNotBlank(item.getTypeName()))
                                .collect(Collectors.toList()));
                    }
                }

                // 优化：使用Map进行聚合，避免重复的Stream查找
                for (TypeTreeNode node : allL4Nodes) {
                    Long typeId = node.getTypeId();
                    if (typeNodeMap.containsKey(typeId)) {
                        TypeTreeNode existingNode = typeNodeMap.get(typeId);
                        existingNode.setNum(existingNode.getNum().add(node.getNum()));
                    } else {
                        typeNodeMap.put(typeId, node);
                    }
                }
                listL5.addAll(typeNodeMap.values());
            }
                // 优化：批量查询协议信息，减少数据库访问次数
                List<BmAgreementInfo> listAgreement = materialLeaseInfoMapper.getAgreementIdByProId(bean);
                if (!CollectionUtils.isEmpty(listAgreement)) {
                    // 批量查询所有协议的使用类型树
                    List<TypeTreeNode> allTypeNodes = new ArrayList<>();
                    for (BmAgreementInfo agreementInfo : listAgreement) {
                        bean.setAgreementId(agreementInfo.getAgreementId());
                        List<TypeTreeNode> list6 = materialLeaseInfoMapper.getUseTypeTree(bean);
                        if (!CollectionUtils.isEmpty(list6)) {
                            allTypeNodes.addAll(list6);
                        }
                    }

                    // 优化：使用Map进行聚合，避免重复的Stream查找
                    Map<Long, TypeTreeNode> aggregatedMap = new HashMap<>();
                    for (TypeTreeNode node : allTypeNodes) {
                        Long typeId = node.getTypeId();
                        if (aggregatedMap.containsKey(typeId)) {
                            TypeTreeNode existingNode = aggregatedMap.get(typeId);
                            existingNode.setNum(existingNode.getNum().add(node.getNum()));
                        } else {
                            aggregatedMap.put(typeId, node);
                        }
                    }
                    list7.addAll(aggregatedMap.values());
                }
                // 根据协议id去clz_slt_agreement_info材料站协议表中查询在用设备，进行数据筛选去除
                if (!CollectionUtils.isEmpty(listL5)) {
                    if (!CollectionUtils.isEmpty(list7)) {
                        // 将list5中typeId和list7中相同数据进行num相减，并剔除相减后为0的数据
                        Map<Long, BigDecimal> typeIdToNum = list7.stream()
                                .collect(Collectors.toMap(
                                        TypeTreeNode::getTypeId,
                                        TypeTreeNode::getNum,
                                        BigDecimal::add
                                ));
                        Iterator<TypeTreeNode> iterator = listL5.iterator();
                        while (iterator.hasNext()) {
                            TypeTreeNode node = iterator.next();
                            Long typeId = node.getTypeId();
                            // 获取要减去的值，默认值为BigDecimal.ZERO
                            BigDecimal subtractNum = typeIdToNum.getOrDefault(typeId, BigDecimal.ZERO);
                            // 计算新值，处理num为null的情况（若业务允许）
                            BigDecimal currentNum = Optional.ofNullable(node.getNum()).orElse(BigDecimal.ZERO);
                            BigDecimal newNum = currentNum.subtract(subtractNum);
                            node.setNum(newNum.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : newNum);
                        }
                    }
                }
                if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(listL5)) {
                    // 优化：预先查询班组和协议信息，避免在循环中重复查询
                    BmTeam team = null;
                    BmAgreementInfo agreementInfo = null;

                    if (StringUtils.isNotBlank(bean.getTeamName())) {
                        team = getTeamByNameCached(bean.getTeamName());

                        if (team != null) {
                            bean.setTeamId(team.getId().toString());
                            agreementInfo = getAgreementInfoCached(bean);
                        }
                    }

                    // 优化：如果有协议信息，批量查询所有类型的使用数量
                    Map<Long, BigDecimal> useNumMap = new HashMap<>();
                    if (agreementInfo != null && !listL5.isEmpty()) {
                        // 收集所有需要查询的typeId
                        List<Long> typeIds = listL5.stream()
                                .map(TypeTreeNode::getTypeId)
                                .collect(Collectors.toList());

                        // 批量查询使用数量 - 性能优化关键点
                        List<Type> batchResults = typeMapper.getNumListBatch(agreementInfo.getAgreementId(), typeIds);

                        // 转换为Map
                        if (!CollectionUtils.isEmpty(batchResults)) {
                            useNumMap = batchResults.stream()
                                    .filter(type -> type.getTypeId() != null && type.getUseNum() != null)
                                    .collect(Collectors.toMap(Type::getTypeId, Type::getUseNum));
                        }
                    }

                    // 设置使用数量
                    for (TypeTreeNode node : listL5) {
                        BigDecimal useNum = useNumMap.getOrDefault(node.getTypeId(), BigDecimal.ZERO);
                        node.setUseNum(useNum);
                    }
                    List<Long> list4ParentIds = listL5.stream().map(TypeTreeNode::getParentId).collect(Collectors.toList());
                    // 根据第四层parentId 查第三层类型
                    listL3 = mapper.getUseTypeTreeL3(list4ParentIds);
                    List<Long> list3ParentIds = listL3.stream().map(TypeTreeNode::getParentId).collect(Collectors.toList());
                    // 根据第三层parentId 查第1.2层类型
                    listL21 = mapper.getUseTypeTreeL21(list3ParentIds);
                    list.addAll(listL5);
                    list.addAll(listL3);
                    list.addAll(listL21);
                }
                if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(list)) {
                    // 创建树形结构（数据集合作为参数）
                    TypeTreeBuild treeBuild = new TypeTreeBuild(list);
                    // 原查询结果转换树形结构
                    groupList = treeBuild.buildTree();
                }
        } catch (Exception e) {
            log.error("getUseTypeTree方法执行失败", e);
            return AjaxResult.error("类型树-查询失败", e);
        } finally {
            long endTime = System.currentTimeMillis();
            long executionTime = endTime - startTime;
            log.info("getUseTypeTree方法执行完成，耗时：{}ms，返回数据量：{}", executionTime, groupList.size());
        }
        return AjaxResult.success(groupList);
    }

    /**
     * 缓存班组查询 - 性能优化
     * @param teamName 班组名称
     * @return 班组信息
     */
    private BmTeam getTeamByNameCached(String teamName) {
        BmTeam bmTeam = new BmTeam();
        bmTeam.setTeamName(teamName);
        return bmTeamMapper.selectByName(bmTeam);
    }

    /**
     * 缓存协议信息查询 - 性能优化
     * @param bean 查询参数
     * @return 协议信息
     */
    private BmAgreementInfo getAgreementInfoCached(MaterialLeaseApplyInfo bean) {
        return materialLeaseInfoMapper.getAgreeId(bean);
    }

    /**
     * 根据班组和工程id查询领料机具
     * @param dto
     * @return
     */
    @Override
    public AjaxResult getMachineById(MaterialLeaseApplyInfo dto) {
        // 获取所有机具列表
        List<MaterialMaCodeVo> allMachines = materialLeaseInfoMapper.getMachineById(dto);

        // 如果没有机具，直接返回空列表
        if (CollectionUtils.isEmpty(allMachines)) {
            return AjaxResult.success(Collections.emptyList());
        }

        // 获取已使用的机具列表
        List<MaterialMaCodeVo> usedMachines = materialLeaseInfoMapper.getUseMachineById(dto);

        // 如果没有已使用的机具，则所有机具都是未使用的
        if (CollectionUtils.isEmpty(usedMachines)) {
            return AjaxResult.success(allMachines);
        }

        // 创建已使用机具ID的Set，提高查找效率
        Set<Long> usedMachineIds = usedMachines.stream()
                .map(MaterialMaCodeVo::getMaId)
                .collect(Collectors.toSet());

        // 筛选出未使用的机具
        List<MaterialMaCodeVo> unusedMachines = allMachines.stream()
                .filter(machine -> !usedMachineIds.contains(machine.getMaId()))
                .collect(Collectors.toList());

        return AjaxResult.success(unusedMachines);
    }

    /**
     * 获取领料单信息
     * @param leaseApplyInfo
     * @return
     */
    @Override
    public AjaxResult getPickList(MaterialLeaseApplyInfo leaseApplyInfo) {
        try {
            MaterialLeaseApplyInfo info = materialLeaseInfoMapper.selectLeaseApplyInfoById(leaseApplyInfo);
            // 电子签名进行base64拼接
            if (StringUtils.isNotBlank(info.getLeaseSignUrl())) {
                //如果info.getLeaseSignUrl()以http开头，则直接返回，否则进行拼接
                if (!info.getLeaseSignUrl().startsWith("http")) {
                    info.setLeaseSignUrl("data:image/png;base64," + info.getLeaseSignUrl());
                }
            }
            MaterialLeaseApplyRequestVo leaseApplyRequestVo = new MaterialLeaseApplyRequestVo();
            leaseApplyRequestVo.setLeaseApplyInfo(info);
            // 获取领料单详情
            List<MaterialLeaseApplyDetails> details = materialLeaseInfoMapper.selectLeaseApplyDetailsList(new MaterialLeaseApplyDetails(info.getId(), null, null));
            //根据id查询领料单详情
            if (!CollectionUtils.isEmpty(details)) {
                for (MaterialLeaseApplyDetails detail : details) {
                    leaseApplyRequestVo.setLeaseApplyDetailsList(details);
                    // 获取编码详情
                    List<MaterialLeaseMaCodeDto> maCodeVoList = materialLeaseInfoMapper.getCodeList(leaseApplyInfo.getId(), detail.getTypeId());
                    if (!CollectionUtils.isEmpty(maCodeVoList)) {
                        // 将maCodeVoList中的materialModel值赋值给typeName
                        maCodeVoList.forEach(maCodeVo -> maCodeVo.setTypeName(maCodeVo.getMaterialModel()));
                        detail.setMaCodeVoList(maCodeVoList);
                    }
                }
                List<MaterialLeaseMaCodeDto> detailsList = materialLeaseInfoMapper.getList(leaseApplyInfo.getId(), details.get(0).getTypeId());
                LeaseOutSign leaseOutSign = new LeaseOutSign(0, null);
                if (CollectionUtil.isNotEmpty(detailsList)) {
                    if (!detailsList.get(0).getSignUrl().startsWith("http")) {
                        leaseOutSign = new LeaseOutSign(detailsList.get(0).getSignType(),
                                "data:image/png;base64," + detailsList.get(0).getSignUrl());
                    } else {
                        leaseOutSign = new LeaseOutSign(detailsList.get(0).getSignType(), detailsList.get(0).getSignUrl());
                    }
                }
                leaseApplyRequestVo.setLeaseOutSign(leaseOutSign);
            }
            AjaxResult ajaxResult = AjaxResult.success();
            ajaxResult.put("data", leaseApplyRequestVo);
            return ajaxResult;
        } catch (Exception e) {
            throw new RuntimeException("查询失败", e);
        }
    }

    /**
     * OCR出库：根据code查询在库机具信息
     * @param bmQrcodeInfo
     * @return
     */
    @Override
    public AjaxResult getInfoByCode(BmQrcodeInfo bmQrcodeInfo) {
        if (StringUtils.isBlank(bmQrcodeInfo.getMaCode())) {
            return AjaxResult.error(HttpCodeEnum.FAIL.getCode(), "设备编码不能为空");
        }
        // 根据Code查询数据
        List<LeaseOutDetails> clzList = materialLeaseInfoMapper.getMaCodeList(bmQrcodeInfo);
        List<LeaseOutDetails> recordList = materialLeaseInfoMapper.getInfoByCode(bmQrcodeInfo);
        // 判断是否符合出库条件（假设业务规则是：clzList为空且recordList不为空）
        boolean isValid = CollectionUtil.isEmpty(clzList) && CollectionUtil.isNotEmpty(recordList);
        // 构建结果消息
        String msg = isValid
                ? "监测到" + bmQrcodeInfo.getMaCode() + "符合出库条件,请确认是否出库!"
                : "监测到" + bmQrcodeInfo.getMaCode() + "编码不符合出库条件，请检查后重新提交!";
        if (!isValid) {
            recordList = new ArrayList<>();
        }
        // 返回包含设备列表和消息的结果
        Map<String, Object> result = new HashMap<>(2);
        result.put("recordList", recordList);
        result.put("msg", msg);
        return AjaxResult.success(result);
    }

    /**
     * 插入领料任务
     * @param createBy
     * @param taskId
     * @param leaseApplyDetailsList
     * @param parentId
     * @param isOut
     * @return
     */
    private AjaxResult insertPurchaseCheckDetails(String createBy, Long taskId, List<MaterialLeaseApplyDetails> leaseApplyDetailsList, Long parentId, Integer isOut) {
        if (!CollectionUtils.isEmpty(leaseApplyDetailsList)) {
            for (MaterialLeaseApplyDetails details : leaseApplyDetailsList) {
                details.setParentId(parentId); // 设置info.parentId
                details.setCreateTime(DateUtils.getNowDate());
                details.setCreateBy(createBy);
                LeaseOutDetails record = new LeaseOutDetails();
                record.setCreateBy(SecurityUtils.getLoginUser().getUserid().toString());
                record.setIsFinished(isOut == 1 ? 1 : 0);
                // 领料出库
                if (isOut == 1) {
                    if (!CollectionUtils.isEmpty(details.getMaCodeList())) {
                        for (MaterialLeaseMaCodeDto leaseMaCodeDto : details.getMaCodeList()) {
                            record.setMaId(leaseMaCodeDto.getMaId());
                            record.setOutNum(BigDecimal.valueOf(1));
                            record.setParentId(parentId);
                            record.setOutType(leaseMaCodeDto.getOutType());
                            record.setTypeId(Long.parseLong(leaseMaCodeDto.getTypeId()));
                            int res = materialLeaseInfoMapper.insertLeaseOutDetails(record);
                            if (res > 0) {
                                res = insSltInfo(taskId, record);
                            }
                            if (res == 0) {
                                throw new RuntimeException("出库失败,插入结算记录失败");
                            }
                        }
                    } else {
                        record.setTypeId(details.getTypeId());
                        record.setOutNum(details.getOutNum());
                        record.setParentId(parentId);
                        record.setOutType(1);
                        int res = materialLeaseInfoMapper.insertLeaseOutDetails(record);
                        if (res == 0) {
                            throw new RuntimeException("插入lease_out_details表数据失败");
                        }
                        res = insSltInfo(taskId, record);
                        if (res == 0) {
                            throw new RuntimeException("出库失败,插入结算记录失败");
                        }
                    }
                    // 出库暂存
                } else if (isOut == 0) {
                    if (!CollectionUtils.isEmpty(details.getMaCodeList())) {
                        for (MaterialLeaseMaCodeDto leaseMaCodeDto : details.getMaCodeList()) {
                            record.setMaId(leaseMaCodeDto.getMaId());
                            record.setOutNum(BigDecimal.valueOf(1));
                            record.setParentId(parentId);
                            record.setOutType(leaseMaCodeDto.getOutType());
                            record.setTypeId(Long.parseLong(leaseMaCodeDto.getTypeId()));
                            int res = materialLeaseInfoMapper.insertLeaseOutDetails(record);
                            if (res == 0) {
                                return AjaxResult.error("插入lease_out_details表数据失败");
                            }
                        }
                    } else {
                        record.setTypeId(details.getTypeId());
                        record.setOutNum(details.getOutNum());
                        record.setParentId(parentId);
                        record.setOutType(1);
                        int res = materialLeaseInfoMapper.insertLeaseOutDetails(record);
                        if (res == 0) {
                            return AjaxResult.error("插入lease_out_details表数据失败");
                        }
                    }
                }
            }
            // 批量插入详情数据
            int count = materialLeaseInfoMapper.insertLeaseApplyDetailsList(leaseApplyDetailsList);
            if (count > 0) {
                return AjaxResult.success("新增任务成功", parentId);
            } else {
                return AjaxResult.error("新增任务失败,lease_apply_detail详情表插入0条");
            }
        } else {
            return AjaxResult.success("新增任务成功", parentId);
        }
    }

    /**
     * 插入结算记录
     * @param taskId
     * @param record
     * @return
     */
    private int insSltInfo(Long taskId, LeaseOutDetails record) {
        int res = 0;
        MaterialSltAgreementInfo sltAgreementInfo = materialLeaseInfoMapper.getSltAgreementInfo(record);
        if (sltAgreementInfo != null) {
            BigDecimal num = sltAgreementInfo.getNum();
            BigDecimal outNum = record.getOutNum();
            sltAgreementInfo.setNum(num.add(outNum));
            res = materialLeaseInfoMapper.updSltInfo(sltAgreementInfo);
            record.setAgreementId(sltAgreementInfo.getAgreementId());
        } else {
            String agreementId = tmTaskAgreementMapper.getAgreementId(taskId.toString());
            Type maType = typeMapper.getMaType(record.getTypeId());
            maType.setFinalPrice(maType.getLeasePrice());
            res = materialLeaseInfoMapper.insSltInfo(record, agreementId, maType);
        }
        return res;
    }


    /**
     * 生成任务编号
     * @param thisMonthMaxOrder
     * @return
     */
    private static String genderTaskCode(Integer thisMonthMaxOrder) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date nowDate = DateUtils.getNowDate();
        String format = dateFormat.format(nowDate);
        String result = format.replace("-", "");
        return MaterialConstants.MATERIAL_LEASE_TASK_TYPE_LABEL + result + String.format("-%03d", thisMonthMaxOrder + 1);
    }

    /**
     * 校验出库数量是否大于库存数量
     * @param leaseApplyDetailsList
     * @return
     */
    private int checkStorageNum(List<MaterialLeaseApplyDetails> leaseApplyDetailsList) {
        for (MaterialLeaseApplyDetails leaseApplyDetails : leaseApplyDetailsList) {
            if (StringUtils.isNull(leaseApplyDetails)) {
                return 0;
            }
            if (leaseApplyDetails.getOutNum() == null) {
                leaseApplyDetails.setOutNum(BigDecimal.valueOf(0L));
            }
            //判断(ma_type 设备规格表)中的库存够不够出库的
            LeaseOutDetails leaseOutDetails = new LeaseOutDetails();
            leaseOutDetails.setTypeId(leaseApplyDetails.getTypeId());
            Type maType = typeMapper.selectByTypeId(leaseOutDetails);
            if (maType != null) {
                if ("1".equals(maType.getManageType())) {
                    if (maType.getStorageNum() == null || maType.getStorageNum().compareTo(leaseApplyDetails.getOutNum()) < 0) {
                        return 0;
                    }
                }
            }
        }
        return 1;
    }

    /**
     * 工器具领料数据过滤
     * @param item
     * @param keyWord
     * @return
     */
    private boolean containsLeaseKeyword(LeaseApplyDetailsInfo item, String keyWord) {
        return (item.getMaTypeName() != null && item.getMaTypeName().contains(keyWord)) ||
                (item.getTeamName() != null && item.getTeamName().contains(keyWord)) ||
                (item.getProjectName() != null && item.getProjectName().contains(keyWord)) ||
                (item.getTypeName() != null && item.getTypeName().contains(keyWord)) ||
                (item.getLeasePerson() != null && item.getLeasePerson().contains(keyWord)) ||
                (item.getOutPerson() != null && item.getOutPerson().contains(keyWord)) ||
                (item.getLeaseCode() != null && item.getLeaseCode().contains(keyWord));
    }


    /**
     * 总站点领料记录数据过滤
     * @param item
     * @param keyWord
     * @return
     */
    private boolean containsNumKeyword(MaterialLeaseApplyDetails item, String keyWord) {
        return (item.getMaTypeName() != null && item.getMaTypeName().contains(keyWord)) ||
                (item.getTypeName() != null && item.getTypeName().contains(keyWord));
    }

    /**
     * 总站点领料记录数据过滤
     * @param item
     * @param keyWord
     * @return
     */
    private boolean containsTotalKeyword(MaterialLeaseApplyInfo item, String keyWord) {
        return (item.getMaTypeNames() != null && item.getMaTypeNames().contains(keyWord)) ||
                (item.getLeaseUnit() != null && item.getLeaseUnit().contains(keyWord)) ||
                (item.getLeaseProject() != null && item.getLeaseProject().contains(keyWord)) ||
                (item.getLeasePerson() != null && item.getLeasePerson().contains(keyWord)) ||
                (item.getCode() != null && item.getCode().contains(keyWord));
    }

    /**
     * 预计算在用量数据
     */
    private Map<Long, BigDecimal> preCalculateUseNums(MaterialLeaseApplyInfo info, List<Long> typeIds) {
        Map<Long, BigDecimal> useNumMap = new HashMap<>();

        try {
            for (Long typeId : typeIds) {
                try {
                    Type type = new Type();
                    type.setAgreementId(info.getAgreementId());
                    type.setTypeId(typeId);

                    Type dto = typeMapper.getNumList(type);
                    BigDecimal useNum = (dto != null) ? dto.getUseNum() : BigDecimal.ZERO;
                    useNumMap.put(typeId, useNum);

                } catch (Exception e) {
                    log.warn("计算typeId {}的在用量失败: {}", typeId, e.getMessage());
                    useNumMap.put(typeId, BigDecimal.ZERO);
                }
            }

            log.info("预计算在用量完成，为{}个类型计算了在用量", typeIds.size());

        } catch (Exception e) {
            log.error("预计算在用量失败", e);
            for (Long typeId : typeIds) {
                useNumMap.put(typeId, BigDecimal.ZERO);
            }
        }

        return useNumMap;
    }

    /**
     * 预计算库存数据，重现原始的类型树计算逻辑
     * 业务逻辑：总领料数量 - 已在用数量 = 剩余可用库存
     */
    private Map<Long, BigDecimal> preCalculateStorageNums(MaterialLeaseApplyInfo info,
                                                          List<AgreementVo> agreementList,
                                                          List<Long> typeIds) {
        Map<Long, BigDecimal> storageNumMap = new HashMap<>();

        try {
            log.info("开始预计算库存，原始类型树逻辑，处理{}个类型", typeIds.size());

            // 第1步：从协议中获取总领料数量（原listL5逻辑）
            Map<Long, BigDecimal> totalLeaseNums = new HashMap<>();
            if (!CollectionUtils.isEmpty(agreementList)) {
                for (AgreementVo agreementVo : agreementList) {
                    BackApplyInfo backApplyInfo = new BackApplyInfo();
                    backApplyInfo.setAgreementId(Long.valueOf(agreementVo.getAgreementId()));
                    List<TypeTreeNode> listL4 = mapper.getUseTypeTreeL4(backApplyInfo);

                    if (!CollectionUtils.isEmpty(listL4)) {
                        for (TypeTreeNode node : listL4) {
                            if (node.getTypeId() != 0L && node.getNum() != null) {
                                totalLeaseNums.merge(node.getTypeId(), node.getNum(), BigDecimal::add);
                            }
                        }
                    }
                }
            }

            // 第2步：通过工程获取已在用数量（原list7逻辑）
            Map<Long, BigDecimal> usedNums = new HashMap<>();
            MaterialLeaseApplyInfo bean = new MaterialLeaseApplyInfo();
            bean.setProId(info.getProId());
            List<BmAgreementInfo> listAgreement = materialLeaseInfoMapper.getAgreementIdByProId(bean);

            if (!CollectionUtils.isEmpty(listAgreement)) {
                for (BmAgreementInfo agreementInfo : listAgreement) {
                    bean.setAgreementId(agreementInfo.getAgreementId());
                    List<TypeTreeNode> list6 = materialLeaseInfoMapper.getUseTypeTree(bean);

                    if (!CollectionUtils.isEmpty(list6)) {
                        for (TypeTreeNode node : list6) {
                            if (node.getTypeId() != 0L && node.getNum() != null) {
                                usedNums.merge(node.getTypeId(), node.getNum(), BigDecimal::add);
                            }
                        }
                    }
                }
            }

            // 第3步：计算剩余库存 = 总领料数量 - 已在用数量
            for (Long typeId : typeIds) {
                BigDecimal totalNum = totalLeaseNums.getOrDefault(typeId, BigDecimal.ZERO);
                BigDecimal usedNum = usedNums.getOrDefault(typeId, BigDecimal.ZERO);
                BigDecimal storageNum = totalNum.subtract(usedNum);

                // 确保不为负数
                if (storageNum.compareTo(BigDecimal.ZERO) < 0) {
                    storageNum = BigDecimal.ZERO;
                }

                storageNumMap.put(typeId, storageNum);
            }

            log.info("库存计算完成 - 总领料：{}项，已在用：{}项，计算库存：{}项",
                    totalLeaseNums.size(), usedNums.size(), storageNumMap.size());

        } catch (Exception e) {
            log.error("预计算库存失败: {}", e.getMessage(), e);
            // 失败时为所有类型设置默认值
            for (Long typeId : typeIds) {
                storageNumMap.put(typeId, BigDecimal.ZERO);
            }
        }

        return storageNumMap;
    }
}
