package cn.ezhizao.project.business.controller;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import cn.ezhizao.common.utils.PdfUtil;
import cn.ezhizao.common.utils.poi.ExcelUtil;
import cn.ezhizao.framework.aspectj.lang.annotation.Log;
import cn.ezhizao.framework.aspectj.lang.enums.BusinessType;
import cn.ezhizao.framework.web.controller.BaseController;
import cn.ezhizao.framework.web.domain.AjaxResult;
import cn.ezhizao.framework.web.page.TableDataInfo;
import cn.ezhizao.project.business.domain.*;
import cn.ezhizao.project.business.service.IBizDayworkItemRejectService;
import cn.ezhizao.project.business.service.IBizDayworkItemService;
import cn.ezhizao.project.system.domain.SysUser;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.extra.template.TemplateException;
import cn.hutool.poi.excel.ExcelWriter;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageInfo;
import freemarker.template.Template;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;


/**
 * 报工废品记录Controller
 *
 * @author ezhizao
 * @date 2024-06-18
 */
@RestController
@RequestMapping("/business/reject")
public class BizDayworkItemRejectController extends BaseController
{
    @Resource
    private IBizDayworkItemRejectService bizDayworkItemRejectService;
    @Autowired
    private FreeMarkerConfigurer freeMarkerConfigurer;
    @Resource
    private IBizDayworkItemService bizDayworkItemService;
    @Value("${file.excelTemplate.url}")
    private  String templatePath;

