package com.zt.plat.module.qms.business.reportdoc.service;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zt.plat.framework.common.pojo.CommonResult;
import com.zt.plat.framework.common.pojo.PageResult;
import com.zt.plat.framework.common.util.object.BeanUtils;
import com.zt.plat.module.qms.business.bus.dal.dataobject.BusinessAssayReportDataDO;
import com.zt.plat.module.qms.business.config.controller.vo.ConfigReportFieldPageReqVO;
import com.zt.plat.module.qms.business.config.dal.dataobject.ConfigReportFieldDO;
import com.zt.plat.module.qms.business.config.dal.dataobject.ConfigUserSignatureDO;
import com.zt.plat.module.qms.business.config.service.ConfigReportFieldService;
import com.zt.plat.module.qms.business.config.service.ConfigUserSignatureService;
import com.zt.plat.module.qms.business.reportdoc.controller.vo.*;
import com.zt.plat.module.qms.business.reportdoc.dal.dataobject.ReportDocumentMainDO;
import com.zt.plat.module.qms.business.reportdoc.dal.dataobject.ReportDocumentTypeDO;
import com.zt.plat.module.qms.business.reportdoc.dal.mapper.ReportDocumentDataMapper;
import com.zt.plat.module.qms.business.reportdoc.dal.dataobject.ReportDocumentDataDO;
import com.zt.plat.module.qms.common.dic.controller.vo.DictionaryBusinessRespVO;
import com.zt.plat.module.qms.common.dic.dal.dataobject.DictionaryBusinessDO;
import com.zt.plat.module.qms.common.dic.service.DictionaryBusinessService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.annotation.Validated;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.zt.plat.module.qms.enums.ErrorCodeConstants.REPORT_DOCUMENT_DATA_NOT_EXISTS;
import static com.zt.plat.module.qms.enums.ErrorCodeConstants.REPORT_DOCUMENT_TYPE_NOT_EXISTS;
import static com.zt.plat.module.qms.enums.QmsCommonConstant.FIELD_DYNAMIC;
import static com.zt.plat.module.qms.enums.QmsCommonConstant.FIELD_CALCULATED;
import static com.zt.plat.module.qms.enums.QmsCommonConstant.FIELD_FIXED;

/**
 * 检测报告明细 Service 实现类
 *
 * @author 后台管理
 */
@Service
@Validated
@Slf4j
public class ReportDocumentDataServiceImpl implements ReportDocumentDataService {

    @Resource private ReportDocumentDataMapper reportDocumentDataMapper;
    @Resource private ConfigReportFieldService configReportFieldService;
    @Resource private ConfigUserSignatureService configUserSignatureService;
    @Resource private DictionaryBusinessService dictionaryBusinessService;
    private final String colPrefix = "col";
    private final String sampleCodeKey = "SMP_CD";
    private final String sampleNameKey = "SMP_NAME";
    private final String sampleNameAndCodeKey = "SMP_NAME_CD";
    private final String entrustSampleNameKey = "ENTT_SMP_NAME";
    private final String entrustSampleCodeKey = "ENTT_SMP_CD";
    private final String entrustSampleNameCodeKey = "ENTT_SMP_NAME_CD";
    private final String rowTypeKey = "rowType";    //行类型
    private final String rowTypeTitle = "title";    //行类型-标题
    private final String rowTypeLimit = "limit";    //行类型-检出限
    private final String rangeKey = "minLimitValue";
    private final String emptyText = "以下为空白";
    private final String emptyTextLastRow = "此行为空白";


    /*
    * 组装动态报表数据
    * */
    @Override
    public CommonResult<JSONArray> assembleDynamicData(ReportDocumentMainDO mainData, ReportDocumentTypeDO typeDO, String pageFlag) {
        if(typeDO == null || typeDO.getConfigReportTypeId() == null)
            return CommonResult.error(REPORT_DOCUMENT_TYPE_NOT_EXISTS.getCode(), "报告配置为空，或未配置报表类型，请联系管理员处理！");
        String customConfig = typeDO.getCustomConfig();
        JSONObject configJson = JSONObject.parseObject(customConfig);
        String verticalFlag = configJson.getString("verticalFlag");
        String maxRowCountStr = configJson.getString("maxRowCount");                    //最大行数
        Integer maxRowCount = 3;
        if(!ObjectUtils.isEmpty(maxRowCountStr))
            maxRowCount = Integer.parseInt(maxRowCountStr);
        //查询报表字段配置
        ConfigReportFieldPageReqVO fieldParam = new ConfigReportFieldPageReqVO();
        fieldParam.setConfigReportTypeId(typeDO.getConfigReportTypeId());
        fieldParam.setPageSize(9999);
        List<ConfigReportFieldDO> fieldListAll = configReportFieldService.getConfigReportFieldPage(fieldParam).getList();
        if(fieldListAll.isEmpty())
            return CommonResult.error(REPORT_DOCUMENT_TYPE_NOT_EXISTS.getCode(), "未配置报表字段，请联系管理员处理！");
        List<ReportDocumentDataDO> dataList = listByMainDataId(mainData.getId()).getData();
        ReportDocumentDataDO firstDataDO = null;
        if(!dataList.isEmpty())
            firstDataDO = dataList.get(0);
        //拆分dataList，按样品分类key拆分
        List<List<ReportDocumentDataDO>> dataListGroup = new ArrayList<>();
        String[] sampleTypeKeys = new String[]{"inspectionAnalysisSample", "comprehensiveInspectionSample"};    //商检分析样、商检综合样
        for(String sampleTypeKey : sampleTypeKeys){
            List<ReportDocumentDataDO> dataListByKey = new ArrayList<>();
            for(ReportDocumentDataDO dataDO: dataList){
                if(sampleTypeKey.equals(dataDO.getSampleTypeKey())){
                    dataListByKey.add(dataDO);
                }
            }
            if(!dataListByKey.isEmpty())
                dataListGroup.add(dataListByKey);
        }
        if(dataListGroup.isEmpty() && !dataList.isEmpty())
            dataListGroup.add(dataList);
        JSONArray rowList = new JSONArray();
        for(int i = 0; i < dataListGroup.size(); i++){
            List<ReportDocumentDataDO> dataListByKey = dataListGroup.get(i);
            //处理字段，提取有数据的字段
            List<ConfigReportFieldDO> fieldList = new ArrayList<>();
            List<String> hasFields = new ArrayList<>();
            for(ConfigReportFieldDO fieldDO : fieldListAll){
                String field = fieldDO.getField();
                String fieldName = fieldDO.getFieldName();
                String fieldType = fieldDO.getFieldType();
                //先处理固定列
                if(FIELD_FIXED.equals(fieldType)){
                    if(!hasFields.contains( field)){
                        fieldList.add(fieldDO);
                        hasFields.add(field);
                    }
                    continue;
                }
                for(ReportDocumentDataDO dataDO : dataListByKey){
                    String documentContent = dataDO.getDocumentContent();
                    JSONObject dataJson = JSONObject.parseObject(documentContent);
                    if(dataJson == null)
                        continue;
                    if(!dataJson.containsKey(field))
                        continue;
                    if(!hasFields.contains( fieldName)){
                        JSONObject valueJson = dataJson.getJSONObject(field);
                        String usage = valueJson.getString("usage");
                        if(!"report".equals( usage) && ! "ingredient_report".equals(usage))
                            continue;
                        fieldList.add(fieldDO);
                        hasFields.add(fieldName);
                    }
                }
            }
            assembleStep1(rowList, fieldList, dataListByKey, customConfig, i);  //处理后的组数对象
        }
        if(!"1".equals(verticalFlag)){
            //处理空数据，填充/
            rowList = assembleEmpty(configJson, rowList);
            //处理数据分页
            if("1".equals(pageFlag)){
                JSONArray pageRowList = assemblePageRowList(rowList, configJson, mainData, firstDataDO);
                return CommonResult.success(pageRowList);
            }
        }
        //以下为空白/本行为空白
        String lastRowText = emptyText;
        if(rowList.size() + 1 == maxRowCount)
            lastRowText = emptyTextLastRow;
        if(rowList.size() < maxRowCount && !rowList.isEmpty()){
            JSONObject t = new JSONObject();
            t.put(colPrefix + "01", lastRowText);
            putEmptyData(t, 2,10);
            rowList.add(t.clone());
        }
        while(rowList.size() < maxRowCount){
            JSONObject t = new JSONObject();
            putEmptyData(t, 1,10);
            rowList.add(t.clone());
        }
        /*
        * 修改数据结构
        [
          {
            "headerData": {},
            "tableList": [{},]
          },
        ]
        * */
        JSONArray result = new JSONArray();
        JSONObject resultData = assembleResultData(mainData, rowList, firstDataDO);
        result.add(resultData);
        return CommonResult.success(result);
    }

