package com.yida.data.mall.service.impl;

import cc.mrbird.febs.common.redis.service.RedisService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yida.data.common.core.entity.Dict;
import com.yida.data.common.core.entity.constant.CachePrefixConstant;
import com.yida.data.common.core.entity.constant.StringConstant;
import com.yida.data.common.core.entity.mall.EduBill;
import com.yida.data.common.core.entity.mall.EduBillStudent;
import com.yida.data.common.core.entity.user.EduStudent;
import com.yida.data.common.core.entity.user.EduUserDept;
import com.yida.data.common.core.entity.user.enums.UserDeptTypeEnum;
import com.yida.data.common.core.enums.DictType;
import com.yida.data.common.core.utils.FileUtil;
import com.yida.data.common.service.CommonService;
import com.yida.data.mall.dto.BillStudentSelectPageDTO;
import com.yida.data.mall.dto.ExportBillStatisticsDTO;
import com.yida.data.mall.mapper.EduBillMapper;
import com.yida.data.mall.mapper.EduBillStatisticsMapper;
import com.yida.data.mall.mapper.EduBillStudentMapper;
import com.yida.data.mall.service.*;
import com.yida.data.mall.vo.*;
import com.yida.data.system.feign.RemoteCommonService;
import com.yida.data.user.feign.RemoteStudentService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 缴费账单统计
 *
 * @author ZYJ
 * @date 2022/7/7
 */
@Slf4j
@Service
@Transactional
@RequiredArgsConstructor
public class EduBillStatisticsServiceImpl implements EduBillStatisticsService {

    private final EduBillService eduBillService;
    private final EduBillOrderService eduBillOrderService;
    private final EduBillStudentService eduBillStudentService;
    private final EduBillOrderItemService eduBillOrderItemService;

    private final EduBillMapper eduBillMapper;
    private final EduBillStudentMapper eduBillStudentMapper;
    private final EduBillStatisticsMapper eduBillStatisticsMapper;

    private final RemoteCommonService remoteCommonService;
    private final RemoteStudentService remoteStudentService;

    private final CommonService commonService;
    private final RedisService redisService;

    @Value("${febs.uploadUrl}")
    private String uploadUrl;

    private static final ExecutorService BILL_STATISTICS_POOL = new ThreadPoolExecutor(5, 10, 1,
            TimeUnit.MINUTES, new LinkedBlockingQueue<>(),
            ThreadUtil.newNamedThreadFactory("bill-statistics-pool-%d", false));

    @Override
    public List<Map<String, Object>> billStatistics(Long billId) {
        List<Map<String, Object>> resultList = new ArrayList<>();

        String result = (String) redisService.get(CachePrefixConstant.BILL_STATISTICS_DATA + billId);
        JSONArray jsonArray = JSONUtil.parseArray(result);
        for (Object object : jsonArray) {
            // 取出list里面的值转为map
            Map<String, Object> ret = (Map<String, Object>) object;
            resultList.add(ret);
        }
        return resultList;
    }

    @Override
    public String exportBillStatistics(ExportBillStatisticsDTO dto) {
        return (String) redisService.get(CachePrefixConstant.BILL_STATISTICS_EXPORT_URL + dto.getBillId());
    }

    @Override
    public void updateBillStatistics() {
        // 查询已开始未结束的账单
        List<EduBill> billList = eduBillMapper.selectNeedStatisticsBill();
        if (CollUtil.isNotEmpty(billList)) {
            billList.forEach(eduBill -> {
                // 更新账单缴费统计数据
                BILL_STATISTICS_POOL.execute(() -> updateBillStatistics(eduBill));
                // 更新账单导出excel缓存
                BILL_STATISTICS_POOL.execute(() -> updateExportBillStatistics(ExportBillStatisticsDTO.builder().billId(eduBill.getId()).build()));
            });
        }
    }

