package com.qmth.teachcloud.common.contant;

import com.alibaba.fastjson.JSONObject;
import com.aventrix.jnanoid.jnanoid.NanoIdUtils;
import com.qmth.boot.core.uid.service.UidService;
import com.qmth.teachcloud.common.annotation.DBVerify;
import com.qmth.teachcloud.common.bean.result.DBVerifyResult;
import com.qmth.teachcloud.common.config.DictionaryConfig;
import com.qmth.teachcloud.common.entity.BasicSchool;
import com.qmth.teachcloud.common.entity.SysConfig;
import com.qmth.teachcloud.common.entity.SysUser;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.enums.LocalCatalogEnum;
import com.qmth.teachcloud.common.enums.TFCustomTypeEnum;
import com.qmth.teachcloud.common.enums.UploadFileEnum;
import com.qmth.teachcloud.common.service.CommonCacheService;
import com.qmth.teachcloud.common.util.*;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: 系统常量
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2019/10/11
 */
public class SystemConstant {
    private final static Logger log = LoggerFactory.getLogger(SystemConstant.class);

    public static final String DEFAULT_PAPER_TYPE_A = "A";

    /**
     * mq中台
     */
    public static final String GDPU_TODOTASK_URL = "/api/open/mq/gdpu/todotask";
    public static final String GDPU_DONETASK_URL = "/api/open/mq/gdpu/donetask";

    public static final String INIT_PASSWORD = "12345678";
    public static final String OLD_INIT_PASSWORD = "123456";

    /**
     * 分布式印刷api前缀
     */
    public static final String PREFIX_URL_COMMON = "/admin/common";
    public static final String PREFIX_URL_SYS = "/admin/sys";
    public static final String PREFIX_URL_BASIC = "/admin/basic";
    public static final String PREFIX_URL_MARK = "/admin/mark";
    public static final String PREFIX_URL_SCAN = "/scan";
    public static final String PREFIX_URL_EXAM = "/admin/exam";
    public static final String PREFIX_URL_DATA = "/admin/data";
    public static final String PREFIX_URL_WORK = "/admin/work";
    public static final String PREFIX_URL_CLIENT = "/admin/client";
    public static final String PREFIX_URL_STATISTICS = "/admin/statistics";
    public static final String PREFIX_URL_SYNC = "/admin/sync";
    public static final String PREFIX_URL_SET = "/admin/set";
    public static final String PREFIX_URL_CUSTOM_FLOW = "/admin/custom/flow";
    public static final String PREFIX_URL_TEACH = "/admin/teach";
    public static final String PREFIX_URL_AUTH = "/admin/auth";
    public static final String PREFIX_URL_OPEN = "/admin/print/open";
    public static final String PREFIX_URL_NOTIFY = "/admin/print/notify";
    public static final String PREFIX_URL_GRADE = "/admin/grade";
    public static final String PREFIX_URL_COURSE_DEGREE = "/admin/course/degree";
    public static final String PREFIX_URL_PROFESSIONAL = "/admin/basic/professional";
    public static final String PREFIX_URL_CULTURE_PROGRAM = "/admin/obe/culture/program";
    public static final String PREFIX_URL_OBE = "/admin/obe";

    /**
     * 教研分析api前缀
     */
    public static final String PREFIX_URL_REPORT_WUDA = "/report/wuda/open";
    public static final String PREFIX_URL_REPORT_SCHOOL = "/report/school";
    public static final String PREFIX_URL_REPORT_COURSE = "/report/course";
    public static final String PREFIX_URL_REPORT_EXAM_STUDENT = "/report/exam_student";
    public static final String PREFIX_URL_REPORT_DATASOURCE = "/report/datasource";
    public static final String PREFIX_URL_REPORT_ANALYZE = "/report/analyze";
    public static final String PREFIX_URL_REPORT_OPEN = "/report/open";
    public static final String PREFIX_URL_REPORT_SSO = "/report/sso";
    public static final String PREFIX_URL_REPORT_SET = "/report/set";

    /**
     * 云阅卷api
     */
//    public static final String CLOUD_MARK_SCHOOL_SAVE_API = "/api/school/sub/save";
//    public static final String CLOUD_MARK_EXAM_SAVE_API = "/api/exam/save";
//    public static final String CLOUD_MARK_SUBJECT_SAVE_API = "/api/exam/subject/save";
//    public static final String CLOUD_MARK_EXAM_LIST_API = "/api/exams";
//    public static final String CLOUD_MARK_EXAM_STUDENT_SAVE_API = "/api/exam/student/save";
//    public static final String CLOUD_MARK_FILE_UPLOAD_API = "/api/file/{type}/upload";
//    public static final String CLOUD_MARK_EXAM_PAPER_QUERY_API = "/api/exam/paper/query";
//    public static final String CLOUD_MARK_OPEN_MARK_LOGIN_API = "/open/mark/login";
//    public static final String CLOUD_MARK_OPEN_SUBJECT_HEADER_LOGIN_API = "/open/subject_header/login";
//    public static final String CLOUD_MARK_EXAM_STUDENT_COUNT_API = "/api/exam/student/count";
    public static final String CLOUD_MARK_EXAM_STUDENT_SCORE_API = "/api/exam/student/score";
//    public static final String CLOUD_MARK_EXAM_PAPER_SAVE_API = "/api/exam/paper/save";
//    public static final String CLOUD_MARK_USER_EXTERNAL_SAVE_API = "/api/user/external/save";
//    public static final String CLOUD_MARK_EXAM_MARK_GROUP_SAVE_API = "/api/exam/mark_group/save";
//    public static final String CLOUD_MARK_EXAM_MARK_GROUP_COUNT_API = "/api/exam/mark_group/count";
//    public static final String CLOUD_MARK_EXAM_MARK_GROUP_DELETE_API = "/api/exam/mark_group/delete";
//    public static final String CLOUD_MARK_EXAM_MARKER_SAVE_API = "/api/exam/marker/save";
//    public static final String CLOUD_MARK_EXAM_SUBJECT_HEADER_SAVE_API = "/api/exam/subject_header/save";
//    public static final String CLOUD_MARK_USER_CLASS_SAVE_API = "/api/user/class/save";
//    public static final String CLOUD_MARK_EXAM_SUBJECT_CALCULATE_API = "/api/exam/subject/calculate";

    /**
     * 教研分析api
     */
    public static final String TEACHCLOUD_REPORT_OPEN_SEMESTER_EDIT_API = "/api/report/open/semester_edit";
    public static final String TEACHCLOUD_REPORT_OPEN_EXAM_EDIT_API = "/api/report/open/exam_edit";
    public static final String TEACHCLOUD_REPORT_OPEN_EXAM_DELETE_API = "/api/report/open/exam_delete";
    public static final String TEACHCLOUD_REPORT_OPEN_COURSE_EDIT_API = "/api/report/open/course_edit";
    //    public static final String TEACHCLOUD_REPORT_OPEN_COURSE_DEL_API = "/api/report/open/course_del";
    public static final String TEACHCLOUD_REPORT_OPEN_CALCULATE_API = "/api/report/open/calculate";
    public static final String TEACHCLOUD_REPORT_OPEN_PUBLISH_API = "/api/report/open/publish";
    public static final String TEACHCLOUD_REPORT_SSO_LOGIN_API = "/api/report/sso/login";
    public static final String TEACHCLOUD_REPORT_LOGIN_URL = "/#/login-authen/";
    public static final String TEACHCLOUD_REPORT_STUDENT_URL = "/#/student-report/";