    void putEmptyData(JSONObject t, int start, int length){
        for(int i = start; i < start + length; i++){
            t.put(colPrefix + parseNumToString(i, 2), " ");
        }
    }

    /*
    * 处理分页
    *
    * */
    private JSONArray assemblePageRowList(JSONArray rowList, JSONObject configJson, ReportDocumentMainDO mainData, ReportDocumentDataDO firstDataDO){
        JSONArray pageRowList = new JSONArray();
        Integer maxRowCount = 20;
        String maxRowCountStr = configJson.getString("maxRowCount");                    //最大行数
        if(!ObjectUtils.isEmpty(maxRowCountStr))    maxRowCount = Integer.parseInt(maxRowCountStr);
        int rowLength = rowList.size();
        String lastRowText = emptyText;
        if(rowList.size() + 1 == maxRowCount)
            lastRowText = emptyTextLastRow;
        if(rowLength <= maxRowCount){
            //以下为空白
            if(rowList.size() < maxRowCount){
                JSONObject t = new JSONObject();
                t.put(colPrefix + "01", lastRowText);
                putEmptyData(t, 2,10);
                rowList.add(t.clone());
            }
            pageRowList.add(rowList);
            return assemblePageResult(mainData, pageRowList, maxRowCount, firstDataDO);
        }
        JSONArray remainingRows = new JSONArray();
        remainingRows.addAll(rowList);
        while(remainingRows.size() > 0){
            JSONArray pageRow = new JSONArray();
            for(int i = 0; i < maxRowCount ; i++){
                if(remainingRows.isEmpty())
                    break;
                pageRow.add(remainingRows.getJSONObject(0));
                remainingRows.remove(0);
            }
            /*
            在每页开头插入“标题行”
            如果最后一行是标题，直接移到下一页；如果不是，往上寻找最近的“标题行”
             */
            JSONObject lastTitleRow = pageRow.getJSONObject(pageRow.size() - 1);
            String rowType = lastTitleRow.getString(rowTypeKey);
            if(rowTypeTitle.equals(rowType)){
                //如果最后一行是“标题行”，移除
                pageRow.remove(pageRow.size() - 1);
            }else {
                for(int i = pageRow.size() - 1; i >= 0; i--){
                    JSONObject t = pageRow.getJSONObject(i);
                    rowType = t.getString(rowTypeKey);
                    if(rowTypeTitle.equals(rowType)){
                        lastTitleRow = t;
                        break;
                    }
                }
            }
            if(!remainingRows.isEmpty()){
                JSONObject firstRemainingRow = remainingRows.getJSONObject(0);
                String val01 = firstRemainingRow.getString(colPrefix + "01");
                if(!ObjectUtils.isEmpty(val01) && !" ".equals(val01) && !rowTypeTitle.equals(firstRemainingRow.getString(rowTypeKey))){
                    //如果下一页的第一行不为空，且不是标题行，则插入标题
                    remainingRows.add(0, lastTitleRow);
                }else{
                    //如果下一页的第一行为空，则删除空行
                    while (ObjectUtils.isEmpty(val01) || " ".equals(val01)){
                        remainingRows.remove(0);
                        if(remainingRows.isEmpty())
                            break;
                        firstRemainingRow = remainingRows.getJSONObject(0);
                        val01 = firstRemainingRow.getString(colPrefix + "01");
                    }
                }
            }
            pageRowList.add(pageRow);
        }

        //在最后一页插入“以下为空”
        JSONArray pageRow = pageRowList.getJSONArray(pageRowList.size() - 1);
        lastRowText = emptyText;
        if(pageRow.size() + 1 == maxRowCount)
            lastRowText = emptyTextLastRow;
        if(pageRow.size() < maxRowCount){
            JSONObject t = new JSONObject();
            t.put(colPrefix + "01", lastRowText);
            putEmptyData(t, 2,10);
            pageRow.add(t.clone());
        }

        return assemblePageResult(mainData, pageRowList, maxRowCount, firstDataDO);
    }
    /*
        * 修改数据结构
        [{
            "headerData": {},
            "tableList": [{},]
        },]
        * */
    private JSONArray assemblePageResult(ReportDocumentMainDO mainData, JSONArray pageRowList, Integer maxRowCount, ReportDocumentDataDO firstDataDO){
        JSONArray result = new JSONArray();

        //在最后一页填充空行
        JSONArray pageRow = pageRowList.getJSONArray(pageRowList.size() - 1);
        while(pageRow.size() < maxRowCount){
            JSONObject t = new JSONObject();
            putEmptyData(t, 1,10);
            pageRow.add(t.clone());
        }
        for(int i=0;i<pageRowList.size();i++){
            JSONArray rows = pageRowList.getJSONArray(i);
            JSONObject resultData = assembleResultData(mainData, rows, firstDataDO);
            result.add(resultData);
        }
//        log.error("assemblePageRowList result: {}", result.toJSONString());
        return result;
    }