    @Override
    public void updateBillPayDetail(Long billId) {
        List<EduBill> billList = new ArrayList<>();
        if (Objects.isNull(billId)) {
            // 查询已开始未结束的账单
            billList = eduBillMapper.selectNeedStatisticsBill();
        } else {
            // 查询指定账单数据
            billList.add(eduBillService.getById(billId));
        }
        // 查询已开始的账单
//        List<EduBill> billList = eduBillMapper.selectStartBill();

        if (CollUtil.isNotEmpty(billList)) {
            for (EduBill eduBill : billList) {
                String fileName = FileUtil.getLocalUploadAddress() + UUID.randomUUID() + ".xls";
                File file = null;
                try {
                    // 查询学生列表
                    EduStudent eduStudent = new EduStudent();
                    eduStudent.setSchoolId(eduBill.getDeptId());
                    List<EduStudent> studentList = remoteStudentService.listBaseStudent(eduStudent).getData();
                    // 导出人员列表数据
                    List<List<String>> exportDataList = new ArrayList<>();
                    if (CollUtil.isNotEmpty(studentList)) {
                        // 学生分组
                        Map<Long, List<EduStudent>> studentMap = studentList.stream().collect(
                                Collectors.groupingBy(EduStudent::getId));
                        // 查询账单人员列表
                        List<BillStudentInfoVO> list = eduBillStudentMapper.listBillUserPage(null,
                                BillStudentSelectPageDTO.builder()
                                        .billId(eduBill.getId())
                                        .build(),
                                studentList);
                        // 查询家庭类型
                        List<Dict> familyTypeList = remoteCommonService.getDict(DictType.FAMILY_TYPE.getValue()).getData();

                        list.forEach(billStudentInfoVO -> {
                            // 匹配学生信息
                            EduStudent student = studentMap.get(billStudentInfoVO.getStudentId()).get(0);
                            // 查询学生具体缴费金额
                            List<BillPayVO> payList = eduBillOrderItemService.listItemPayInfo(eduBill.getId(), student.getId());

                            List<String> price = payList.stream().map(billPayVO -> {
                                BillPayPriceVO billPayPriceVO = billPayVO.getBillPayPriceVO();
                                if (Objects.isNull(billPayPriceVO) || Objects.isNull(billPayPriceVO.getItemPrice())) {
                                    return "—";
                                }
                                BigDecimal returnPrice = NumberUtil.sub(billPayPriceVO.getItemPrice(), billPayPriceVO.getReductionPrice());
                                return Objects.isNull(returnPrice) ? "—" : returnPrice.toString();
                            }).collect(Collectors.toList());
                            // 查询总金额数据
                            BigDecimal payOrderPrice = eduBillOrderService.sumPayOrderPrice(eduBill.getId(), student.getId());
                            // 封装每一行数据
                            ArrayList<String> singleList = CollUtil.newArrayList(student.getStuName(),
                                    student.getCampusName(), student.getGradeName(),
                                    student.getClassName(), student.getStuNumber(),
                                    handelStudentType(student.getType()),
                                    handleFamilyType(student.getFamilyType(), familyTypeList));
                            singleList.addAll(price);
                            singleList.add(Objects.isNull(payOrderPrice) ? "—" : payOrderPrice.toString());
                            // 添加excel数据
                            exportDataList.add(singleList);
                        });
                    }

                    file = new File(fileName);
                    // 导出数据
                    EasyExcel.write(file)
                            .excelType(ExcelTypeEnum.XLS)
                            // 这里放入动态头
                            .head(getDetailExportHead(eduBill.getId())).sheet("缴费明细")
                            // 当然这里数据也可以用 List<List<String>> 去传入
                            .doWrite(exportDataList);
                    // 上传文件到媒资
                    String fileUrl = FileUtil.uploadFileToMediaServer(uploadUrl, file);
                    redisService.set(CachePrefixConstant.BILL_PAY_DETAIL_EXPORT_URL + eduBill.getId(), fileUrl);
                } catch (Exception e) {
                    log.error("更新导出缴费明细数据错误, billId: {}", eduBill.getId(), e);
                } finally {
                    if (Objects.nonNull(file)) {
                        cn.hutool.core.io.FileUtil.del(file);
                    }
                }
            }
        }
    }

