package com.suyun.utils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.suyun.common.result.RestResponse;
import com.suyun.common.result.Result;
import com.suyun.modules.vehicle.constants.ExcelInfoConstants;
import com.suyun.modules.vehicle.constants.StringConstants;
import com.suyun.modules.vehicle.form.ExcelInfo;
import com.suyun.modules.vehicle.form.ImportFailMessage;
import com.suyun.utils.json.JSONMapToBean;
import com.suyun.utils.json.ListToJSONArray;
import com.suyun.utils.json.SimpleJsonFormat;
import com.suyun.vehicle.utils.DatetimeUtil;
import com.suyun.vehicle.utils.ObjectUtil;
import com.thinkgem.jeesite.common.utils.excel.ExportExcel;
import com.thinkgem.jeesite.common.utils.excel.ImportExcel;
import com.thinkgem.jeesite.modules.sys.utils.DictUtils;
import com.thinkgem.jeesite.modules.sys.utils.UserUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.Row;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Description:
 * <p>
 * EXCEL 导出/导入/JAVA执行Excel公式
 * </p>
 *
 * @Author: leo.xiong
 * @CreateDate: 2022/11/24 10:46
 * @Email: leo.xiong@suyun360.com
 * @Since:
 */
public class ExcelUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(ExcelUtil.class);
    /**
     * 每次计算列个数最大为50
     */
    private static final int MAX_CACULATE_COLUMN = 50;

    /**
     * 公式计算
     *
     * @param formulaList
     * @return
     */
    public static Map<String, BigDecimal> caculateFormula(List<String> formulaList) {
        if (CollectionUtils.isEmpty(formulaList)) {
            return Collections.EMPTY_MAP;
        }
        HSSFWorkbook workbook = new HSSFWorkbook();
        HSSFSheet sheet = workbook.createSheet();
        HSSFFormulaEvaluator hssfFormulaEvaluator = new HSSFFormulaEvaluator(workbook);
        int rows = (formulaList.size() / MAX_CACULATE_COLUMN) + 1;
        AtomicInteger dataIndexAtomicInteger = new AtomicInteger(0);
        Map<String, BigDecimal> formulaBigDecimalMap = Maps.newConcurrentMap();
        int len = formulaList.size();
        for (int row = 0; row < rows; row++) {
            HSSFRow hssfRow = sheet.createRow(row);
            for (int column = 0; column < MAX_CACULATE_COLUMN; column++) {
                int index = dataIndexAtomicInteger.getAndIncrement();
                //考虑是否需要多线程并行计算
                if (index >= len) {
                    break;
                }
                HSSFCell hssfCell = hssfRow.createCell(column);
                hssfCell.setCellType(Cell.CELL_TYPE_FORMULA);
                String formula = formulaList.get(index);
                hssfCell.setCellFormula(formula);
                BigDecimal value = null;
                try {
                    value = new BigDecimal(hssfFormulaEvaluator.evaluate(hssfCell).getNumberValue())
                            .setScale(10, BigDecimal.ROUND_HALF_UP)
                            .stripTrailingZeros();
                } catch (Exception e) {
                    LOGGER.warn("计算错误 formula: {}", formula, e);
                    return null;
                }
                formulaBigDecimalMap.put(formula, value);
            }
        }
        return formulaBigDecimalMap;
    }

    /**
     * 将数据写入指定EXCEL,并用response直接写出到前端
     *
     * @param excel
     * @param filePath
     * @param props
     * @param dataList
     * @param request
     * @param response
     * @param flag     是否需要生成序号
     * @return
     */
    public static RestResponse exportExcelWithResponse(ExportExcel excel, String filePath, String[] props, List dataList,
                                                       HttpServletRequest request, HttpServletResponse response, boolean flag) {
        int index = 0;
        for (Object item : dataList) {
            Row row = excel.addRow();
            index++;
            for (int j = 0; j < props.length; j++) {
                Object cellValue;
                // 以“-”开头的属性,表示是固定值
                if (flag && j == 0) {
                    cellValue = index;
                } else if (props[j].startsWith(StringConstants.STRIPING_LINE)) {
                    cellValue = props[j].substring(1);
                    //以“:”分割的属性,表示需要字典转换
                } else if (props[j].contains(StringConstants.DEFAULT_COLON)) {
                    String[] propArrays = props[j].split(StringConstants.DEFAULT_COLON);
                    cellValue = ObjectUtil.getObjectProp(item, propArrays[0]);
                    cellValue = DictUtils.getDictLabel((String) cellValue, propArrays[1], "");
                } else {
                    cellValue = ObjectUtil.getObjectProp(item, props[j]);
                }
                excel.addCell(row, j, cellValue);
            }
        }
        try {
            excel.uploadWrite(request, response, filePath).dispose();
        } catch (IOException e) {
            e.printStackTrace();
            return new Result("uploadFile " + filePath + " error, Exception:" + e).newMessageTips(false, "-1", "导出失败");
        }
        return null;
    }

    public static RestResponse exportExcelWithNumber(String title, String filePath, Map<String, String> map, List list, String fomate, int deep, HttpServletRequest request, HttpServletResponse response, boolean flag) {
        ExcelTitle excelTitle = buildExcelTitle(map, flag);
        ExportExcel excel = new ExportExcel(title, excelTitle.getNames());
        int len = list.size() % ExcelInfoConstants.EXPORT_WRITE_ROW == 0 ? list.size() / ExcelInfoConstants.EXPORT_WRITE_ROW : (list.size() / ExcelInfoConstants.EXPORT_WRITE_ROW) + 1;
        List newList = new ArrayList();
        for (int i = 0; i < len; i++) {
            //遍历次数
            int size = i == len - 1 ? list.size() - i * ExcelInfoConstants.EXPORT_WRITE_ROW : ExcelInfoConstants.EXPORT_WRITE_ROW;
            for (int j = i * ExcelInfoConstants.EXPORT_WRITE_ROW, time = i * ExcelInfoConstants.EXPORT_WRITE_ROW + size; j < time; j++) {
                newList.add(list.get(j));
            }
            excel = exportExcel(excel, excelTitle.getCodes(), ListToJSONArray.getJSONArrayByList(newList, fomate, deep), i * ExcelInfoConstants.EXPORT_WRITE_ROW, flag);
            newList.clear();
        }
        return exportExcel(excel, filePath, request, response);
    }

    /**
     * 下载
     *
     * @param title
     * @param filePath
     * @param map
     * @param jsonArray
     * @param request
     * @param response
     * @param flag
     * @return
     */
    public static RestResponse exportExcelWithJSONArray(String title, String filePath, Map<String, String> map, JSONArray jsonArray,
                                                        HttpServletRequest request, HttpServletResponse response, boolean flag) {
        ExcelTitle excelTitle = buildExcelTitle(map, flag);
        ExportExcel excel = new ExportExcel(title, excelTitle.getNames());
        excel = exportExcel(excel, excelTitle.getCodes(), jsonArray, 0, flag);
        return exportExcel(excel, filePath, request, response);
    }

    /**
     * 写入数据信息
     *
     * @param excel
     * @param codes
     * @param jsonArray
     * @param index
     * @param flag
     * @return
     */
    public static ExportExcel exportExcel(ExportExcel excel, String[] codes, JSONArray jsonArray, Integer index, Boolean flag) {
        JSONObject jsonObject;
        int firstIndex = index;
        for (; index < firstIndex + jsonArray.size(); ) {
            jsonObject = jsonArray.getJSONObject(index - firstIndex);
            Row row = excel.addRow();
            Object cellValue;
            for (int i = 0, len = codes.length; i < len; i++) {
                Integer importDefault = null;
                if (codes[i].startsWith(ExcelInfoConstants.EXPORT_NO_DEFAULT)) {
                    String[] codeArray = codes[i].split(StringConstants.STRIPING_LINE);
                    codes[i] = codeArray[4];
                    importDefault = Integer.parseInt(codeArray[3]);
                }
                if (flag && "index".equals(codes[i])) {
                    cellValue = index + 1;
                } else if (codes[i].startsWith(StringConstants.STRIPING_LINE)) {
                    cellValue = codes[i].substring(1);
                    //以“:”分割的属性,表示需要字典转换
                } else if (codes[i].contains(StringConstants.DICT)) {
                    String[] propArrays = codes[i].split(StringConstants.DEFAULT_COLON);
                    cellValue = jsonObject.get(propArrays[1]);
                    if (cellValue != null) {
                        cellValue = DictUtils.getDictLabel(cellValue.toString(), propArrays[2], propArrays.length > 3 ? propArrays[3] : StringConstants.DEFAULT_EMPTY);
                    } else {
                        cellValue = propArrays.length > 3 ? propArrays[3] : StringConstants.DEFAULT_EMPTY;
                    }
                    //json多层嵌套
                } else if (codes[i].contains(StringConstants.DEFAULT_DOT)) {
                    cellValue = ListToJSONArray.getNesting(jsonObject, codes[i].split(StringConstants.SPLIT_DOT), 0);
                } else {
                    cellValue = jsonObject.get(codes[i]);
                }
                excel.addCell(row, i, cellValue, importDefault);
            }
            index += 1;
        }
        return excel;
    }

    public static ExportExcel exportExcel(ExportExcel excel, String[] codes, JSONArray jsonArray, int cloumn) {
        int index = 0;
        JSONObject jsonObject;
        for (; index < jsonArray.size(); ) {
            jsonObject = jsonArray.getJSONObject(index);
            Row row = excel.addRow();
            excel.addCell(row, 0, jsonObject.get(codes[0]));
            index += 1;
        }
        return excel;
    }

    public static ExportExcel exportExcel(ExportExcel excel, Map linkedHashMap, List<Map<String, Object>> maps) {
        linkedHashMap.forEach((k, v) -> {
            Row row = excel.addRow();
            excel.addCell(row, 0, v);
            Map map;
            for (int i = 0, len = maps.size(); i < len; i++) {
                map = maps.get(i);
                excel.addCell(row, i + 1, map.get(k));
            }
        });
        return excel;
    }

    public static ExportExcel exportExcel(ExportExcel excel, String[] cloumns) {
        Row row = excel.addRow();
        for (int i = 0; i < cloumns.length; i++) {
            excel.addCell(row, i, cloumns[i]);
        }
        return excel;
    }

    /**
     * 写出Excel
     *
     * @param excel
     * @param filePath
     * @param request
     * @param response
     * @return
     */
    public static RestResponse exportExcel(ExportExcel excel, String filePath, HttpServletRequest request, HttpServletResponse response) {
        try {
            excel.uploadWrite(request, response, filePath).dispose();
        } catch (IOException e) {
            LOGGER.error("写出数据异常,filePath:{},error:{}", e);
            return new Result("uploadFile " + filePath + " error, Exception:" + e).newMessageTips(false, "-1", "导出失败");
        }
        return null;
    }

    /**
     * 组装excel的头部信息
     *
     * @param map
     * @param flag
     * @return
     */
    public static ExcelTitle buildExcelTitle(Map<String, String> map, Boolean flag) {
        try {
            String[] codes, names;
            if (flag) {
                codes = new String[map.size() + 1];
                names = new String[map.size() + 1];
                codes[0] = "index";
                names[0] = UserUtils.isEn() ? "NO." : "序号";
            } else {
                codes = new String[map.size()];
                names = new String[map.size()];
            }
            String language = UserUtils.getLanguage();
            List<Map.Entry<String, String>> entryList = Lists.newArrayList(map.entrySet());
            for (int i = 0, len = entryList.size(); i < len; i++) {
                Map.Entry<String, String> entryValue = entryList.get(i);
                if (flag) {
                    codes[i + 1] = entryValue.getKey();
                    names[i + 1] = UserUtils.getValueByLanguage(entryValue.getValue(), language);
                } else {
                    codes[i] = entryValue.getKey();
                    names[i] = UserUtils.getValueByLanguage(entryValue.getValue(), language);
                }
            }
            return new ExcelTitle(codes, names);
        } catch (Exception e) {
            LOGGER.error(e.getMessage());
            return null;
        }
    }

    /**
     * 添加错误信息进入Map中
     *
     * @param map
     * @param rowNumber 使用excel遍历的i
     * @param message
     * @return
     */
    public static Map<Integer, List<String>> importFailInfo(Map<Integer, List<String>> map, Integer rowNumber, String message) {
        if (map == null) {
            map = new HashMap<>(16);
        }
        if (map.get(rowNumber + ExcelInfoConstants.EXCEL_ADD_CELL_NUMBER) == null) {
            map.put(rowNumber + ExcelInfoConstants.EXCEL_ADD_CELL_NUMBER, new ArrayList<>());
        }
        map.get(rowNumber + ExcelInfoConstants.EXCEL_ADD_CELL_NUMBER).add(message);
        return map;
    }

    public static boolean isSuccess(Map<Integer, List<String>> map, Integer rowNumber) {
        return !CollectionUtils.isEmpty(map) && map.get(rowNumber + 1) != null;
    }

    /**
     * 通过ExcelFile获取列信息
     * 一次导入数据量不用超过500条
     *
     * @param map   导入失败的存储信息,key第几行失败,value,失败的原因集合
     * @param file  需要导入的文件流
     * @param cells 定义的列信息,参照ImportColumnName接口规范
     * @return
     */
    public static ExcelInfo getRowInfosByFile(Map<Integer, List<String>> map, MultipartFile file, Map<Integer, String[]> cells) {
        boolean isEn = UserUtils.isEn();
        if (file.isEmpty()) {
            ExcelUtil.importFailInfo(map, -3, isEn ? "file does not exist" : "文件不存在");
            return null;
        }
        ImportExcel ei;
        try {
            ei = new ImportExcel(file, 0, 0);
        } catch (InvalidFormatException | IOException e) {
            ExcelUtil.importFailInfo(map, -1, isEn ? "excel import failed" : "excel导入失败" + e);
            return null;
        }
        Row r = ei.getRow(0);
        if (isEmptyRow(r)) {
            ExcelUtil.importFailInfo(map, -5, isEn ? "excel is empty" : "excel为空");
            return null;
        }
        //校验列名是否都正确,判断是否使用模版
        AtomicInteger atomicInteger = new AtomicInteger(-1);
        Row finalR = r;
        try {
            cells.forEach((index, columnName) -> {
                String excelColumnName = finalR.getCell(index).getStringCellValue();
                if (excelColumnName.indexOf("\n") > -1) {
                    excelColumnName = excelColumnName.replace("\n", " ");
                }
                String columnNameValue = UserUtils.getCurrentValue(columnName[0]);
                if (!columnNameValue.equalsIgnoreCase(excelColumnName)) {
                    if (isEn) {
                        ExcelUtil.importFailInfo(map, -2, "The " + (index + 1) + " column name of the column is abnormal, the template is" + columnNameValue + ", the template is used incorrectly, please download the template and import it again");
                    } else {
                        ExcelUtil.importFailInfo(map, -2, "第" + (index + 1) + "列的列名异常,模版为" + columnNameValue + ",模板使用错误,请下载模板重新导入");
                    }
                    atomicInteger.set(index);
                }
            });
        } catch (Exception e) {
        }
        if (atomicInteger.get() != -1) {
            return null;
        }
        List<Integer> columns = new ArrayList(cells.keySet());
        ExcelInfo excelInfo = new ExcelInfo(ei.getLastDataRowNum(), columns);
        for (int i = ei.getDataRowNum(), len = ei.getLastDataRowNum(); i <= len; i++) {
            r = ei.getRow(i);
            if (isEmptyRow(r)) {
                continue;
            }
            insertColumnInfoToExcelInfo(map, cells, excelInfo, r, columns, i);
        }
        validateNoRepeaterColumn(map, cells, excelInfo);
        validateDoubleRepeate(map, cells, excelInfo);
        return excelInfo;
    }

    /**
     * 判断当前行是否为空
     *
     * @param row
     * @return
     */
    public static boolean isEmptyRow(Row row) {
        if (row == null) {
            return true;
        }
        for (int c = row.getFirstCellNum(); c < row.getLastCellNum(); c++) {
            Cell cell = row.getCell(c);
            if (cell != null && !StringConstants.DEFAULT_EMPTY.equals(cell.toString())) {
                return false;
            }
        }
        return true;
    }

    /**
     * 添加excle数据进入ExcelInfo对象中
     *
     * @param map
     * @param cells
     * @param excelInfo
     * @param r
     * @param columns
     * @param i         : EXCEL行号
     */
    private static void insertColumnInfoToExcelInfo(Map<Integer, List<String>> map, Map<Integer, String[]> cells, ExcelInfo excelInfo, Row r, List<Integer> columns, int i) {
        boolean isEn = UserUtils.isEn();
        cells.forEach((index, columnType) -> {
            String columnName = UserUtils.getCurrentValue(columnType[0]);
            Cell cell = r.getCell(columns.get(index));
            Object obj = null;
            if (cell != null && StringUtils.isNotEmpty(cell.toString().trim())) {
                try {
                    switch (columnType[1]) {
                        case ExcelInfoConstants.INTEGER:
                            cell.setCellType(Cell.CELL_TYPE_NUMERIC);
                            obj = Double.valueOf(cell.getNumericCellValue()).intValue();
                            break;
                        case ExcelInfoConstants.DOUBLE:
                            cell.setCellType(Cell.CELL_TYPE_NUMERIC);
                            obj = Double.valueOf(cell.getNumericCellValue());
                            break;
                        case ExcelInfoConstants.DATE:
                            if (DateUtil.isCellDateFormatted(cell)) {
                                String pattern = columnType.length > 4 ? columnType[4] : DatetimeUtil.TIME_FORMAT_Y_M_D;
                                obj = DatetimeUtil.changeToDate(DatetimeUtil.formatDate(cell.getDateCellValue(), pattern), pattern);
                            } else {
                                ExcelUtil.importFailInfo(map, (i - 1), columnName + (isEn ? "time format exception" : "时间格式异常"));
                            }
                            break;
                        case ExcelInfoConstants.BOOLEAN:
                            cell.setCellType(Cell.CELL_TYPE_BOOLEAN);
                            obj = cell.getBooleanCellValue();
                            break;
                        default:
                            /**
                             * 常规类型不做处理,特殊情况需要设置cell属性,否则报错
                             */
                            try {
                                obj = cell.getStringCellValue().trim();
                            } catch (Exception e) {
                            }
                            if (obj == null || StringConstants.DEFAULT_EMPTY.equals(obj)) {
                                cell.setCellType(Cell.CELL_TYPE_STRING);
                                obj = cell.getStringCellValue().trim();
                                if (StringConstants.DEFAULT_EMPTY.equals(obj)) {
                                    obj = null;
                                }
                            }
                            if (columnType.length > 5) {
                                String val = obj.toString();
                                if (columnType[5].contains(StringConstants.VERTICAL_LINE)) {
                                    String[] strValueList = columnType[5].split("\\" + StringConstants.VERTICAL_LINE);
                                    for (String str : strValueList) {
                                        String[] strValues = str.split(StringConstants.DEFAULT_EQUAL_SIGN);
                                        str = UserUtils.getCurrentValue(strValues[0]);
                                        if (str.contains(val)) {
                                            obj = strValues[1];
                                            break;
                                        }
                                    }
                                } else if (columnType[5].contains(StringConstants.DICT)) {
                                    String[] labels = columnType[5].split(StringConstants.DEFAULT_COLON);
                                    obj = DictUtils.getDictValue(val, labels[1], labels.length > 2 ? labels[2] : StringConstants.DEFAULT_EMPTY);
                                }
                                if (StringUtils.isEmpty(obj.toString()) && ExcelInfoConstants.CAN_NOT_NULL.equals(columnType[3])) {
                                    ExcelUtil.importFailInfo(map, (i - 1), columnName + (isEn ? "Data conversion exception, dictionary mapping information does not exist" : "数据转换异常,字典映射信息不存在"));
                                }
                            }
                            break;
                    }
                } catch (Exception e) {
                    ExcelUtil.importFailInfo(map, (i - 1), columnName + (isEn ? "type" : "类型") + columnType[1] + (isEn ? "Abnormal data format" : "数据格式异常"));
                }
            } else if (ExcelInfoConstants.CAN_NOT_NULL.equals(columnType[3])) {
                ExcelUtil.importFailInfo(map, (i - 1), columnName + (isEn ? "Can not be empty" : "不能为空"));
            }
            if (excelInfo.getRowsMap().get(i) == null) {
                excelInfo.getRowsMap().put(i, new HashMap<>(16));
            }
            if (columnType[2].indexOf(StringConstants.DEFAULT_DOT) > -1) {
                String[] columnsName = columnType[2].split(StringConstants.SPLIT_DOT);
                if (excelInfo.getRowsMap().get(i).get(columnsName[0]) == null) {
                    excelInfo.getRowsMap().get(i).put(columnsName[0], new HashMap<>());
                }
                ((Map) (excelInfo.getRowsMap().get(i).get(columnsName[0]))).put(columnsName[1], obj);
            } else {
                excelInfo.getRowsMap().get(i).put(columnType[2], obj);
            }
            excelInfo.getColumnsMap().get(index).add(obj);
        });
    }

    /**
     * 对标记为不能重复的列进行判断
     *
     * @param map
     * @param cells
     * @param excelInfo
     */
    private static void validateNoRepeaterColumn(Map<Integer, List<String>> map, Map<Integer, String[]> cells, ExcelInfo excelInfo) {
        cells.forEach((index, columnType) -> {
            if (columnType.length > 4 && ExcelInfoConstants.NO_REPEAT.equals(columnType[4])) {
                validateRepeateInfo(map, UserUtils.getCurrentValue(columnType[0]), excelInfo.getColumnsMap().get(index), columnType);
            }
        });
    }

    /**
     * 多个字段比较重复
     *
     * @param map
     * @param cells
     * @param excelInfo
     */
    private static void validateDoubleRepeate(Map<Integer, List<String>> map, Map<Integer, String[]> cells, ExcelInfo excelInfo) {
        cells.forEach((index, columnType) -> {
            if (columnType.length > 4 && columnType[4].startsWith(ExcelInfoConstants.DOUBLE_REPEAT)) {
                String[] doubleIndexs = columnType[4].split("_");
                String prefix = "";
                for (int j = 2, len = doubleIndexs.length; j < len; j++) {
                    prefix += UserUtils.getCurrentValue(cells.get(Integer.parseInt(doubleIndexs[j]))[0]) + "、";
                }
                prefix = prefix.substring(0, prefix.length() - 1);
                int size = excelInfo.getRowsMap().size();
                Object[] repeatInfos = new Object[size];
                for (int j = 2, len = doubleIndexs.length; j < len; j++) {
                    List<Object> columnsInfos = excelInfo.getColumnsMap().get(Integer.parseInt(doubleIndexs[j]));
                    for (int i = 0; i < size; i++) {
                        repeatInfos[i] = repeatInfos[i] == null ? columnsInfos.get(i) : columnsInfos.get(i) + String.valueOf(repeatInfos[i]);
                    }
                }
                validateRepeateInfo(map, prefix, Lists.newArrayList(repeatInfos), columnType);
            }
        });
    }

    /**
     * 判断list是否出现重复
     *
     * @param map
     * @param prefix
     * @param columnValues
     * @param columnType
     */
    private static void validateRepeateInfo(Map<Integer, List<String>> map, String prefix, List<Object> columnValues, String[] columnType) {
        Set<Object> columnSet = Sets.newHashSet(columnValues);
        boolean isEn = UserUtils.isEn();
        if (columnValues.size() != columnSet.size()) {
            Map<Object, RepeateValue> repeaterValueMap = new HashMap<>(16);
            for (int i = 0; i < columnValues.size(); i++) {
                if (ObjectUtil.isEmpty(columnValues.get(i))) {
                    continue;
                }
                RepeateValue repeateValue = repeaterValueMap.get(columnValues.get(i));
                if (repeateValue == null) {
                    Set<Integer> setValues = new TreeSet<>();
                    setValues.add(i);
                    repeateValue = new RepeateValue((i + 2) + "", setValues);
                    repeaterValueMap.put(columnValues.get(i), repeateValue);
                } else {
                    repeateValue.setMsg(repeateValue.getMsg() + "、" + (i + 2));
                    repeateValue.getRepeateValues().add(i);
                }
            }
            List<RepeateValue> list = new ArrayList<>(repeaterValueMap.values());
            list.removeIf(repeaterValue -> repeaterValue.getRepeateValues().size() < 2);
            list.forEach(repeaterValue -> {
                repeaterValue.getRepeateValues().forEach(columnIndex -> {
                    ExcelUtil.importFailInfo(map, columnIndex, prefix + repeaterValue.getMsg() + (isEn ? " repeat" : "重复"));
                });
            });
        }
    }

    /**
     * 把行信息转换为对象信息。
     *
     * @param clazz   需要转换的对象
     * @param rowsMap 行信息
     * @return
     */
    public static <T> List<T> addObjectToData(Class<T> clazz, Map<Integer, Map<String, Object>> rowsMap) {
        List<T> data = new ArrayList<>(rowsMap.size());
        //获取所有的行数
        rowsMap.forEach((index, value) -> {
            data.add(JSONMapToBean.caseToJavaBean(JSONObject.parseObject(new SimpleJsonFormat(value).serialize()), clazz));
        });
        return data;
    }

    /**
     * Excel数据不为空
     *
     * @param excelInfo
     * @param importFailMessage
     * @return
     */
    public static boolean isNotEmpty(ExcelInfo excelInfo, ImportFailMessage importFailMessage) {
        boolean flag = false;
        int total = 0, fail = 0;
        if (excelInfo != null && excelInfo.getColumnsMap() != null) {
            if (excelInfo.getColumnsMap().size() <= 0) {
                ExcelUtil.importFailInfo(importFailMessage.getMap(), -6, UserUtils.isEn() ? "Import data is empty" : "导入数据为空");
            } else {
                total = excelInfo.getRowsMap().size();
                flag = true;
            }
        }
        importFailMessage.setTotal(total);
        importFailMessage.setFail(fail);
        return flag;
    }

    /**
     * Excel 数据为空
     *
     * @param excelInfo
     * @param importFailMessage
     * @return
     */
    public static boolean isEmpty(ExcelInfo excelInfo, ImportFailMessage importFailMessage) {
        return !isNotEmpty(excelInfo, importFailMessage);
    }

    /**
     * 校验后,不存在错误数据
     *
     * @param importFailMessage
     * @return
     */
    public static boolean isEmptyFail(ImportFailMessage importFailMessage) {
        boolean flag = true;
        if (!CollectionUtils.isEmpty(importFailMessage.getMap())) {
            importFailMessage.setFail(importFailMessage.getMap().size());
            flag = false;
        }
        return flag;
    }

    /**
     * 校验后,存在错误数据,并设置错误数据条数
     *
     * @param importFailMessage
     * @return
     */
    public static boolean isNotEmptyFail(ImportFailMessage importFailMessage) {
        return !isEmptyFail(importFailMessage);
    }
}