    /*
    商检报告的“签发”“方法”要按样品类型显示：
        非铜金矿：签发名显示为/，方法名显示为/
        铜精矿综合样：方法名显示为/
    * */
    private JSONObject assembleResultData(ReportDocumentMainDO mainData, JSONArray rows, ReportDocumentDataDO firstDataDO){
//        String emptyImgBase64 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAeCAIAAACubtl7AAAACXBIWXMAAA7EAAAOxAGVKw4bAAABF0lEQVQ4jWP8//8/A+mAiQw9g1jb32ebe2ec+kqitp+XV214LavMSZK2f+/2rbysE+4izESKtj/3Nmz85hqqxw4TIErb15OrjkgHecsww0WI0Pbv+fa1Dy3CrHmRxAhr+3V17Q5W3yBVFmRBQtr+vT+w8rxmqIsIqkIC2v4+3Ljho1OYIQeaOH5t30+vOiwW5CvLjC6BT9u/FzvW3DMNt+XDlMKj7ff19dsZvILVWbDI4db28dCqM6rhbqJYVeDS9vfh5vVvHUONOLFL49D24/zqA8IBvgoYYYFP27/Xu1beMgqz58ehCbu2P7fWbvvvGaTJilMXNm2fj6w6oxjiIYEvbjDl/n74rRwWYYojLKCAcbTAG1htAK4eXQ1h4qkRAAAAAElFTkSuQmCC";
        String formData = mainData.getFormData();
        String signatureData = mainData.getDocumentSignature();
        String signatureJsonStr = assembleSignature(signatureData);
        JSONObject formDataJson = new JSONObject();
        if(!ObjectUtils.isEmpty(formData))
            formDataJson = JSONObject.parseObject(formData);
        JSONObject signatureJson = new JSONObject();
        if(!ObjectUtils.isEmpty(signatureJsonStr))
            signatureJson = JSONObject.parseObject(signatureJsonStr);
        JSONObject resultData = new JSONObject();
        JSONObject headerData = new JSONObject();
        JSONObject firstRow = rows.getJSONObject(0);
        if(rowTypeTitle.equals(firstRow.getString(rowTypeKey))){
            headerData = firstRow.clone();
            rows.remove(0);
        }
        putEmptyTitleToNotFirstRow(rows);
        //======根据样品类型，动态处理“方法”、“签发”的值========start
        String confKey = "SJ_FormField";
        String docConfig = mainData.getDocumentConfig();
        JSONObject docConfigJson = (!ObjectUtils.isEmpty(docConfig)) ? JSONObject.parseObject(docConfig) : new JSONObject();
        String customConfig = docConfigJson.getString("customConfig");
        JSONObject customConfigJson = (!ObjectUtils.isEmpty(customConfig)) ? JSONObject.parseObject(customConfig) : new JSONObject();
        JSONObject confJson = customConfigJson.containsKey(confKey) ? customConfigJson.getJSONObject(confKey) : new JSONObject();
        String tongJingKuang = confJson.getString("tongJingKuang");
        String comprehensiveInspectionSample = confJson.getString("comprehensiveInspectionSample");
        String signatureKey = confJson.getString("signatureKey");
        String standardKey = confJson.getString("standardKey");
        String materialName = "";
        boolean hideMethod = false;
        boolean hideSignature = false;
        if(firstDataDO != null){
            String sampleTypeKey = firstDataDO.getSampleTypeKey();
            List<Map<String, Object>> baseSampleList = reportDocumentDataMapper.queryBaseSampleBySourceId(firstDataDO.getSourceId());
            if(!baseSampleList.isEmpty()){
                materialName = String.valueOf(baseSampleList.get(0).get("MTRL_NAME"));
            }

            if(!materialName.equals(tongJingKuang)){
                hideMethod = true;
                hideSignature = true;
            }else if(sampleTypeKey.equals(comprehensiveInspectionSample)){
                hideMethod = true;
            }
        }
        if(hideMethod){
            formDataJson.replace(standardKey, "/");
        }
        if(hideSignature){
            if(!ObjectUtils.isEmpty(signatureKey)){
                JSONObject opinion = signatureJson.getJSONObject(signatureKey);
                if(opinion != null){
                    opinion.replace("signTime", "");
                    opinion.replace("signatureId", "");
                    opinion.replace("userName", "/");
                    opinion.replace("signatureIdBase64", "");
                    opinion.replace("userId", "");
                }
            }
        }
        //======根据样品类型，动态处理“方法”、“签发”的值========end
        resultData.put("headerData", headerData);
        resultData.put("tableList", rows);
        resultData.put("formData", formDataJson);
        if(!ObjectUtils.isEmpty(signatureJsonStr))
            resultData.put("signatureData", signatureJson);
        return resultData;
    }

    private void putEmptyTitleToNotFirstRow(JSONArray rows){
        for(int i = 1; i < rows.size(); i++){
            JSONObject t = rows.getJSONObject(i);
            if(!rowTypeTitle.equals(t.getString(rowTypeKey))){
                continue;
            }
            String fixedColKeys = t.getString("fixedColKeys");
            if(ObjectUtils.isEmpty(fixedColKeys))
                continue;
            String[] keyV = fixedColKeys.split(",");
            for(String s : keyV){
                t.put(s, " ");
            }
//            t.put(colPrefix + "01", t.getString(colPrefix + "01"));
//            t.put(colPrefix + "01", "");
        }

    }

    private JSONArray assembleEmpty(JSONObject configJson, JSONArray rowList){
        if(rowList.isEmpty())
            return rowList;
        JSONArray fixedCol = configJson.getJSONArray("fixedCol");                       //固定列，举例：["SMP_NAME", "SMP_CD"]
        if(fixedCol == null) fixedCol = new JSONArray();
        JSONArray fixedColRight = configJson.getJSONArray("fixedColRight");                       //右侧固定列
        if(fixedColRight == null)   fixedColRight = new JSONArray();
        String dynamicColCountStr = configJson.getString("dynamicColCount");            //动态列（检测项）数量
        Integer dynamicColCount = 0;
        Integer fixedColCount_left = 0;
        Integer fixedColCount_right = 0;
        if(!ObjectUtils.isEmpty(dynamicColCountStr))    dynamicColCount = Integer.parseInt(dynamicColCountStr);
        fixedColCount_left = fixedCol.size();
        fixedColCount_right = fixedColRight.size();

        for(int i = 0; i < rowList.size(); i++){
            JSONObject row = rowList.getJSONObject(i);
            if(" ".equals(row.getString(colPrefix + "01")))
                continue;
            int colIndex = 1;
            while(colIndex <= dynamicColCount){
                String colKey = colPrefix + parseNumToString(colIndex + fixedColCount_left, 2);
                if(!row.containsKey(colKey))
                    row.put(colKey, "/");
                colIndex ++;
            }
        }
        return rowList;
    }