    /**
     * 查询报工废品记录列表
     */
    @GetMapping("/list")
    @Log(title = "查询报工废品记录列表", businessType = BusinessType.SELECT)
    public TableDataInfo list(BizDayworkItemReject bizDayworkItemReject) throws NoSuchFieldException, IllegalAccessException
    {
        setTenantId(bizDayworkItemReject);
        startPage();
        List<BizDayworkItemReject> list = bizDayworkItemRejectService.getList(bizDayworkItemReject);
        return getDataTable(list);
    }
    @GetMapping("/rejectReportList")
    @Log(title = "修改报工信息最高权限", businessType = BusinessType.SELECT)
    public AjaxResult rejectReportList(BizDayworkItemReject bizDayworkItemReject) throws NoSuchFieldException, IllegalAccessException
    {
        setTenantId(bizDayworkItemReject);
        List<BizDayworkItemReject> list = bizDayworkItemRejectService.getRejectReport(bizDayworkItemReject);
        long count = list.stream().mapToInt(BizDayworkItemReject::getTotalRejectNum).sum();
        return success(count);
    }
    @GetMapping("/rejectReport")
    @Log(title = "查询废品报表", businessType = BusinessType.SELECT)
    public TableDataInfo getRejectReport(BizDayworkItemReject bizDayworkItemReject) throws NoSuchFieldException, IllegalAccessException
    {
        startPage();
        List<BizDayworkItemReject> list = bizDayworkItemRejectService.getRejectReport(bizDayworkItemReject);
        return getDataTable(list);
    }
    @GetMapping("/rejectRecords")
    @Log(title = "查询废品记录", businessType = BusinessType.SELECT)
    public TableDataInfo getRejectRecords(BizDayworkItemReject bizDayworkItemReject) throws NoSuchFieldException, IllegalAccessException
    {
        List<BizDayworkItemReject> list = bizDayworkItemRejectService.getRejectRecords(bizDayworkItemReject);
        list.forEach(item ->{
            if(item.getDayworkAuxiliaryItemId() != 0) {
                item.setDayworkAuxiliaryItemId(1L);
            }
        });
        return getDataTable(list);
    }
    @GetMapping("/getSortCheckStandard")
    @Log(title = "查询分选标准列表", businessType = BusinessType.SELECT)
    public AjaxResult getSortCheckStandard(BizDayworkItemReject bizDayworkItemReject) throws NoSuchFieldException, IllegalAccessException
    {
        if(bizDayworkItemReject.getStartTime()!=null) {
            bizDayworkItemReject.setStartTime(bizDayworkItemReject.getStartTime()+ " 00:00:00");
        }
        if(bizDayworkItemReject.getEndTime()!=null) {
            bizDayworkItemReject.setEndTime(bizDayworkItemReject.getEndTime()+ " 23:59:59");
        }
        List<BizDayworkItemReject> list = bizDayworkItemRejectService.getSortCheckStandard(bizDayworkItemReject);
        return success(list);
    }
   // @GetMapping("/getSortRejectList")
    public AjaxResult getSortRejectList(BizDayworkItemReject bizDayworkItemReject) throws NoSuchFieldException, IllegalAccessException
    {
        if(bizDayworkItemReject.getStartTime()!=null) {
            bizDayworkItemReject.setStartTime(bizDayworkItemReject.getStartTime()+ " 00:00:00");
        }
        if(bizDayworkItemReject.getEndTime()!=null) {
            bizDayworkItemReject.setEndTime(bizDayworkItemReject.getEndTime()+ " 23:59:59");
        }
        List<BizDayworkItemReject> oldList = bizDayworkItemRejectService.getSortRejectList(bizDayworkItemReject);
        Map<String, List<BizDayworkItemReject>> groupedByDate = new TreeMap<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        for (BizDayworkItemReject obj : oldList) {
            String key = sdf.format(obj.getCreateTime());
            if (!groupedByDate.containsKey(key)) {
                groupedByDate.put(key, new ArrayList<>());
            }
            groupedByDate.get(key).add(obj);
        }
        List<BizDayworkItemReject> newList = new ArrayList<>();
        List<BizDayworkItemReject> sortCheckList = new ArrayList<>();
        for (Map.Entry<String, List<BizDayworkItemReject>> entry : groupedByDate.entrySet()) {
            List<BizDayworkItemReject> values = entry.getValue();
            String date = entry.getKey();
            //根据时间分组后获得这个分组下的所有的productionPlanDetailId
            Map<Long, String> productionPlanDetailList = values.stream()
                    .collect(Collectors.toMap(
                            item -> item.getProductionPlanDetailId(), // 作为键的函数
                            item -> item.getProductDescription(),      // 作为值的函数
                            (existingValue, newValue) -> existingValue // 如果有重复的键，使用旧值
                    ));
            for (Map.Entry<Long, String> productionPlanDetail : productionPlanDetailList.entrySet()) {
                //生产计划id
                Long  productionPlanDetailId = productionPlanDetail.getKey();
                //产品描述
                String productDescription = productionPlanDetail.getValue();
                    //将同一个产品分出来
                    List<BizDayworkItemReject> equalsProductionPlanDetail = values.stream().filter(item -> item.getProductionPlanDetailId().equals(productionPlanDetailId)).collect(Collectors.toList());
                    //产品规格
                    String specification = equalsProductionPlanDetail.get(0).getSpecification();
                //获得同一个生产计划的所有批次
                    List<String> lotCodes = equalsProductionPlanDetail.stream().map(BizDayworkItemReject::getLotCode).distinct().collect(Collectors.toList());
                    lotCodes.forEach(info ->{
                        //给新列表赋值
                        BizDayworkItemReject reject = new BizDayworkItemReject();
                        reject.setLotCode(info);
                        reject.setProductionPlanDetailId(productionPlanDetailId);
                        reject.setProductDescription(productDescription);
                        reject.setSpecification(specification);
                        reject.setDate(date.substring(2,10));
                        //拿到同一个批次的所有数据
                        List<BizDayworkItemReject> equalsLotCode = equalsProductionPlanDetail.stream().filter(item -> info.equals(item.getLotCode())).collect(Collectors.toList());
                        //同一个批次所有的分选废品
                        Map<Long, String> sortCheckStandard = equalsLotCode.stream()
                                .collect(Collectors.toMap(
                                        item -> item.getInspectionInstructionId(), // 作为键的函数
                                        item -> item.getCheckStandard(),      // 作为值的函数
                                        (existingValue, newValue) -> existingValue // 如果有重复的键，使用旧值
                                ));
                        List<BizDayworkItemReject> checkList = new ArrayList<>();
                                for (Map.Entry<Long, String> standard : sortCheckStandard.entrySet()) {
                                    //分选标准id
                                    Long inspectionInstructionId = standard.getKey();
                                    //分选标准详情
                                    String checkStandard = standard.getValue();
                                    BizDayworkItemReject check = new BizDayworkItemReject();
                                    Long sum = equalsLotCode.stream().filter(item -> item.getInspectionInstructionId().equals(inspectionInstructionId)).mapToLong(BizDayworkItemReject::getRejectNum).sum();
                                    check.setInspectionInstructionId(inspectionInstructionId);
                                    check.setRejectNum(sum);
                                    checkList.add(check);
                                }
                            reject.setSortCheckList(checkList);
                                newList.add(reject);
                    });
            }
        }
        //添加小计行
        List<BizDayworkItemReject> list = new ArrayList<>();
       for(int i = 0; i < newList.size(); i++) {
           int index = i;
           newList.get(i).setLineNumber(i+1);
           list.add(newList.get(i));
           if(i!= newList.size() - 1 && newList.get(i).getProductionPlanDetailId() != newList.get(i+1).getProductionPlanDetailId() || i == newList.size() - 1) {
               List<BizDayworkItemReject> checkList = new ArrayList<>();
                BizDayworkItemReject total = new BizDayworkItemReject();
                total.setSpecification("小计");
               List<BizDayworkItemReject> equalsPro = newList.stream()
                       .filter(item -> item.getProductionPlanDetailId().equals(newList.get(index).getProductionPlanDetailId()) && item.getDate().equals(newList.get(index).getDate()))
                       .collect(Collectors.toList());
               //同一个生产计划的所有分选标准
               List<BizDayworkItemReject> check = equalsPro.stream().flatMap(item -> item.getSortCheckList().stream()).collect(Collectors.toList());
               List<Long> standardIds = check.stream().map(BizDayworkItemReject::getInspectionInstructionId).collect(Collectors.toList());
               standardIds.forEach(item ->{
                   BizDayworkItemReject info = new BizDayworkItemReject();
                   Long sum = check.stream().filter(ch -> ch.getInspectionInstructionId().equals(item)).mapToLong(BizDayworkItemReject::getRejectNum).sum();
                   info.setInspectionInstructionId(item);
                   info.setRejectNum(sum);
                   checkList.add(info);
               });
               total.setSortCheckList(checkList);
               list.add(total);
           }
       }
        return success(list);
    }
    @GetMapping("/getSortRejectList")
    @Log(title = "查询分选废品列表", businessType = BusinessType.SELECT)
    public TableDataInfo getSortRejectStandardList(BizDayworkItemReject bizDayworkItemReject) throws NoSuchFieldException, IllegalAccessException, ParseException {
        if(bizDayworkItemReject.getStartTime()!=null) {
            bizDayworkItemReject.setStartTime(bizDayworkItemReject.getStartTime()+ " 00:00:00");
        }
        if(bizDayworkItemReject.getEndTime()!=null) {
            bizDayworkItemReject.setEndTime(bizDayworkItemReject.getEndTime()+ " 23:59:59");
        }
        startPage();
        //查询批次信息
        List<BizDayworkItemReject> lotCodeList = bizDayworkItemRejectService.getSortStandardLot(bizDayworkItemReject);
        long total = new PageInfo(lotCodeList).getTotal();
        List<Long> lotIds = lotCodeList.stream().map(BizDayworkItemReject::getLotId).collect(Collectors.toList());

        //查询分选废品信息
        List<BizDayworkItemReject> sortRejectList = new ArrayList<>();
        List<BizDayworkItem> sortDayworkItem;
        if(!lotIds.isEmpty()) {
            bizDayworkItemReject.setLotIds(lotIds);
            sortRejectList = bizDayworkItemRejectService.getSortCheckStandardList(bizDayworkItemReject);
            //获得批次报工信息的分选量
            sortDayworkItem = bizDayworkItemService.getListByLotIds(lotIds);
        } else {
            sortDayworkItem = new ArrayList<>();
        }
        //对数据进行操作
        //根据产品先进行分组，再根据时间分组
        Map<Long, List<BizDayworkItemReject>> groupedByDate = new TreeMap<>();
        for (BizDayworkItemReject obj : lotCodeList) {
            Long key = obj.getProductionPlanDetailId();
            if (!groupedByDate.containsKey(key)) {
                groupedByDate.put(key, new ArrayList<>());
            }
            groupedByDate.get(key).add(obj);
        }
        for (Map.Entry<Long, List<BizDayworkItemReject>> entry : groupedByDate.entrySet()) {
            List<BizDayworkItemReject> values = entry.getValue();
            //根据生产计划单分组后，再根据时间分组
//            Map<Long, String> productionPlanDetailList = values.stream()
//                    .collect(Collectors.toMap(
//                            item -> item.getLotId(), // 作为键的函数
//                            item -> item.getDate(),      // 作为值的函数
//                            (existingValue, newValue) -> existingValue // 如果有重复的键，使用旧值
//                    ));
            Map<Long, List<String>> productionPlanDetailList = values.stream()
                    .collect(Collectors.groupingBy(
                            BizDayworkItemReject::getLotId, // 作为键的函数
                            Collectors.mapping(BizDayworkItemReject::getDate, Collectors.toList()) // 作为值的函数，收集所有不同的date
                    ));
            for (Map.Entry<Long, List<String>> productionPlanDetail : productionPlanDetailList.entrySet()) {
                //批次id
                Long lotId = productionPlanDetail.getKey();
                //时间
                List<String> dates = productionPlanDetail.getValue();
                for (String date : dates) {
                    //将同一个产品的同一个时间段内的数据拿出来
                    List<BizDayworkItemReject> equalsDateDetail = values.stream().filter(item -> item.getDate().equals(date)).collect(Collectors.toList());
                    //产品规格
                    String specification = equalsDateDetail.get(0).getSpecification();
                    //获得同一个时间段的所有批次
                    List<Long> equLotIds = equalsDateDetail.stream().map(BizDayworkItemReject::getLotId).distinct().collect(Collectors.toList());
                    //根据日期拿出分选标准数据
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                    List<BizDayworkItemReject> finalSortRejectList = sortRejectList;
                    lotCodeList.forEach(info -> {
                        //设置分选量
                        BizDayworkItem firstSortItem = sortDayworkItem.stream().filter(item -> item.getLotId().equals(info.getLotId())).sorted(Comparator.comparing(BizDayworkItem::getCreateTime)).collect(Collectors.toList()).get(0);
                        info.setFirstSortProd(firstSortItem.getProdNum());
                        //设置实际量(要status是3最后一道序的合格量)
                        BizDayworkItem lastSortItem = sortDayworkItem.stream().filter(item -> item.getLotId().equals(info.getLotId())).sorted(Comparator.comparing(BizDayworkItem::getCreateTime).reversed()).collect(Collectors.toList()).get(0);
                        info.setActualQuantity(lastSortItem.getQualifiedNum());
                        //设置废品量(分选报工所有状态为3的废品总数)
                        info.setTotalRejectNum(sortDayworkItem.stream().filter(item -> item.getLotId().equals(info.getLotId()) && sdf.format(item.getCreateTime()).equals(info.getDate())).mapToInt(item -> item.getRejectNum()).sum());
                        //设置不明量
                        info.setUnknownQuantity(info.getFirstSortProd() - info.getActualQuantity() - info.getTotalRejectNum());
                        //设置不良率
                        info.setRejectRate(Float.valueOf(String.format("%.2f", (info.getTotalRejectNum() / (float) info.getFirstSortProd()) * 100)));
                        //设置不明率
                        info.setUnknownRate(Float.valueOf(String.format("%.2f", ((float) info.getUnknownQuantity() / (float) info.getFirstSortProd()) * 100)));
                        //设置批次率
                        info.setLotRate(Float.valueOf(String.format("%.2f", ((info.getTotalRejectNum() + info.getUnknownQuantity()) / (float) info.getFirstSortProd()) * 100)));
                        if (info.getDate().equals(date) && info.getLotId().equals(lotId)) {
                            List<BizDayworkItemReject> lotSortCheckList = finalSortRejectList.stream().filter(item -> sdf.format(item.getCreateTime()).equals(date) && item.getLotId().equals(lotId)).collect(Collectors.toList());
                            List<Long> lotInspectionIds = lotSortCheckList.stream().map(BizDayworkItemReject::getInspectionInstructionId).collect(Collectors.toList());
                            List<BizDayworkItemReject> checkList = new ArrayList<>();
                            for (Long data : lotInspectionIds) {
                                if (!checkList.stream()
                                        .anyMatch(v -> Objects.equals(v.getInspectionInstructionId(), data))) {
                                    BizDayworkItemReject check = new BizDayworkItemReject();
                                    Long sum = lotSortCheckList.stream().filter(item -> item.getInspectionInstructionId().equals(data)).mapToLong(BizDayworkItemReject::getRejectNum).sum();
                                    check.setInspectionInstructionId(data);
                                    check.setRejectNum(sum);
                                    checkList.add(check);
                                }

                            }
                            info.setCheckStandardList(checkList);
                        }
                    });
                }
            }
        }
//        //添加小计行
//        List<BizDayworkItemReject> list = new ArrayList<>();
//        for(int i = 0; i < lotCodeList.size(); i++) {
//            int index = i;
//            lotCodeList.get(i).setLineNumber(i+1);
//            list.add(lotCodeList.get(i));
//            if(i!= lotCodeList.size() - 1 && !lotCodeList.get(i).getProductionPlanDetailId().equals(lotCodeList.get(i+1).getProductionPlanDetailId()) || i == lotCodeList.size() - 1) {
//                List<BizDayworkItemReject> checkList = new ArrayList<>();
//                BizDayworkItemReject total = new BizDayworkItemReject();
//                total.setSpecification("小计");
//                List<BizDayworkItemReject> equalsPro = lotCodeList.stream()
//                        .filter(item -> item.getProductionPlanDetailId().equals(lotCodeList.get(index).getProductionPlanDetailId()) && item.getDate().equals(lotCodeList.get(index).getDate()))
//                        .collect(Collectors.toList());
//                //同一个生产计划的所有分选标准
//                List<BizDayworkItemReject> check = equalsPro.stream().flatMap(item -> item.getCheckStandardList().stream()).collect(Collectors.toList());
//                List<Long> standardIds = check.stream().map(BizDayworkItemReject::getInspectionInstructionId).collect(Collectors.toList());
//                standardIds.forEach(item ->{
//                    BizDayworkItemReject info = new BizDayworkItemReject();
//                    Long sum = check.stream().filter(ch -> ch.getInspectionInstructionId().equals(item)).mapToLong(BizDayworkItemReject::getRejectNum).sum();
//                    info.setInspectionInstructionId(item);
//                    info.setRejectNum(sum);
//                    checkList.add(info);
//                });
//                total.setCheckStandardList(checkList);
//                list.add(total);
//            }
//        }
        //再对lotCodeList进行操作，通过生产计划分组
        List<BizDayworkItemReject> newList = new ArrayList<>();
        if(!lotCodeList.isEmpty()) {
            Map<Long, List<BizDayworkItemReject>> groupedByProductionPlanDetailId = new TreeMap<>();
            for (BizDayworkItemReject obj : lotCodeList) {
                Long key = obj.getProductionPlanDetailId();
                if (!groupedByProductionPlanDetailId.containsKey(key)) {
                    groupedByProductionPlanDetailId.put(key, new ArrayList<>());
                }
                groupedByProductionPlanDetailId.get(key).add(obj);
            }
            for (Map.Entry<Long, List<BizDayworkItemReject>> entry : groupedByProductionPlanDetailId.entrySet()) {
                List<BizDayworkItemReject> values = entry.getValue();
                values.forEach(item -> {
                    newList.add(item);
                });
            }
        }
        newList.forEach(item -> {
            item.setDate(item.getDate().substring(2,10));
        });
        TableDataInfo dataTable = getDataTable(newList);
        dataTable.setTotal(total);
        return dataTable;
    }
//    @PostMapping("/download")
    public void download(HttpServletResponse response, BizDayworkItemReject bizDayworkItemReject) throws NoSuchFieldException, IllegalAccessException {
        List<BizDayworkItemReject> list = bizDayworkItemRejectService.getRejectReport(bizDayworkItemReject);
        ExcelUtil<BizDayworkItemReject> util = new ExcelUtil<>(BizDayworkItemReject.class);
        util.exportExcel(response, list, "废品报表数据");
    }