    /**
     * 生成缴费账单动态表头数据
     *
     * @param billId 账单id
     * @return java.util.List<java.util.List < java.lang.String>>
     * @author ZYJ
     * @date 2022/4/19 16:06
     */
    private List<List<String>> getDetailExportHead(Long billId) {
        // 表头list的生成，实际的表头信息可以从数据库或者缓存等处动态读取
        List<List<String>> allColList = new ArrayList<>();
        // 姓名表头
        allColList.add(CollUtil.newArrayList("姓名"));
        // 校区表头
        allColList.add(CollUtil.newArrayList("校区"));
        // 年级表头
        allColList.add(CollUtil.newArrayList("年级"));
        // 班级表头
        allColList.add(CollUtil.newArrayList("班级"));
        // 学号表头
        allColList.add(CollUtil.newArrayList("学号"));
        // 学生类型表头
        allColList.add(CollUtil.newArrayList("学生类型"));
        // 家庭类型表头
        allColList.add(CollUtil.newArrayList("家庭类型"));

        // 项目动态表头
        List<BillItemInfoVO> colList = eduBillService.listBillPayDetailTableCol(billId);
        colList.forEach(item -> {
            if (CollUtil.isNotEmpty(item.getSubItemList())) {
                item.getSubItemList().forEach(subItem -> allColList.add(CollUtil.newArrayList("缴费项目", item.getItemName(), subItem.getSubItemName())));
            } else {
                allColList.add(CollUtil.newArrayList("缴费项目", item.getItemName()));
            }
        });
        // 总金额表头
        allColList.add(CollUtil.newArrayList("总金额"));
        return allColList;
    }

    /**
     * 转换学生类别
     *
     * @param studentType 学生类别，0-走读，1-住宿
     * @return java.lang.String
     * @author ZYJ
     * @date 2022/4/19 16:19
     */
    private String handelStudentType(Integer studentType) {
        if (Objects.nonNull(studentType)) {
            return studentType.equals(0) ? "走读" : "住宿";
        } else {
            return "";
        }
    }

    /**
     * 转换家庭类型
     *
     * @param familyType     学生家庭类型
     * @param familyTypeList 家庭类型字典
     * @return java.lang.String
     * @author ZYJ
     * @date 2022/4/19 16:21
     */
    private String handleFamilyType(String familyType, List<Dict> familyTypeList) {
        if (StringUtils.isNotBlank(familyType)) {
            List<String> list = new ArrayList<>();
            for (Dict dict : familyTypeList) {
                if (familyType.contains(dict.getValue())) {
                    list.add(dict.getLabel());
                }
            }
            return String.join(StringConstant.COMMA, list);
        } else {
            return "";
        }
    }