    /**
    * 将数据按colCount分组。返回2维数组
    * @param fieldList 要显示的字段列表。固定字段在最前
    * @param customConfig 报告配置项
    * */
    private JSONArray assembleStep1(JSONArray rowList, List<ConfigReportFieldDO> fieldList, List<ReportDocumentDataDO> dataList, String customConfig, int groupIndex){
        if(dataList.isEmpty())
            return new JSONArray();
        JSONObject jsonObject = JSONObject.parseObject(customConfig);
        Integer dynamicColCount = 3;
        Integer fixedColCount_left = 0;

        String dynamicColCountStr = jsonObject.getString("dynamicColCount");            //动态列（检测项）数量
        JSONArray fixedCol = jsonObject.getJSONArray("fixedCol");                       //固定列，举例：["SMP_NAME", "SMP_CD"]
        if(fixedCol == null) fixedCol = new JSONArray();
        JSONArray fixedColRight = jsonObject.getJSONArray("fixedColRight");                       //右侧固定列
        if(fixedColRight == null)   fixedColRight = new JSONArray();
        String hasRemark = jsonObject.getString("hasRemark");                           //是否有备注
        String hasRange = jsonObject.getString("hasRange");                             //是否有检出限
        String verticalFlag = jsonObject.getString("verticalFlag");                     //vertical-纵表， 否则为横表
        String fixedFields = jsonObject.getString("fixedFields");                       //固定检测项。如果固定检测项，则以检测项作为数据Key
        if("1".equals(verticalFlag)){   //纵表
            return assembleVerticalData(rowList, fieldList, dataList, customConfig);
        }
        if(!ObjectUtils.isEmpty(fixedFields)){  //固定列
            return assembleFixedFieldsData(rowList, fieldList, dataList, customConfig);
        }
        if(!ObjectUtils.isEmpty(dynamicColCountStr))    dynamicColCount = Integer.parseInt(dynamicColCountStr);
        fixedColCount_left = fixedCol.size();
        Integer colCountOneSample = fixedColCount_left + dynamicColCount;    //每个样品要占的列数
        //=============处理表头============
        JSONObject t = new JSONObject();
        JSONObject r = new JSONObject();    //检出限
        //取第一行数据，用来处理检出限
        JSONObject firstData = JSONObject.parseObject(dataList.get(0).getDocumentContent());        //取第一行数据，用于处理检出限
        if("1".equals(hasRemark)){
            //在最后一列增加备注
            t.put(colPrefix + parseNumToString(colCountOneSample + 1, 2), "备注");
        }
        //取fieldList的动态字段，并分组
        List<List<ConfigReportFieldDO>> dynamicFieldListGroup = new ArrayList<>();
        int fieldIndex = 1;
        List<ConfigReportFieldDO> list = new ArrayList<>();
        for(int i = 0; i < fieldList.size(); i++){
            ConfigReportFieldDO fieldDO = fieldList.get(i);
            String fieldType = fieldDO.getFieldType();
            if(FIELD_FIXED.equals(fieldType))
                continue;
            list.add(fieldDO);
            if(fieldIndex % dynamicColCount == 0){
                dynamicFieldListGroup.add(list);
                list = new ArrayList<>();
            }
            fieldIndex ++;
        }
        if(!list.isEmpty())
            dynamicFieldListGroup.add(list);
        int colIndex = 1;
        for(int i = 0; i < dynamicFieldListGroup.size(); i++){
            List<ConfigReportFieldDO> dynamicFieldList = dynamicFieldListGroup.get(i);
            t = new JSONObject();
            t.put(rowTypeKey, rowTypeTitle);
            r = new JSONObject();
            r.put(rowTypeKey, rowTypeLimit);
            colIndex = fixedColCount_left + 1;   //第二组以后，从固定列数开始
            for(ConfigReportFieldDO fieldDO : dynamicFieldList) {
                String field = fieldDO.getField();
                String fieldName = fieldDO.getFieldName();
                String colKey = parseNumToString(colIndex, 2);
                t.put(colPrefix + colKey, fieldName);
                //查询当前字段的检出限
                JSONObject fieldObj = null;
                if(firstData != null && !ObjectUtils.isEmpty(field)){
                    fieldObj = firstData.getJSONObject(field);
                }
                String rangeVal = "";
                if (fieldObj != null) {
                    rangeVal = fieldObj.getString(rangeKey);
                }
                r.put(colPrefix + colKey, rangeVal);
                r.put(colPrefix + "01", "方法检出限");
                colIndex ++;
            }
            //处理备注列
            if(i == 0 && groupIndex == 0 && "1".equals(hasRemark)){
                //在最后一列增加备注
                t.put(colPrefix + parseNumToString(colCountOneSample + 1, 2), "备注");
            }
            if(i > 0 || groupIndex > 0){        //插入空行
                JSONObject emptyRow = new JSONObject();
                putEmptyData(emptyRow, 1,10);
                rowList.add(emptyRow);
            }
            addTitleToRowList(fixedCol, fixedColRight, dynamicColCount, t, rowList, fieldList);
            //插入样品数据
            addDataToRowList(fixedCol, fixedColRight, dynamicFieldList, dataList, rowList, fixedColCount_left, dynamicColCount, hasRemark);
            //检出限
            if("1".equals(hasRange)){
                rowList.add(r);
            }
        }
        return rowList;
    }

