package com.yifu.cloud.plus.v1.yifu.common.core.util;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.CacheConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.CommonConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.ExcelAttribute;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.ValidityConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.exception.ExcelException;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Pattern;

/**
 * @Author fxj
 * @Date 2022/6/23
 * @Description
 * @Version 1.0
 */
@Data
@Slf4j
public class ExcelUtil <T> implements Serializable {
	private Class<T> clazz;
	/**
	 * 用于返回错误信息
	 */
	private List<ErrorMessage> errorInfo;

	private HashMap<Integer, ErrorMessage> errorMessageHashMap;

	/**
	 * 用于返回实体
	 */
	private List<T> entityList;

	public ExcelUtil(Class<T> clazz) {
		this.clazz = clazz;
		this.fields =clazz.getDeclaredFields();
	}
	private Field[] fields;

	public void convertEntity(T vo, String[] exportFields, Map<String,String> diyDicMap, String dateFormat) {
		// 得到所有定义字段
		Field[] allFields = clazz.getDeclaredFields();
		List<Field> fields = new ArrayList<>();
		Class<?> superClazz = clazz.getSuperclass();
		// 将需要字典表头存起来备用，如果没传，则全部翻译
		List<String> allField = new ArrayList<>();
		ExcelAttribute annotation;
		for (Field field : allFields) {
			if (field.isAnnotationPresent(ExcelAttribute.class)) {
				fields.add(field);
				annotation = field.getAnnotation(ExcelAttribute.class);
				if (annotation != null && Common.isNotNull(annotation.name())) {
					allField.add(annotation.name());
				}
			}
		}
		if (Common.isEmpty(exportFields) && !allField.isEmpty()) {
			exportFields = new String[allField.size()];
			for (int i = 0; i < allField.size(); i++) {
				exportFields[i] = allField.get(i);
			}
		}
		if (superClazz != null) {
			Field[] superFields = superClazz.getDeclaredFields();
			for (Field field : superFields) {
				if (field.isAnnotationPresent(ExcelAttribute.class)) {
					fields.add(field);
				}
			}
		}

		fields = getFiledsByParamFiled(fields, exportFields);
		ExcelAttribute attr;
		Field field;
		//分割符
		String divider;
		for (int j = 0; j < fields.size(); j++) {
			// 获得field
			field = fields.get(j);
			// 设置实体类私有属性可访问
			field.setAccessible(true);
			attr = field.getAnnotation(ExcelAttribute.class);
			if (attr.isExport()) {
				// 如果数据存在就填入,不存在填入空格
				Class<?> classType = field.getType();
				String value = null;
				Date date;
				try {
					if (field.get(vo) != null && (classType.isAssignableFrom(Date.class) || classType.isAssignableFrom(LocalDateTime.class) || classType.isAssignableFrom(LocalDate.class))) {
						if (Common.isNotNull(attr.dateFormatExport())) {
							date = DateUtil.stringToDate2(String.valueOf(field.get(vo)), attr.dateFormatExport());
							if (classType.isAssignableFrom(LocalDateTime.class)){
								value = LocalDateTimeUtils.formatTime((LocalDateTime)field.get(vo),attr.dateFormatExport());
							}else {
								value = DateUtil.dateToString(date, attr.dateFormatExport());
							}
						} else {
							date = DateUtil.stringToDate2(String.valueOf(field.get(vo)), !Common.isNotNull(dateFormat) ? DateUtil.ISO_EXPANDED_DATE_FORMAT : dateFormat);
							if (classType.isAssignableFrom(LocalDateTime.class)){
								value = LocalDateTimeUtils.formatTime((LocalDateTime)field.get(vo),!Common.isNotNull(dateFormat) ? DateUtil.ISO_EXPANDED_DATE_FORMAT : dateFormat);
							}else {
								value = cn.hutool.core.date.DateUtil.format(date, !Common.isNotNull(dateFormat) ? DateUtil.ISO_EXPANDED_DATE_FORMAT : dateFormat);
							}
						}
					}
					//如果有默认字典数据直接取值
					if (Common.isNotNull(attr.readConverterExp())) {
						value = convertByExp(field.get(vo) == null ? "" : String.valueOf(field.get(vo)), attr.readConverterExp());
					} else if (attr.isDataId()) {
						//加入分割符逻辑
						divider = attr.divider();
						if (!"".equals(divider) && field.get(vo) != null){
							try {
								value = "";
								for(String key : String.valueOf(field.get(vo)).split(divider)){
									value += getLableById(attr, diyDicMap, key) + divider;
								}
								if(Common.isNotNull(value)){
									value = value.substring(0,value.length()-1);
								}
							}catch (Exception e){
								log.error("excel数据导出字符切割错误",e);
								value = "字符切割错误";
							}
						} else {
							//如果是字典数据ID或区域ID 去dicMap（包含了区域） 取值 取不到返回空
							value = getLableById(attr, diyDicMap, field.get(vo) == null ? "" : String.valueOf(field.get(vo)));
						}
					} else if (attr.isArea()){
						//区域字段处理 TODO
						value = getAreaLabel((String) field.get(vo));
					}
					field.set(vo, Common.isNotNull(value)?value:field.get(vo));
				}catch (Exception e){
					log.error("字典数据解析异常",e);
				}
			}
		}
	}
	/**
	 * 通过标志_字典ID的方式去dicMap 取值
	 *
	 * @param attr
	 * @param dicMap 字典值  key: 类型标识_ID  value：实际要导出的内容
	 * @param value  对应字段的ID值
	 * @return
	 * @Author fxj
	 * @Date 2019-08-06
	 **/
	private String getLableById(ExcelAttribute attr, Map<String, String> dicMap, String value) {
		String tempValue = null;
		if (null != dicMap && dicMap.size() > 0 && Common.isNotNull(value)) {
			if (Common.isNotNull(attr.dataType())) {
				tempValue =  dicMap.get(attr.dataType() + CommonConstants.DOWN_LINE_STRING + value);
				if (Common.isEmpty(tempValue)){
					tempValue  = dicMap.get(attr.dataType() + CommonConstants.DOWN_LINE_STRING +"id"+CommonConstants.DOWN_LINE_STRING +  value);
				}
			} else {
				tempValue = dicMap.get(value);
			}
		}
		// 默认字典获取不到 去 缓存获取
		if (Common.isEmpty(tempValue) && Common.isNotNull(attr.dataType())){
			Map<String,String> dicObj = (Map<String, String>) RedisUtil.redis.opsForValue()
					.get(CacheConstants.DICT_DETAILS
					+ CommonConstants.COLON_STRING
					+attr.dataType());
			if (dicObj != null) {
				for (Map.Entry<String, String> entry : dicObj.entrySet()) {
					if (Common.isNotNull(entry.getKey()) && entry.getKey().equals(value.trim())) {
						tempValue = entry.getValue();
						break;
					}
				}
			}
		}
		return tempValue;
	}
	/**
	 * @Author fxj
	 * @Description  单独转义字典值
	 * @Date 15:26 2022/11/8
	 * @Param
	 * @return
	**/
	public static String getDicValueByDataType(String value, String dataType){
		String tempStr = null;
		Map<String,String> dicObj = (Map<String, String>) RedisUtil.redis.opsForValue()
				.get(CacheConstants.DICT_DETAILS
						+ CommonConstants.COLON_STRING
						+ dataType);
		for (Map.Entry<String,String> entry:dicObj.entrySet()){
			if (Common.isNotNull(entry.getValue()) && entry.getValue().equals(value.trim())){
				tempStr = entry.getKey();
				break;
			}
		}
		return tempStr;
	}
	/**
	 * 返回传参对应的fileds
	 *
	 * @param fields
	 * @param paramFields
	 * @return
	 * @Author fxj
	 * @Date 2019-08-05
	 **/
	private List<Field> getFiledsByParamFiled(List<Field> fields, String[] paramFields) {
		List<Field> fieldsTemp = new ArrayList<Field>();
		List<String> attrName = new ArrayList();//存中文名 wangan修改
		if (null != paramFields && paramFields.length > 0) {
			ExcelAttribute attr;
			Field field;
			for (int j = 0; j < paramFields.length; j++) {
				for (int i = 0; i < fields.size(); i++) {
					field = fields.get(i);
					attr = field.getAnnotation(ExcelAttribute.class);
					//如果有同样的中文名数据字段，后面不再添加。  wangan修改
					if (!attrName.contains(attr.name())) {
						if (attr.name().equals(paramFields[j])) {
							fieldsTemp.add(field);
							attrName.add(attr.name());
							break;
						}
					}
				}
			}
		} else {
			return fields;
		}
		return fieldsTemp;
	}
	public ErrorMessage checkEntity(T data , Integer rowNum) {
		if (!Common.isNotNull(fields)){
			return null;
		}
		//存储错误数据
		Class<?> fieldType;
		String error = "";
		String c = null;
		//临时存储单元格数据
		String tempStr = "";
		ErrorMessage errorTemp = null;
		errorMessageHashMap = new HashMap<>();
		Map<String,Field> mapArea = new HashMap<>();
		// 参数校验
		ExcelAttribute attr = null;
		try{

			for (Field field : fields) {
				if (field == null) {
					continue;
				}
				tempStr=null;
				// 设置实体类私有属性可访问
				field.setAccessible(true);
				attr = field.getAnnotation(ExcelAttribute.class);
				if (Common.isEmpty(attr)){
					continue;
				}
				// 单元格中的内容.
				c = getStringValByObject(field.get(data));
				if (c != null) {
					c = c.trim();
				}
				//校验字段是否符合要求 返回错误信息
				error = validateUtil(c, attr, rowNum);
				if (null != error) {
					errorMessageHashMap = initErrorMessage(errorMessageHashMap, new ErrorMessage(rowNum, error), errorTemp);
					continue;
				}
				//单元格数据为空不需要处理了
				if (!StringUtils.isNotBlank(c)) {
					continue;
				}
				//如果是需要从字典表取值数据的话在这里处理即可

				if (Common.isNotNull(attr.readConverterExp())) {
					tempStr= reverseByExp( c, attr.readConverterExp());
					if (Common.isEmpty(tempStr)){
						errorMessageHashMap = initErrorMessage(errorMessageHashMap, new ErrorMessage(rowNum, "未找到:" + c + "的字典数据"), errorTemp);
						continue;
					}else {
						c = tempStr;
					}
				} else if (attr.isDataId()) {
					if (Common.isNotNull(attr.dataType())) {
						//非区域字段处理 TODO
						tempStr = getDicValue(c, tempStr, attr,rowNum,errorTemp);
					/*if (Common.isNotNull(attr.parentField())){
						tempStr = dicMap.get(attr.dataType() + "_" + c.trim() + "_" + getFieldValueByName(attr.parentField(), entity, DateUtil.ISO_EXPANDED_DATE_FORMAT));
					}else {
						tempStr = dicMap.get(attr.dataType() + "_" + c.trim());
					}*/

					}
				}else {
					if (attr.isArea()) {
						//区域字段处理 TODO
						if (!Common.isNotNull(attr.parentField())) {
							tempStr = getAreaValue(c.trim(), tempStr, attr,rowNum,errorTemp);
						} else {
							// TODO
							tempStr = getAreaValue(c.trim()+ "_" + getFieldValueByName(attr.parentField(), data, DateUtil.ISO_EXPANDED_DATE_FORMAT), tempStr, attr,rowNum,errorTemp);
						}
					}
				}
				if (StringUtils.isEmpty(tempStr) && (attr.isArea() || attr.isDataId())) {
					if (attr.isOrgan()) {
						errorMessageHashMap = initErrorMessage(errorMessageHashMap, new ErrorMessage(rowNum, "未找到:" + c + "的单位或项目数据，请确认存在项目权限"), errorTemp);
					}
					if (attr.isArea()) {
						errorMessageHashMap = initErrorMessage(errorMessageHashMap, new ErrorMessage(rowNum, "未找到:" + c + "的区域数据"), errorTemp);
					} else {
						if (Common.isNotNull(attr.errorInfoImport())) {
							errorMessageHashMap = initErrorMessage(errorMessageHashMap, new ErrorMessage(rowNum, "数据'" + c + "':" + attr.errorInfoImport()), errorTemp);
						} else {
							errorMessageHashMap = initErrorMessage(errorMessageHashMap, new ErrorMessage(rowNum, "未找到:" + c + "的字典数据"), errorTemp);
						}
					}
					continue;
				}
				if (Common.isNotNull(tempStr)){
					c = tempStr;
					mapArea.put(tempStr+CommonConstants.DOWN_LINE_STRING+attr.name(),field);
				}
				// 取得类型,并根据对象类型设置值.
				fieldType = field.getType();
				if (fieldType == null) {
					continue;
				}
				if (attr.isArea()){
					// 区域字段单独处理
					continue;
				}else if (String.class == fieldType) {
					field.set(data, c);
				} else if (BigDecimal.class == fieldType) {
					c = c.indexOf('%') != -1 ? c.replace("%", "") : c;
					field.set(data, BigDecimal.valueOf(Double.valueOf(c)));
				} else if (Date.class == fieldType && Common.isNotNull(c.trim())) {
					field.set(data, DateUtil.parseDate(c.trim(), Common.isEmpty(attr.dateFormat()) ? DateUtil.ISO_EXPANDED_DATE_FORMAT : attr.dateFormat()));
				} else if ((Integer.TYPE == fieldType) || (Integer.class == fieldType)) {
					field.set(data, Integer.parseInt(c));
				} else if ((Long.TYPE == fieldType) || (Long.class == fieldType)) {
					field.set(data, Long.valueOf(c));
				} else if ((Float.TYPE == fieldType) || (Float.class == fieldType)) {
					field.set(data, Float.valueOf(c));
				} else if ((Short.TYPE == fieldType) || (Short.class == fieldType)) {
					field.set(data, Short.valueOf(c));
				} else if ((Double.TYPE == fieldType) || (Double.class == fieldType)) {
					field.set(data, Double.valueOf(c));
				} else if (Character.TYPE == fieldType) {
					if ((c != null) && (c.length() > 0)) {
						field.set(data, Character.valueOf(c.charAt(0)));
					}
				} else if (LocalDateTime.class == fieldType && Common.isNotNull(c.trim())) {
					String dc = c.trim().replace(CommonConstants.CENTER_SPLIT_LINE_STRING, "")
							.replace(CommonConstants.SLASH_SPLIT_LINE_STRING, "");
					try {
						if (dc.length() > CommonConstants.EIGHT_INT) {
							field.set(data, LocalDateTimeUtils.convertDateToLDT(DateUtil.stringToDate(dc, DateUtil.DATETIME_PATTERN_CONTAINS)));
						}else {
							field.set(data, LocalDateTimeUtils.convertDateToLDT(DateUtil.stringToDate(dc, DateUtil.ISO_DATE_FORMAT)));
						}
					} catch (Exception e) {
						if (dc.length() > CommonConstants.EIGHT_INT) {
							errorMessageHashMap = initErrorMessage(errorMessageHashMap,
									new ErrorMessage(rowNum, attr.name() + "：" +
											c.trim() + "应满足时间格式：" + DateUtil.DATETIME_PATTERN_SECOND), errorTemp);
							continue;
						} else {
							errorMessageHashMap = initErrorMessage(errorMessageHashMap,
									new ErrorMessage(rowNum, attr.name() + "：" +
											c.trim() + "应满足时间格式：" + DateUtil.ISO_DATE_FORMAT), errorTemp);
							continue;
						}
					}
				} else if (LocalDate.class == fieldType && Common.isNotNull(c.trim())) {
					try {
						field.set(data, LocalDate.parse(c.trim().replace(CommonConstants.CENTER_SPLIT_LINE_STRING, ""), DateTimeFormatter.ofPattern(DateUtil.ISO_DATE_FORMAT)));

					} catch (Exception e) {
						errorMessageHashMap = initErrorMessage(errorMessageHashMap, new ErrorMessage(rowNum, attr.name() + "：" + c.trim() + "应满足时间格式：" + DateUtil.ISO_DATE_FORMAT), errorTemp);
						continue;
					}
				}
			}
			if (Common.isNotNull(mapArea)){
				for (Map.Entry<String, Field> entry: mapArea.entrySet()){
					entry.getValue().set(data,entry.getKey().substring(0,entry.getKey().indexOf(CommonConstants.DOWN_LINE_STRING)));
				}
			}
		}catch (Exception e){
			errorMessageHashMap = initErrorMessage(errorMessageHashMap, new ErrorMessage(rowNum, attr.name() + "：" + c.trim() + "校验异常，请联系管理人员"), errorTemp);
		}finally {

		}
		return errorMessageHashMap.get(rowNum);
	}
	/**
	 * 例如：解析值 0=男,1=女,2=未知  传参 男解析为 0
	 *
	 * @param propertyValue 参数值
	 * @param converterExp  翻译注解
	 * @return 解析后值
	 * @throws Exception
	 */
	public static String reverseByExp(String propertyValue, String converterExp) throws Exception {
		try {
			String[] convertSource = converterExp.split(",");
			for (String item : convertSource) {
				String[] itemArray = item.split("=");
				if (itemArray[1].equals(propertyValue)) {
					return itemArray[0];
				}
			}
		} catch (Exception e) {
			throw e;
		}
		return null;
	}