class ExcelTitle {
    private String[] codes;
    private String[] names;

    public String[] getCodes() {
        return codes;
    }

    public void setCodes(String[] codes) {
        this.codes = codes;
    }

    public String[] getNames() {
        return names;
    }

    public void setNames(String[] names) {
        this.names = names;
    }

    public ExcelTitle(String[] codes, String[] names) {
        this.codes = codes;
        this.names = names;
    }
}

class RepeateValue {
    private String msg;
    private Set<Integer> repeateValues;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Set<Integer> getRepeateValues() {
        return repeateValues;
    }

    public void setRepeateValues(Set<Integer> repeateValues) {
        this.repeateValues = repeateValues;
    }

    public RepeateValue(String msg, Set<Integer> repeateValues) {
        this.msg = msg;
        this.repeateValues = repeateValues;
    }
}
package com.suyun.modules.vehicle.constants;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @Description:导出配置信息 (导出和返回类型的字段信息映射,建议直接放在Entity里面)
 * @Author: leo.xiong
 * @CreateDate: 2019/1/8 15:02
 * @Email: leo.xiong@suyun360.com
 * @Version:
 */
public interface ExportProperty {
    /**
     * 导出规则
     * 1、保留小数位数信息
     * INT,LONG,默认保留0位小数
     * Double默认保留2位小数
     * Float默认保留1位小数
     * BigDecimal默认保留2位小数
     * 修改默认保留小数位数可以使用ExcelInfoConstants.EXPORT_NO_DEFAULT开头,中间是保留位数,后面是取值的属性
     * ExcelInfoConstants.EXPORT_NO_DEFAULT + "_1_driverMileage"
     * 2、支持数据字典获取值,格式 dict:属性名称:对应字典的type名称,如dict:chargeAndDischargeStatus:hydBottleStatus:未知
     * 前面表示获取氢瓶存放状态在数据库里面的值,后面表示根据hydBottleStatus和对应值查询字典对应的中文信息
     * 3、已"-"开头,表示直接取值"-"后面的内容,不支持一个数据多条横杠信息
     * 4、flag参数表示是否需要添加默认的索引信息
     * 5、支持多层子查询取值,只查询用".",如:busInfo.busModel.name
     */
    /**
     * OTS存储生命周求
     */
    Map<String, String> OTS_SAVE_LIFE_CYCLE = new LinkedHashMap() {{
        put("busInfo.busModel.name", "{\"zh\":\"车型\",\"en\":\"Plate No\"}");
        put("busInfo.plateNo", "{\"zh\":\"车牌号\",\"en\":\"Plate No\"}");
        put("enableTime", "{\"zh\":\"配置生效日期\",\"en\":\"start time\"}");
        put("unableTime", "{\"zh\":\"配置失效日期\",\"en\":\"End Time\"}");
        put("dict:active:isActive:", "{\"zh\":\"生效状态\",\"en\":\"Start purge flow\"}");
        put("dict:otsLifeCycle:ots_table_life_cycle:", "{\"zh\":\"生命周期\",\"en\":\"Driving Total Mileage\"}");
        put("companyName", "{\"zh\":\"公司\",\"en\":\"End purge flow\"}");
        put("createName", "{\"zh\":\"配置人\",\"en\":\"Driving Total Time\"}");
    }};
}