    /**
     * @param
     *
     * */
    private void addTitleToRowList(JSONArray fixedCol, JSONArray fixedColRight, Integer dynamicColCount, JSONObject t, JSONArray rowList, List<ConfigReportFieldDO> fieldList){
        //处理固定列
        int index = 1;
        String colKey = "";
        //固定列-左
        String fixedColKeys = "";
        for(int i=0;i<fixedCol.size();i++) {
            String col = fixedCol.getString(i);
            for(ConfigReportFieldDO fieldDO : fieldList) {
                colKey = "";
                String fieldName = fieldDO.getFieldName();
                String fieldType = fieldDO.getFieldType();
                String field = fieldDO.getField();
                if (FIELD_DYNAMIC.equals(fieldType) || FIELD_CALCULATED.equals(fieldType))
                    continue;
                if(sampleNameAndCodeKey.equals( col) && sampleNameAndCodeKey.equals(field)
                        || sampleNameKey.equals( col) && sampleNameKey.equals(field)
                        || sampleCodeKey.equals( col) && sampleCodeKey.equals(field)
                        || entrustSampleNameKey.equals( col) && entrustSampleNameKey.equals(field)
                        || entrustSampleCodeKey.equals( col) && entrustSampleCodeKey.equals(field)
                        || entrustSampleNameCodeKey.equals( col) && entrustSampleNameCodeKey.equals(field)){
                    colKey = parseNumToString(index, 2);
                }
                if(!ObjectUtils.isEmpty(colKey)){
                    t.put(colPrefix + colKey, fieldName);
                    fixedColKeys += colPrefix + colKey + ",";
                    index++;
                }
            }
        }
        if(!ObjectUtils.isEmpty(fixedColKeys))
            fixedColKeys = fixedColKeys.substring(0, fixedColKeys.length() - 1);
        t.put("fixedColKeys", fixedColKeys);
        //固定列-右
        index = fixedCol.size() + dynamicColCount + 1;
        for(int i=0;i<fixedColRight.size();i++) {
            String col = fixedColRight.getString(i);
            for(ConfigReportFieldDO fieldDO : fieldList) {
                colKey = "";
                String fieldName = fieldDO.getFieldName();
                String fieldType = fieldDO.getFieldType();
                String field = fieldDO.getField();
                if (FIELD_DYNAMIC.equals(fieldType) || FIELD_CALCULATED.equals(fieldType))
                    continue;
                if(sampleNameAndCodeKey.equals( col) && sampleNameAndCodeKey.equals(field)
                        || sampleNameKey.equals( col) && sampleNameKey.equals(field)
                        || sampleCodeKey.equals( col) && sampleCodeKey.equals(field)
                        || entrustSampleNameKey.equals( col) && entrustSampleNameKey.equals(field)
                        || entrustSampleCodeKey.equals( col) && entrustSampleCodeKey.equals(field)
                        || entrustSampleNameCodeKey.equals( col) && entrustSampleNameCodeKey.equals(field)){
                    colKey = parseNumToString(index, 2);
                }
                if(!ObjectUtils.isEmpty(colKey)){
                    t.put(colPrefix + colKey, fieldName);
                    index++;
                }
            }
        }
        rowList.add(t.clone());
    }

    //添加行数据
    private void addDataToRowList(JSONArray fixedCol, JSONArray fixedColRight, List<ConfigReportFieldDO> fieldList, List<ReportDocumentDataDO> dataList, JSONArray rowList, int fixedColCount, int dynamicColCount, String hasRemark){
        int colIndex = 0;
        JSONObject t = new JSONObject();
        for(ReportDocumentDataDO dataDO : dataList){
            String documentContent = dataDO.getDocumentContent();
            String externalContent = dataDO.getExternalContent();
            JSONObject s = JSONObject.parseObject(documentContent);
            //判断样品是否有值，若无值则跳过
            boolean hasValue = false;
            for(ConfigReportFieldDO fieldDO : fieldList) {
                String fieldType = fieldDO.getFieldType();
                if (FIELD_FIXED.equals(fieldType))  //这里只处理动态列。固定列在 addDataToRowList 处理
                    continue;
                String field = fieldDO.getField();
                JSONObject fieldObj = new JSONObject();
                if(s != null)
                    fieldObj = s.getJSONObject(field);
                String fieldValue = "";
                if (fieldObj != null)
                    fieldValue = fieldObj.getString("fieldValue");
                if(!ObjectUtils.isEmpty(fieldValue))
                    hasValue = true;
            }
            if(!hasValue)
                continue;
            JSONObject e = new JSONObject();
            if(!ObjectUtils.isEmpty(externalContent))
                e = JSONObject.parseObject(externalContent);
            String remark = e.getString("remark");
            if(ObjectUtils.isEmpty(remark))
                remark = " ";
            colIndex = fixedColCount + 1;
            t = new JSONObject();
            int colCountOneSample = fixedColCount + dynamicColCount;
            if("1".equals(hasRemark)){
                t.put(colPrefix + parseNumToString(colCountOneSample + 1, 2), remark);
            }
            for(ConfigReportFieldDO fieldDO : fieldList){
                String fieldType = fieldDO.getFieldType();
                if(FIELD_FIXED.equals(fieldType)){  //这里只处理动态列。固定列在 addDataToRowList 处理
                    continue;
                }
                String field = fieldDO.getField();
                String colKey = parseNumToString(colIndex, 2);
                JSONObject fieldObj = s.getJSONObject( field);
                String fieldValue = "";
                String mathSymbol = "";
                if(fieldObj != null){
                    fieldValue = fieldObj.getString("fieldValue");
                    mathSymbol = fieldObj.getString("mathSymbol");
                }
                if(!ObjectUtils.isEmpty(mathSymbol) && !"=".equals(mathSymbol))
                    fieldValue = mathSymbol + fieldValue;
                if(ObjectUtils.isEmpty(fieldValue))
                    fieldValue = "/";
                t.put(colPrefix + colKey, fieldValue);
                colIndex++;
            }
            t.put("id", dataDO.getId());
            //处理固定列-左
            int index = 1;
            String colKey = "";
            for(int i=0;i<fixedCol.size();i++){
                String col = fixedCol.getString(i);
                colKey = parseNumToString(index, 2);
                if(sampleNameKey.equals(col)){
                    t.put(colPrefix + colKey, dataDO.getSampleName());
                }
                else if(sampleCodeKey.equals(col)){
                    t.put(colPrefix + colKey, dataDO.getSampleCode());
                }
                else if(sampleNameAndCodeKey.equals( col)){
                    t.put(colPrefix + colKey, dataDO.getSampleName() + " " + dataDO.getSampleCode());
                }else if(entrustSampleNameKey.equals( col)){
                    t.put(colPrefix + colKey, dataDO.getEntrustSampleName());
                }else if(entrustSampleCodeKey.equals( col)){
                    t.put(colPrefix + colKey, dataDO.getEntrustSampleCode());
                }else if(entrustSampleNameCodeKey.equals( col)){
                    t.put(colPrefix + colKey, dataDO.getEntrustSampleName() + " " + dataDO.getEntrustSampleCode());
                }
                index ++;
            }
            //处理固定列-右
            index = fixedColRight.size() + dynamicColCount + 1;
            for(int i=0;i<fixedColRight.size();i++){
                String col = fixedColRight.getString(i);
                colKey = parseNumToString(index, 2);
                if(sampleNameKey.equals(col)){
                    t.put(colPrefix + colKey, dataDO.getSampleName());
                }
                else if(sampleCodeKey.equals(col)){
                    t.put(colPrefix + colKey, dataDO.getSampleCode());
                }
                else if(sampleNameAndCodeKey.equals( col)){
                    t.put(colPrefix + colKey, dataDO.getSampleName() + " " + dataDO.getSampleCode());
                }else if(entrustSampleNameKey.equals( col)){
                    t.put(colPrefix + colKey, dataDO.getEntrustSampleName());
                }else if(entrustSampleCodeKey.equals( col)){
                    t.put(colPrefix + colKey, dataDO.getEntrustSampleCode());
                }else if(entrustSampleNameCodeKey.equals( col)){
                    t.put(colPrefix + colKey, dataDO.getEntrustSampleName() + " " + dataDO.getEntrustSampleCode());
                }
                index ++;
            }
            //添加入行数据
            rowList.add(t.clone());
        }
    }