	/**
	 * 例如：解析值 0=男,1=女,2=未知  传参 0解析为 男
	 *
	 * @param propertyValue 参数值
	 * @param converterExp  翻译注解
	 * @return 解析后值
	 * @throws Exception
	 */
	public static String convertByExp(String propertyValue, String converterExp) throws Exception {
		try {
			String[] convertSource = converterExp.split(",");
			if(propertyValue.contains(",")){
				String[] valueSource = propertyValue.split(",");
				propertyValue = "";
				for(String value:valueSource){
					for (String item : convertSource) {
						String[] itemArray = item.split("=");
						if (itemArray[0].equals(value)) {
							propertyValue += itemArray[1] + ",";
							break;
						}
					}
				}
				if(propertyValue.endsWith(",")){
					propertyValue = propertyValue.substring(CommonConstants.dingleDigitIntArray[0],propertyValue.length()-1);
				}
			}else{
				for (String item : convertSource) {
					String[] itemArray = item.split("=");
					if (itemArray[0].equals(propertyValue)) {
						return itemArray[1];
					}
				}
			}
		} catch (Exception e) {
			throw e;
		}
		return propertyValue;
	}
	private String getAreaLabel(String c) {
		return (String)RedisUtil.redis.opsForValue().get(CacheConstants.AREA_LABEL + c);
	}