    /**
     * 更新账单缴费统计数据
     *
     * @param eduBill 账单信息
     * @author ZYJ
     * @date 2022/7/28 17:48
     */
    private void updateBillStatistics(EduBill eduBill) {
        Long billId = eduBill.getId();
        try {
            // 返回数据
            List<Map<String, Object>> result = new ArrayList<>();
            // 统计全校总数
            Map<String, Object> total = new HashMap<>(16);
            // 部门名称
            total.put("deptId", "all");
            total.put("deptName", "全校");
            // 缴费总金额
            BigDecimal totalMoney = eduBillOrderService.sumPayOrderPrice(billId, null);
            total.put("payMoney", String.valueOf(totalMoney));
            // 缴费单总人数
            Long totalCount = eduBillStudentService.count(Wrappers.lambdaQuery(new EduBillStudent()).eq(EduBillStudent::getBillId, billId));
            total.put("totalCount", String.valueOf(totalCount));

            // 缴费项目统计
            if (Objects.nonNull(totalMoney)) {
                // 查询账单总缴费信息
                List<BillStatisticsItemVO> payInfo = eduBillStatisticsMapper.getPayInfo(billId);
                payInfo.forEach(item -> {
                    String itemPayName = "i" + item.getItemId() + item.getItemName();
                    if (CollUtil.isNotEmpty(item.getSubItemList())) {
                        item.getSubItemList().forEach(subItem -> {
                            // 选项金额拼接方式为 i+项目id+项目名称+s+选项id+选项名称
                            total.put(itemPayName + "s" + subItem.getSubItemId() + subItem.getSubItemName(),
                                    NumberUtil.sub(subItem.getSubItemPrice(), item.getReductionPrice()).toString());
                            // 选项缴费人数拼接方式为 i+项目id+项目名称+s+选项id+选项名称+n
                            total.put(itemPayName + "s" + subItem.getSubItemId() + subItem.getSubItemName() + "n",
                                    String.valueOf(subItem.getPayNum()));
                        });
                    } else {
                        // 项目金额拼接方式为 i+项目id+项目名称
                        total.put(itemPayName, NumberUtil.sub(item.getItemPrice(), item.getReductionPrice()).toString());
                        // 项目人数拼接方式为 i+项目id+项目名称+n
                        total.put(itemPayName + "n", String.valueOf(item.getPayNum()));
                    }
                });
            }
            result.add(total);

            // 查询年级信息
            List<EduUserDept> gradeList = commonService.findChildIdByParentAndType(-eduBill.getDeptId(), UserDeptTypeEnum.GRADE_TYPE.getValue());
            if (CollUtil.isNotEmpty(gradeList)) {
                gradeList.forEach(gradeDept -> {
                    Map<String, Object> gradeMap = new HashMap<>(16);
                    gradeMap.put("deptId", gradeDept.getDeptId());
                    gradeMap.put("deptType", UserDeptTypeEnum.GRADE_TYPE.getValue());
                    // 查询班级信息
                    List<EduUserDept> classList = commonService.findChildIdByParentAndType(gradeDept.getDeptId(), UserDeptTypeEnum.CLASS_TYPE.getValue());
                    // 年级缴费总金额
                    BigDecimal gradeTotalMoney = eduBillOrderService.sumDeptPayOrderPrice(billId, gradeDept.getDeptId(), UserDeptTypeEnum.GRADE_TYPE.getValue());
                    gradeMap.put("payMoney", String.valueOf(gradeTotalMoney));
                    // 年级总缴费人数
                    gradeMap.put("totalCount", String.valueOf(eduBillStudentService.count(
                            Wrappers.lambdaQuery(new EduBillStudent())
                                    .eq(EduBillStudent::getBillId, billId)
                                    .in(EduBillStudent::getDeptId, classList.stream().map(EduUserDept::getDeptId).collect(Collectors.toList()))
                    )));
                    // 账单年级缴费信息统计
                    List<BillStatisticsItemVO> gradePayInfo = eduBillStatisticsMapper.getDeptPayInfo(billId, gradeDept.getDeptId(), UserDeptTypeEnum.GRADE_TYPE.getValue());
                    if (CollUtil.isEmpty(gradePayInfo)) {
                        gradeMap.put("deptName", gradeDept.getDeptName());
                    }
                    gradePayInfo.forEach(item -> {
                        if (!gradeMap.containsKey("deptName")) {
                            gradeMap.put("deptName", item.getDeptName());
                        }
                        String itemPayName = "i" + item.getItemId() + item.getItemName();
                        if (CollUtil.isNotEmpty(item.getSubItemList())) {
                            item.getSubItemList().forEach(subItem -> {
                                // 选项金额拼接方式为 i+项目id+项目名称+s+选项id+选项名称
                                gradeMap.put(itemPayName + "s" + subItem.getSubItemId() + subItem.getSubItemName(),
                                        NumberUtil.sub(subItem.getSubItemPrice(), item.getReductionPrice()).toString());
                                // 选项缴费人数拼接方式为 i+项目id+项目名称+s+选项id+选项名称+n
                                gradeMap.put(itemPayName + "s" + subItem.getSubItemId() + subItem.getSubItemName() + "n",
                                        String.valueOf(subItem.getPayNum()));
                            });
                        } else {
                            // 项目金额拼接方式为 i+项目id+项目名称
                            gradeMap.put(itemPayName, NumberUtil.sub(item.getItemPrice(), item.getReductionPrice()).toString());
                            // 项目人数拼接方式为 i+项目id+项目名称+n
                            gradeMap.put(itemPayName + "n", String.valueOf(item.getPayNum()));
                        }
                    });

                    List<Map<String, Object>> children = new ArrayList<>();
                    if (CollUtil.isNotEmpty(classList)) {
                        classList.forEach(classDept -> {
                            // 班级缴费信息
                            Map<String, Object> classMap = new HashMap<>(16);
                            classMap.put("deptId", classDept.getDeptId());
                            classMap.put("deptType", UserDeptTypeEnum.CLASS_TYPE.getValue());
                            // 班级缴费总金额
                            BigDecimal classTotalMoney = eduBillOrderService.sumDeptPayOrderPrice(billId, classDept.getDeptId(), UserDeptTypeEnum.CLASS_TYPE.getValue());
                            classMap.put("payMoney", String.valueOf(classTotalMoney));
                            // 班级总缴费人数
                            classMap.put("totalCount", String.valueOf(eduBillStudentService.count(
                                    Wrappers.lambdaQuery(new EduBillStudent())
                                            .eq(EduBillStudent::getBillId, billId)
                                            .eq(EduBillStudent::getDeptId, classDept.getDeptId())
                            )));
                            // 账单班级缴费信息统计
                            List<BillStatisticsItemVO> classPayInfo = eduBillStatisticsMapper.getDeptPayInfo(billId, classDept.getDeptId(), UserDeptTypeEnum.CLASS_TYPE.getValue());
                            if (CollUtil.isEmpty(classPayInfo)) {
                                classMap.put("deptName", classDept.getDeptName());
                            }
                            classPayInfo.forEach(item -> {
                                if (!classMap.containsKey("deptName")) {
                                    classMap.put("deptName", item.getDeptName());
                                }
                                String itemPayName = "i" + item.getItemId() + item.getItemName();
                                if (CollUtil.isNotEmpty(item.getSubItemList())) {
                                    item.getSubItemList().forEach(subItem -> {
                                        // 选项金额拼接方式为 i+项目id+项目名称+s+选项id+选项名称
                                        classMap.put(itemPayName + "s" + subItem.getSubItemId() + subItem.getSubItemName(),
                                                NumberUtil.sub(subItem.getSubItemPrice(), item.getReductionPrice()).toString());
                                        // 选项缴费人数拼接方式为 i+项目id+项目名称+s+选项id+选项名称+n
                                        classMap.put(itemPayName + "s" + subItem.getSubItemId() + subItem.getSubItemName() + "n",
                                                String.valueOf(subItem.getPayNum()));
                                    });
                                } else {
                                    // 项目金额拼接方式为 i+项目id+项目名称
                                    classMap.put(itemPayName, NumberUtil.sub(item.getItemPrice(), item.getReductionPrice()).toString());
                                    // 项目人数拼接方式为 i+项目id+项目名称+n
                                    classMap.put(itemPayName + "n", String.valueOf(item.getPayNum()));
                                }
                            });
                            children.add(classMap);
                        });
                    }
                    gradeMap.put("children", children);
                    result.add(gradeMap);
                });
            }
            redisService.set(CachePrefixConstant.BILL_STATISTICS_DATA + billId, JSONUtil.toJsonStr(result));

        } catch (Exception e) {
            log.error("更新账单缴费统计数据失败, billId: {}", billId, e);
        }
    }