    /**
     * 分布式印刷api
     */
    public static final String TEACHCLOUD_PRINT_NOTIFY_ANALYSIS_PROGRESS_API = "/api/admin/print/notify/analysis/progress";
    public static final String TEACHCLOUD_PRINT_OPEN_PAPER_CONFIG_API = "/api/admin/print/open/paper_config";
    public static final String TEACHCLOUD_PRINT_OPEN_PAPER_DIMENSION_API = "/api/admin/print/open/paper_dimension";
    public static final String TEACHCLOUD_PRINT_OPEN_PAPER_STRUCTURE_API = "/api/admin/print/open/paper_structure";
    public static final String TEACHCLOUD_PRINT_OPEN_PAPER_EVALUATION_API = "/api/admin/print/open/paper_evaluation";
    public static final String TEACHCLOUD_PRINT_OPEN_EXAM_STUDENT_SCORE_API = "/api/admin/print/open/exam_student_score";


    /**
     * 题库接口地址
     */
    public static final String TIKU_CAS_ADMIN_LOGIN_OPEN_API = "/admin/login-open";// 题库cas登录地址
    public static final String TIKU_SSO_LOGIN_API = "/api/open/sso/login";// 题库单点登录接口地址
    public static final String TIKU_PAPER_LIST_API = "/api/open/paper/page";// 获取试卷列表接口地址
    public static final String TIKU_PAPER_DATA_API = "/api/open/paper/data";// 获取试卷数据接口地址
    public static final String TIKU_PAPER_PROPERTY_API = "/api/open/property";// 获取知识点接口地址

    /**
     * 系统配置
     */
    public static final String EXAM_TASK = "examTask";
    public static final String START_PARENT = "../";
    public static final String DATE_TIME_FORMAT = "%02d";
    public static final String PRINT_DELETE_DATA_FILE_NAME = "db/delete-data.sql";
    //    public static final String SYS_USER_INIT_PASSWORD = "sys.user.initPassword";
//    public static final String SYS_WARNING_DAYS = "sys.warning.days";
    public static final String SYS_CODE_ENABLE = "sys.code.enable";
    //    public static final String SYS_MESSAGE_ENABLE = "sys.message.enable";
//    public static final String SYS_MESSAGE_RESEND_COUNT = "sys.message.resendCount";
    public static final String SCHOOL_COURSE_DEGREE_TEMPLATE = "school.course.degree.template";
    public static final String SYS_CONFIG_KEY_CHARSETS = "sys.txt.charset";
    public static final String PACKAGE_BARCODE_POSITION = "package.barcode.position";
    public static final String SYS_PDF_SIZE_LIST = "sys.pdf.size.list";
    public static final String ADMIN_LOGO_URL = "admin.logo.url";
    public static final String ATTACHMENT_TYPE = "attachment.type";
    public static final String ATTACHMENT_LENGTH = "attachment.length";
    public static final String ATTACHMENT_SIZE = "attachment.size";
    public static final String AUTO_CREATE_PDF_RESET_MAX_COUNT = "auto.create.pdf.reset.max.count";
    public static final String THREAD_POOL_CORE_SIZE = "thread.pool.core.size";
    public static final String CUSTOM_THREAD_POOL_CORE_SIZE = "custom.thread.pool.core.size";
    public static final String SESSION_ACTIVE = "session.active";
    public static final String SMS_NORMAL_CODE = "sms.normal.code";
    public static final String CODE_EXPIRED_TIME = "code.expired.time";
    public static final String CODE_SEND_INTERVAL = "code.send.interval";
    public static final String TEACHCLOUD_REPORT_HOST_URL = "teachcloud.report.host.url";
    public static final String TEACHCLOUD_PRINT_OPEN_CALLBACK_PWD = "teachcloud.print.open.callback.pwd";
    public static final String QUESTION_HOST_URL = "question.host.url";
    public static final String TEACHCLOUD_PRINT_HOST_URL = "teachcloud.print.host.url";
    public static final String TEACHCLOUD_REPORT_LOCATION_URL = "teachcloud.report.location.url";
    public static final String TEACHCLOUD_PRINT_HOST_DEFAULT_URL = "teachcloud.print.host.default.url";
    public static final String TEACHCLOUD_REPORT_HOST_DEFAULT_URL = "teachcloud.report.host.default.url";

    public static final String OPEN_FLOW_MESSAGE_PUSH = "open.flow.message.push";//是否开启消息推送
    public static final String FLOW_MESSAGE_TYPE = "flow.message.type";//消息类型，标准/非标准
    public static final String MQ_HOST_URL = "mq.host.url";//消息中心地址，目前是cas单点登录地址

    public static final String SMS_SIGN_NAME = "sms.sign.name";
    public static final String SMS_TPL_CODE = "sms.tpl.code";
    public static final String SMS_AUDIT_PASS_CODE = "sms.audit.pass.code";
    public static final String SMS_AUDIT_NOT_PASS_CODE = "sms.audit.not.pass.code";
    public static final String SMS_EXAM_TASK_CREATE_CODE = "sms.exam.task.create.code";
    public static final String SMS_EXAM_TASK_WILL_EXPIRE_CODE = "sms.exam.task.will.expire.code";
    public static final String SMS_EXAM_TASK_OVERDUE_CODE = "sms.exam.task.overdue.code";
    public static final String SMS_ALLOCATION_WILL_EXPIRE_CODE = "sms.allocation.will.expire.code";
    public static final String SMS_ALLOCATION_OVERDUE_CODE = "sms.allocation.overdue.code";
    public static final String SMS_AUDIT_CREATE_CODE = "sms.audit.create.code";
    public static final String SMS_AUDIT_REVIEW_CODE = "sms.audit.review.code";
    public static final String SMS_AUDIT_WILL_EXPIRE_CODE = "sms.audit.will.expire.code";
    public static final String SMS_AUDIT_OVERDUE_CODE = "sms.audit.overdue.code";
    public static final String SMS_AUDIT_REJECT_CODE = "sms.audit.reject.code";
    public static final String SMS_UPLOAD_STRUCTURE_CODE = "sms.upload.structure.code";
    public static final String SMS_AUDIT_COPY_USER_CODE = "sms.audit.copy.user.code";

    /**
     * 系统学校配置
     */
    public static final String ACCOUNT_SMS_VERIFY = "account.sms.verify";
    public static final String TEACHCLOUD_EXCHANGE_HOST_URL = "teachcloud.exchange.host.url";
    public static final String PDF_SIZE_LIST = "pdf.size.list";