	public String getAreaLabelPublic(String c) {
		return (String)RedisUtil.redis.opsForValue().get(CacheConstants.AREA_LABEL + c);
	}

	private String getAreaValue(String c, String tempStr, ExcelAttribute attr,Integer rowNum, ErrorMessage errorTemp) {
		tempStr =  String.valueOf(RedisUtil.redis.opsForValue().get(CacheConstants.AREA_VALUE + c));
		if (Common.isEmpty(tempStr)){
			errorMessageHashMap = initErrorMessage(errorMessageHashMap, new ErrorMessage(rowNum, attr.name() + "：" + c.trim() + "校验异常"), errorTemp);
			return CommonConstants.EMPTY_STRING;
		}
		return tempStr;
	}

	// 简单的获取区域字典value
	public static String getRedisAreaValue(String c) {
		Object value = RedisUtil.redis.opsForValue().get(c);
		if (value != null) {
			return String.valueOf(value);
		} else {
			return null;
		}
	}

	private String getDicValue(String c, String tempStr, ExcelAttribute attr,Integer rowNum, ErrorMessage errorTemp) {
		Map<String,String> dicObj = (Map<String, String>) RedisUtil.redis.opsForValue()
				.get(CacheConstants.DICT_DETAILS
				+ CommonConstants.COLON_STRING
				+attr.dataType());
		boolean flag = true;
		for (Map.Entry<String,String> entry:dicObj.entrySet()){
			if (Common.isNotNull(entry.getValue()) && entry.getValue().equals(c.trim())){
				if (attr.isConvert()){
					tempStr = entry.getKey();
				}else {
					tempStr = c;
				}
				flag = false;
				break;
			}
		}
		if (flag){
			errorMessageHashMap = initErrorMessage(errorMessageHashMap, new ErrorMessage(rowNum, attr.name() + "：" + c.trim() + "校验异常，请联系管理人员"), errorTemp);
		return CommonConstants.EMPTY_STRING;
		}
		return tempStr;
	}