在这里插入图片描述

package com.suyun.modules.vehicle.constants;

/**
 * @Description:EXCEL辅助常量信息
 * @Author: leo.xiong
 * @CreateDate: 2019/1/8 15:02
 * @Email: leo.xiong@suyun360.com
 * @Version:
 */
public interface ExcelInfoConstants {
    /**
     * 初始读取位置
     */
    Integer FIRST_INDEX = 0;
    /**
     * 每次读取增加一个单元格
     */
    Integer EXCEL_ADD_CELL_NUMBER = 1;
    /**
     * 支持的数据格式
     */
    String INTEGER = "INTEGER";
    String DOUBLE = "DOUBLE";
    String DATE = "DATE";
    String BOOLEAN = "BOOLEAN";
    String STRING = "STRING";
    /**
     * 该单元格是否可以为空
     */
    String CAN_NULL = "NULL";
    String CAN_NOT_NULL = "NOT NULL";
    /**
     * 该单元格是否可以重复
     */
    String CAN_REPEAT = "CAN_REPEAT";
    String NO_REPEAT = "NO_REPEAT";
    /**
     * 出现多个字段共同判断重复使用
     */
    String DOUBLE_REPEAT = "DOUBLE_REPEAT";
    /**
     * 修改默认的导出保留小数位数使用
     */
    String EXPORT_NO_DEFAULT = "EXPORT_NO_DEFAULT";
    /**
     * 导出每次落盘的数据条数
     */
    Integer EXPORT_WRITE_ROW = 500;
}