    /**
     * 更新账单导出excel缓存
     *
     * @param dto 导出账单缴费统计数据请求类
     * @author ZYJ
     * @date 2022/7/28 17:45
     */
    private void updateExportBillStatistics(ExportBillStatisticsDTO dto) {
        String fileName = FileUtil.getLocalUploadAddress() + UUID.randomUUID() + ".xls";
        File file = null;
        try {
            // 账单信息
            EduBill eduBill = eduBillService.getById(dto.getBillId());

            // 导出数据总集合
            List<List<String>> exportDataList = new ArrayList<>();
            // 缴费单总人数
            Long totalCount = eduBillStudentService.count(Wrappers.lambdaQuery(new EduBillStudent()).eq(EduBillStudent::getBillId, dto.getBillId()));

            // 处理缴费信息
            List<BillPayVO> payList = eduBillStatisticsMapper.listTotalItemPayInfo(dto.getBillId());
            // 处理第一行数据
            ArrayList<String> firstList = CollUtil.newArrayList("全校");
            payList.forEach(billPayVO -> {
                // 处理人数
                firstList.add(billPayVO.getPayNum() + "/" + totalCount);
                // 缴费数据
                String price;
                BillPayPriceVO billPayPriceVO = billPayVO.getBillPayPriceVO();
                if (Objects.isNull(billPayPriceVO) || Objects.isNull(billPayPriceVO.getItemPrice())) {
                    price = "—";
                } else {
                    BigDecimal returnPrice = NumberUtil.sub(billPayPriceVO.getItemPrice(), billPayPriceVO.getReductionPrice());
                    price = Objects.isNull(returnPrice) ? "—" : returnPrice.toString();
                }
                firstList.add(price);
            });
            // 缴费总金额
            BigDecimal totalMoney = eduBillOrderService.sumPayOrderPrice(dto.getBillId(), null);
            firstList.add(Objects.isNull(totalMoney) ? "—" : totalMoney.toString());
            // 添加excel数据
            exportDataList.add(firstList);

            // 查询年级信息
            List<EduUserDept> gradeList = commonService.findChildIdByParentAndType(-eduBill.getDeptId(), UserDeptTypeEnum.GRADE_TYPE.getValue());
            gradeList.forEach(gradeDept -> {
                // 查询班级信息
                List<EduUserDept> classList = commonService.findChildIdByParentAndType(gradeDept.getDeptId(), UserDeptTypeEnum.CLASS_TYPE.getValue());
                // 年级总缴费人数
                Long gradeCount = eduBillStudentService.count(Wrappers.lambdaQuery(new EduBillStudent())
                        .eq(EduBillStudent::getBillId, dto.getBillId())
                        .in(EduBillStudent::getDeptId, classList.stream().map(EduUserDept::getDeptId).collect(Collectors.toList())));
                // 账单年级缴费信息统计
                List<BillPayVO> gradePayList = eduBillStatisticsMapper.listDeptItemPayInfo(dto.getBillId(), gradeDept.getDeptId(), UserDeptTypeEnum.GRADE_TYPE.getValue());
                // 部门名称
                String gradeName = "";
                if (CollUtil.isEmpty(gradePayList)) {
                    gradeName = gradeDept.getDeptName();
                }
                // 处理年级每一行数据
                ArrayList<String> gradeCheckList = CollUtil.newArrayList();
                for (BillPayVO deptPayInfo : gradePayList) {
                    if (StringUtils.isEmpty(gradeName)) {
                        if (Objects.nonNull(deptPayInfo.getBillPayPriceVO())) {
                            gradeName = deptPayInfo.getBillPayPriceVO().getDeptName();
                        } else {
                            gradeName = gradeDept.getDeptName();
                        }
                    }
                    // 处理人数
                    gradeCheckList.add(deptPayInfo.getPayNum() + "/" + gradeCount);
                    // 缴费数据
                    String price;
                    BillPayPriceVO gradePayPriceVO = deptPayInfo.getBillPayPriceVO();
                    if (Objects.isNull(gradePayPriceVO) || Objects.isNull(gradePayPriceVO.getItemPrice())) {
                        price = "—";
                    } else {
                        BigDecimal returnPrice = NumberUtil.sub(gradePayPriceVO.getItemPrice(), gradePayPriceVO.getReductionPrice());
                        price = Objects.isNull(returnPrice) ? "—" : returnPrice.toString();
                    }
                    gradeCheckList.add(price);
                }
                ArrayList<String> singleGradeList = CollUtil.newArrayList(gradeName);
                singleGradeList.addAll(gradeCheckList);
                // 年级缴费总金额
                BigDecimal gradeTotalMoney = eduBillOrderService.sumDeptPayOrderPrice(dto.getBillId(), gradeDept.getDeptId(), UserDeptTypeEnum.GRADE_TYPE.getValue());
                singleGradeList.add(Objects.isNull(gradeTotalMoney) ? "—" : gradeTotalMoney.toString());
                // 添加excel数据
                exportDataList.add(singleGradeList);

                // 处理班级数据
                for (EduUserDept classDept : classList) {
                    // 班级总缴费人数
                    Long classCount = eduBillStudentService.count(Wrappers.lambdaQuery(new EduBillStudent())
                            .eq(EduBillStudent::getBillId, dto.getBillId())
                            .eq(EduBillStudent::getDeptId, classDept.getDeptId()));
                    // 账单班级缴费信息统计
                    List<BillPayVO> classPayList = eduBillStatisticsMapper.listDeptItemPayInfo(dto.getBillId(), classDept.getDeptId(), UserDeptTypeEnum.CLASS_TYPE.getValue());
                    // 部门名称
                    String className = "";
                    if (CollUtil.isEmpty(classPayList)) {
                        className = classDept.getDeptName();
                    }
                    // 处理班级每一行数据
                    ArrayList<String> classCheckList = CollUtil.newArrayList();
                    for (BillPayVO classPayInfo : classPayList) {
                        if (StringUtils.isEmpty(className)) {
                            if (Objects.nonNull(classPayInfo.getBillPayPriceVO())) {
                                className = classPayInfo.getBillPayPriceVO().getDeptName();
                            } else {
                                className = classDept.getDeptName();
                            }
                        }
                        // 处理人数
                        classCheckList.add(classPayInfo.getPayNum() + "/" + classCount);
                        // 缴费数据
                        String price;
                        BillPayPriceVO classPayPriceVO = classPayInfo.getBillPayPriceVO();
                        if (Objects.isNull(classPayPriceVO) || Objects.isNull(classPayPriceVO.getItemPrice())) {
                            price = "—";
                        } else {
                            BigDecimal returnPrice = NumberUtil.sub(classPayPriceVO.getItemPrice(), classPayPriceVO.getReductionPrice());
                            price = Objects.isNull(returnPrice) ? "—" : returnPrice.toString();
                        }
                        classCheckList.add(price);
                    }
                    ArrayList<String> singleClassList = CollUtil.newArrayList(className);
                    singleClassList.addAll(classCheckList);
                    // 年级缴费总金额
                    BigDecimal classTotalMoney = eduBillOrderService.sumDeptPayOrderPrice(dto.getBillId(), classDept.getDeptId(), UserDeptTypeEnum.CLASS_TYPE.getValue());
                    singleClassList.add(Objects.isNull(classTotalMoney) ? "—" : classTotalMoney.toString());
                    // 添加excel数据
                    exportDataList.add(singleClassList);
                }
            });

            file = new File(fileName);
            // 导出数据
            EasyExcel.write(file)
                    .excelType(ExcelTypeEnum.XLS)
                    // 这里放入动态头
                    .head(getExportHead(eduBill)).sheet("缴费统计")
                    // 当然这里数据也可以用 List<List<String>> 去传入
                    .doWrite(exportDataList);
            // 上传文件到媒资
            String fileUrl = FileUtil.uploadFileToMediaServer(uploadUrl, file);
            redisService.set(CachePrefixConstant.BILL_STATISTICS_EXPORT_URL + dto.getBillId(), fileUrl);

        } catch (Exception e) {
            log.error("更新导出缴费统计数据错误, billId: {}", dto.getBillId(), e);
        } finally {
            if (Objects.nonNull(file)) {
                cn.hutool.core.io.FileUtil.del(file);
            }
        }
    }