    @PostMapping("/download")
    @Log(title = "下载导出废品列表", businessType = BusinessType.SELECT)
    public void downloadNew(HttpServletResponse response, BizDayworkItemReject bizDayworkItemReject) throws NoSuchFieldException, IllegalAccessException, IOException {
        List<BizDayworkItemReject> list = bizDayworkItemRejectService.getRejectReport(bizDayworkItemReject);
        List<BizDayworkItemReject> records = new ArrayList<>();
        list.forEach(l -> {
            records.addAll(bizDayworkItemRejectService.getRejectRecords(l));
        });
        String template = "rejectReportTemplate";
        String templateFilePath =  templatePath + template + ".xlsx";
        com.alibaba.excel.ExcelWriter writer = EasyExcel.write(response.getOutputStream())
                .withTemplate(templateFilePath)
                .build();
        WriteSheet firstSheet = EasyExcel.writerSheet(0).build();
        WriteSheet secondSheet = EasyExcel.writerSheet(1).build();
        FillConfig fillConfig = FillConfig.builder()
                // 开启填充行 不开启是在一行覆盖，开启会创建新的行
                .forceNewRow(true)
                .build();
        // 执行填充操作
        writer.fill(list, fillConfig, firstSheet);
        writer.fill(records, fillConfig, secondSheet);
        writer.finish();
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        //test.xls是弹出下载对话框的文件名，不能为中文，中文请自行编码
        response.setHeader("Content-Disposition", "attachment;filename=test.xlsx");
        ServletOutputStream out = null;
        try {
            out = response.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //此处记得关闭输出Servlet流
        IoUtil.close(out);

//        ExcelUtil<BizDayworkItemReject> util = new ExcelUtil<>(BizDayworkItemReject.class);
//        util.exportExcel(response, list, "废品报表数据");
    }

    /**
     * 导出报工废品记录列表
     */
    @Log(title = "报工废品记录", businessType = BusinessType.EXPORT)
    @PostMapping("/printDetailExport")
    public void export(HttpServletResponse response, BizDayworkItemReject bizDayworkItemReject) throws NoSuchFieldException, IllegalAccessException
    {
        //获得动态列名
        if(bizDayworkItemReject.getStartTime()!=null) {
            bizDayworkItemReject.setStartTime(bizDayworkItemReject.getStartTime()+ " 00:00:00");
        }
        if(bizDayworkItemReject.getEndTime()!=null) {
            bizDayworkItemReject.setEndTime(bizDayworkItemReject.getEndTime()+ " 23:59:59");
        }
        List<BizDayworkItemReject> dynamicColumn = bizDayworkItemRejectService.getSortCheckStandard(bizDayworkItemReject);
        //拿到动态列的id，为了后续按顺序加分选标准
        List<Long> dynamicIds = dynamicColumn.stream().map(BizDayworkItemReject::getInspectionInstructionId).collect(Collectors.toList());
        ExcelWriter writer = cn.hutool.poi.excel.ExcelUtil.getWriter(true);
//        writer.writeCellValue(0,4,"德迈仕质量检查不良原因数据查询");
        writer.merge(0,0,4,13,"德迈仕质量检查不良原因数据查询" ,false);
        writer.writeCellValue(0,1,"列印日期" + ":" + DateUtil.format(new Date(), "yyyy-MM-dd"));
        writer.merge(1,1,0,1,"列印日期" + ":" + DateUtil.format(new Date(), "yyyy-MM-dd"),false);
        writer.merge(1,1,4,8,"统计范围" +":" + (bizDayworkItemReject.getStartTime() != null? bizDayworkItemReject.getStartTime().substring(0,10) :" " )+"-" + (bizDayworkItemReject.getEndTime() != null? bizDayworkItemReject.getEndTime().substring(0,10) :" "),false);
        writer.writeCellValue(0,2,"序号");
        writer.writeCellValue(1,2,"规格");
        writer.writeCellValue(2,2,"日期");
        writer.writeCellValue(3,2,"批次号");
        writer.writeCellValue(4,2,"产品描述");
        writer.writeCellValue(5,2,"分选量");
        writer.writeCellValue(6,2,"实际量");
        writer.writeCellValue(7,2,"废品量");
        writer.writeCellValue(8,2,"不明量");
        writer.writeCellValue(9,2,"不良率");
        writer.writeCellValue(10,2,"不明率");
        writer.writeCellValue(11,2,"批次率");
        int index = 0;
        for(int i= 0;i<dynamicColumn.size(); i++){
            writer.writeCellValue(12+i,2,dynamicColumn.get(i).getCheckStandard());
            index = 12+i;
        }

        // writer.write(CollUtil.newArrayList(," ","统计范围" +":" + (bizDayworkItemReject.getStartTime() != null? String.format(bizDayworkItemReject.getStartTime(), "yyyy-MM-dd") :" " )+"-" + (bizDayworkItemReject.getEndTime() != null? String.format(bizDayworkItemReject.getEndTime(), "yyyy-MM-dd") :" " )));
//        List<String> rowHead = CollUtil.newArrayList("序号","规格","日期","批次号","产品描述","分选量","实际量","废品量","不明量","不良率","批次率");
//        dynamicColumn.forEach(item ->{
//            rowHead.add(item.getCheckStandard());
//        });
//        writer.write(rowHead);
        //数据
        //查询批次信息
        List<BizDayworkItemReject> lotCodeList = bizDayworkItemRejectService.getSortStandardLot(bizDayworkItemReject);
        List<Long> lotIds = lotCodeList.stream().map(BizDayworkItemReject::getLotId).collect(Collectors.toList());

        //查询分选废品信息
        List<BizDayworkItemReject> sortRejectList = new ArrayList<>();
        List<BizDayworkItem> sortDayworkItem;
        if(!lotIds.isEmpty()) {
            bizDayworkItemReject.setLotIds(lotIds);
            sortRejectList = bizDayworkItemRejectService.getSortCheckStandardList(bizDayworkItemReject);
            //获得批次报工信息的分选量
            sortDayworkItem = bizDayworkItemService.getListByLotIds(lotIds);
        } else {
            sortDayworkItem = new ArrayList<>();
        }
        //对数据进行操作
        //根据产品先进行分组，再根据时间分组
        Map<Long, List<BizDayworkItemReject>> groupedByDate = new TreeMap<>();
        for (BizDayworkItemReject obj : lotCodeList) {
            Long key = obj.getProductionPlanDetailId();
            if (!groupedByDate.containsKey(key)) {
                groupedByDate.put(key, new ArrayList<>());
            }
            groupedByDate.get(key).add(obj);
        }
        for (Map.Entry<Long, List<BizDayworkItemReject>> entry : groupedByDate.entrySet()) {
            List<BizDayworkItemReject> values = entry.getValue();
            //根据生产计划单分组后，再根据时间分组
//            Map<Long, String> productionPlanDetailList = values.stream()
//                    .collect(Collectors.toMap(
//                            item -> item.getLotId(), // 作为键的函数
//                            item -> item.getDate(),      // 作为值的函数
//                            (existingValue, newValue) -> existingValue // 如果有重复的键，使用旧值
//                    ));
            Map<Long, List<String>> productionPlanDetailList = values.stream()
                    .collect(Collectors.groupingBy(
                            BizDayworkItemReject::getLotId, // 作为键的函数
                            Collectors.mapping(BizDayworkItemReject::getDate, Collectors.toList()) // 作为值的函数，收集所有不同的date
                    ));
            for (Map.Entry<Long, List<String>> productionPlanDetail : productionPlanDetailList.entrySet()) {
                //批次id
                Long lotId = productionPlanDetail.getKey();
                //时间
                List<String> dates = productionPlanDetail.getValue();
                for (String date : dates) {
                    //将同一个产品的同一个时间段内的数据拿出来
                    List<BizDayworkItemReject> equalsDateDetail = values.stream().filter(item -> item.getDate().equals(date)).collect(Collectors.toList());
                    //产品规格
                    String specification = equalsDateDetail.get(0).getSpecification();
                    //获得同一个时间段的所有批次
                    List<Long> equLotIds = equalsDateDetail.stream().map(BizDayworkItemReject::getLotId).distinct().collect(Collectors.toList());
                    //根据日期拿出分选标准数据
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                    List<BizDayworkItemReject> finalSortRejectList = sortRejectList;
                    lotCodeList.forEach(info -> {
                        //设置分选量
                        BizDayworkItem firstSortItem = sortDayworkItem.stream().filter(item -> item.getLotId().equals(info.getLotId())).sorted(Comparator.comparing(BizDayworkItem::getCreateTime)).collect(Collectors.toList()).get(0);
                        info.setFirstSortProd(firstSortItem.getProdNum());
                        //设置实际量(要status是3最后一道序的合格量)
                        BizDayworkItem lastSortItem = sortDayworkItem.stream().filter(item -> item.getLotId().equals(info.getLotId())).sorted(Comparator.comparing(BizDayworkItem::getCreateTime).reversed()).collect(Collectors.toList()).get(0);
                        info.setActualQuantity(lastSortItem.getQualifiedNum());
                        //设置废品量(分选报工所有状态为3的废品总数)
                        info.setTotalRejectNum(sortDayworkItem.stream().filter(item -> item.getLotId().equals(info.getLotId()) && sdf.format(item.getCreateTime()).equals(info.getDate())).mapToInt(item -> item.getRejectNum()).sum());
                        //设置不明量
                        info.setUnknownQuantity(info.getFirstSortProd() - info.getActualQuantity() - info.getTotalRejectNum());
                        //设置不良率
                        info.setRejectRate(Float.valueOf(String.format("%.2f", (info.getTotalRejectNum() / (float) info.getFirstSortProd()) * 100)));
                        //设置不明率
                        info.setUnknownRate(Float.valueOf(String.format("%.2f", ((float) info.getUnknownQuantity() / (float) info.getFirstSortProd()) * 100)));
                        //设置批次率
                        info.setLotRate(Float.valueOf(String.format("%.2f", ((info.getTotalRejectNum() + info.getUnknownQuantity()) / (float) info.getFirstSortProd()) * 100)));
                        if (info.getDate().equals(date) && info.getLotId().equals(lotId)) {
                            List<BizDayworkItemReject> lotSortCheckList = finalSortRejectList.stream().filter(item -> sdf.format(item.getCreateTime()).equals(date) && item.getLotId().equals(lotId)).collect(Collectors.toList());
                            List<Long> lotInspectionIds = lotSortCheckList.stream().map(BizDayworkItemReject::getInspectionInstructionId).collect(Collectors.toList());
                            List<BizDayworkItemReject> checkList = new ArrayList<>();
                            dynamicIds.forEach(inspectionId -> {
                                BizDayworkItemReject check = new BizDayworkItemReject();
                                if (lotInspectionIds.indexOf(inspectionId) > -1) {
                                    Long sum = lotSortCheckList.stream().filter(item -> item.getInspectionInstructionId().equals(inspectionId)).mapToLong(BizDayworkItemReject::getRejectNum).sum();
                                    check.setInspectionInstructionId(inspectionId);
                                    check.setRejectNum(sum);
                                    checkList.add(check);
                                } else {
                                    check.setInspectionInstructionId(inspectionId);
                                    check.setRejectNum(null);
                                    checkList.add(check);
                                }
                                info.setCheckStandardList(checkList);
                            });
                        }
                    });
                }
            }
        }
        List<BizDayworkItemReject> newList = new ArrayList<>();
        if(!lotCodeList.isEmpty()) {
            Map<Long, List<BizDayworkItemReject>> groupedByProductionPlanDetailId = new TreeMap<>();
            for (BizDayworkItemReject obj : lotCodeList) {
                Long key = obj.getProductionPlanDetailId();
                if (!groupedByProductionPlanDetailId.containsKey(key)) {
                    groupedByProductionPlanDetailId.put(key, new ArrayList<>());
                }
                groupedByProductionPlanDetailId.get(key).add(obj);
            }
            for (Map.Entry<Long, List<BizDayworkItemReject>> entry : groupedByProductionPlanDetailId.entrySet()) {
                List<BizDayworkItemReject> values = entry.getValue();
                values.forEach(item -> {
                    newList.add(item);
                });
            }
        }
        newList.forEach(item -> {
            item.setDate(item.getDate().substring(2,10));
        });
        //对导出表格操作
        int currentRow = 2;
        int quotationMergeRow = 0;
        for (int i = 0; i < newList.size(); i++) {
                writer.writeCellValue(0, currentRow + 1,i+1);
                writer.writeCellValue(1, currentRow + 1, newList.get(i).getSpecification());
                writer.writeCellValue(2, currentRow + 1,newList.get(i).getDate());
                writer.writeCellValue(3, currentRow + 1,newList.get(i).getLotCode());
                writer.writeCellValue(4, currentRow + 1, newList.get(i).getProductDescription());
                writer.writeCellValue(5, currentRow + 1, newList.get(i).getFirstSortProd());
                writer.writeCellValue(6, currentRow + 1, newList.get(i).getActualQuantity());
                writer.writeCellValue(7, currentRow + 1, newList.get(i).getTotalRejectNum());
                writer.writeCellValue(8, currentRow + 1, newList.get(i).getUnknownQuantity());
                writer.writeCellValue(9, currentRow + 1, newList.get(i).getRejectRate());
                writer.writeCellValue(10, currentRow + 1, newList.get(i).getUnknownRate());
                writer.writeCellValue(11, currentRow + 1, newList.get(i).getLotRate());
            for(int j = 0;j<newList.get(i).getCheckStandardList().size();j++) {
                writer.writeCellValue(12+j, currentRow + 1,newList.get(i).getCheckStandardList().get(j).getRejectNum());

            }
            currentRow++;
            }

        // 默认的，未添加alias的属性也会写出，如果想只写出加了别名的字段，可以调用此方法排除之
        writer.setOnlyAlias(true);
        // 设置列宽行高
        // writer.setDefaultRowHeight(22);
        writer.setRowHeight(0, 22);

        //设置普通单元格 样式
        Font contentFont = writer.createFont();
        // 设置字体大小，加载到样式中
        contentFont.setFontHeightInPoints((short) 11);
        contentFont.setFontName("宋体");
        CellStyle cellstyle = writer.getStyleSet().getCellStyle();
        CellStyle headCellStyle = writer.getStyleSet().getHeadCellStyle();
        cellstyle.setFont(contentFont);
        cellstyle.setAlignment(HorizontalAlignment.CENTER);
        cellstyle.setVerticalAlignment(VerticalAlignment.CENTER);
        for(int i =0;i<index+1;i++) {
            writer.setStyle(headCellStyle, i, 2);
        }
//        Font headerFont = writer.createFont();
//        // 设置字体大小，加载到样式中
//        contentFont.setFontHeightInPoints((short) 13);
//        contentFont.setFontName("黑体");
//        contentFont.setBold(true);
//        CellStyle headerStyle = writer.getStyleSet().getCellStyle();
//        headerStyle.setFont(headerFont);
//        for(int i =4;i<14;i++) {
//            writer.setStyle(headCellStyle,i, 0);
//        }
        // writer.setRowHeight(0, 22);
        // headSize 为表格 标题 和 表头所占的 行数
        // int headSize = 2;
        // 设置所有列宽自适应 writer.autoSizeColumnAll();
        writer.setColumnWidth(0, 10);
        writer.setColumnWidth(1, 10);
        writer.setColumnWidth(2, 20);
        writer.setColumnWidth(3, 20);
        writer.setColumnWidth(4, 40);


        //out为OutputStream，需要写出到的目标流 response 为 HttpServletResponse 对象
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        //test.xls是弹出下载对话框的文件名，不能为中文，中文请自行编码
        response.setHeader("Content-Disposition", "attachment;filename=test.xlsx");
        ServletOutputStream out = null;
        try {
            out = response.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        writer.flush(out, true);
        // 关闭writer，释放内存
        writer.close();
        //此处记得关闭输出Servlet流
        IoUtil.close(out);

    }

    /**
     * 获取报工废品记录详细信息
     */
    @PreAuthorize("@ss.hasPermi('business:reject:query')")
    @GetMapping(value = "/{id}")
    @Log(title = "获取报工废品记录详细信息", businessType = BusinessType.SELECT)
    public AjaxResult getInfo(@PathVariable("id") Long id)
    {
        return success(bizDayworkItemRejectService.getById(id));
    }

    /**
     * 新增报工废品记录
     */
    @Log(title = "新增报工废品记录", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody BizDayworkItemReject bizDayworkItemReject) throws NoSuchFieldException, IllegalAccessException
    {
        setTenantId(bizDayworkItemReject);
        return toAjax(bizDayworkItemRejectService.save(bizDayworkItemReject));
    }

    /**
     * 修改报工废品记录
     */
    @Log(title = "修改报工废品记录", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody BizDayworkItemReject bizDayworkItemReject) throws NoSuchFieldException, IllegalAccessException
    {
        setTenantId(bizDayworkItemReject);
        return toAjax(bizDayworkItemRejectService.updateById(bizDayworkItemReject));
    }

    /**
     * 删除报工废品记录
     */
    @Log(title = "删除报工废品记录", businessType = BusinessType.DELETE)
	@DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable List<Long> ids)
    {
        return toAjax(bizDayworkItemRejectService.removeBatchByIds(ids));
    }
}