java 设置表格公式 java执行excel公式_excel

package com.suyun.modules.vehicle.constants;

import java.util.HashMap;
import java.util.Map;

/**
 * @Description:导入配置信息 (导入信息和实体字段的配置信息,建议直接放在Entity里面)
 * @Author: leo.xiong
 * @CreateDate: 2019/1/8 15:03
 * @Email: leo.xiong@suyun360.com
 * @Version:
 */
public interface ImportColumnName {
    /**
     * INTEGER,DOUBLE,STRING,BOOLEAN,DATE,TIMESTAMP
     * 子对象目前只支持2层处理;
     * 第一个参数表示模版的列名称;
     * 第二个参数表示获取的数据类型;
     * 第三个参数表示对应的对象取值属性;
     * 第四个参数表示是否需要校验为空;
     * 属性为DATE第五个参数表示时间类型的格式化规则;
     * 属性为非DATE第五个参数表示是否可以重复;
     * 多个字段联合不能重复为第五个参数,用StatusType.DOUBLE_REPEATE 开头,下划线分开,后面接索引(包含当前字段索引)
     * 属性为String第六个参数表示转换的值,支持数据字典格式 dict:province_location_code:默认值;
     * 注意:阿里接口的属性是取得set方法,所以属性第一个字母为大写,set方法会变为小写。模版存在“\n”会替换为“ ”;
     */
    /**
     * 车型计算公式
     */
    Map<Integer, String[]> BUS_MODEL_FORMULA_MAP = new HashMap() {{
        put(0, new String[]{"{\"en\":\"*Business name\",\"zh\":\"*业务分析名称\"}", ExcelInfoConstants.STRING, "caculateBusiness", ExcelInfoConstants.CAN_NULL, ExcelInfoConstants.CAN_REPEAT});
        put(1, new String[]{"{\"en\":\"*X name\",\"zh\":\"*横轴名称\"}", ExcelInfoConstants.STRING, "xName", ExcelInfoConstants.CAN_NULL, ExcelInfoConstants.CAN_REPEAT});
        put(2, new String[]{"{\"en\":\"*Y name\",\"zh\":\"*纵轴名称\"}", ExcelInfoConstants.STRING, "yName", ExcelInfoConstants.CAN_NULL, ExcelInfoConstants.CAN_REPEAT});
        put(3, new String[]{"{\"en\":\"*Bus model\",\"zh\":\"*车型\"}", ExcelInfoConstants.STRING, "modelName", ExcelInfoConstants.CAN_NULL, ExcelInfoConstants.CAN_REPEAT});
        put(4, new String[]{"{\"en\":\"*Signal name\",\"zh\":\"*信号名称\"}", ExcelInfoConstants.STRING, "signalName", ExcelInfoConstants.CAN_NULL, ExcelInfoConstants.CAN_REPEAT});
        put(5, new String[]{"{\"en\":\"Delay num\",\"zh\":\"Delay行数\"}", ExcelInfoConstants.STRING, "delayNum", ExcelInfoConstants.CAN_NULL, ExcelInfoConstants.CAN_REPEAT});
        put(6, new String[]{"{\"en\":\"Delay formula\",\"zh\":\"Delay计算公式\"}", ExcelInfoConstants.STRING, "delayFormula", ExcelInfoConstants.CAN_NULL, ExcelInfoConstants.CAN_REPEAT});
        put(7, new String[]{"{\"en\":\"Delay select\",\"zh\":\"Delay结果筛选\"}", ExcelInfoConstants.STRING, "delaySelect", ExcelInfoConstants.CAN_NULL, ExcelInfoConstants.CAN_REPEAT});
        put(8, new String[]{"{\"en\":\"Before select\",\"zh\":\"前置筛选\"}", ExcelInfoConstants.STRING, "processBefore", ExcelInfoConstants.CAN_NULL, ExcelInfoConstants.CAN_REPEAT});
        put(9, new String[]{"{\"en\":\"*X excel formula\",\"zh\":\"*横坐标计算公式\"}", ExcelInfoConstants.STRING, "xExcelFormula", ExcelInfoConstants.CAN_NULL, ExcelInfoConstants.CAN_REPEAT});
        put(10, new String[]{"{\"en\":\"*Y excel formula\",\"zh\":\"*纵坐标计算公式\"}", ExcelInfoConstants.STRING, "yExcelFormula", ExcelInfoConstants.CAN_NULL, ExcelInfoConstants.CAN_REPEAT});
        put(11, new String[]{"{\"en\":\"X after select\",\"zh\":\"横坐标后置筛选\"}", ExcelInfoConstants.STRING, "xProcessAfter", ExcelInfoConstants.CAN_NULL, ExcelInfoConstants.CAN_REPEAT});
        put(12, new String[]{"{\"en\":\"Y after select\",\"zh\":\"纵坐标后置筛选\"}", ExcelInfoConstants.STRING, "yProcessAfter", ExcelInfoConstants.CAN_NULL, ExcelInfoConstants.CAN_REPEAT});
        put(13, new String[]{"{\"en\":\"X min value\",\"zh\":\"横轴最小值\"}", ExcelInfoConstants.STRING, "xMinValue", ExcelInfoConstants.CAN_NULL, ExcelInfoConstants.CAN_REPEAT});
        put(14, new String[]{"{\"en\":\"X max value\",\"zh\":\"横轴最大值\"}", ExcelInfoConstants.STRING, "xMaxValue", ExcelInfoConstants.CAN_NULL, ExcelInfoConstants.CAN_REPEAT});
        put(15, new String[]{"{\"en\":\"X number tick\",\"zh\":\"横轴分割值\"}", ExcelInfoConstants.STRING, "xNumberTick", ExcelInfoConstants.CAN_NULL, ExcelInfoConstants.CAN_REPEAT});
        put(16, new String[]{"{\"en\":\"Y min value\",\"zh\":\"纵轴最小值\"}", ExcelInfoConstants.STRING, "yMinValue", ExcelInfoConstants.CAN_NULL, ExcelInfoConstants.CAN_REPEAT});
        put(17, new String[]{"{\"en\":\"Y max value\",\"zh\":\"纵轴最大值\"}", ExcelInfoConstants.STRING, "yMaxValue", ExcelInfoConstants.CAN_NULL, ExcelInfoConstants.CAN_REPEAT});
        put(18, new String[]{"{\"en\":\"Y number tick\",\"zh\":\"纵轴分割值\"}", ExcelInfoConstants.STRING, "yNumberTick", ExcelInfoConstants.CAN_NULL, ExcelInfoConstants.CAN_REPEAT});
    }};
}

java 设置表格公式 java执行excel公式_excel_02