    /**
     * 系统常量
     */
    public static final String SEND_FLOW_MQ = "sendFlowMq";
    public static final String SEND_FLOW_START_MQ = "sendFlowStartMq";
    public static final String PT = "PT";
    public static final String CHARSET_NAME = "UTF-8";
    //    public static final String CHARSET_GB2312 = "gb2312";
    public static final String CHARSET_GBK = "gbk";
    public static final Charset CHARSET = Charset.forName(CHARSET_NAME);
    public static final String MD5 = "MD5";
    public static final String SUCCESS = "success";
    public static final String EXCEL_ERROR = "error";
    public static final String EXTEND_COLUMN = "extendColumn";
    public static final String USER_DIR = "user.dir";
    public static final String OS_NAME = "os.name";
    public static final String TMP_DIR = "java.io.tmpdir";
    //    public static final String PDF_TEMP = "pdf-temp";
//    public static final String FILE_TEMP = "file-temp";
    public static final String TEMP = "temp";
    public static final String SESSION = "session:";
    public static final String TASK = "task";
    public static final String ORG_PREFIX = "code";
    public static final String TB_TASK_ID = "tbTaskId";
    //    public static final String TB_SYNC_TASK = "tbSyncTask";
//    public static final String TB_SYNC_TASK_ID = "tbSyncTaskId";
    public static final String USER = "account";
    public static final String USER_ID = "userId";
    public static final String SCHOOL_ID = "schoolId";
    public static final String SCHOOL = "school";
    public static final String ORG = "org";
    public static final String ERROR = "/error";
    public static final String METHOD = "post";
    public static final String DEFAULT_PASSWORD = "MTIzNDU2";
    public static final String UPDATE_TIME = "updateTime";
    public static final String PATH = "path";
    public static final String PDF_PATH = "pdfPath";
    public static final String HTML_PATH = "htmlPath";
    public static final String TYPE = "type";
    public static final String LOCAL = "local";
    public static final String OSS = "oss";
    public static final String LOGO = "logo";
    public static final String UPLOAD_TYPE = "uploadType";
    public static final String ID = "id";
    public static final String MODEL = "model";
    public static final String VERSION = "version";
    public static final String VERSION_VALUE = "3.3.3.1";
    public static final String FLOW_ENTITY_ID = "flowEntityId";
    public static final String CUSTOM_FLOW_ID = "customFlowId";
    public static final String ACT_FLOW_ID = "actFlowId";
    public static final String FLOW_PROCESS_VAR_MAP = "flowProcessVarMap";
    public static final String PROCESS_DEFINITION_ID = "processDefinitionId";
    public static final String FILE = "file";
    public static final String SIZE = "size";
    public static final String HTML_PREFIX = ".html";
    public static final String PDF_PREFIX = ".pdf";
    public static final String JSON_PREFIX = ".json";
    public static final String FTL_PREFIX = ".ftl";
    public static final String ZIP_PREFIX = ".zip";
    public static final String TXT_PREFIX = ".txt";
    public static final String WINDOWS = "Windows";
    public static final DecimalFormat df = new DecimalFormat("0.##");

    public static final String EXCEL_PREFIX = ".xlsx";
    public static final String WORD_PREFIX = ".docx";
    public static final String JPG_PREFIX = ".jpg";
    public static final String TEMP_PREFIX = ".temp";
    public static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_PATTERN = "yyyy-MM-dd";
    public static final String TIME_PATTERN = "HH:mm";
    public static final String BACK_UP_DATE_PATTERN = "yyyyMMddHHmmss";
    public static final int PAGE_NUMBER = 0;
    public static final int PAGE_SIZE = 10000000;
    public static final int PAGE_SIZE_MIN = 10;
    public static final int PAGE_SIZE_MAX = 500;
    public static final int PAGE_NUMBER_MIN = 1;
    public static final int IN_SIZE_MAX = 1000;
    public static final int ALL_CARD = -1;
    public static final String MANUAL = "manual";
    public static final String CREATE_PDF_TYPE = "createPdfType";
    public static final String DELIMITER = ":";
    public static final String COMMA = ",";
    public static final int FINAL_SCALE = 1;
    public static final int CALCULATE_SCALE = 4;
    //    public static final int OPER_SCALE = 8;
    public static final BigDecimal PERCENT = new BigDecimal(100);
    public static final String HYPHEN = "-";
    public static final String DEFAULT_SIGN = "#";
    public static final String PARENT_ORG = "教务处";
    public static final String SCHOOL_CODE = "wdfx";
    public static final String ADMIN_CODE = "admin";
    public static final String AUTH = "auth";//命题老师id
    //    public static final int MAX_RETRY_CREATE_PDF_COUNT = 5;
    //英文字母、数字、中文括号、英文括号、下划线(_)、减号(-)、中文横线(—)
    public static final String REGULAR_EXPRESSION_OF_CODE = "[a-zA-Z0-9](\\w+)?-?(\\w+)?—?(\\w+)?(\\((\\w+)?-?(\\w+)?—?(\\w+)?\\))?(\\（(\\w+)?-?(\\w+)?—?(\\w+)?\\）)?(\\w+)?";
    public static final String REGULAR_EXPRESSION_OF_CODE1 = "^[a-zA-Z0-9]+$";
    public static final String REGULAR_EXPRESSION_OF_PHONE = "((\\d{3,4})|(\\(\\d{3,4}\\)-))?\\d{7,8}";
    public static final String REGULAR_EXPRESSION_OF_CODE_PRIMARY_DIMENSION = "[A-Z]";
    public static final String REGULAR_EXPRESSION_OF_CODE_SECOND_DIMENSION = "[A-Z][1-9][0-9]*";
    public static final String SYS_USER = "sysUser";
    public static final String FINAL_SCORE_STR = "期末考试";

    public static final String ERROR_DATA_LIST = "errorDataList";
    public static final String DATASOURCE = "datasource";
    public static final String DATA_COUNT = "dataCount";
    public static final String SUCCESS_DATA_COUNT = "successDataCount";
    public static final String ERROR_DATA_COUNT = "errorDataCount";
    public static final List<Long> MENU_MANAGE = Arrays.asList(507L, 508L, 530L, 531L, 675L, 676L, 795L, 796L, 797L, 798L, 799L, 800L, 801L, 802L);
    public static final float PAPER_DEVIATION = 2;
    public static final String COMMA_OF_ENGLISH = ",";
    public static final String COMMA_OF_CHINESE = "，";
    public static final String PAUSE_SIGN = "、";
    public static final String ORG_SPLIT = "/";
//    public static final String ORG_POINT = "\\.";
    public static final String PUSH_OPERATE_NOTICE = "操作成功，请去基础配置 -> 系统设置 -> 同步管理中查看结果";
    public static final String EXCEL_PROTECT_KEY = "Qmth87863577";
    public static final String ZIP_ENCRYPT_PWD = "qmthzip";
    public static final String GET = "get";
    public static final String POST = "post";
    //    public static final String PARAMS = "params";
    public static final String RETURN_URL = "returnUrl";
    //    public static final String SIGNATURE = "signature";
    public static final String GET_UNKNOWN = "?";
    public static final String GET_SYMBOL = "&";
    public static final String GET_EQUAL = "=";
    public static final String PATH_MATCH = "*";
    public static final String CATALOG_LINK = "->";
//    public static final String OPERATE_LINK = "--";
    public static final String LIMIT1 = "limit 1";

    public static final Integer DEFAULT_BACKUP_COUNT = 1;
    public static final String IMPORT = ":import";
    public static final String SYNC = ":sync";
    public static final String OBE_COURSE_REQUIREMENT_DTO_LIST = "obeCourseRequirementDtoList";
    public static final String OBE_SUB_REQUIREMENT_DTO_MAP = "obeSubRequirementsDtoMap";

    /**
     * oss url过期时间
     */
//    public static final int OSS_URL_EXPIRE = 5 * 60 * 1000;//过期时间5分钟

    /**
     * 缓存配置
     */
    public static final String USER_OAUTH_CACHE = "user:oauth:cache";
    public static final String USER_ACCOUNT_CACHE = "user:account:cache";
    public static final String USER_MENU_CACHE = "user:menu:cache";
    public static final String SCHOOL_CACHE = "school:cache";
    public static final String SCHOOL_CODE_CACHE = "school:code:cache";
    public static final String ORG_CACHE = "org:cache";
    public static final String PRIVILEGE_URL_CACHE = "privilege:url:cache";
    public static final String ROLE_PRIVILEGE_CACHE = "role:privilege:cache";
    public static final String USER_ROLE_PRIVILEGE_CACHE = "user:role:privilege:cache";
    public static final String ROLE_CACHE = "role:cache";
    //    public static final String AUTH_INFO_CACHE = "auth:info:cache";
    public static final String SYS_CONFIG_CACHE = "sys:config:cache";
    public static final String SCHOOL_PRIVILEGE_CACHE = "school:privilege:cache";
    public static final String SCHOOL_ROLE_CACHE = "school:role:cache";
    public static final String CUSTOM_PRIVILEGE_CACHE = "custom:privilege:cache";
    public static final String CUSTOM_ROLE_CACHE = "custom:role:cache";
    //    public static final String NUMBER_CACHE = "school:number:cache:";
    public static final String ORG_COLLEGE_LEVEL_CACHE = "org:college:level:cache";
    public static final String ORG_CODE_CACHE = "org:code:cache";