    /**
     * 生成缴费账单统计动态表头数据
     *
     * @param bill 账单信息
     * @return java.util.List<java.util.List < java.lang.String>>
     * @author ZYJ
     * @date 2022/7/12 10:08
     */
    private List<List<String>> getExportHead(EduBill bill) {
        // 表头list的生成，实际的表头信息可以从数据库或者缓存等处动态读取
        List<List<String>> allColList = new ArrayList<>();
        // 部门名称表头
        allColList.add(CollUtil.newArrayList(commonService.getDept(bill.getDeptId()).getDeptName()));

        // 项目动态表头
        List<BillItemInfoVO> colList = eduBillService.listBillPayDetailTableCol(bill.getId());
        colList.forEach(item -> {
            if (CollUtil.isNotEmpty(item.getSubItemList())) {
                item.getSubItemList().forEach(subItem -> {
                    allColList.add(CollUtil.newArrayList("缴费项目", item.getItemName(), subItem.getSubItemName(), "缴费人数"));
                    allColList.add(CollUtil.newArrayList("缴费项目", item.getItemName(), subItem.getSubItemName(), "缴费金额"));
                });
            } else {
                allColList.add(CollUtil.newArrayList("缴费项目", item.getItemName(), "缴费人数"));
                allColList.add(CollUtil.newArrayList("缴费项目", item.getItemName(), "缴费金额"));
            }
        });
        // 总金额表头
        allColList.add(CollUtil.newArrayList("总金额"));
        return allColList;
    }
}
