package com.wms.controller;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wms.annotation.MyLog;
import com.wms.constants.enums.*;
import com.wms.entity.app.ResponseEntity;
import com.wms.entity.app.dto.PageDto;
import com.wms.entity.app.request.*;
import com.wms.entity.app.vo.FileVo;
import com.wms.entity.app.vo.UploadRecordVo;
import com.wms.entity.table.*;
import com.wms.service.*;
import com.wms.utils.HttpUtils;
import com.wms.utils.StringUtils;
import com.wms.utils.excel.listener.*;
import com.wms.utils.excel.style.ExcelContentStyle;
import com.wms.utils.excel.vo.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

import static com.wms.constants.WmsConstants.MYSQL_JSON_CI;
import static com.wms.utils.HttpUtils.getIpAddr;
import static com.wms.utils.StringUtils.convertJsonString;

/**
 *
 */
@Controller
@CrossOrigin
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@RequestMapping(value = "/wms/excel")
public class ExcelController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());// 日志
    private final StockService stockService;// 库存服务
    private final HttpServletRequest servletRequest;// 请求服务
    private final TaskRecordService taskRecordService;// 任务记录服务
    private final VehicleService vehicleService;// 载具服务
    private final LocationService locationService;// 库位服务
    private final UploadRecordService uploadRecordService;// 上传服务
    private final KateDBSService kateDbsService;// Dbs服务
    private final KateOrdersService kateOrdersService;// 工单服务
    private final GoodsService goodsService;// 物料服务
    private final WorkStationConfigService workStationConfigService;// 工站配置服务
    private final WorkSummaryService workSummaryService;// 工作分析服务
    private final KanbanService kanbanService;// 看板服务
    private final WorkFlowService workFlowService;// 工作流服务
    private final WorkDateService workDateService;// 工作日历服务

    private final List<String> uploadFileHashStringList = new ArrayList<>();

    /**
     * 查询上传记录
     *
     * @param uploadRecordQuery 查询参数
     * @return 结果
     */
    @PostMapping("/queryUploadRecord")
    @ResponseBody
    @Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED)
    @MyLog(logTitle = "查询上传记录", logMethod = "queryUploadRecord")
    public String queryUploadRecord(@RequestBody UploadRecordQuery uploadRecordQuery) {
        logger.info("接收到查询上传记录请求：{}，请求ip：{}", convertJsonString(uploadRecordQuery), HttpUtils.getIpAddr(servletRequest));
        ResponseEntity response = new ResponseEntity();
        try {
            Page<UploadRecord> page = uploadRecordQuery.toMpPage();
            Page<UploadRecord> recordPage = uploadRecordService.page(page, new LambdaQueryWrapper<UploadRecord>()
                    .like(StringUtils.isNotEmpty(uploadRecordQuery.getFileType()), UploadRecord::getFileType, uploadRecordQuery.getFileType())
                    .like(StringUtils.isNotEmpty(uploadRecordQuery.getFileDescription()), UploadRecord::getFileDescription, uploadRecordQuery.getFileDescription())
                    .like(StringUtils.isNotEmpty(uploadRecordQuery.getFileName()), UploadRecord::getFileName, uploadRecordQuery.getFileName()));

            PageDto<UploadRecordVo> pageDto = PageDto.of(recordPage, record -> BeanUtil.copyProperties(record, UploadRecordVo.class));
            response.setCode(ResponseCode.OK.getCode());
            response.setMessage("查询成功");
            response.setReturnData(pageDto);
            return convertJsonString(response);
        } catch (Exception e) {
            // 回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            logger.error("查询上传记录发生异常：{}", convertJsonString(e));
            response.setCode(ResponseCode.ERROR.getCode());
            response.setMessage("查询上传记录发生异常");
            return convertJsonString(response);
        }
    }

    /**
     * 导入库存信息
     *
     * @param file 文件
     * @return 导入结果
     */
    @PostMapping("/uploadStocks")
    @ResponseBody
    @Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED)
    public String uploadStocks(@RequestPart("file") MultipartFile file, @RequestPart("obj") FileVo fileVo) {
        logger.info("导入库存，请求ip：{}，文件详情：{}", getIpAddr(servletRequest), convertJsonString(fileVo));
        ResponseEntity response = new ResponseEntity();
        try {
            // 判断是否重复导入
            if (uploadFileHashStringList.contains(fileVo.getHash())) {
                response.setCode(ResponseCode.ERROR.getCode());
                response.setMessage("请勿导入相同文件。");
                return convertJsonString(response);
            }
            uploadFileHashStringList.add(fileVo.getHash());
            // 导入excel
            EasyExcel.read(file.getInputStream(), StockExcelVo.class, new UploadStocksListener(stockService)).sheet().doRead();
            // 添加导入记录
            uploadRecordService.save(UploadRecord.ofFileVo(fileVo, "库存"));
            uploadFileHashStringList.remove(fileVo.getHash());
            response.setCode(ResponseCode.OK.getCode());
            response.setMessage("导入库存成功。");
            return convertJsonString(response);
        } catch (Exception e) {
            logger.error("导入库存异常：{}", convertJsonString(e));
            // 回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            uploadFileHashStringList.remove(fileVo.getHash());
            response.setCode(ResponseCode.ERROR.getCode());
            response.setMessage("导入库存异常。");
            return convertJsonString(response);
        }
    }

    /**
     * 导入工作日
     *
     * @param file 文件
     * @return 导入结果
     */
    @PostMapping("/uploadWorkDate")
    @ResponseBody
    @Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED)
    public String uploadWorkDate(@RequestPart("file") MultipartFile file, @RequestPart("obj") FileVo fileVo) {
        logger.info("导入工作日历，请求ip：{}，文件详情：{}", getIpAddr(servletRequest), convertJsonString(fileVo));
        ResponseEntity response = new ResponseEntity();
        try {
            // 判断是否重复导入
            if (uploadFileHashStringList.contains(fileVo.getHash())) {
                response.setCode(ResponseCode.ERROR.getCode());
                response.setMessage("请勿导入相同文件。");
                return convertJsonString(response);
            }
            uploadFileHashStringList.add(fileVo.getHash());
            // 移除之前的工作日历
            workDateService.remove(new LambdaQueryWrapper<>());
            // 导入新的工作日历
            EasyExcel.read(file.getInputStream(), WorkDateExcelVo.class, new UploadWorkDateListener(workDateService)).sheet().doRead();
            // 添加导入记录
            uploadRecordService.save(UploadRecord.ofFileVo(fileVo, "WORK_DATE"));
            uploadFileHashStringList.remove(fileVo.getHash());
            response.setCode(ResponseCode.OK.getCode());
            response.setMessage("导入工作日历成功。");
            return convertJsonString(response);
        } catch (Exception e) {
            logger.error("导入工作日历异常：{}", convertJsonString(e));
            // 回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            uploadFileHashStringList.remove(fileVo.getHash());
            response.setCode(ResponseCode.ERROR.getCode());
            response.setMessage("导入工作日历异常。");
            return convertJsonString(response);
        }
    }

    /**
     * 导入DBS
     *
     * @param file 文件
     * @return 导入结果
     */
    @PostMapping("/uploadDbs")
    @ResponseBody
    @Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED)
    public String uploadDbs(@RequestPart("file") MultipartFile file, @RequestPart("obj") FileVo fileVo) {
        logger.info("导入DBS，请求ip：{}，文件详情：{}", getIpAddr(servletRequest), convertJsonString(fileVo));
        ResponseEntity response = new ResponseEntity();
        try {
            // 判断是否重复导入
            if (uploadFileHashStringList.contains(fileVo.getHash())) {
                response.setCode(ResponseCode.ERROR.getCode());
                response.setMessage("请勿导入相同文件。");
                return convertJsonString(response);
            }
            uploadFileHashStringList.add(fileVo.getHash());
            // 获取之前DBS表的内容
            Map<String, KateDBS> kateDbsMap = kateDbsService.list().stream().collect(Collectors.toMap(KateDBS::getWorkOrder, kateDBS -> kateDBS));
            // 导入excel
            EasyExcel.read(file.getInputStream(), KateDbsExcelVo.class, new UploadDbsListener(kateDbsService, kateDbsMap, fileVo.getUserName())).sheet().headRowNumber(8).doRead();
            // 添加导入记录
            uploadRecordService.save(UploadRecord.ofFileVo(fileVo, "DBS"));
            uploadFileHashStringList.remove(fileVo.getHash());
            response.setCode(ResponseCode.OK.getCode());
            response.setMessage("导入DBS成功。");
            return convertJsonString(response);
        } catch (Exception e) {
            logger.error("导入DBS异常：{}", convertJsonString(e));
            // 回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            uploadFileHashStringList.remove(fileVo.getHash());
            response.setCode(ResponseCode.ERROR.getCode());
            response.setMessage("导入DBS异常。");
            return convertJsonString(response);
        }
    }

    /**
     * 导入工单
     *
     * @param file 文件
     * @return 导入结果
     */
    @PostMapping("/uploadKateOrders")
    @ResponseBody
    @Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED)
    public String uploadKateOrders(@RequestPart("file") MultipartFile file, @RequestPart("obj") FileVo fileVo) {
        logger.info("导入工单，请求ip：{}，文件详情：{}", getIpAddr(servletRequest), convertJsonString(fileVo));
        ResponseEntity response = new ResponseEntity();
        try {
            // 判断是否重复导入
            if (uploadFileHashStringList.contains(fileVo.getHash())) {
                response.setCode(ResponseCode.ERROR.getCode());
                response.setMessage("请勿导入相同文件。");
                return convertJsonString(response);
            }
            uploadFileHashStringList.add(fileVo.getHash());
            // 获取之前工单表的内容
            Map<String, KateOrders> kateOrdersMap = kateOrdersService.list().stream().collect(Collectors.toMap(kateOrders -> kateOrders.getWorkOrder() + kateOrders.getGoodsId() + kateOrders.getSupplyArea(), kateOrders -> kateOrders));
            // 导入excel
            EasyExcel.read(file.getInputStream(), KateOrdersExcelVo.class, new UploadKateOrdersListener(kateOrdersService, kateOrdersMap, fileVo.getUserName())).sheet().doRead();
            // 添加导入记录
            uploadRecordService.save(UploadRecord.ofFileVo(fileVo, "ORDERS"));
            uploadFileHashStringList.remove(fileVo.getHash());
            response.setCode(ResponseCode.OK.getCode());
            response.setMessage("导入工单成功。");
            return convertJsonString(response);
        } catch (Exception e) {
            logger.error("导入工单异常：{}", convertJsonString(e));
            // 回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            uploadFileHashStringList.remove(fileVo.getHash());
            response.setCode(ResponseCode.ERROR.getCode());
            response.setMessage("导入工单异常。");
            return convertJsonString(response);
        }
    }

    /**
     * 导入工作流
     *
     * @param file 文件
     * @return 导入结果
     */
    @PostMapping("/uploadWorkFlow")
    @ResponseBody
    @Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED)
    public String uploadWorkFlow(@RequestPart("file") MultipartFile file, @RequestPart("obj") FileVo fileVo) {
        logger.info("导入工作流，请求ip：{}，文件详情：{}", getIpAddr(servletRequest), convertJsonString(fileVo));
        ResponseEntity response = new ResponseEntity();
        try {
            // 判断是否重复导入
            if (uploadFileHashStringList.contains(fileVo.getHash())) {
                response.setCode(ResponseCode.ERROR.getCode());
                response.setMessage("请勿导入相同文件。");
                return convertJsonString(response);
            }
            uploadFileHashStringList.add(fileVo.getHash());
            // 获取之前工单表的内容
            List<WorkFlow> workFlows = workFlowService.list();
            Map<String, WorkFlow> oldWorkFlowMap = workFlows.stream().collect(Collectors.toMap(workFlow -> workFlow.getWorkOrder() + workFlow.getGoodsId() + workFlow.getWorkCenter(), workFlow -> workFlow));
            // 已经有任务的工作流
            List<String> workStationList = workFlows.stream().map(WorkFlow::getWorkStation).distinct().toList();
            // 导入excel
            EasyExcel.read(file.getInputStream(), KateWorkFlowExcelVo.class, new UploadWorkFlowListener(workFlowService, oldWorkFlowMap, workStationList)).sheet().doRead();
            // 添加导入记录
            uploadRecordService.save(UploadRecord.ofFileVo(fileVo, "WORKFLOW"));
            uploadFileHashStringList.remove(fileVo.getHash());
            response.setCode(ResponseCode.OK.getCode());
            // 设置返回信息
            StringBuilder message = new StringBuilder();
            if (!workStationList.isEmpty()) {
                message.append("以下工作站已有任务，不执行导入：");
                for (String workStation : workStationList) {
                    message.append(workStation).append("、");
                }
                message = new StringBuilder(message.substring(0, message.length() - 1));
            }
            if (StringUtils.isEmpty(message.toString())) {
                response.setMessage("导入工作流成功。");
            } else {
                response.setMessage(message.toString());
            }
            return convertJsonString(response);
        } catch (Exception e) {
            logger.error("导入工作流异常：{}", convertJsonString(e));
            // 回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            uploadFileHashStringList.remove(fileVo.getHash());
            response.setCode(ResponseCode.ERROR.getCode());
            response.setMessage("导入工作流异常。");
            return convertJsonString(response);
        }
    }

    /**
     * 导入物料
     *
     * @param file 文件
     * @return 导入结果
     */
    @PostMapping("/uploadGoods")
    @ResponseBody
    @Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED)
    public String uploadGoods(@RequestPart("file") MultipartFile file, @RequestPart("obj") FileVo fileVo) {
        logger.info("导入物料，请求ip：{}，文件详情：{}", getIpAddr(servletRequest), convertJsonString(fileVo));
        ResponseEntity response = new ResponseEntity();
        try {
            // 判断是否重复导入
            if (uploadFileHashStringList.contains(fileVo.getHash())) {
                response.setCode(ResponseCode.ERROR.getCode());
                response.setMessage("请勿导入相同文件。");
                return convertJsonString(response);
            }
            uploadFileHashStringList.add(fileVo.getHash());
            // 导入excel
            EasyExcel.read(file.getInputStream(), GoodsExcelVo.class, new UploadGoodsListener(goodsService, fileVo.getUserName())).sheet("基本信息").doRead();
            // 添加导入记录
            uploadRecordService.save(UploadRecord.ofFileVo(fileVo, "GOODS"));
            uploadFileHashStringList.remove(fileVo.getHash());
            response.setCode(ResponseCode.OK.getCode());
            response.setMessage("导入物料成功。");
            return convertJsonString(response);
        } catch (Exception e) {
            logger.error("导入物料异常：{}", e.getMessage());
            // 回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            uploadFileHashStringList.remove(fileVo.getHash());
            response.setCode(ResponseCode.ERROR.getCode());
            response.setMessage("导入物料异常：" + e.getMessage());
            return convertJsonString(response);
        }
    }

    /**
     * 导入物料基本信息
     *
     * @param file 文件
     * @return 导入结果
     */
    @PostMapping("/uploadBaseGoods")
    @ResponseBody
    @Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED)
    public String uploadBaseGoods(@RequestPart("file") MultipartFile file, @RequestPart("obj") FileVo fileVo) {
        logger.info("导入物料基本信息，请求ip：{}，文件详情：{}", getIpAddr(servletRequest), convertJsonString(fileVo));
        ResponseEntity response = new ResponseEntity();
        try {
            // 判断是否重复导入
            if (uploadFileHashStringList.contains(fileVo.getHash())) {
                response.setCode(ResponseCode.ERROR.getCode());
                response.setMessage("请勿导入相同文件。");
                return convertJsonString(response);
            }
            uploadFileHashStringList.add(fileVo.getHash());
            // 导入excel
            EasyExcel.read(file.getInputStream(), BaseGoodsExcelVo.class, new UploadBaseGoodsListener(goodsService, fileVo.getUserName())).sheet("基本信息").doRead();
            // 添加导入记录
            uploadRecordService.save(UploadRecord.ofFileVo(fileVo, "GOODS_BASE"));
            uploadFileHashStringList.remove(fileVo.getHash());
            response.setCode(ResponseCode.OK.getCode());
            response.setMessage("导入物料基本信息成功。");
            return convertJsonString(response);
        } catch (Exception e) {
            logger.error("导入物料基本信息异常：{}", e.getMessage());
            // 回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            uploadFileHashStringList.remove(fileVo.getHash());
            response.setCode(ResponseCode.ERROR.getCode());
            response.setMessage("导入物料基本信息异常：" + e.getMessage());
            return convertJsonString(response);
        }
    }

    /**
     * 导入看板
     *
     * @param file 文件
     * @return 导入结果
     */
    @PostMapping("/uploadKanban")
    @ResponseBody
    @Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED)
    public String uploadKanban(@RequestPart("file") MultipartFile file, @RequestPart("obj") FileVo fileVo) {
        logger.info("导入看板，请求ip：{}，文件详情：{}", getIpAddr(servletRequest), convertJsonString(fileVo));
        ResponseEntity response = new ResponseEntity();
        try {
            // 判断是否重复导入
            if (uploadFileHashStringList.contains(fileVo.getHash())) {
                response.setCode(ResponseCode.ERROR.getCode());
                response.setMessage("请勿导入相同文件。");
                return convertJsonString(response);
            }
            uploadFileHashStringList.add(fileVo.getHash());
            // 获取之前物料表的内容
            Map<String, Goods> goodsMap = goodsService.list().stream().collect(Collectors.toMap(Goods::getGoodsId, goods -> goods));
            if (goodsMap.isEmpty()) {
                response.setCode(ResponseCode.ERROR.getCode());
                response.setMessage("请先导入物料基本信息。");
                return convertJsonString(response);
            }
            // 查询之前的看板
            Map<String, Kanban> kanbanMap = kanbanService.list().stream().collect(Collectors.toMap(kanban -> kanban.getGoodsId() + kanban.getKanbanId(), kanban -> kanban));
            // 导入excel
            EasyExcel.read(file.getInputStream(), KanbanGoodsExcelVo.class, new UploadKanbanListener(goodsService, goodsMap, kanbanService, kanbanMap, fileVo.getUserName())).sheet("CLC看板信息").doRead();
            // 添加导入记录
            uploadRecordService.save(UploadRecord.ofFileVo(fileVo, "KANBAN"));
            uploadFileHashStringList.remove(fileVo.getHash());
            response.setCode(ResponseCode.OK.getCode());
            response.setMessage("导入看板成功。");
            return convertJsonString(response);
        } catch (Exception e) {
            logger.error("导入看板异常：{}", e.getMessage());
            // 回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            uploadFileHashStringList.remove(fileVo.getHash());
            response.setCode(ResponseCode.ERROR.getCode());
            response.setMessage("导入看板异常：" + e.getMessage());
            return convertJsonString(response);
        }
    }

    /**
     * 导入工站配置
     *
     * @param file 文件
     * @return 导入结果
     */
    @PostMapping("/uploadStationConfig")
    @ResponseBody
    @Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED)
    public String uploadStationConfig(@RequestPart("file") MultipartFile file, @RequestPart("obj") FileVo fileVo) {
        logger.info("导入工站配置，请求ip：{}，文件详情：{}", getIpAddr(servletRequest), convertJsonString(fileVo));
        ResponseEntity response = new ResponseEntity();
        try {
            // 判断是否重复导入
            if (uploadFileHashStringList.contains(fileVo.getHash())) {
                response.setCode(ResponseCode.ERROR.getCode());
                response.setMessage("请勿导入相同文件。");
                return convertJsonString(response);
            }
            uploadFileHashStringList.add(fileVo.getHash());
            // 导入excel
            Map<String, WorkStationConfig> oldWorkStationConfigMap = workStationConfigService.list().stream().collect(Collectors.toMap(WorkStationConfig::getSmallBox, workStationConfig -> workStationConfig));
            EasyExcel.read(file.getInputStream(), StationConfigExcelVo.class, new UploadStationConfigListener(workStationConfigService, oldWorkStationConfigMap, fileVo.getUserName())).sheet("工站配置").doRead();
            // 添加导入记录
            uploadRecordService.save(UploadRecord.ofFileVo(fileVo, "STATION-CONFIG_"));
            uploadFileHashStringList.remove(fileVo.getHash());
            response.setCode(ResponseCode.OK.getCode());
            response.setMessage("导入工站配置。");
            return convertJsonString(response);
        } catch (Exception e) {
            logger.error("导入工站配置异常：{}", convertJsonString(e));
            // 回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            uploadFileHashStringList.remove(fileVo.getHash());
            response.setCode(ResponseCode.ERROR.getCode());
            response.setMessage("导入工站配置异常。");
            return convertJsonString(response);
        }
    }

    /**
     * 导出库存数据
     *
     * @param response 请求
     */
    @PostMapping("/downloadStockExcel")
    @ResponseBody
    public void downloadStockExcel(@RequestBody StockQuery stockQuery, HttpServletResponse response) throws IOException {
        logger.info("导出库存记录，筛选参数：{}，请求ip：{}", convertJsonString(stockQuery), getIpAddr(servletRequest));
        //设置响应格式
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
//        response.setContentType("application/vnd.ms-excel"); //文件扩展名为excel格式
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode("库存报表", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
        response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        // 内容样式
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = ExcelContentStyle.getContentStyle();
        // 查询参数
        List<Stock> stockPoList = stockService.list(new LambdaQueryWrapper<Stock>()
                .like(StringUtils.isNotEmpty(stockQuery.getVehicleId()), Stock::getVehicleId, stockQuery.getVehicleId())
                .like(StringUtils.isNotEmpty(stockQuery.getLocationId()), Stock::getLocationId, stockQuery.getLocationId())
                .eq(stockQuery.getStockStatus() != null, Stock::getStockStatus, stockQuery.getStockStatus())
                .apply(StringUtils.isNotEmpty(stockQuery.getGoodsId()), "goods_related ->> '$.goodsId' like concat('%', {0}, '%')" + MYSQL_JSON_CI, stockQuery.getGoodsId())
                .apply(StringUtils.isNotEmpty(stockQuery.getGoodsName()), "goods_related ->> '$.goodsName' like concat('%', {0}, '%')" + MYSQL_JSON_CI, stockQuery.getGoodsName()));
        EasyExcel.write(response.getOutputStream(), StockExcelVo.class)
                .excelType(ExcelTypeEnum.XLSX)
                .registerWriteHandler(horizontalCellStyleStrategy)
                .sheet("库存")
                .doWrite(stockPoList.stream().map(StockExcelVo::of).toList());
    }

    /**
     * 导出CLC看板需求
     *
     * @param response 请求
     */
    @PostMapping("/downloadClcKanbanRequirementExcel")
    @ResponseBody
    public void downloadClcKanbanRequirementExcel(@RequestBody KanbanRequest request, HttpServletResponse response) throws IOException {
        logger.info("导出CLC看板需求，筛选参数：{}，请求ip：{}", convertJsonString(request), getIpAddr(servletRequest));
        //设置响应格式
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
//        response.setContentType("application/vnd.ms-excel"); //文件扩展名为excel格式
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode("CLC看板需求", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
        response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        // 内容样式
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = ExcelContentStyle.getContentStyle();
        // 获取看板需求
        LambdaQueryWrapper<Kanban> queryWrapper = new LambdaQueryWrapper<Kanban>()
                .like(StringUtils.isNotEmpty(request.getGoodsId()), Kanban::getGoodsId, request.getGoodsId())
                .eq(request.getKanbanStatus() != null, Kanban::getKanbanStatus, request.getKanbanStatus());
        if (request.getLastPullTime() != null) {
            // 设置收货
            queryWrapper.likeRight(Kanban::getLastPullTime, request.getLastPullTime().toString().substring(0, 10));
        }
        List<Kanban> KanbanList = kanbanService.list(queryWrapper);

        EasyExcel.write(response.getOutputStream(), ClcKanbanExcelVo.class)
                .excelType(ExcelTypeEnum.XLSX)
                .registerWriteHandler(horizontalCellStyleStrategy)
                .sheet("CLC看板需求")
                .doWrite(KanbanList.stream().map(ClcKanbanExcelVo::of).toList());
    }

//    /**
//     * 导出CLC看板需求
//     *
//     * @param response 请求
//     */
//    @PostMapping("/downloadClcKanbanRequirementExcel")
//    @ResponseBody
//    public void downloadClcKanbanRequirementExcel(@RequestBody ClcKanbanRequirementRequest request, HttpServletResponse response) throws IOException {
//        logger.info("导出CLC看板需求，筛选参数：{}，请求ip：{}", convertJsonString(request), getIpAddr(servletRequest));
//        //设置响应格式
//        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
////        response.setContentType("application/vnd.ms-excel"); //文件扩展名为excel格式
//        response.setCharacterEncoding("utf-8");
//        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
//        String fileName = URLEncoder.encode("CLC看板需求", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
//        response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
//        // 内容样式
//        HorizontalCellStyleStrategy horizontalCellStyleStrategy = ExcelContentStyle.getContentStyle();
//        // 获取导出结果
//        List<ClcKanbanRequirementExcelVo> clcKanbanRequirementExcelVoList = new ArrayList<>();
//        // 查询物料库存信息
//        List<StockOfGoodsDto> stockOfGoodsDtoList = stockService.selectSumOfGoods("");
//        if (stockOfGoodsDtoList == null || stockOfGoodsDtoList.isEmpty()) {
//            clcKanbanRequirementExcelVoList = Collections.emptyList();
//        } else {
//            for (StockOfGoodsDto stockOfGoodsDto : stockOfGoodsDtoList) {
//                if (Objects.equals(stockOfGoodsDto.getFeedType(), "PULL")) {
//                    // 剩余数量少于补货点时，需要补货
//                    if (stockOfGoodsDto.getRemainNumSum().compareTo(stockOfGoodsDto.getFeedPoint()) <= 0) {
//                        ClcKanbanRequirementExcelVo tempClcKanbanRequirementExcelVo = new ClcKanbanRequirementExcelVo();
//                        // 目标数量
//                        BigDecimal targetNum = stockOfGoodsDto.getNumOfKanban().multiply(stockOfGoodsDto.getNumOfPerKanban());
//                        // 计算需要多少个看板
//                        BigDecimal needKanbanQuantity = targetNum.subtract(stockOfGoodsDto.getRemainNumSum()).divide(stockOfGoodsDto.getNumOfPerKanban(), 0, RoundingMode.FLOOR);
//                        // 设定物流数据
//                        tempClcKanbanRequirementExcelVo.setGoodsId(stockOfGoodsDto.getGoodsId());
//                        tempClcKanbanRequirementExcelVo.setReleasePoint(stockOfGoodsDto.getReleasePoint());
//                        // 设定看板
//                        List<KanbanEntity> needKanbanList = new ArrayList<>();
//                        for (KanbanEntity kanbanEntity : stockOfGoodsDto.getKanbanList()) {
//                            if (needKanbanQuantity.compareTo(BigDecimal.ZERO) <= 0) {
//                                break;
//                            }
//                            needKanbanQuantity = needKanbanQuantity.subtract(BigDecimal.ONE);
//                            needKanbanList.add(kanbanEntity);
//                        }
//                        if (!needKanbanList.isEmpty()) {
//                            tempClcKanbanRequirementExcelVo.setKanban(needKanbanList);
//                        }
//                        clcKanbanRequirementExcelVoList.add(tempClcKanbanRequirementExcelVo);
//                    }
//                }
//            }
//        }
//
//        EasyExcel.write(response.getOutputStream(), ClcKanbanRequirementExcelVo.class)
//                .excelType(ExcelTypeEnum.XLSX)
//                .registerWriteHandler(horizontalCellStyleStrategy)
//                .sheet("CLC看板需求")
//                .doWrite(clcKanbanRequirementExcelVoList);
//    }

    /**
     * 导出入库记录
     *
     * @param response 请求
     */
    @PostMapping("/downloadInRecordExcel")
    @ResponseBody
    public void downloadInRecordExcel(@RequestBody TaskRecordQuery query, HttpServletResponse response) throws IOException {
        logger.info("导出入库记录，筛选参数：{}，请求ip：{}", convertJsonString(query), getIpAddr(servletRequest));
        //设置响应格式
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode("入库记录", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
        response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        // 内容样式
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = ExcelContentStyle.getContentStyle();
        // 查询参数
        List<TaskRecord> inRecord = taskRecordService.selectInTaskRecord(query.toTaskRecordPO());
        EasyExcel.write(response.getOutputStream(), TaskRecordExcelVo.class)
                .excelType(ExcelTypeEnum.XLSX)
                .registerWriteHandler(horizontalCellStyleStrategy)
                .sheet("入库记录")
                .doWrite(inRecord.stream().map(TaskRecordExcelVo::of).toList());
    }

    /**
     * 导出出库记录
     *
     * @param response 请求
     */
    @PostMapping("/downloadOutRecordExcel")
    @ResponseBody
    public void downloadOutRecordExcel(@RequestBody TaskRecordQuery query, HttpServletResponse response) throws IOException {
        logger.info("导出出库记录，筛选参数：{}，请求ip：{}", convertJsonString(query), getIpAddr(servletRequest));
        //设置响应格式
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode("出库记录", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
        response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        // 内容样式
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = ExcelContentStyle.getContentStyle();
        // 查询参数
        List<TaskRecord> inRecord = taskRecordService.selectOutTaskRecord(query.toTaskRecordPO());
        EasyExcel.write(response.getOutputStream(), TaskRecordExcelVo.class)
                .excelType(ExcelTypeEnum.XLSX)
                .registerWriteHandler(horizontalCellStyleStrategy)
                .sheet("出库记录")
                .doWrite(inRecord.stream().map(TaskRecordExcelVo::of).toList());
    }

    /**
     * 导出盘点记录
     *
     * @param response 请求
     */
    @PostMapping("/downloadInventoryRecordExcel")
    @ResponseBody
    public void downloadInventoryRecordExcel(@RequestBody TaskRecordQuery query, HttpServletResponse response) throws IOException {
        logger.info("导出盘点记录，筛选参数：{}，请求ip：{}", convertJsonString(query), getIpAddr(servletRequest));
        //设置响应格式
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode("盘点记录", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
        response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        // 内容样式
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = ExcelContentStyle.getContentStyle();
        // 查询参数
        List<TaskRecord> inRecord = taskRecordService.selectInventoryTaskRecord(query.toTaskRecordPO());
        EasyExcel.write(response.getOutputStream(), TaskRecordExcelVo.class)
                .excelType(ExcelTypeEnum.XLSX)
                .registerWriteHandler(horizontalCellStyleStrategy)
                .sheet("盘点记录")
                .doWrite(inRecord.stream().map(TaskRecordExcelVo::of).toList());
    }

    /**
     * 导出载具记录
     *
     * @param response 请求
     */
    @PostMapping("/downloadVehicleExcel")
    @ResponseBody
    public void downloadVehicleExcel(@RequestBody VehicleQuery vehicleQuery, HttpServletResponse response) throws IOException {
        logger.info("导出料箱报表，筛选参数：{}，请求ip：{}", convertJsonString(vehicleQuery), getIpAddr(servletRequest));
        //设置响应格式
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode("料箱报表", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
        response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        // 内容样式
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = ExcelContentStyle.getContentStyle();
        // 查询参数
        List<Vehicle> vehicles = vehicleService.list(new LambdaQueryWrapper<Vehicle>()
                .like(StringUtils.isNotEmpty(vehicleQuery.getVehicleId()), Vehicle::getVehicleId, vehicleQuery.getVehicleId())
                .like(StringUtils.isNotEmpty(vehicleQuery.getCurrentLocation()), Vehicle::getCurrentLocation, vehicleQuery.getCurrentLocation())
                .eq(vehicleQuery.getIsEmpty() != null, Vehicle::getIsEmpty, vehicleQuery.getIsEmpty())
                .eq(vehicleQuery.getVehicleStatus() != null, Vehicle::getVehicleStatus, vehicleQuery.getVehicleStatus()));
        EasyExcel.write(response.getOutputStream(), VehicleExcelVo.class)
                .excelType(ExcelTypeEnum.XLSX)
                .registerWriteHandler(horizontalCellStyleStrategy)
                .sheet("料箱报表")
                .doWrite(vehicles.stream().map(VehicleExcelVo::of).toList());
    }

    /**
     * 导出物料信息
     *
     * @param response 请求
     */
    @PostMapping("/downloadGoodsExcel")
    @ResponseBody
    public void downloadGoodsExcel(@RequestBody GoodsQuery goodsQuery, HttpServletResponse response) throws IOException {
        logger.info("导出物料报表，筛选参数：{}，请求ip：{}", convertJsonString(goodsQuery), getIpAddr(servletRequest));
        //设置响应格式
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode("物料报表", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
        response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        // 内容样式
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = ExcelContentStyle.getContentStyle();
        // 查询参数
        List<Goods> goodsList = goodsService.list(new LambdaQueryWrapper<Goods>()
                .like(StringUtils.isNotEmpty(goodsQuery.getGoodsId()), Goods::getGoodsId, goodsQuery.getGoodsId()));
        EasyExcel.write(response.getOutputStream(), GoodsExcelVo.class)
                .excelType(ExcelTypeEnum.XLSX)
                .registerWriteHandler(horizontalCellStyleStrategy)
                .sheet("物料报表")
                .doWrite(goodsList.stream().map(GoodsExcelVo::of).toList());
    }

    /**
     * 导出工作总结
     *
     * @param response 请求
     */
    @PostMapping("/downloadWorkSummaryExcel")
    @ResponseBody
    public void downloadWorkSummaryExcel(@RequestBody WorkSummaryQuery workSummaryQuery, HttpServletResponse response) throws IOException {
        logger.info("导出物料报表，筛选参数：{}，请求ip：{}", convertJsonString(workSummaryQuery), getIpAddr(servletRequest));
        //设置响应格式
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode("工作分析报表", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
        response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        // 内容样式
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = ExcelContentStyle.getContentStyle();
        // 查询参数
        List<WorkSummary> goodsList = workSummaryService.list(new LambdaQueryWrapper<WorkSummary>()
                .eq(workSummaryQuery.getLackStatus() != null, WorkSummary::getLackStatus, workSummaryQuery.getLackStatus())
                .eq(workSummaryQuery.getWorkDate() != null, WorkSummary::getWorkDate, workSummaryQuery.getWorkDate())
                .like(StringUtils.isNotEmpty(workSummaryQuery.getWorkStation()), WorkSummary::getWorkStation, workSummaryQuery.getWorkStation())
                .like(StringUtils.isNotEmpty(workSummaryQuery.getWorkOrder()), WorkSummary::getWorkOrder, workSummaryQuery.getWorkOrder())
                .like(StringUtils.isNotEmpty(workSummaryQuery.getWorkCenter()), WorkSummary::getWorkCenter, workSummaryQuery.getWorkCenter())
                .like(StringUtils.isNotEmpty(workSummaryQuery.getGoodsId()), WorkSummary::getGoodsId, workSummaryQuery.getGoodsId()));
        EasyExcel.write(response.getOutputStream(), WorkSummaryExcelVo.class)
                .excelType(ExcelTypeEnum.XLSX)
                .registerWriteHandler(horizontalCellStyleStrategy)
                .sheet("工作分析报表")
                .doWrite(goodsList.stream().map(WorkSummaryExcelVo::of).toList());
    }

    /**
     * 导出库位详情
     *
     * @param response 请求
     */
    @PostMapping("/downloadLocationsExcel")
    @ResponseBody
    public void downloadLocationsExcel(@RequestBody LocationQuery locationQuery, HttpServletResponse response) throws IOException {
        logger.info("导出库位报表，筛选参数：{}，请求ip：{}", convertJsonString(locationQuery), getIpAddr(servletRequest));
        //设置响应格式
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode("库位报表", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
        response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        // 内容样式
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = ExcelContentStyle.getContentStyle();
        // 查询参数
        List<Location> locations = locationService.list(new LambdaQueryWrapper<Location>()
                .like(StringUtils.isNotEmpty(locationQuery.getLocationId()), Location::getLocationId, locationQuery.getLocationId())
                .eq(locationQuery.getAreaId() != null, Location::getAreaId, locationQuery.getAreaId())
                .eq(locationQuery.getIsLock() != null, Location::getIsLock, locationQuery.getIsLock())
                .eq(locationQuery.getLocationStatus() != null, Location::getLocationStatus, locationQuery.getLocationStatus()));
        EasyExcel.write(response.getOutputStream(), LocationExcelVo.class)
                .excelType(ExcelTypeEnum.XLSX)
                .registerWriteHandler(horizontalCellStyleStrategy)
                .sheet("库位报表")
                .doWrite(locations.stream().map(LocationExcelVo::of).toList());
    }
}