    public static final String EXAM_TASK_SEQUENCE_CACHE = "exam:task:sequence:cache";

    /**
     * 报表缓存
     */
    public static final String EXAM_STUDENT_REPORT = "report:cache:examStudent";
    public static final String COLLEGE_DEAN_REPORT = "report:cache:collegeDean";
    public static final String COLLEGE_COURSE_REPORT = "report:cache:collegeCourse";
    public static final String SURVEY_TEACHER_VIEW_REPORT = "report:cache:surveyTeacherView";
//    public static final String TEACHER_VIEW_REPORT = "report:cache:teacherView";
//    public static final String TEACHER_ANSWER_VIEW_REPORT = "report:cache:teacherAnswerView";

    /**
     * 鉴权
     */
    public static final String HEADER_AUTHORIZATION = "Authorization";
    public static final String HEADER_TIME = "time";
    public static final String HEADER_PLATFORM = "platform";
    public static final String HEADER_DEVICE_ID = "deviceId";
    public static final String CURRENT_PRIVILEGE_ID = "privilegeId";
    public static final String TOKEN = "token";
    public static final String SIGN = "sign";

    /**
     * redis
     */
    public static final int DEFAULT_SESSION_EXPIRE = 1;//过期时间1天
    public static final long REDIS_DEFAULT_EXPIRE_TIME = 24 * 60L * 60L;//过期时间24小时
    public static final long REDIS_THIRD_USER_AUTH_EXPIRE_TIME = 2 * 60L;//过期时间2分钟

    /**
     * redis mq
     */
    public static final String REDIS_LOCK_MQ_PREFIX = "redis:lock:mq:";
    public static final int REDIS_MQ_MAX_RECONSUME = 5;
    public static final String MQ_TOPIC_BUFFER_LIST = "mq:topic:buffer:list";
    public static final String REDIS_LOCK_BATCH_NO_PREFIX = "redis:lock:batchNo:";//
    public static final String REDIS_LOCK_GRADE_COURSE_DELETE_PREFIX = "redis:lock:courseInfo:";
    public static final String REDIS_LOCK_GRADE_EXAM_DELETE_PREFIX = "redis:lock:exam:";

    /**
     * redis lock
     */
    public static final int MAX_RETRY_COUNT = 30;
    public static final long REDIS_CACHE_TIME_OUT = 60L;
    public static final long REDIS_LOCK_MQ_TIME_OUT = 60L;
    public static final long REDIS_LOCK_BATCH_NO_TIME_OUT = 60L * 30;

    /**
     * aes相关
     */
    public static final String AES = "AES";
    public static final String AES_MODE_PKCS5 = "AES/CBC/PKCS5Padding";//用这个模式，规则必须为16位
    public static final String AES_MODE_PKCS7 = "AES/CBC/PKCS7Padding";//用这个模式，规则必须为16位
    public static final String AES_RULE = "1234567890123456";//aes密钥

    /**
     * 变量
     */
//    public static String TEMP_FILES_DIR;
//    public static String PDF_TEMP_FILES_DIR;

    /**
     * excel相关
     */
    public static final String XLSX = "xlsx";
    public static final String XLS = "xls";
    public static final String EXAMINATION_DESCRIBE = "说明\n" +
            "1、【学号】必填；\n" +
            "2、【座位号】必填；\n" +
            "3、【姓名】必填；\n" +
            "4、【课程代码】必填,且与命题任务中的课程代码相互对应；\n" +
            "5、【课程名称】必填,且与命题任务中的课程名称相互对应；\n" +
            "6、【试卷编号】必填,且与命题任务中的试卷编号相互对应；\n" +
            "7、【考点】必填；\n" +
            "8、【考场】必填；\n" +
            "9、【考试日期】必填,且格式为YYYY-MM-DD。例如2023-07-09；\n" +
            "10、【考试时间】必填,且格式为HH:mm-HH:mm。例如18:30-20:30；\n" +
            "11、请不要删除此行，也不要删除模板中的任何列。\n" +
            "12、使用前请先删除样例数据。\n";

    public static final String BASIC_EXAM_STUDENT_DESCRIBE = "说明\n" + "1、课程名称、课程代码、姓名、学号、教学班均必填；\n"
            + "2、试卷编号存在时，任课老师、任课老师工号、考试日期、考试时间、考点（校区）、考场（考试教师）均必填\n" + "3、【考试日期】必填,且格式为YYYY-MM-DD。例如2023-07-09；\n"
            + "4、【考试时间】必填,且格式为HH:mm-HH:mm。例如18:30-20:30；\n" + "5、请不要删除此行，也不要删除模板中的任何列。\n" + "6、使用前请先删除样例数据。";

    public static final String MARK_STUDENT_DESCRIBE = "说明\n" +
            "1、课程名称、课程编号、试卷编号、姓名、学号均必填；\n" +
            "2、学号在课程下唯一；\n" +
            "3、同一个课程、试卷下的班级信息要么全填要么全不填；\n" +
            "4、【考试日期】必填,且格式为YYYY-MM-DD。例如2023-07-09；\n" +
            "5、【考试时间】必填,且格式为HH:mm-HH:mm。例如18:30-20:30；\n" +
            "6、请不要删除此行，也不要删除模板中的任何列。\n" +
            "7、使用前请先删除样例数据。";

    /**
     * 线程池配置
     */
    public static final String THREAD_POOL_NAME = "taskThreadPool";
    //    public static final int THREAD_POOL_CORE_POOL_SIZE = 5;
//    public static final int THREAD_POOL_MAX_POOL_SIZE = 100;
    public static final int THREAD_POOL_KEEP_ALIVE_SECONDS = 10;
    public static final int THREAD_POOL_QUEUE_CAPACITY = 500;

    /**
     * mq消息
     */
    public static final int DELIVERED_ACK_TYPE = 0;//消息"已发出"，但尚未处理结束
    public static final int POSION_ACK_TYPE = 1;//消息"错误",通常表示"抛弃"此消息，比如消息重发多次后，都无法正确处理时，消息将会被删除或者DLQ(死信队列)
    public static final int STANDARD_ACK_TYPE = 2;//"标准"类型,通常表示为消息"处理成功"，broker端可以删除消息了
    public static final int REDELIVERED_ACK_TYPE = 3;//消息需"重发"，比如consumer处理消息时抛出了异常，broker稍后会重新发送此消息
//    public static final int INDIVIDUAL_ACK_TYPE = 4;//表示只确认"单条消息",无论在任何ACK_MODE下
//    public static final int UNMATCHED_ACK_TYPE = 5;//BROKER间转发消息时,接收端"拒绝"消息
//    public static final int UNSEND_ACK_TYPE = 6;//消息未发出