	/**
	 * @param fieldName 字段名
	 * @param o         对象
	 * @return 字段值
	 * @MethodName : getFieldValueByName
	 * @Description : 根据字段名获取字段值
	 */
	public static Object getFieldValueByName(String fieldName, Object o, String dateFormat) {

		Object value = null;
		Field field = null;
		if (o == null) {
			return "";
		}
		field = getFieldByName(fieldName, o.getClass());
		String type = getFieldType(fieldName, o.getClass());
		if (field != null) {
			field.setAccessible(true);
			try {
				if (null != type && type.equals("Date")) {
					Date date = (Date) field.get(o);
					return DateUtil.dateToString(date, dateFormat == null ? "yyyy-MM-dd" : dateFormat);
				} else {
					value = field.get(o);
				}
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		} else {
			log.info(o.getClass().getSimpleName() + "类不存在字段名 " + fieldName);
		}

		return value;
	}

	/**
	 * @param fieldName 字段名
	 * @param clazz     包含该字段的类
	 * @return 字段
	 * @MethodName : getFieldByName
	 * @Description : 根据字段名获取字段
	 */
	private static Field getFieldByName(String fieldName, Class<?> clazz) {
		// 拿到本类的所有字段
		Field[] selfFields = clazz.getDeclaredFields();

		// 如果本类中存在该字段，则返回
		for (Field field : selfFields) {
			if (field.getName().equals(fieldName)) {
				return field;
			}
		}
		// 否则，查看父类中是否存在此字段，如果有则返回
		Class<?> superClazz = clazz.getSuperclass();
		if (superClazz != null && superClazz != Object.class) {
			return getFieldByName(fieldName, superClazz);
		}

		// 如果本类和父类都没有，则返回空
		return null;
	}
	/**
	 * @param fieldName 字段名
	 * @param clazz     包含该字段的类
	 * @return 字段
	 * @MethodName : getFieldType
	 * @Description : 根据字段名获取字段类型
	 */
	private static String getFieldType(String fieldName, Class<?> clazz) {
		// 拿到本类的所有字段
		Field[] selfFields = clazz.getDeclaredFields();

		// 如果本类中存在该字段，则返回
		for (Field field : selfFields) {
			if (field.getName().equals(fieldName)) {
				//如果type是类类型，则前面包含"class "，后面跟类名
				String type = field.getGenericType().toString();
				if (type.equals("class java.lang.String")) {
					return "String";
				} else if (type.equals("class java.lang.Integer")) {
					return "Integer";
				} else if (type.equals("class java.lang.Short")) {
					return "Short";
				} else if (type.equals("class java.lang.Double")) {
					return "Double";
				} else if (type.equals("class java.lang.Boolean")) {
					return "Boolean";
				} else if (type.equals("class java.util.Date")) {
					return "Date";
				} else {
					return null;
				}
			}
		}
		// 否则，查看父类中是否存在此字段，如果有则返回
		Class<?> superClazz = clazz.getSuperclass();
		if (superClazz != null && superClazz != Object.class) {
			return getFieldType(fieldName, superClazz);
		}
		// 如果本类和父类都没有，则返回空
		return null;
	}
	/**
	 * 输出错误数据
	 *
	 * @param attr
	 * @param msg
	 * @param i
	 * @return
	 */
	private String errorInfo(ExcelAttribute attr, String msg, Integer i) {
		return (Common.isEmpty(msg) ? (Common.isEmpty(attr.errorInfo()) ? "" : attr.errorInfo()) : (attr.name() + msg));
	}
	/**
	 * 正则匹配返回
	 *
	 * @param c
	 * @param attr
	 * @param pattern
	 * @return
	 * @Author fxj
	 * @Date 2019-08-06
	 **/
	private boolean getMatchRes(String c, ExcelAttribute attr, String pattern) {
		return !c.matches(Common.isEmpty(attr.pattern()) ? pattern : attr.pattern());
	}
	/**
	 * 实现各种校验方式的错误返回新
	 *
	 * @param c
	 * @param attr
	 * @param i
	 * @return
	 */
	private String validateUtil(String c, ExcelAttribute attr, int i) {
		//非空校验
		if (attr.isNotEmpty() && !Common.isNotNull(c)) {
			return errorInfo(attr, "_不可为空", i);
		}
		if (Common.isNotNull(c)) {
			//日期格式校验
			if (attr.isDate()) {
				if (null == DateUtil.stringToDate(c.trim(), "yyyyMMdd")) {
					return errorInfo(attr, "_日期格式有误", i);
				}
			}
			//手机号码校验
			if (attr.isPhone() && getMatchRes(c.trim(), attr, ValidityConstants.MOBILE_PATTERN)) {
				return errorInfo(attr, "_手机号码有误", i);
			}
			//身份证校验
			if (attr.isIdCard() && getMatchRes(c.trim(), attr, ValidityConstants.IDCARD_PATTERN)) {
				return errorInfo(attr, "_身份证格式有误", i);
			}
			//邮箱验证
			if (attr.isEmail() && getMatchRes(c.trim(), attr, ValidityConstants.EMAIL_PATTERN)) {
				return errorInfo(attr, "_邮箱格式有误", i);
			}
			//integer 验证
			if (attr.isInteger() && getMatchRes(c.trim(), attr, ValidityConstants.INTEGER_PATTERN)) {
				return errorInfo(attr, "_整数格式有误", i);
			}
			//float、double 验证
			if (attr.isFloat() && getMatchRes(c.trim(), attr, ValidityConstants.FLOAT_PATTERN)) {
				return errorInfo(attr, "_数字格式有误", i);
			}
			if (attr.isDouble() && getMatchRes(c.trim(), attr, ValidityConstants.FLOAT_PATTERN)) {
				return errorInfo(attr, "_数字格式有误", i);
			}
			//最大长度校验
			if (attr.maxLength() > 0 && c.length() > attr.maxLength()) {
				return errorInfo(attr, "_超出最大长度", i);
			}
			//最大值校验
			if (Common.isNotNull(attr.max()) && !CommonConstants.ZERO_STRING.equals(attr.max())) {
				if (Common.isNumber(c)) {
					if (attr.isDouble() && Double.doubleToLongBits(Double.valueOf(c).doubleValue()) > Double.valueOf(attr.max()).doubleValue()){
						return errorInfo(attr, "_超出最大值", i);
					}else if (attr.isFloat() &&
							BigDecimalUtils.strToBigdecimal(c).compareTo(BigDecimalUtils.strToBigdecimal(attr.max())) > 0){
						return errorInfo(attr, "_超出最大值", i);
					}else{
						if (Float.valueOf(c).intValue() > Float.valueOf(attr.max()).intValue()) {
							return errorInfo(attr, "_超出最大值", i);
						}
					}
				} else {
					return errorInfo(attr, "_必须为数字且最多两位小数", i);
				}
			}
			//最小值校验
			if (attr.min() > 0) {
				if (Common.isNumber(c)) {
					if (attr.isFloat()){
						if (Float.valueOf(c).compareTo(attr.min()) < CommonConstants.ZERO_INT) {
							return errorInfo(attr, "_小于最小值", i);
						}
					}else{
						if (String.valueOf(Float.valueOf(c).intValue()).length()  < attr.min()) {
							return errorInfo(attr, "_长度小于" + Float.valueOf(attr.min()).intValue() + "位", i);
						}
					}
				} else {
					return errorInfo(attr, "_必须为数字且最多两位小数", i);
				}
			}
		}
		return null;
	}

	/**
	 * 根据属性名获取属性值
	 *
	 * @param fieldName
	 * @param hashMap
	 * @return
	 */
	private static Object getFieldValueByName(String fieldName, HashMap hashMap) {
		try {
			return hashMap.get(fieldName);
		} catch (Exception e) {
			return null;
		}
	}
	/**
	 * 按类型统一返回String内容
	 *
	 * @param param
	 * @return
	 */
	private static String getStringValByObject(Object param) {
		if (null == param) {
			return null;
		} else if (param instanceof Integer) {
			return Integer.toString(((Integer) param).intValue());
		} else if (param instanceof String) {
			return (String) param;
		} else if (param instanceof Double) {
			return Double.toString(((Double) param).doubleValue());
		} else if (param instanceof Float) {
			return Float.toString(((Float) param).floatValue());
		} else if (param instanceof Long) {
			return Long.toString(((Long) param).longValue());
		} else if (param instanceof Boolean) {
			return Boolean.toString(((Boolean) param).booleanValue());
		} else if (param instanceof Date) {
			return DateUtil.dateToString((Date) param);
		} else if (param instanceof LocalDateTime) {
			return LocalDateTimeUtils.formatTime((LocalDateTime) param, DateUtil.DATETIME_PATTERN_SECOND);
		} else {
			return param.toString();
		}
	}

	private HashMap<Integer, ErrorMessage> initErrorMessage(HashMap<Integer, ErrorMessage> errorMessageHashMap, ErrorMessage errorMessage, ErrorMessage temp) {
		if (null != errorMessageHashMap && null != errorMessage) {
			temp = errorMessageHashMap.get(errorMessage.getLineNum());
			if (null != temp) {
				temp.setMessage(temp.getMessage() + "；" + errorMessage.getMessage());
				errorMessageHashMap.put(temp.getLineNum(), temp);
			} else {
				errorMessageHashMap.put(errorMessage.getLineNum(), errorMessage);
			}
		}
		return errorMessageHashMap;
	}

	/**
	 * 将JSONSTRING数据源的数据导入到list
	 *
	 * @param jsonStr 接收的对象JSON串
	 * @param dicMap  HashMap<dateType_value,dataValue_dataId>  如 {EMPTYPE_兼职工伤，ID}
	 * @author fxj
	 * @date 2019/08/01
	 */
	public void getJsonStringToList(String jsonStr, Map<String, String> dicMap) {
		List<HashMap> list = null;
		List<T> listt = new ArrayList<T>();
		list = JSONObject.parseArray(jsonStr, HashMap.class);
		List<ErrorMessage> errorList = new ArrayList<ErrorMessage>();
		HashMap<Integer, ErrorMessage> errorMessageHashMap = new HashMap<Integer, ErrorMessage>();
		try {

			// 得到数据的条数
			int rows = list.size();
			// 有数据时才处理
			if (rows > 0) {
				// 得到类的所有field
				Field[] allFields = clazz.getDeclaredFields();
				Field field;
				// 定义一个map用于存放列的序号和field
				Map<Integer, Field> fieldsMap = new HashMap<Integer, Field>();
				for (int i = 0, index = 0; i < allFields.length; i++) {
					field = allFields[i];
					// 将有注解的field存放到map中
					if (field.isAnnotationPresent(ExcelAttribute.class)) {
						// 设置类的私有字段属性可访问
						field.setAccessible(true);
						fieldsMap.put(index, field);
						index++;

					}
				}
				//存储错误数据
				String error = "";
				//临时存储单元格数据
				String tempStr = "";
				// 从第1行开始取数据
				T entity = null;
				HashMap temp;
				ExcelAttribute attr;
				String c = null;
				Class<?> fieldType;
				ErrorMessage errorTemp = null;
				for (int i = 0; i < rows; i++) {
					// 得到一行中的所有单元格对象.
					temp = list.get(i);
					entity = clazz.newInstance();
					for (int j = 0; j < fieldsMap.size(); j++) {
						// 从map中得到对应列的field
						field = fieldsMap.get(j);
						//获取属性对应的注解属性
						attr = field.getAnnotation(ExcelAttribute.class);
						// 单元格中的内容.
						c = getStringValByObject(getFieldValueByName(attr.name(), temp));
						if (c != null) {
							c = c.trim();
						}
						//校验字段是否符合要求 返回错误信息
						error = validateUtil(c, attr, i + 2);
						if (null == error && attr.isDate() && Common.isNotNull(c)) {
							c = c.replace("/","-").replace(CommonConstants.YEAR,"-")
									.replace(CommonConstants.MONTH,"-").replace(CommonConstants.DAY,"");
							Pattern pattern = Pattern.compile("[0-9]*");
							if (pattern.matcher(c).matches()) {
								StringBuilder sb = new StringBuilder(c);
								sb.insert(4, "-");
								sb.insert(7,"-");
								c = sb.toString();
							}
						}
						if (null != error) {
							errorList.add(new ErrorMessage(i + 2, error));
							errorMessageHashMap = initErrorMessage(errorMessageHashMap, new ErrorMessage(i + 2, error), errorTemp);
							continue;
						}
						if (field == null) {
							continue;
						}
						//单元格数据为空不需要处理了
						if (!StringUtils.isNotBlank(c)) {
							continue;
						}
						//如果是需要从字典表取值数据的话在这里处理即可
						if (attr.isDataId() && null != dicMap) {
							if (Common.isNotNull(attr.dataType())) {
								//非区域字段处理
								if (Common.isNotNull(attr.parentField())){
									tempStr = dicMap.get(attr.dataType() + "_" + c.trim() + "_" + getFieldValueByName(attr.parentField(), entity, DateUtil.ISO_EXPANDED_DATE_FORMAT));
								}else {
									tempStr = dicMap.get(attr.dataType() + "_" + c.trim());
								}

							} else {
								if (attr.isArea()) {
									//区域字段处理
									if (Common.isEmpty(attr.parentField())) {
										tempStr = dicMap.get(c.trim() + "_0");
									} else {
										tempStr = dicMap.get(c.trim() + "_" + getFieldValueByName(attr.parentField(), entity, DateUtil.ISO_EXPANDED_DATE_FORMAT));
									}
								} else {
									//直接按值去找数据
									tempStr = dicMap.get(c.trim());
								}
							}
							if (!StringUtils.isNotBlank(tempStr)) {
								if (attr.isOrgan()) {
									errorList.add(new ErrorMessage(i + 2, "未找到:" + c + "的单位或项目数据，请确认存在项目权限"));
									errorMessageHashMap = initErrorMessage(errorMessageHashMap, new ErrorMessage(i + 2, "未找到:" + c + "的单位或项目数据，请确认存在项目权限"), errorTemp);
								}
								if (attr.isArea()) {
									errorList.add(new ErrorMessage(i + 2, "未找到:" + c + "的区域数据"));
									errorMessageHashMap = initErrorMessage(errorMessageHashMap, new ErrorMessage(i + 2, "未找到:" + c + "的区域数据"), errorTemp);
								} else {
									if (Common.isNotNull(attr.errorInfoImport())) {
										errorList.add(new ErrorMessage(i + 2, "数据'" + c + "':" + attr.errorInfoImport()));
										errorMessageHashMap = initErrorMessage(errorMessageHashMap, new ErrorMessage(i + 2, "数据'" + c + "':" + attr.errorInfoImport()), errorTemp);
									} else {
										errorList.add(new ErrorMessage(i + 2, "未找到:" + c + "的字典数据"));
										errorMessageHashMap = initErrorMessage(errorMessageHashMap, new ErrorMessage(i + 2, "未找到:" + c + "的字典数据"), errorTemp);
									}
								}
								continue;
							} else {
								c = tempStr;
							}
						}
						// 取得类型,并根据对象类型设置值.
						fieldType = field.getType();
						if (fieldType == null) {
							continue;
						}
						if (String.class == fieldType) {
							field.set(entity, c);
						} else if (BigDecimal.class == fieldType) {
							c = c.indexOf('%') != -1 ? c.replace("%", "") : c;
							field.set(entity, BigDecimal.valueOf(Double.valueOf(c)));
						} else if (Date.class == fieldType && Common.isNotNull(c.trim())) {
							field.set(entity, DateUtil.stringToDate(c.trim(), Common.isEmpty(attr.dateFormat()) ? DateUtil.ISO_EXPANDED_DATE_FORMAT : attr.dateFormat()));
						} else if ((Integer.TYPE == fieldType) || (Integer.class == fieldType)) {
							field.set(entity, Integer.parseInt(c));
						} else if ((Long.TYPE == fieldType) || (Long.class == fieldType)) {
							field.set(entity, Long.valueOf(c));
						} else if ((Float.TYPE == fieldType) || (Float.class == fieldType)) {
							field.set(entity, Float.valueOf(c));
						} else if ((Short.TYPE == fieldType) || (Short.class == fieldType)) {
							field.set(entity, Short.valueOf(c));
						} else if ((Double.TYPE == fieldType) || (Double.class == fieldType)) {
							field.set(entity, Double.valueOf(c));
						} else if (Character.TYPE == fieldType) {
							if ((c != null) && (c.length() > 0)) {
								field.set(entity, Character.valueOf(c.charAt(0)));
							}
						} else if (LocalDateTime.class == fieldType && Common.isNotNull(c.trim())) {
							String dc = c.trim().replace(CommonConstants.CENTER_SPLIT_LINE_STRING, "")
									.replace(CommonConstants.SLASH_SPLIT_LINE_STRING, "");
							try {
								if (dc.length() > CommonConstants.EIGHT_INT) {
									field.set(entity, LocalDateTimeUtils.convertDateToLDT(DateUtil.stringToDate(dc, DateUtil.DATETIME_PATTERN_CONTAINS)));
								}else {
									field.set(entity, LocalDateTimeUtils.convertDateToLDT(DateUtil.stringToDate(dc, DateUtil.ISO_DATE_FORMAT)));
								}
							} catch (Exception e) {
								if (dc.length() > CommonConstants.EIGHT_INT) {
									errorList.add(new ErrorMessage(i + 2, attr.name() + "：" +
											c.trim() + "应满足时间格式：" + DateUtil.DATETIME_PATTERN_SECOND));
									errorMessageHashMap = initErrorMessage(errorMessageHashMap,
											new ErrorMessage(i + 2, attr.name() + "：" +
													c.trim() + "应满足时间格式：" + DateUtil.DATETIME_PATTERN_SECOND), errorTemp);
									continue;
								} else {
									errorList.add(new ErrorMessage(i + 2, attr.name() + "：" +
											c.trim() + "应满足时间格式：" + DateUtil.ISO_DATE_FORMAT));
									errorMessageHashMap = initErrorMessage(errorMessageHashMap,
											new ErrorMessage(i + 2, attr.name() + "：" +
													c.trim() + "应满足时间格式：" + DateUtil.ISO_DATE_FORMAT), errorTemp);
									continue;
								}
							}
						} else if (LocalDate.class == fieldType && !Common.isEmpty(c.trim())) {
							try {
								field.set(entity, LocalDate.parse(c.trim().replace(CommonConstants.CENTER_SPLIT_LINE_STRING, ""), DateTimeFormatter.ofPattern(DateUtil.ISO_DATE_FORMAT)));

							} catch (Exception e) {
								errorList.add(new ErrorMessage(i + 2, attr.name() + "：" + c.trim() + "应满足时间格式：" + DateUtil.ISO_DATE_FORMAT));
								errorMessageHashMap = initErrorMessage(errorMessageHashMap, new ErrorMessage(i + 2, attr.name() + "：" + c.trim() + "应满足时间格式：" + DateUtil.ISO_DATE_FORMAT), errorTemp);
								continue;
							}
						}
					}
					if (null == error) {
						if (entity != null) {
							listt.add(entity);
						}
					} else {
						continue;
					}
				}
			}
		} catch (Exception e) {
			throw new ExcelException("将jsonString数据源的数据导入到list异常：" + e.getMessage(), e);
		}
		this.setEntityList(listt);
		this.setErrorInfo(errorList);
		this.setErrorMessageHashMap(errorMessageHashMap);
	}

	/**
	 * @param clazz
	 * @Author: wangan
	 * @Date: 2020/9/28
	 * @Description:  获取导出中文字段
	 * @return: com.yifu.cloud.v1.common.core.util.R
	 **/
	public static R<List<String>> getExportfieldsName(Class<?> clazz){
		ArrayList<String> exportfieldsName = Lists.newArrayList();
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			ExcelAttribute annotation = field.getAnnotation(ExcelAttribute.class);
			if (annotation != null && Common.isNotNull(annotation.name()) && annotation.needExport()) {
				exportfieldsName.add(annotation.name());
			}
		}
		return R.ok(exportfieldsName,"成功");
	}