    private String parseNumToString(int num, int len){
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < len - String.valueOf(num).length(); i++){
            sb.append("0");
        }
        return sb.append(num).toString();
    }

    /**
     * 组装固定检测项的数据，以检测项作为数据Key
     * */
    private JSONArray assembleFixedFieldsData(JSONArray rowList, List<ConfigReportFieldDO> fieldList, List<ReportDocumentDataDO> dataList, String customConfig){
        JSONObject jsonObject = JSONObject.parseObject(customConfig);

        Integer maxRowCount = 3;
        String maxRowCountStr = jsonObject.getString("maxRowCount");                    //最大行数
        String hasRemark = jsonObject.getString("hasRemark");                           //是否有备注
        String hasRange = jsonObject.getString("hasRange");                             //是否有检出限
        String fixedFields = jsonObject.getString("fixedFields");                       //固定检测项。如果固定检测项，则以检测项作为数据Key
        JSONArray fixedFieldsArray = JSONArray.parseArray(fixedFields);
        if(!ObjectUtils.isEmpty(maxRowCountStr))    maxRowCount = Integer.parseInt(maxRowCountStr);
//        for(int i = 0; i < maxRowCount; i++){
//            JSONObject row = new JSONObject();
//            row.put("sampleNameCode", " ");
//            row.put("sampleName", " ");
//            row.put("sampleCode", " ");
//            rowList.add( row);
//        }
        for(ReportDocumentDataDO dataDO : dataList) {
            JSONObject t = new JSONObject();
            String documentContent = dataDO.getDocumentContent();
            String externalContent = dataDO.getExternalContent();
            JSONObject s = JSONObject.parseObject(documentContent);
            JSONObject e = new JSONObject();
            if (!ObjectUtils.isEmpty(externalContent)) {
                e = JSONObject.parseObject(externalContent);
            }
            String remark = e.getString("remark");
            String sampleName = dataDO.getSampleName();
            String sampleCode = dataDO.getSampleCode();
            String sampleNameCode = sampleName + " " + sampleCode;
            t.put("id", dataDO.getId());
            t.put("sampleNameCode", sampleNameCode);
            t.put("sampleName", sampleName);
            t.put("sampleCode", sampleCode);
            t.put("remark", remark);
            for(ConfigReportFieldDO fieldDO : fieldList){
                String fieldName = fieldDO.getFieldName();
                String field = fieldDO.getField();
                for(int i=0;i<fixedFieldsArray.size();i++){
                    String fieldKey = fixedFieldsArray.getString(i);
                    if(!fieldName.equals(fieldKey))
                        continue;
                    JSONObject fieldObj = s.getJSONObject( field);
                    String fieldValue = "";
                    String mathSymbol = "";
                    if(fieldObj != null){
                        fieldValue = fieldObj.getString("fieldValue");
                        mathSymbol = fieldObj.getString("mathSymbol");
                    }
                    if(!ObjectUtils.isEmpty(mathSymbol) && !"=".equals(mathSymbol))
                        fieldValue = mathSymbol + fieldValue;
                    t.put(fieldName, fieldValue);
                }
            }
            rowList.add(t);
        }
        String lastRowText = emptyText;
        if(rowList.size() + 1 == maxRowCount)
            lastRowText = emptyTextLastRow;
        if(rowList.size() < maxRowCount){
            JSONObject t = new JSONObject();
            t.put("sampleNameCode", lastRowText);
            t.put("sampleName", lastRowText);
            t.put("sampleCode", lastRowText);
            rowList.add( t);
        }
        while(rowList.size() < maxRowCount){
            JSONObject t = new JSONObject();
            t.put("sampleNameCode", " ");
            t.put("sampleName", " ");
            t.put("sampleCode", " ");
            rowList.add( t);
        }
        return rowList;
    }

    /**
     * 组装纵表数据
     * 第1列固定为：元素； 第2列：方法检出限（%）；第三列开始为各个样品
    * */
    private JSONArray assembleVerticalData(JSONArray rowList, List<ConfigReportFieldDO> fieldList, List<ReportDocumentDataDO> dataList, String customConfig){
        JSONObject jsonObject = JSONObject.parseObject(customConfig);
        Integer dynamicColCount = 3;
        Integer fixedColCount = 1;
        Integer maxRowCount = 20;
        String hasRemark = jsonObject.getString("hasRemark");                   //是否有备注
        String hasRange = jsonObject.getString("hasRange");                     //是否有检出限
        if("1".equals(hasRange))
            fixedColCount ++;
        //取数据第一行，用于处理方法检出限
        String content = "";
        if(!ObjectUtils.isEmpty(dataList))
            content = dataList.get(0).getDocumentContent();
        JSONObject firstData = new JSONObject();
        if(!ObjectUtils.isEmpty(content)){
            firstData = JSONObject.parseObject(content);
        }
        //处理第一行-样品编号
        int colIndex = fixedColCount + 1;
        int rowIndex = 1;
        JSONObject t = new JSONObject();
        t.put(colPrefix + "01", "元素");
        if("1".equals(hasRange)){
            t.put(colPrefix + "02", "方法检出限");
        }
        for(ReportDocumentDataDO dataDO : dataList){
            String colKey = parseNumToString(colIndex, 2);
            t.put(colPrefix + colKey, dataDO.getSampleCode());
            colIndex++;
        }
        rowList.add(t);
        //处理其他行
        rowIndex = 1;
        for(ConfigReportFieldDO fieldDO : fieldList) {
            t = new JSONObject();
            String fieldType = fieldDO.getFieldType();
            String field = fieldDO.getField();
            if (FIELD_FIXED.equals(fieldType)) {  //这里只处理动态列。固定列在 addTitleToRowList 处理
                continue;
            }
            String fieldName = fieldDO.getFieldName();
            String colKey = "";
            t.put(colPrefix + "01", fieldName); //第1列：元素
            if("1".equals(hasRange)){
                //方法检出限
                JSONObject fieldObj = firstData.getJSONObject( field);
                String rangeVal = "";
                if(fieldObj != null){
                    rangeVal = fieldObj.getString(rangeKey);
                }
                t.put(colPrefix + "02", rangeVal); //第2列：检出限
            }
            colIndex = fixedColCount + 1;
            for(ReportDocumentDataDO dataDO : dataList){
                colKey = parseNumToString(colIndex, 2);
                content = dataDO.getDocumentContent();
                JSONObject dataJson = new JSONObject();
                if(!ObjectUtils.isEmpty(content)){
                    dataJson = JSONObject.parseObject(content);
                }
                JSONObject fieldObj = firstData.getJSONObject( field);
                String fieldValue = "";
                String mathSymbol = "";
                if(fieldObj != null){
                    fieldValue = fieldObj.getString("fieldValue");
                    mathSymbol = fieldObj.getString("mathSymbol");
                }
                if(!ObjectUtils.isEmpty(mathSymbol) && !"=".equals(mathSymbol))
                    fieldValue = mathSymbol + fieldValue;
                t.put(colPrefix + colKey, fieldValue);
                colIndex++;
            }

            rowList.add(t);
            rowIndex ++;
        }
        return rowList;
    }

    /**
     * 传入报表数据、检测项。生成报告数据
     *
     * */
    @Override
    public CommonResult<JSONArray> assembleByReportData(JSONObject jsonObject) {
        List<BusinessAssayReportDataDO> assayReportDataList = jsonObject.getJSONArray("assayReportDataList").toJavaList(BusinessAssayReportDataDO.class);
        List<String> itemNameList = jsonObject.getJSONArray("itemNameList").toJavaList(String.class);
        JSONObject signatureData = jsonObject.getJSONObject("signatureData");
        JSONObject formData = jsonObject.getJSONObject("formData");
        if(assayReportDataList.isEmpty() || itemNameList.isEmpty())
            return CommonResult.success(new JSONArray());
        String pageFlag = "1";
        String reportConfigStr = "{\n" +
                "  \"dynamicColCount\": 3,\n" +
                "  \"fixedCol\": [\n" +
                "    \"SMP_NAME_CD\"\n" +
                "  ],\n" +
                "  \"maxRowCount\": 25,\n" +
                "  \"hasRemark\": \"1\",\n" +
                "  \"hasRange\": \"0\",\n" +
                "  \"verticalFlag\":\"0\",\n" +
                "  \"defaultConclusion\": \"\"\n" +
                "}";
        DictionaryBusinessRespVO dictConf = dictionaryBusinessService.getDataByDataKey("工段报告表单编辑模板参数").getData();
        if(dictConf != null && !ObjectUtils.isEmpty(dictConf.getCustomConfig()))
            reportConfigStr = dictConf.getCustomConfig();
        ReportDocumentMainDO mainData = new ReportDocumentMainDO().builder().formData(formData.toJSONString()).documentSignature(signatureData.toJSONString()).documentConfig("").build();
        JSONObject configJson = JSONObject.parseObject(reportConfigStr);
        String verticalFlag = configJson.getString("verticalFlag");
        String maxRowCountStr = configJson.getString("maxRowCount");                    //最大行数
        Integer maxRowCount = 3;
        if(!ObjectUtils.isEmpty(maxRowCountStr))
            maxRowCount = Integer.parseInt(maxRowCountStr);
        //组装报表字段
        List<ConfigReportFieldDO> fieldListAll = new ArrayList<>();
        for(String itemName : itemNameList){
            ConfigReportFieldDO fieldDO = ConfigReportFieldDO.builder().fieldName(itemName).fieldType(FIELD_DYNAMIC).build();
            fieldListAll.add(fieldDO);
        }
        //通过数据反推field、组装报表数据
        List<ReportDocumentDataDO> dataList = new ArrayList<>();
        for(BusinessAssayReportDataDO assayReportData : assayReportDataList){
            String assayData = assayReportData.getAssayData();
            if(ObjectUtils.isEmpty(assayData))
                continue;
            JSONObject assayDataJson = JSONObject.parseObject(assayData);
            for(String dataKey : assayDataJson.keySet()){
                JSONObject dataJson = assayDataJson.getJSONObject(dataKey);
                String dataFieldName = dataJson.getString("fieldName");
                for(ConfigReportFieldDO fieldDO : fieldListAll){
                    String fieldName = fieldDO.getFieldName();
                    if(fieldName.equals(dataFieldName)){
                        fieldDO.setField(dataKey);
                        break;
                    }
                }
            }
            ReportDocumentDataDO dataDO = ReportDocumentDataDO.builder()
                    .sampleCode(assayReportData.getSampleCode())
                    .sampleName(assayReportData.getSampleName())
                    .baseSampleName(assayReportData.getBaseSampleName())
                    .documentContent(assayData)
                    .sampleTypeKey(assayReportData.getSampleTypeKey())
                    .entrustSampleName(assayReportData.getEntrustSampleName())
                    .entrustSampleCode(assayReportData.getEntrustSampleCode())
                    .sort(assayReportData.getEntrustDetailSort())
                    .build();
            dataList.add(dataDO);
        }
        //增加固定列
        ConfigReportFieldDO fixedFieldDO = ConfigReportFieldDO.builder().field(sampleNameAndCodeKey).fieldName("样品名称及编号").fieldType(FIELD_FIXED).build();
        fieldListAll.add(0, fixedFieldDO);

        ReportDocumentDataDO firstDataDO = null;
        if(!dataList.isEmpty())
            firstDataDO = dataList.get(0);
        //拆分dataList，按样品分类key拆分
        List<List<ReportDocumentDataDO>> dataListGroup = new ArrayList<>();
        String[] sampleTypeKeys = new String[]{"inspectionAnalysisSample", "comprehensiveInspectionSample"};    //商检分析样、商检综合样
        for(String sampleTypeKey : sampleTypeKeys){
            List<ReportDocumentDataDO> dataListByKey = new ArrayList<>();
            for(ReportDocumentDataDO dataDO: dataList){
                if(sampleTypeKey.equals(dataDO.getSampleTypeKey())){
                    dataListByKey.add(dataDO);
                }
            }
            if(!dataListByKey.isEmpty())
                dataListGroup.add(dataListByKey);
        }
        if(dataListGroup.isEmpty() && !dataList.isEmpty())
            dataListGroup.add(dataList);
        JSONArray rowList = new JSONArray();
        for(int i = 0; i < dataListGroup.size(); i++){
            List<ReportDocumentDataDO> dataListByKey = dataListGroup.get(i);
            //处理字段，提取有数据的字段
            List<ConfigReportFieldDO> fieldList = new ArrayList<>();
            List<String> hasFields = new ArrayList<>();
            for(ConfigReportFieldDO fieldDO : fieldListAll){
                String field = fieldDO.getField();
                String fieldName = fieldDO.getFieldName();
                String fieldType = fieldDO.getFieldType();
                //先处理固定列
                if(FIELD_FIXED.equals(fieldType)){
                    if(!hasFields.contains( field)){
                        fieldList.add(fieldDO);
                        hasFields.add(field);
                    }
                    continue;
                }
                for(ReportDocumentDataDO dataDO : dataListByKey){
                    String documentContent = dataDO.getDocumentContent();
                    JSONObject dataJson = JSONObject.parseObject(documentContent);
                    if(dataJson == null)
                        continue;
                    if(!dataJson.containsKey(field))
                        continue;
                    if(!hasFields.contains( fieldName)){
                        JSONObject valueJson = dataJson.getJSONObject(field);
                        String usage = valueJson.getString("usage");
                        if(!"report".equals( usage) && ! "ingredient_report".equals(usage))
                            continue;
                        fieldList.add(fieldDO);
                        hasFields.add(fieldName);
                    }
                }
            }
            assembleStep1(rowList, fieldList, dataListByKey, reportConfigStr, i);  //处理后的组数对象
        }
        if(!"1".equals(verticalFlag)){
            //处理空数据，填充/
            rowList = assembleEmpty(configJson, rowList);
            //处理数据分页
            if("1".equals(pageFlag)){
                JSONArray pageRowList = assemblePageRowList(rowList, configJson, mainData, firstDataDO);
                return CommonResult.success(pageRowList);
            }
        }
        //以下为空白
        if(rowList.size() < maxRowCount && !rowList.isEmpty()){
            JSONObject t = new JSONObject();
            t.put(colPrefix + "01", emptyText);
            putEmptyData(t, 2,10);
            rowList.add(t.clone());
        }
        while(rowList.size() < maxRowCount){
            JSONObject t = new JSONObject();
            putEmptyData(t, 1,10);
            rowList.add(t.clone());
        }
        JSONArray result = new JSONArray();
        JSONObject resultData = assembleResultData(mainData, rowList, firstDataDO);
        result.add(resultData);
        return CommonResult.success(result);
    }

    @Override
    public CommonResult<List<ReportDocumentDataDO>> listByMainDataId(Long mainDataId) {
        QueryWrapper<ReportDocumentDataDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("MAIN_ID", mainDataId);
        queryWrapper.orderByAsc("SRT");
        List<ReportDocumentDataDO> list = reportDocumentDataMapper.selectList(queryWrapper);
        return CommonResult.success(list);
    }

    @Override
    public CommonResult<Long> countMainDataId(Long mainDataId) {
        QueryWrapper<ReportDocumentDataDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("MAIN_ID", mainDataId);
        queryWrapper.orderByAsc("ID");
        return CommonResult.success(reportDocumentDataMapper.selectCount(queryWrapper));
    }

    /*
    * 处理报告签名*/
    @Override
    public String assembleSignature(String docSig) {
        if(ObjectUtils.isEmpty(docSig))
            return "";
        JSONObject docSigJson = JSONObject.parseObject(docSig);
        List<Long> sigIds = new ArrayList<>();
        docSigJson.forEach((key, value) -> {
            JSONObject obj = docSigJson.getJSONObject( key);
            String signatureId = obj.getString("signatureId");
            if(!ObjectUtils.isEmpty(signatureId))
                sigIds.add(Long.parseLong(signatureId));
        });
        if(sigIds.isEmpty())
            return docSigJson.toJSONString();
        List<ConfigUserSignatureDO> sigList = configUserSignatureService.getByIdList(sigIds);
        docSigJson.forEach((key, value) -> {
            JSONObject obj = docSigJson.getJSONObject( key);
            String signatureId = obj.getString("signatureId");
            if(!ObjectUtils.isEmpty(signatureId)){
                ConfigUserSignatureDO sig = sigList.stream().filter(item -> item.getId().equals(Long.parseLong(signatureId))).findFirst().orElse(null);
                if(sig != null){
                    String base64 = sig.getSignatureContent();
                    obj.put("signatureIdBase64", base64);
                }
            }
        });
        return docSigJson.toJSONString();
    }

    @Override
    public CommonResult<String> removeByMainIdAndDetailIds(Long mainDataId, List<Long> detailIds) {
        QueryWrapper<ReportDocumentDataDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("MAIN_ID", mainDataId);
        queryWrapper.in("ID", detailIds);
        reportDocumentDataMapper.delete(queryWrapper);
        return CommonResult.success("移除成功");
    }

    @Override
    public void deleteByMainId(Long mainId) {
        QueryWrapper<ReportDocumentDataDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("MAIN_ID", mainId);
        reportDocumentDataMapper.delete(queryWrapper);
    }

    @Override
    public ReportDocumentDataRespVO createReportDocumentData(ReportDocumentDataSaveReqVO createReqVO) {
        // 插入
        ReportDocumentDataDO reportDocumentData = BeanUtils.toBean(createReqVO, ReportDocumentDataDO.class);
        reportDocumentDataMapper.insert(reportDocumentData);
        // 返回
        return BeanUtils.toBean(reportDocumentData, ReportDocumentDataRespVO.class);
    }

    @Override
    public CommonResult<String> insertBatch(List<ReportDocumentDataDO> list) {
        reportDocumentDataMapper.insertBatch(list);
        return CommonResult.success("添加成功");
    }

    @Override
    public void updateReportDocumentData(ReportDocumentDataSaveReqVO updateReqVO) {
        // 校验存在
        validateReportDocumentDataExists(updateReqVO.getId());
        // 更新
        ReportDocumentDataDO updateObj = BeanUtils.toBean(updateReqVO, ReportDocumentDataDO.class);
        reportDocumentDataMapper.updateById(updateObj);
    }

    @Override
    public void updateBatch(List<ReportDocumentDataSaveReqVO> list) {
        List<ReportDocumentDataDO> updateList = new ArrayList<>();
        for (ReportDocumentDataSaveReqVO updateReqVO : list) {
            ReportDocumentDataDO updateObj = BeanUtils.toBean(updateReqVO, ReportDocumentDataDO.class);
            updateList.add(updateObj);
        }
        reportDocumentDataMapper.updateBatch(updateList);
    }

    @Override
    public void deleteReportDocumentData(Long id) {
        // 校验存在
        validateReportDocumentDataExists(id);
        // 删除
        reportDocumentDataMapper.deleteById(id);
    }

    @Override
    public void deleteReportDocumentDataListByIds(List<Long> ids) {
        // 校验存在
        validateReportDocumentDataExists(ids);
        // 删除
        reportDocumentDataMapper.deleteByIds(ids);
    }

    private void validateReportDocumentDataExists(List<Long> ids) {
        List<ReportDocumentDataDO> list = reportDocumentDataMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(REPORT_DOCUMENT_DATA_NOT_EXISTS);
        }
    }

    private void validateReportDocumentDataExists(Long id) {
        if (reportDocumentDataMapper.selectById(id) == null) {
            throw exception(REPORT_DOCUMENT_DATA_NOT_EXISTS);
        }
    }

    @Override
    public ReportDocumentDataDO getReportDocumentData(Long id) {
        return reportDocumentDataMapper.selectById(id);
    }

    @Override
    public PageResult<ReportDocumentDataDO> getReportDocumentDataPage(ReportDocumentDataPageReqVO pageReqVO) {
        return reportDocumentDataMapper.selectPage(pageReqVO);
    }

}