    /**
     * activiti
     */
    public static final String APPROVE_ID = "approveId";//审批id
    public static final String FLOW_SUBMIT = "flowSubmit";//命题提交申请
    public static final String FLOW_JOIN_TYPE = "flowJoinType";//流程关联类型
    public static final String OLD_FLOW_ID = "oldFlowId";//旧流程id
    public static final String FLOW_TYPE = "flowType";//流程类型
    public static final String FLOW_ID = "flowId";//流程id
    public static final String FLOW_TASK_ID = "flowTaskId";//流程任务id
    public static final String APPROVE = "approve";//流程审核变量
    public static final String AGGINESS_MAP = "agginessMap";//流程审批人变量
    public static final String APPROVE_PASS_MAP = "approvePassMap";//流程审批通过变量
    public static final String APPROVE_REJECT_MAP = "approveRejectMap";//流程审批驳回变量
    public static final String APPROVE_USER_IDS = "approveUserIds";//流程审批人列表
    public static final String SETUP_MAP = "setupMap";//流程步骤变量
    public static final String APPROVE_SETUP = "approveSetup";//流程节点
    public static final String APPROVE_OPERATION = "approveOperation";//流程操作
    public static final String FLOW_STATUS = "flowStatus";//流程状态
    public static final String APPROVE_REMARK = "approveRemark";//流程审批意见
    public static final String OBJECT_ID = "objectId";
    public static final String OBJECT_DATA = "objectData";
    public static final String APPROVE_TF_FLOW_LOG = "TFFlowLog";//流程院长自动审批
    public static final String APPROVE_TF_FLOW_APPROVE = "TFFlowAppove";//流程流转记录
    public static final String FLOW_WORK_MESSAGE = "workMsg";
    public static final String FLOW_VIEW_MESSAGE = "viewMsg";
    public static final String PAPAER_ATTACHMENT_IDS = "paperAttachmentIds";//命题附件ids
    public static final String REDIS_LOCK_FLOW_TASK_PREFIX = "redis:lock:flow:task:";//流程节点锁
    public static final String REDIS_LOCK_EXAM_TASK_FLOW_PREFIX = "redis:lock:exam:task:flow:";//考试任务流程节点锁
    public static final String REDIS_LOCK_PAPER_NUMBER_PREFIX = "redis:lock:paper:number:";//试卷编号锁
    public static final String REDIS_LOCK_COURSE_CODE_SEQUENCE_PREFIX = "redis:lock:courseCode:sequence:";//课程序号锁
    public static final long REDIS_LOCK_FLOW_TASK_TIME_OUT = 60L * 2;
    public static final long REDIS_LOCK_EXAM_TASK_FLOW_TIME_OUT = 60L * 2;
    public static final String REDIS_LOCK_FLOW_PREFIX = "redis:lock:flow:";//流程锁
    public static final long REDIS_LOCK_FLOW_TIME_OUT = 60L * 2;
    public static final String REDIS_LOCK_CUSTOM_FLOW_PREFIX = "redis:lock:custom:flow:";//自定义流程锁
    public static final long REDIS_LOCK_CUSTOM_FLOW_TIME_OUT = 60L * 2;
    public static final String REDIS_LOCK_CALCULATE_PREFIX = "redis:lock:calculate:";//计算锁
    public static final long REDIS_LOCK_CALCULATE_TIME_OUT = 60L * 60;
    public static final long REDIS_LOCK_PAPER_NUMBER_TIME_OUT = 60L * 2;
    public static final String REDIS_FINAL_SCORE_DATA_FLOW_PREFIX = "redis:lock:final:score:data";//期末考试数据锁
    public static final String REDIS_PAPER_STRUCT_FLOW_PREFIX = "redis:lock:final:score:paper:struct";//期末考试试卷结构锁

    public static final String REDIS_LOCK_IMPORT_EXAM_DATA = "redis:lock:import:exam:data:";//导入考务数据锁
    public static final long REDIS_LOCK_IMPORT_EXAM_DATA_TIME_OUT = 60L * 10;
    public static final long REDIS_PAPER_STRUCT_TIME_OUT = 60L * 10;
    /**
     * 机器心跳
     */
    public static final String CURRENT_TASK_MACHINE_ID = "current_task_machine_id";//当前机器id
    public static final String TASK_MACHINE_ID = "task_machine_id:";//任务机器id
    public static final String TASK_MACHINE_ID_LIKE = "task_machine_id*";//任务机器like

    public static final String LOG_ERROR = "请求出错:{}";

    /**
     * http设置
     */
    public static final int CONNECT_TIME_OUT = 1000 * 60 * 2;//请求超时
    public static final int SOCKET_CONNECT_TIME_OUT = 1000 * 60 * 30;//读取数据超时

//    /**
//     * 初始化附件文件路径
//     */
//    public static void initTempFiles() {
//        File fileTempDir = null, pdfTempDir = null;
//        DictionaryConfig dictionaryConfig = SpringContextHolder.getBean(DictionaryConfig.class);
//
//        if (Objects.nonNull(dictionaryConfig.sysDomain().getFileTempPath()) && !Objects.equals("", dictionaryConfig.sysDomain().getFileTempPath())) {
//            fileTempDir = new File(dictionaryConfig.sysDomain().getFileTempPath().trim());
//        } else {
//            StringJoiner fileTempLocalPath = new StringJoiner("").add(System.getProperty(USER_DIR));
//            String mkdir = fileTempLocalPath.toString().substring(0, fileTempLocalPath.toString().lastIndexOf(File.separator));
//            fileTempDir = new File(new StringBuffer(mkdir).append(File.separator).append(FILE_TEMP).toString());
//        }
//        if (Objects.nonNull(fileTempDir) && !fileTempDir.exists()) {
//            fileTempDir.mkdirs();
//        }
//
//        if (Objects.nonNull(dictionaryConfig.sysDomain().getPdfTempPath()) && !Objects.equals("", dictionaryConfig.sysDomain().getPdfTempPath())) {
//            pdfTempDir = new File(dictionaryConfig.sysDomain().getPdfTempPath().trim());
//        } else {
//            StringJoiner pdfTempLocalPath = new StringJoiner("").add(System.getProperty(USER_DIR));
//            String mkdir = pdfTempLocalPath.toString().substring(0, pdfTempLocalPath.toString().lastIndexOf(File.separator));
//            pdfTempDir = new File(new StringBuffer(mkdir).append(File.separator).append(PDF_TEMP).toString());
//        }
//        if (Objects.nonNull(pdfTempDir) && !pdfTempDir.exists()) {
//            pdfTempDir.mkdirs();
//        }
//        TEMP_FILES_DIR = fileTempDir.getPath();
//        PDF_TEMP_FILES_DIR = pdfTempDir.getPath();
//    }

    /**
     * id转换为long
     *
     * @return
     */
    public static Long convertIdToLong(String id) {
        return Objects.nonNull(id) && id.length() > 0 ? Long.parseLong(id) : null;
    }

//    /**
//     * 获取全局uuid
//     *
//     * @return
//     */
//    public static String getUuid() {
//        return String.valueOf(UUID.randomUUID()).replaceAll(SystemConstant.HYPHEN, "");
//    }

    /**
     * 获取全局uuid
     *
     * @return
     */
    public static String getNanoId() {
        return NanoIdUtils.randomNanoId();
    }

    /**
     * 获取根目录
     *
     * @return
     */
    public static String getUserDir() {
        return System.getProperty(SystemConstant.USER_DIR);
    }

    /**
     * 获取数据库uuid
     *
     * @return
     */
    public static Long getDbUuid() {
        UidService uidservice = SpringContextHolder.getBean(UidService.class);
        return uidservice.getId();
    }

    /**
     * 试卷类型转换
     *
     * @param paperType
     * @return
     */
    public static String convertPaperType(String paperType) {
        paperType = paperType.toLowerCase();
        int ascii = (int) paperType.charAt(0);
        return String.valueOf(ascii + 704);
    }