	public void convertEntityAsso(T vo, String[] exportFields, Map<String,String> diyDicMap, String dateFormat,Field[] allFields) {
		// 得到所有定义字段
		if (Common.isEmpty(allFields) || allFields.length == 0){
			allFields = clazz.getDeclaredFields();
		}
		List<Field> fields = new ArrayList<>();
		Class<?> superClazz = clazz.getSuperclass();
		// 将需要字典表头存起来备用，如果没传，则全部翻译
		List<String> allField = new ArrayList<>();
		ExcelAttribute annotation;
		for (Field field : allFields) {
			if (field.isAnnotationPresent(ExcelAttribute.class)) {
				fields.add(field);
				annotation = field.getAnnotation(ExcelAttribute.class);
				if (annotation != null && Common.isNotNull(annotation.name())) {
					allField.add(annotation.name());
				}
			}
		}
		if (Common.isEmpty(exportFields) && !allField.isEmpty()) {
			exportFields = new String[allField.size()];
			for (int i = 0; i < allField.size(); i++) {
				exportFields[i] = allField.get(i);
			}
		}
		if (superClazz != null) {
			Field[] superFields = superClazz.getDeclaredFields();
			for (Field field : superFields) {
				if (field.isAnnotationPresent(ExcelAttribute.class)) {
					fields.add(field);
				}
			}
		}

		fields = getFiledsByParamFiled(fields, exportFields);
		ExcelAttribute attr;
		Field field;
		//分割符
		String divider;
		for (int j = 0; j < fields.size(); j++) {
			// 获得field
			field = fields.get(j);
			// 设置实体类私有属性可访问
			field.setAccessible(true);
			attr = field.getAnnotation(ExcelAttribute.class);
			if (attr.isExport()) {
				// 如果数据存在就填入,不存在填入空格
				Class<?> classType = field.getType();
				String value = null;
				Date date;
				try {
					if (field.get(vo) != null && (classType.isAssignableFrom(Date.class) || classType.isAssignableFrom(LocalDateTime.class) || classType.isAssignableFrom(LocalDate.class))) {
						if (Common.isNotNull(attr.dateFormatExport())) {
							date = DateUtil.stringToDate2(String.valueOf(field.get(vo)), attr.dateFormatExport());
							if (classType.isAssignableFrom(LocalDateTime.class)){
								value = LocalDateTimeUtils.formatTime((LocalDateTime)field.get(vo),attr.dateFormatExport());
							}else {
								value = DateUtil.dateToString(date, attr.dateFormatExport());
							}
						} else {
							date = DateUtil.stringToDate2(String.valueOf(field.get(vo)), !Common.isNotNull(dateFormat) ? DateUtil.ISO_EXPANDED_DATE_FORMAT : dateFormat);
							if (classType.isAssignableFrom(LocalDateTime.class)){
								value = LocalDateTimeUtils.formatTime((LocalDateTime)field.get(vo),!Common.isNotNull(dateFormat) ? DateUtil.ISO_EXPANDED_DATE_FORMAT : dateFormat);
							}else {
								value = cn.hutool.core.date.DateUtil.format(date, !Common.isNotNull(dateFormat) ? DateUtil.ISO_EXPANDED_DATE_FORMAT : dateFormat);
							}
						}
					}
					//如果有默认字典数据直接取值
					if (Common.isNotNull(attr.readConverterExp())) {
						value = convertByExp(field.get(vo) == null ? "" : String.valueOf(field.get(vo)), attr.readConverterExp());
					} else if (attr.isDataId()) {
						//加入分割符逻辑
						divider = attr.divider();
						if (!"".equals(divider) && field.get(vo) != null){
							try {
								value = "";
								for(String key : String.valueOf(field.get(vo)).split(divider)){
									value += getLableById(attr, diyDicMap, key) + divider;
								}
								if(Common.isNotNull(value)){
									value = value.substring(0,value.length()-1);
								}
							}catch (Exception e){
								log.error("excel数据导出字符切割错误",e);
								value = "字符切割错误";
							}
						} else {
							//如果是字典数据ID或区域ID 去dicMap（包含了区域） 取值 取不到返回空
							value = getLableById(attr, diyDicMap, field.get(vo) == null ? "" : String.valueOf(field.get(vo)));
						}
					} else if (attr.isArea()){
						//区域字段处理 TODO
						value = getAreaLabel((String) field.get(vo));
					}
					field.set(vo, Common.isNotNull(value)?value:field.get(vo));
				}catch (Exception e){
					log.error("字典数据解析异常",e);
				}
			}
		}
	}

	public Map<String,String> getConverterDicType() {
		// 得到所有定义字段
		Field[] allFields = clazz.getDeclaredFields();
		Map<String,String> nameDicMap = new HashMap<>();
		List<Field> fields = new ArrayList<>();
		// 将需要字典表头存起来备用，如果没传，则全部翻译
		for (Field field : allFields) {
			if (field.isAnnotationPresent(ExcelAttribute.class)) {
				fields.add(field);
			}
		}
		ExcelAttribute attr;
		Field field;
		for (int j = 0; j < fields.size(); j++) {
			field = fields.get(j);
			attr = field.getAnnotation(ExcelAttribute.class);
			if (Common.isNotNull(field) && Common.isNotNull(attr)){
				nameDicMap.put(field.getName(),attr.dataType());
			}
		}
		return nameDicMap;
	}
}