    /**
     * 模糊查询时调用以去除符号"%","_"特殊字符对查询结果的影响
     *
     * @param param 要校验的参数
     * @return 转译后的参数
     */
    public static String translateSpecificSign(String param) {
        if (param == null) {
            return null;
        }
        if (param.contains("%")) {
            param = param.replaceAll("%", "\\\\%");
        }
        if (param.contains("_")) {
            param = param.replaceAll("_", "\\\\_");
        }
        return param;
    }

    public static void verifyLength(String str, int length, String name) {
        if (str == null || str.length() == 0 || str.equals("null")) {
            throw ExceptionResultEnum.ERROR.exception(name + "不能为空");
        }
        if (str.length() > length) {
            throw ExceptionResultEnum.ERROR.exception("[" + name + ":" + str + "]' 超过长度限制 : " + length);
        }
    }

    public static boolean strNotNull(String str) {
        return str != null && str.length() > 0 && !str.equals("null");
    }

    /**
     * Long 类型的参数不为空
     *
     * @param x 参数
     * @return true：不为空、false：为空
     */
    public static boolean longNotNull(Long x) {
        return x != null && x > 0;
    }

    public static Long getHeadOrUserSchoolId() {
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        Long schoolId;
        if (Objects.nonNull(ServletUtil.getRequestHeaderSchoolIdByNotVaild())) {
            schoolId = Long.parseLong(ServletUtil.getRequestHeaderSchoolIdByNotVaild().toString());
        } else {
            schoolId = sysUser.getSchoolId();
        }
        return schoolId;
    }

    /**
     * 检验字段
     *
     * @param obj   被检验的映射类对象
     * @param clazz 该对象的类
     * @return 检验结果(状态 、 信息)
     * @throws IllegalAccessException 异常
     */
    public static DBVerifyResult verifyDBFields(Object obj, Class<?> clazz) throws IllegalAccessException {
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true); // 解除封装
            String fieldValue = String.valueOf(field.get(obj));
            DBVerify dbVerify = field.getAnnotation(DBVerify.class);
            if (Objects.isNull(dbVerify)) {
                continue;
            }
            String value = dbVerify.value();
            boolean required = dbVerify.required();
            int min = dbVerify.min();
            int max = dbVerify.max();

            if (required) {
                if (fieldValue == null || fieldValue.length() == 0 || fieldValue.equals("null")) {
                    return new DBVerifyResult(false, "[" + value + "]为必须字段，不能为空");
                }
            }
            if (fieldValue != null && min > 0) {
                if (fieldValue.length() < min) {
                    return new DBVerifyResult(false, "[" + value + "]低于最小长度限制，最小限制[" + min + "]");
                }
            }
            if (fieldValue != null && max > 0) {
                if (fieldValue.length() > max) {
                    return new DBVerifyResult(false, "[" + value + "]超过最大长度限制，最大限制[" + max + "]");
                }
            }
        }
        return new DBVerifyResult(true, "成功");
    }

    /**
     * 验证参数任意一个为空
     *
     * @param objects 要非空校验的参数
     */
    public static boolean isOneNull(Object... objects) {
        boolean result = false;
        for (Object object : objects) {
            if (Objects.isNull(object)) {
                result = true;
            } else if (object instanceof String) {
                String param = String.valueOf(object);
                if (param.length() == 0 || param.equals("null")) {
                    result = true;
                }
            } else if (object instanceof Long) {
                Long param = SystemConstant.convertIdToLong(String.valueOf(object));
                if (param == null || param == 0) {
                    result = true;
                }
            } else if (object instanceof Integer) {
                int param = Integer.parseInt(String.valueOf(object));
                if (param == 0) {
                    result = true;
                }
            }
        }
        return result;
    }

    /**
     * 构建流程变量
     *
     * @param objectId
     * @param o
     * @param tfCustomTypeEnum
     * @param approveId
     * @param flowSubmit
     * @return
     */
    public static Map<String, Object> buildFlowVar(Long objectId,
                                                   Object o,
                                                   TFCustomTypeEnum tfCustomTypeEnum,
                                                   Long approveId,
                                                   boolean flowSubmit) {
        Map<String, Object> map = new HashMap<>();
        map.computeIfAbsent(SystemConstant.OBJECT_ID, v -> objectId);
        map.computeIfAbsent(SystemConstant.OBJECT_DATA, v -> o);
        map.computeIfAbsent(SystemConstant.FLOW_TYPE, v -> tfCustomTypeEnum);
        map.computeIfAbsent(SystemConstant.APPROVE_ID, v -> approveId);
        map.computeIfAbsent(SystemConstant.FLOW_SUBMIT, v -> flowSubmit);
        return map;
    }

    /**
     * 跨步数组（将list集合按照cpu核心数量拆分成多个集合）
     *
     * @param datasource 数据源
     * @param <T>        泛型
     * @return 拆分好地集合的集合
     */
    public static <T> List<List<T>> getStepList(List<T> datasource) {
        int cpuNum = Runtime.getRuntime().availableProcessors();
        int step = datasource.size() / cpuNum + 1;
        List<List<T>> result = new ArrayList<>();
        int size = datasource.size();
        for (int i = 0; i < size; i = i + step) {
            List<T> cell = datasource.stream().skip(i).limit(step).collect(Collectors.toList());
            result.add(cell);
        }
        return result;
    }

    /**
     * URL 编码, Encode默认为UTF-8.
     */
    public static String urlEncode(String part) {
        try {
            return URLEncoder.encode(part, SystemConstant.CHARSET_NAME);
        } catch (UnsupportedEncodingException e) {
            throw ExceptionResultEnum.ERROR.exception(e.getMessage());
        }
    }

    /**
     * 图片转换
     *
     * @param imgBase64
     * @param filePath
     * @throws IOException
     */
    public static void base64ToImage(String imgBase64, String filePath) throws IOException {
        OutputStream out = null;
        try {
            byte[] b = Base64Util.decode(imgBase64);
            out = new FileOutputStream(filePath);
            IOUtils.write(b, out);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (Objects.nonNull(out)) {
                out.flush();
                out.close();
            }
        }
    }

    /**
     * 获取本地文件host
     *
     * @param hostUrl
     * @return
     */
    public static String getLocalFileHost(String hostUrl) {
        CommonCacheService commonCacheService = SpringContextHolder.getBean(CommonCacheService.class);
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        BasicSchool basicSchool = commonCacheService.schoolCache(sysUser.getSchoolId());
        return SystemConstant.getHost(hostUrl, basicSchool.getCode());
    }

    /**
     * 获取host
     *
     * @param hostUrl
     * @param schoolCode
     * @return
     */
    public static String getHost(String hostUrl, String schoolCode) {
        if (hostUrl.contains(SystemConstant.PATH_MATCH)) {
            hostUrl = hostUrl.replace(SystemConstant.PATH_MATCH, schoolCode);
        }
        return hostUrl;
    }

    /**
     * 获取本地文件路径
     *
     * @param filePath
     * @return
     */
    public static String getLocalFilePath(String filePath) {
        DictionaryConfig dictionaryConfig = SpringContextHolder.getBean(DictionaryConfig.class);
        FileStoreUtil fileStoreUtil = SpringContextHolder.getBean(FileStoreUtil.class);
        boolean oss = dictionaryConfig.sysDomain().isOss();
        if (oss || (!oss && dictionaryConfig.fssPublicDomain().getConfig().startsWith(SystemConstant.START_PARENT))) {
            if (!filePath.startsWith("http") || !filePath.startsWith("https")) {
                return filePath;
            } else {
                filePath = fileStoreUtil.getPrivateUrl(filePath, UploadFileEnum.FILE.getFssType());
            }
        } else {
            if (filePath.contains(dictionaryConfig.fssPublicDomain().getServer())) {
                filePath = filePath.substring(filePath.indexOf(dictionaryConfig.fssPublicDomain().getServer()), filePath.length());
            } else if (filePath.contains(dictionaryConfig.fssPrivateDomain().getServer())) {
                filePath = filePath.substring(filePath.indexOf(dictionaryConfig.fssPrivateDomain().getServer()), filePath.length());
            }
        }
        return filePath;
    }

    /**
     * 删除缓存
     *
     * @param userId
     */
    public static void deleteUserCache(Long userId) {
        CommonCacheService commonCacheService = SpringContextHolder.getBean(CommonCacheService.class);
        commonCacheService.removeUserCache(userId);
        commonCacheService.removeUserAuthCache(userId);
        commonCacheService.removeUserMenuCache(userId);
        commonCacheService.removeUserRolePrivilegeCache(userId);
    }

    /**
     * 获取临时文件
     *
     * @param suffix
     * @return
     */
    public static File getFileTempVar(String suffix) throws IOException {
        File fileTmpDir = new File(System.getProperty(SystemConstant.TMP_DIR));
        if (!fileTmpDir.exists()) {
            fileTmpDir.mkdirs();
        }
        File file = File.createTempFile(SystemConstant.TEMP, suffix);
        log.info("getFileTempVar_absolutePath:{}", file.getAbsolutePath());
        return file;
    }

    /**
     * 获取临时文件
     *
     * @param suffix
     * @return
     */
    public static File getFileTempDirVar(String suffix) {
        File fileTmpDir = new File(System.getProperty(SystemConstant.TMP_DIR));
        if (!fileTmpDir.exists()) {
            fileTmpDir.mkdirs();
        }
        File file = new File(System.getProperty(SystemConstant.TMP_DIR), SystemConstant.getNanoId() + suffix);
        log.info("getFileTempDirVar_absolutePath:{}", file.getAbsolutePath());
        return file;
    }

    /**
     * 获取临时文件
     *
     * @param fileName
     * @param suffix
     * @return
     */
    public static File getFileTempDirVar(String fileName, String suffix) {
        File file = getFileTempDirVarForZip(fileName, suffix);
        if (!file.exists()) {
            file.getParentFile().mkdirs();
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        log.info("getFileTempDirVar_absolutePath:{}", file.getAbsolutePath());
        return file;
    }

    /**
     * 获取临时目录根路径
     *
     * @param suffix
     * @return
     */
    public static File getFileTempParentDirVar(String suffix) {
        File file = null;
        try {
            file = getFileTempDirVar(suffix);
            return file.getParentFile();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (file != null) {
                FileUtil.deleteFile(file);
            }
        }
    }

    /**
     * 获取临时文件
     *
     * @param fileName
     * @param suffix
     * @return
     */
    public static File getFileTempDirVarForZip(String fileName, String suffix) {
        File fileTmpDir = new File(System.getProperty(SystemConstant.TMP_DIR));
        if (!fileTmpDir.exists()) {
            fileTmpDir.mkdirs();
        }
        String fileNameNew = null;
        if (!StringUtils.isBlank(suffix)) {
            fileNameNew = fileName + suffix;
        } else {
            fileNameNew = fileName;
        }
        File file = new File(System.getProperty(SystemConstant.TMP_DIR), fileNameNew);
        log.info("getFileTempDirVar_absolutePath:{}", file.getAbsolutePath());
        return file;
    }

    /**
     * 获取dirname
     *
     * @param uploadFileEnum
     * @param fileSpearator
     * @return
     */
    public static StringJoiner getDirName(UploadFileEnum uploadFileEnum, boolean fileSpearator) {
        LocalDateTime nowTime = LocalDateTime.now();
        StringJoiner stringJoiner = new StringJoiner("");
        stringJoiner.add(uploadFileEnum.getTitle()).add(File.separator)
                .add(String.valueOf(nowTime.getYear())).add(File.separator)
                .add(String.format(SystemConstant.DATE_TIME_FORMAT, nowTime.getMonthValue())).add(File.separator)
                .add(String.format(SystemConstant.DATE_TIME_FORMAT, nowTime.getDayOfMonth()));
        if (fileSpearator) {
            stringJoiner.add(File.separator);
        }
        return stringJoiner;
    }

    /**
     * 获取dirname
     *
     * @param stringJoiner
     * @param uploadFileEnum
     * @param fileSpearator
     * @return
     */
    public static StringJoiner getDirName(StringJoiner stringJoiner, UploadFileEnum uploadFileEnum, boolean fileSpearator) {
        LocalDateTime nowTime = LocalDateTime.now();
        stringJoiner.add(uploadFileEnum.getTitle()).add(File.separator)
                .add(String.valueOf(nowTime.getYear())).add(File.separator)
                .add(String.format(SystemConstant.DATE_TIME_FORMAT, nowTime.getMonthValue())).add(File.separator)
                .add(String.format(SystemConstant.DATE_TIME_FORMAT, nowTime.getDayOfMonth()));
        if (fileSpearator) {
            stringJoiner.add(File.separator);
        }
        return stringJoiner;
    }

    /**
     * 获取pdf文件路径
     *
     * @param pdfDirName
     * @param file
     * @return
     * @throws Exception
     */
    public static String getPdfFilePath(String pdfDirName, File file) throws Exception {
        DictionaryConfig dictionaryConfig = SpringContextHolder.getBean(DictionaryConfig.class);
        FileStoreUtil fileStoreUtil = SpringContextHolder.getBean(FileStoreUtil.class);
        boolean oss = dictionaryConfig.sysDomain().isOss();
        if (oss || (!oss && dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT))) {
            fileStoreUtil.ossUpload(pdfDirName, file, DigestUtils.md5Hex(new FileInputStream(file)), fileStoreUtil.getUploadEnumByPath(pdfDirName).getFssType());
        } else {
            fileStoreUtil.localUpload(pdfDirName, new FileInputStream(file), DigestUtils.md5Hex(new FileInputStream(file)), LocalCatalogEnum.LOCAL_PDF);
        }
        return pdfDirName;
    }

    /**
     * 创建txt文件
     *
     * @param message
     * @return
     * @throws Exception
     */
    public static JSONObject createTxt(String message) throws Exception {
        File txtFileTemp = null;
        try {
            FileStoreUtil fileStoreUtil = SpringContextHolder.getBean(FileStoreUtil.class);
            DictionaryConfig dictionaryConfig = SpringContextHolder.getBean(DictionaryConfig.class);
            boolean oss = dictionaryConfig.sysDomain().isOss();
            String ossStr = null;
            StringJoiner stringJoiner = new StringJoiner("");
            if (!oss && Objects.nonNull(dictionaryConfig.fssPublicDomain()) && !StringUtils.isBlank(dictionaryConfig.fssPublicDomain().getConfig()) && !dictionaryConfig.fssPublicDomain().getConfig().startsWith(SystemConstant.START_PARENT)) {
                stringJoiner.add(dictionaryConfig.fssPublicDomain().getConfig()).add(File.separator);
            }
            stringJoiner = SystemConstant.getDirName(stringJoiner, UploadFileEnum.FILE, true);
            stringJoiner.add(SystemConstant.getNanoId()).add(SystemConstant.TXT_PREFIX);

            String txtDirName = stringJoiner.toString();
            txtFileTemp = SystemConstant.getFileTempVar(SystemConstant.TXT_PREFIX);

            String charset = SystemConstant.CHARSET_NAME;
            CommonCacheService commonCacheService = SpringContextHolder.getBean(CommonCacheService.class);
            SysConfig sysConfig = commonCacheService.addSysConfigCache(SystemConstant.SYS_CONFIG_KEY_CHARSETS);
            if (Objects.nonNull(sysConfig) && StringUtils.isNotBlank(sysConfig.getConfigValue())) {
                charset = sysConfig.getConfigValue();
            }
            IOUtils.write(message.getBytes(charset), new FileOutputStream(txtFileTemp));

            String txtFileMd5 = DigestUtils.md5Hex(new FileInputStream(txtFileTemp));
            if (oss || (!oss && dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT))) {
                ossStr = oss ? SystemConstant.OSS : SystemConstant.LOCAL;
                fileStoreUtil.ossUpload(txtDirName, txtFileTemp, txtFileMd5, fileStoreUtil.getUploadEnumByPath(txtDirName).getFssType());
            } else {
                ossStr = SystemConstant.LOCAL;
                fileStoreUtil.localUpload(txtDirName, new FileInputStream(txtFileTemp), txtFileMd5, LocalCatalogEnum.LOCAL_FILE);
            }
            JSONObject json = new JSONObject();
            json.put(SystemConstant.PATH, stringJoiner.toString());
            json.put(SystemConstant.TYPE, ossStr);
            json.put(SystemConstant.UPLOAD_TYPE, UploadFileEnum.FILE);
            return json;
        } finally {
            if (Objects.nonNull(txtFileTemp)) {
                txtFileTemp.delete();
            }
        }
    }

    /**
     * 创建加密的zip
     *
     * @param zipFile
     * @param zipLocalRootPath
     * @param zipDirName
     * @return
     * @throws Exception
     */
    public static JSONObject createZip(File zipFile, String zipLocalRootPath, String zipDirName) throws Exception {
        FileStoreUtil fileStoreUtil = SpringContextHolder.getBean(FileStoreUtil.class);
        DictionaryConfig dictionaryConfig = SpringContextHolder.getBean(DictionaryConfig.class);
        Zip4jUtil.zipEncryptFile(zipFile.getPath(), zipLocalRootPath, SystemConstant.ZIP_ENCRYPT_PWD);

        boolean oss = dictionaryConfig.sysDomain().isOss();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put(SystemConstant.PATH, zipDirName);
        String zipFileMd5 = DigestUtils.md5Hex(new FileInputStream(zipFile));
        if (oss || (!oss && dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT))) {//上传至oss
            fileStoreUtil.ossUpload(zipDirName, zipFile, zipFileMd5, fileStoreUtil.getUploadEnumByPath(zipDirName).getFssType());
            jsonObject.put(SystemConstant.TYPE, oss ? SystemConstant.OSS : SystemConstant.LOCAL);
        } else {
            fileStoreUtil.localUpload(zipDirName, new FileInputStream(zipFile), zipFileMd5, LocalCatalogEnum.LOCAL_FILE);
            jsonObject.put(SystemConstant.TYPE, SystemConstant.LOCAL);
        }
        jsonObject.put(SystemConstant.UPLOAD_TYPE, UploadFileEnum.FILE);
        return jsonObject;
    }

    /**
     * 创建加密的zip
     *
     * @param zipFile
     * @param sourceFileList
     * @param zipDirName
     * @return
     * @throws Exception
     */
    public static JSONObject createZip(File zipFile, List<File> sourceFileList, String zipDirName) throws Exception {
        FileStoreUtil fileStoreUtil = SpringContextHolder.getBean(FileStoreUtil.class);
        DictionaryConfig dictionaryConfig = SpringContextHolder.getBean(DictionaryConfig.class);
        Zip4jUtil.zipEncryptFile(zipFile.getPath(), sourceFileList, SystemConstant.ZIP_ENCRYPT_PWD);

        boolean oss = dictionaryConfig.sysDomain().isOss();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put(SystemConstant.PATH, zipDirName);
        String zipFileMd5 = DigestUtils.md5Hex(new FileInputStream(zipFile));
        if (oss || (!oss && dictionaryConfig.fssPrivateDomain().getConfig().startsWith(SystemConstant.START_PARENT))) {//上传至oss
            fileStoreUtil.ossUpload(zipDirName, zipFile, zipFileMd5, fileStoreUtil.getUploadEnumByPath(zipDirName).getFssType());
            jsonObject.put(SystemConstant.TYPE, oss ? SystemConstant.OSS : SystemConstant.LOCAL);
        } else {
            fileStoreUtil.localUpload(zipDirName, new FileInputStream(zipFile), zipFileMd5, LocalCatalogEnum.LOCAL_FILE);
            jsonObject.put(SystemConstant.TYPE, SystemConstant.LOCAL);
        }
        jsonObject.put(SystemConstant.UPLOAD_TYPE, UploadFileEnum.FILE);
        return jsonObject;
    }

    public static int calcBackupCount(Double backupCount, Integer studentCount, Integer defaultValue) {
        if (defaultValue == null) {
            defaultValue = DEFAULT_BACKUP_COUNT;
        }
        if (backupCount == null || backupCount <= 0) {
            return defaultValue;
        }
        // <1按比例，>=1按数量
        if (backupCount < 1) {
            if (studentCount == null || studentCount == 0) {
                return defaultValue;
            } else {
                BigDecimal bigDecimal = new BigDecimal(studentCount).multiply(new BigDecimal(backupCount)).setScale(0, RoundingMode.CEILING);
                if (bigDecimal.intValue() == 0) {
                    return defaultValue;
                } else {
                    return bigDecimal.intValue();
                }
            }
        } else {
            return backupCount.intValue();
        }
    }

    /**
     * 生成文件
     *
     * @param url   文件路径+文件名称
     * @param bytes 要生成的文件内容
     */
    public static File createJsonFile(String url, byte[] bytes) {
        File file = new File(url);
        try {
            if (!file.exists()) {
                file.getParentFile().mkdirs();
                file.createNewFile();
            } else {
                file.delete();
            }
            IOUtils.write(bytes, new FileOutputStream(file));
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
        }
        return file;
    }

    /**
     * 实现首字母大写
     *
     * @param str str
     * @return 首字母大写
     */
    public static String initCap(String str) {
        if (str == null || "".equals(str)) {
            return str;
        } else if (str.length() == 1) {
            return str.toUpperCase();
        } else {
            return str.substring(0, 1).toUpperCase() + str.substring(1);
        }
    }

    public static String generateRandomNumber(int n) {
        StringBuilder sb = new StringBuilder();
        Random rand = new Random();

        for (int i = 0; i < n; i++) {
            char digit = (char) (rand.nextInt('9' - '0') + '0');
            sb.append(digit);
        }

        return sb.toString();
    }

//    /**
//     * 获取版本号
//     *
//     * @return
//     */
//    public static String getVersion() {
//        MavenXpp3Reader reader = new MavenXpp3Reader();
//        Model model = null;
//        String version = null;
//        try {
//            model = reader.read(new FileReader("pom.xml"));
//            version = model.getVersion();
//        } catch (Exception e) {
//            log.error(SystemConstant.LOG_ERROR, e);
//        }
//        return version;
//    }

    /**
     * 判断是否是数字
     *
     * @param str
     * @return
     */
    public static Double isDouble(String str) {
        Double score = null;
        try {
            score = Double.valueOf(SystemConstant.df.format(Double.valueOf(str)));
        } catch (Exception e) {
        }
        return score;
    }
}
