Kaynağa Gözat

第一次提交

zero 2 gün önce
işleme
5b04382a16
74 değiştirilmiş dosya ile 9259 ekleme ve 0 silme
  1. 23 0
      src/main/java/com/cslg/ids/IdsApplication.java
  2. 179 0
      src/main/java/com/cslg/ids/common/core/auth/AuthAop.java
  3. 155 0
      src/main/java/com/cslg/ids/common/core/auth/Response.java
  4. 51 0
      src/main/java/com/cslg/ids/common/core/auth/ResponseEnum.java
  5. 362 0
      src/main/java/com/cslg/ids/common/core/auth/TreeUtils.java
  6. 30 0
      src/main/java/com/cslg/ids/common/core/auth/WxResultStatus.java
  7. 17 0
      src/main/java/com/cslg/ids/common/core/auth/checkAuth.java
  8. 150 0
      src/main/java/com/cslg/ids/common/core/base/Constants.java
  9. 27 0
      src/main/java/com/cslg/ids/common/core/base/MailConstants.java
  10. 30 0
      src/main/java/com/cslg/ids/common/core/base/RedisConf.java
  11. 23 0
      src/main/java/com/cslg/ids/common/core/log/BusinessLogTypeEnum.java
  12. 213 0
      src/main/java/com/cslg/ids/common/core/log/LogHelper.java
  13. 48 0
      src/main/java/com/cslg/ids/common/core/redis/CacheTTLEnum.java
  14. 493 0
      src/main/java/com/cslg/ids/common/core/redis/RedisService.java
  15. 47 0
      src/main/java/com/cslg/ids/common/exception/BusinessException.java
  16. 100 0
      src/main/java/com/cslg/ids/common/exception/ExceptionEnum.java
  17. 45 0
      src/main/java/com/cslg/ids/common/exception/GlobalException.java
  18. 16 0
      src/main/java/com/cslg/ids/common/exception/PermissionException.java
  19. 17 0
      src/main/java/com/cslg/ids/common/exception/ThrowException.java
  20. 45 0
      src/main/java/com/cslg/ids/common/exception/XiaoShiException.java
  21. 9 0
      src/main/java/com/cslg/ids/common/utils/BackupUtils.java
  22. 83 0
      src/main/java/com/cslg/ids/common/utils/BeanUtil.java
  23. 36 0
      src/main/java/com/cslg/ids/common/utils/CacheUtils.java
  24. 244 0
      src/main/java/com/cslg/ids/common/utils/DataUtils.java
  25. 445 0
      src/main/java/com/cslg/ids/common/utils/DateUtil.java
  26. 763 0
      src/main/java/com/cslg/ids/common/utils/DateUtils.java
  27. 180 0
      src/main/java/com/cslg/ids/common/utils/ExcelUtils.java
  28. 304 0
      src/main/java/com/cslg/ids/common/utils/FileUtils.java
  29. 381 0
      src/main/java/com/cslg/ids/common/utils/JsonUtils.java
  30. 66 0
      src/main/java/com/cslg/ids/common/utils/LoginUtils.java
  31. 25 0
      src/main/java/com/cslg/ids/common/utils/RabbitMQUtils.java
  32. 58 0
      src/main/java/com/cslg/ids/common/utils/RandomUtil.java
  33. 323 0
      src/main/java/com/cslg/ids/common/utils/ReadExcelUtils.java
  34. 1325 0
      src/main/java/com/cslg/ids/common/utils/RedisUtil.java
  35. 99 0
      src/main/java/com/cslg/ids/common/utils/RegexUtil.java
  36. 563 0
      src/main/java/com/cslg/ids/common/utils/StringUtils.java
  37. 20 0
      src/main/java/com/cslg/ids/config/MybatisPlusConfig.java
  38. 68 0
      src/main/java/com/cslg/ids/config/RabbitMQConfig.java
  39. 11 0
      src/main/java/com/cslg/ids/config/WebSocketConfig.java
  40. 78 0
      src/main/java/com/cslg/ids/controller/TranslateController.java
  41. 24 0
      src/main/java/com/cslg/ids/dto/FMSDeleteFileDTO.java
  42. 28 0
      src/main/java/com/cslg/ids/dto/FileInfoDTO.java
  43. 8 0
      src/main/java/com/cslg/ids/dto/FileInfoIdDTO.java
  44. 9 0
      src/main/java/com/cslg/ids/dto/SelectTranslatePlanDTO.java
  45. 9 0
      src/main/java/com/cslg/ids/dto/TaskIdDTO.java
  46. 13 0
      src/main/java/com/cslg/ids/dto/TranslateFileDTO.java
  47. 38 0
      src/main/java/com/cslg/ids/dto/TranslateFilePayLoadDTO.java
  48. 48 0
      src/main/java/com/cslg/ids/entity/FileInfo.java
  49. 28 0
      src/main/java/com/cslg/ids/entity/common/BaseEntity.java
  50. 30 0
      src/main/java/com/cslg/ids/entity/common/BaseVO.java
  51. 35 0
      src/main/java/com/cslg/ids/entity/common/Calculate.java
  52. 45 0
      src/main/java/com/cslg/ids/entity/common/DataSource.java
  53. 15 0
      src/main/java/com/cslg/ids/entity/common/DifyFile.java
  54. 25 0
      src/main/java/com/cslg/ids/entity/common/PatentData.java
  55. 168 0
      src/main/java/com/cslg/ids/entity/common/PersonnelVO.java
  56. 11 0
      src/main/java/com/cslg/ids/entity/common/Records.java
  57. 33 0
      src/main/java/com/cslg/ids/entity/common/SystemFile.java
  58. 9 0
      src/main/java/com/cslg/ids/mapper/FileInfoMapper.java
  59. 62 0
      src/main/java/com/cslg/ids/service/FileInfoService.java
  60. 864 0
      src/main/java/com/cslg/ids/service/TranslateService.java
  61. 248 0
      src/main/java/com/cslg/ids/service/common/FileManagerService.java
  62. 12 0
      src/main/java/com/cslg/ids/vo/FileTranslateVO.java
  63. 32 0
      src/main/java/com/cslg/ids/vo/SelectFileInfoVO.java
  64. 10 0
      src/main/java/com/cslg/ids/vo/SelectTranslateLogsVO.java
  65. 11 0
      src/main/java/com/cslg/ids/vo/SelectTranslatePlanVO.java
  66. 18 0
      src/main/java/com/cslg/ids/vo/SelectTranslateStatusVO.java
  67. 10 0
      src/main/java/com/cslg/ids/vo/TranslateAttachmentVO.java
  68. 8 0
      src/main/java/com/cslg/ids/vo/TranslateDownloadVO.java
  69. 10 0
      src/main/java/com/cslg/ids/vo/TranslateFileVO.java
  70. 70 0
      src/main/resources/application-dev.yml
  71. 43 0
      src/main/resources/application.yml
  72. 2 0
      src/main/resources/config/cron.setting
  73. 110 0
      src/main/resources/config/logback-spring.xml
  74. 21 0
      src/test/java/com/cslg/ids/IdsApplicationTests.java

+ 23 - 0
src/main/java/com/cslg/ids/IdsApplication.java

@@ -0,0 +1,23 @@
+package com.cslg.ids;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+@EnableCaching
+@EnableAsync
+@EnableScheduling
+@SpringBootApplication
+public class IdsApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(IdsApplication.class, args);
+        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "-----The Project started");
+    }
+
+}

+ 179 - 0
src/main/java/com/cslg/ids/common/core/auth/AuthAop.java

@@ -0,0 +1,179 @@
+package com.cslg.ids.common.core.auth;
+
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.cslg.ids.common.exception.XiaoShiException;
+import com.cslg.ids.common.utils.CacheUtils;
+import com.cslg.ids.common.utils.JsonUtils;
+import com.cslg.ids.common.utils.LoginUtils;
+import com.cslg.ids.entity.common.DataSource;
+import com.cslg.ids.entity.common.PersonnelVO;
+import io.swagger.v3.oas.annotations.Operation;
+import okhttp3.FormBody;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Objects;
+
+
+@Order(2)
+@Aspect
+@Component
+public class AuthAop {
+    public static Logger log = LoggerFactory.getLogger(JsonUtils.class);
+    @Value("${authorUrl}")
+    private String url;
+    @Autowired
+    private CacheUtils cacheUtils;
+    @Autowired
+    private LoginUtils loginUtils;
+
+    /**
+     * 定义切点
+     */
+    @Pointcut("@annotation(com.cslg.ids.common.core.auth.checkAuth)")
+    public void annotationPointcut() {
+
+    }
+
+    /**
+     * @param joinPoint 当前执行的方法
+     */
+    @Around("annotationPointcut()")
+    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
+        try {
+            //获得登录人信息
+            PersonnelVO personnelVO = cacheUtils.getLoginUserPersonnel(loginUtils.getId());
+            if (personnelVO.getState() == 0) {
+                return Response.error("登录账号已被禁用,请联系管理员启用");
+            }
+
+
+            // 是否通过切面过滤标记
+            Boolean isPass = true;
+            MethodSignature ms = (MethodSignature) joinPoint.getSignature();
+            //获得执行方法对象
+            Method method = ms.getMethod();
+            //获得执行方法对象上的@checkAuth,@Operation注解对象
+            checkAuth myAnnotation = method.getAnnotation(checkAuth.class);
+            Operation operAnnotation = method.getAnnotation(Operation.class);
+            //获得@checkAuth注解上FunId参数的值
+            String functionId = myAnnotation.FunId();
+            //获得执行方法的参数对象
+            Object[] args = joinPoint.getArgs();
+            //根据登录人的id以及功能id获得规则信息
+            //将登录人的id以及功能id放入requestBody中
+            RequestBody requestBody = new FormBody.Builder()
+                    .add("loginId", loginUtils.getId().toString())
+                    .add("functionId", functionId)
+                    .build();
+            //建立远程连接
+            OkHttpClient okHttpClient = new OkHttpClient();
+            //发送请求
+            Request request = new Request.Builder()
+                    .url(url + "/permission/api/data/queryDataRule")
+                    .addHeader("Cookie", LoginUtils.getToken())
+                    .post(requestBody)
+                    .build();
+            //获得请求结果
+            String resBody = Objects.requireNonNull(okHttpClient.newCall(request).execute().body()).string();
+            JSONArray jsonArray = JSONArray.parseArray(resBody);
+            //如果获得规则的返回值为[-1]则代表登录人没有使用该功能的权限
+            if (jsonArray.get(0).toString().equals("-1")) {
+                return Response.noPermissions("没有" + operAnnotation.summary() + "的功能");
+            }
+            //如果获得规则的返回值为[0],则直接通过判断
+            else if (jsonArray.size() == 1 && jsonArray.get(0).equals("0")) {
+                return joinPoint.proceed();
+            }
+            // 如果查询结果的size大于0证明有限制逻辑
+            if (jsonArray.size() > 0) {
+                RequestBody reBodySource = new FormBody.Builder()
+                        .add("tableName", "local")
+                        .build();
+                //处理jsonObject,变为(x==y)&&(z==t)的形式 ,并用js引擎进行boolean判断
+                //建立连接去获得字典信息
+                OkHttpClient okHttpClientSou = new OkHttpClient();
+                //发送请求
+                Request requestSou = new Request.Builder()
+                        .url(url + "/permission/api/data/getDataSource")
+                        .post(reBodySource)
+                        .addHeader("Cookie", LoginUtils.getToken())
+                        .build();
+                //获得请求返回
+                String resSource = Objects.requireNonNull(okHttpClientSou.newCall(requestSou).execute().body()).string();
+
+                JSONArray jsonArray1 = JSON.parseArray(resSource);
+                // 获得字典
+                List<DataSource> dataSources = jsonArray1.toJavaList(DataSource.class);
+                //循环遍历将多个规则拼接起来
+                StringBuilder sqlStr = new StringBuilder();
+                for (int i = 0; i < jsonArray.size(); i++) {
+                    //将数据库里存的规则转换为可识别的判断逻辑
+                    String sql = TreeUtils.reCompute(JSONObject.parseObject(jsonArray.get(i).toString()), args, dataSources, personnelVO);
+                    sqlStr.append(jsonArray.size() != i + 1 ? sql + " || " : sql);
+                }
+                //js引擎进行判断
+                ScriptEngineManager manager = new ScriptEngineManager();
+                //根据名字获得引擎
+                ScriptEngine engine = manager.getEngineByName("javascript");
+                //进行判断,生成判断结果并将判断结果赋给isPass
+                Object result = engine.eval(sqlStr.toString());//进行判断
+                isPass = (Boolean) result;
+            }
+
+            //判断不通过
+            if (!isPass) {
+                return Response.noPermissions("没有权限进行" + operAnnotation.summary() + "的操作");
+            }
+            //判断通过
+            return joinPoint.proceed();
+        } catch (XiaoShiException e) { // 捕获自定义异常
+            log.error("切面捕获XiaoShiException", e);
+            throw e; // 重新抛出,交由全局拦截器处理
+        } catch (Exception e) {
+            log.error("切面捕获其他异常", e);
+            throw new RuntimeException("切面处理失败", e); // 包装后重新抛出
+        }
+
+    }
+
+
+    @Before(value = "annotationPointcut()")
+    public void doAfterReturning(JoinPoint joinPoint) {
+        this.handleAfterLog(joinPoint);
+
+    }
+
+    protected void handleAfterLog(JoinPoint joinPoint) {
+        try {
+            log.info("after ----> title:{}, desc:{}",1,2);
+            return;
+        } catch (Exception var10) {
+            log.error("operlog exception:{}", var10);
+            return;
+        }
+    }
+
+}
+

+ 155 - 0
src/main/java/com/cslg/ids/common/core/auth/Response.java

@@ -0,0 +1,155 @@
+package com.cslg.ids.common.core.auth;
+
+
+import com.cslg.ids.common.utils.JsonUtils;
+import com.cslg.ids.entity.common.BaseVO;
+
+public class Response {
+
+    private Integer code;
+    private Object data;
+    private String message;
+    private Object pageColumn;
+
+    public Response(Integer code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+
+    public Response() {
+    }
+
+    public static String success() {
+        Response response = new Response();
+        response.setResultEnum(ResponseEnum.SUCCESS);
+        return JsonUtils.objectToJson(response);
+    }
+
+    public static String success(Object data) {
+        Response response = new Response();
+        response.setResultEnum(ResponseEnum.SUCCESS);
+        response.setData(data);
+        return JsonUtils.objectToJson(response);
+    }
+
+    public static String success(Object data, BaseVO baseVO) {
+        Response response = new Response();
+        response.setResultEnum(ResponseEnum.SUCCESS);
+        response.setData(data);
+        response.setPageColumn(baseVO);
+        return JsonUtils.objectToJson(response);
+    }
+
+    public static String websocket(Object data, ResponseEnum responseEnum) {
+        Response response = new Response();
+        response.setResultEnum(responseEnum);
+        response.setData(data);
+        return JsonUtils.objectToJson(response);
+    }
+
+    public static String error() {
+        Response response = new Response();
+        response.setData(Boolean.FALSE);
+        response.setResultEnum(ResponseEnum.ERROR);
+        return JsonUtils.objectToJson(response);
+    }
+
+    public static Response fail(Object data) {
+        Response response = new Response();
+        response.setCode(ResponseEnum.ERROR.getCode());
+        response.setMessage(data + "");
+        response.setData(data);
+        return response;
+    }
+
+    public static String error(String message) {
+        Response response = new Response();
+        response.setCode(ResponseEnum.ERROR.getCode());
+        response.setData(Boolean.FALSE);
+        response.setMessage(message);
+        return JsonUtils.objectToJson(response);
+    }
+
+    public static String error(Object data,String message) {
+        Response response = new Response();
+        response.setCode(ResponseEnum.ERROR.getCode());
+        response.setData(data);
+        response.setMessage(message);
+        return JsonUtils.objectToJson(response);
+    }
+
+    public static String error(ResponseEnum responseEnum) {
+        Response response = new Response();
+        response.setResultEnum(responseEnum);
+        return JsonUtils.objectToJson(response);
+    }
+
+    public static String error(Integer code, String message) {
+        Response response = new Response();
+        response.setCode(code);
+        response.setData(Boolean.FALSE);
+        response.setMessage(message);
+        return JsonUtils.objectToJson(response);
+    }
+
+    public static Response error1(String message) {
+        Response response = new Response();
+        response.setCode(ResponseEnum.ERROR.getCode());
+        response.setData(Boolean.FALSE);
+        response.setMessage(message);
+        return response;
+    }
+
+    public static Response error(String code,String message) {
+        Integer erCode= Integer.parseInt(code);
+        Response response = new Response();
+        response.setCode(erCode);
+        response.setMessage(message);
+        return response;
+    }
+
+    public static Response noPermissions(String message) {
+        Response response = new Response();
+        response.setCode(ResponseEnum.NO_PERMISSION.getCode());
+        response.setData(Boolean.FALSE);
+        response.setMessage(message);
+        return response;
+    }
+
+    public Object getData() {
+        return data;
+    }
+
+    public void setData(Object data) {
+        this.data = data;
+    }
+
+    public Object getPageColumn() {
+        return pageColumn;
+    }
+
+    public void setPageColumn(Object pageColumn) {
+        this.pageColumn = pageColumn;
+    }
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public void setCode(Integer code) {
+        this.code = code;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    private void setResultEnum(ResponseEnum responseEnum) {
+        this.code = responseEnum.getCode();
+        this.message = responseEnum.getMessage();
+    }
+}

+ 51 - 0
src/main/java/com/cslg/ids/common/core/auth/ResponseEnum.java

@@ -0,0 +1,51 @@
+package com.cslg.ids.common.core.auth;
+
+public enum ResponseEnum {
+
+    SUCCESS(200, "请求成功"),
+    NO_PERMISSION(201,"无权限"),
+    WEB_SOCKET_SUCCESS(2, "WebSocket请求成功"),
+    BATCH_UPLOAD_INSTRUCTION_TASK_SUCCESS(900, "WebSocket请求成功"),
+    PROJECT_IMPORT_TASK_SUCCESS(901, "WebSocket请求成功"),
+    PROJECT_EXPORT_TASK_SUCCESS(902, "WebSocket请求成功"),
+    PATENT_IMPORT_TASK_SUCCESS(903, "WebSocket请求成功"),
+    PATENT_EXPORT_TASK_SUCCESS(904, "WebSocket请求成功"),
+    UNAUTHORIZED(401, "未登录"),
+    NOT_PERMISSION(402, "无操作权限"),
+    FORBIDDEN(403, "拒绝访问"),
+    USERNAME_ERROR(0, "用户名不存在"),
+    PASSWORD_ERROR(0, "密码错误"),
+    VERIFY_CODE_ERROR(0, "验证码错误"),
+    QUERY_CACHE_ERROR(0, "专利检索缓存失效,请重试"),
+    BATCH_UPLOAD_INSTRUCTION_TASK_ERROR(800, "导入说明书失败"),
+    PROJECT_EXPORT_TASK_ERROR(802, "专题库数据导出失败"),
+    PATENT_IMPORT_TASK_ERROR(803, "专利导入专利失败"),
+    PATENT_EXPORT_TASK_ERROR(804, "专利导出专利失败"),
+    SYSTEM_ERROR(500, "系统异常"),
+    ERROR(0, "请求失败");
+
+
+    private Integer code;
+    private String message;
+
+    ResponseEnum(Integer code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public void setCode(Integer code) {
+        this.code = code;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+}

+ 362 - 0
src/main/java/com/cslg/ids/common/core/auth/TreeUtils.java

@@ -0,0 +1,362 @@
+package com.cslg.ids.common.core.auth;
+
+
+import com.alibaba.fastjson.JSONObject;
+import com.cslg.ids.entity.common.DataSource;
+import com.cslg.ids.entity.common.PersonnelVO;
+import org.springframework.stereotype.Component;
+
+import java.lang.reflect.Field;
+import java.util.List;
+
+@Component
+public class TreeUtils {
+    /**
+     * 将二叉树json对象转为sql where后的条件语句
+     * liRJ
+     *
+     * @param jsonObject  要处理的jsonObject对象
+     * @param dataSource  要使用的数据字典
+     * @param personnelVO 登录人的信息
+     * @return 拼接的sql
+     */
+    // 处理sql语句,返回拼接sql
+    public static String reSql(JSONObject jsonObject, List<DataSource> dataSource, PersonnelVO personnelVO) throws NoSuchFieldException, IllegalAccessException {
+        String sql;
+        //判断是否为规则,是的话则返回为“”,不对其他sql条件产生影响
+        if (jsonObject.get("nodeType").equals("logic")) {
+            sql = "";
+        }
+        //符合二叉树形式
+        else if (jsonObject.containsKey("left") && jsonObject.containsKey("right")) {
+            //将二叉树转换为sql条件
+            sql = recursionTree(jsonObject, dataSource, personnelVO);
+        }
+        // 不符合二叉树形式(单条数据)
+        else {
+            //获得规则的field字段,作为sql条件的栏位
+            String field = jsonObject.get("field").toString();
+            //获得规则的栏位值,并且要对值进行识别操作
+            String value = distinguishFields(jsonObject.get("value").toString(), dataSource, personnelVO);
+            if (jsonObject.get("opr").toString().equals("FIND_IN_SET")) {
+                sql = "FIND_IN_SET(" + value + "," + field + ")";
+            } else {
+                sql = field + " " + jsonObject.get("opr").toString() + " " + value;
+            }
+        }
+
+        return sql;
+    }
+
+    /**
+     * 将二叉树json对象转为sql where后的条件语句
+     * liRJ
+     *
+     * @param jsonObject  要处理的jsonObject对象
+     * @param dataSource  要使用的数据字典
+     * @param personnelVO 登录人的信息
+     * @return 拼接的sql
+     */
+    // 处理规则
+    public static String reCompute(JSONObject jsonObject, Object[] object, List<DataSource> dataSource, PersonnelVO personnelVO) throws NoSuchFieldException, IllegalAccessException {
+        String sql;
+        //判断是否为sql类型规则,是的话规则转换为1==1,不对其他规则产生影响
+        if (jsonObject.get("nodeType").equals("sql")) {
+            sql = "1==1";
+        }
+        //符合二叉树形式
+        else if (jsonObject.containsKey("left") && jsonObject.containsKey("right")) {
+            //将二叉树转换为规则判断
+            sql = cRecursionTree(jsonObject, object, dataSource, personnelVO);
+        }
+        // 不符合二叉树形式(单条数据)
+        else {
+            //获得规则的 field字段,并进行识别操作
+            String field = distinguishFields(jsonObject.get("field").toString(), object, dataSource, personnelVO);
+            //获得规则的 value字段,并进行识别操作
+            String value = distinguishValues(jsonObject.get("value").toString(), object);
+            //获得规则的 运算符字段,并进行识别操作
+            String opr = distinguishLogic(jsonObject.getString("nodeType"), jsonObject.getString("opr"));
+            //field 和value若为以,隔开的数组时,将被拆开,并合成为新的规则
+            sql = arrayEqlToString(field, value, opr);
+        }
+
+        return sql;
+    }
+
+    /**
+     * 递归将二叉树转换为字符串
+     * liRJ
+     *
+     * @param jsonObject jsonObject
+     */
+    //将二叉树转换为sql条件
+    public static String recursionTree(JSONObject jsonObject, List<DataSource> dataSource, PersonnelVO personnelVO) throws NoSuchFieldException, IllegalAccessException {
+        String str1;
+        String str2;
+        // 获得规则左边
+        JSONObject jsonLeft = jsonObject.getJSONObject("left");
+        // 获得规则右边
+        JSONObject jsonRight = jsonObject.getJSONObject("right");
+        //判断是否含有left分支,有的话进行递归
+        if (jsonLeft.containsKey("left")) {
+            str1 = recursionTree(jsonLeft, dataSource, personnelVO);//递归
+        }
+        //没有的话解析字符串拼接成子sql
+        else {
+            String field = jsonLeft.get("field").toString();
+            //获得规则的 value字段,并进行识别操作
+            String value = distinguishFields(jsonLeft.get("value").toString(), dataSource, personnelVO); //没有的话解析字符串拼接成子sql
+            if (jsonLeft.get("opr").toString().equals("FIND_IN_SET")) {
+                str1 = "FIND_IN_SET(" + value + "," + field + ")";
+            } else {
+                str1 = field + " " + jsonLeft.get("opr").toString() + " " + value;
+            }
+        }
+        //同上部分处理left分支
+        if (jsonRight.containsKey("right")) {
+            str2 = recursionTree(jsonRight, dataSource, personnelVO);
+        } else {
+            String field = jsonRight.get("field").toString();
+            String value = distinguishFields(jsonRight.get("value").toString(), dataSource, personnelVO);
+            if (jsonRight.get("opr").toString().equals("FIND_IN_SET")) {
+                str2 = "FIND_IN_SET(" + value + "," + field + ")";
+            } else {
+                str2 = field + " " + jsonRight.get("opr").toString() + " " + value;
+            }
+        }
+        return "(" + str1 + ") " + jsonObject.get("logicOpr") + " (" + str2 + ")";
+    }
+
+    //将二叉树转换为规则判断
+    public static String cRecursionTree(JSONObject jsonObject, Object[] object, List<DataSource> dataSource, PersonnelVO personnelVO) throws NoSuchFieldException, IllegalAccessException {
+        String str1;
+        String str2;
+        // 获得规则左边
+        JSONObject jsonLeft = jsonObject.getJSONObject("left");
+        // 获得规则右边
+        JSONObject jsonRight = jsonObject.getJSONObject("right");
+        //判断是否含有left分支,有的话进行递归
+        if (jsonLeft.containsKey("left")) {
+            str1 = cRecursionTree(jsonLeft, object, dataSource, personnelVO);
+        } else {
+            //获得规则的 field字段,并进行识别操作
+            String field = distinguishFields(jsonLeft.get("field").toString(), object, dataSource, personnelVO);
+            //获得规则的 value字段,并进行识别操作
+            String value = distinguishValues(jsonLeft.get("value").toString(), object);
+            //获得规则的 opr字段,并进行识别操作
+            String opr = distinguishLogic(jsonLeft.getString("nodeType"), jsonLeft.getString("opr"));
+            str1 = arrayEqlToString(field, value, opr);
+        }
+        //同上部分处理right分支
+        if (jsonRight.containsKey("right")) {
+            str2 = cRecursionTree(jsonRight, object, dataSource, personnelVO);
+        } else {
+            String field = distinguishFields(jsonRight.get("field").toString(), object, dataSource, personnelVO);
+            String value = distinguishValues(jsonRight.get("value").toString(), object);
+            String opr = distinguishLogic(jsonRight.getString("nodeType"), jsonRight.getString("opr"));
+            str2 = arrayEqlToString(field, value, opr);
+        }
+
+        return "(" + str1 + ") " + distinguishLogic(jsonObject.getString("nodeType"), jsonObject.getString("logicOpr")) + " (" + str2 + ")";
+    }
+
+    //对field和value部分进行计算 sql查询
+    public static String distinguishFields(String field, List<DataSource> dataSources, PersonnelVO personnelVO) throws NoSuchFieldException, IllegalAccessException {
+        //获得登录用户部门列表信息
+        List<PersonnelVO.DP> dps = personnelVO.getDpList();
+        //获得登录用户角色列表信息
+        List<PersonnelVO.PerRole> perRoles = personnelVO.getRList();
+        String tem = "";
+        String reField = field;
+        //如果参数是sql语句
+        if (field.contains("select")) {
+            for (DataSource dataSource : dataSources) {
+                String sourceField = dataSource.getDataSourceField();
+                if (field.contains("local." + sourceField)) {
+                    // 判断是否是部门信息
+                    if (sourceField.contains("DP.")) {
+                        // 分割字符串获得部门字段
+                        String Fields = sourceField.split("\\.")[1];
+                        // 遍历部门信息,用反射将对应字段转换成(*,*,...)格式
+                        for (PersonnelVO.DP dp : dps) {
+                            Class<?> DPClass = dp.getClass();
+                            Field dataField = DPClass.getDeclaredField(Fields);
+                            dataField.setAccessible(true);
+                            tem = dataField.get(dp).toString() + ",";
+
+                        }
+                        reField = sourceField.replace("local." + sourceField, "(" + tem.substring(0, tem.length() - 1) + ")");
+                    }
+                    //判断是否是角色信息(处理过程同部门信息处理过程)
+                    else if (sourceField.contains("PerRole.")) {
+                        String Fields = sourceField.split("\\.")[1];
+                        for (PersonnelVO.PerRole perRole : perRoles) {
+                            Class<?> DPClass = perRole.getClass();
+                            Field dataField = DPClass.getDeclaredField(Fields);
+                            dataField.setAccessible(true);
+                            tem = dataField.get(perRole).toString() + ",";
+                        }
+                        reField = sourceField.replace("local." + sourceField, "(" + tem.substring(0, tem.length() - 1) + ")");
+                    } else {
+                        Class<?> personClass = personnelVO.getClass();
+                        Field dataField = personClass.getDeclaredField(sourceField);
+                        dataField.setAccessible(true);
+                        reField = reField.replace("local." + sourceField, dataField.get(personnelVO).toString());
+                    }
+                }
+            }
+        }
+        //遍历字典数据
+        else {
+            for (DataSource dataSource : dataSources) {
+                // 如果匹配上字典字段则进行处理
+                if (field.equals(dataSource.getDataSourceField())) {
+                    // 判断是否是部门信息
+                    if (field.contains("DP.")) {
+                        // 分割字符串获得部门字段
+                        String Fields = field.split("\\.")[1];
+                        // 遍历部门信息,用反射将对应字段转换成(*,*,...)格式
+                        for (PersonnelVO.DP dp : dps) {
+                            Class<?> DPClass = dp.getClass();
+                            Field dataField = DPClass.getDeclaredField(Fields);
+                            dataField.setAccessible(true);
+                            tem = dataField.get(dp).toString() + ",";
+
+                        }
+                        reField = "(" + tem.substring(0, tem.length() - 1) + ")";
+                    }
+                    //判断是否是角色信息(处理过程同部门信息处理过程)
+                    else if (field.contains("PerRole.")) {
+                        String Fields = field.split("\\.")[1];
+                        for (PersonnelVO.PerRole perRole : perRoles) {
+                            Class<?> DPClass = perRole.getClass();
+                            Field dataField = DPClass.getDeclaredField(Fields);
+                            dataField.setAccessible(true);
+                            tem = dataField.get(perRole).toString() + ",";
+                        }
+                        reField = "(" + tem.substring(0, tem.length() - 1) + ")";
+                    } else {
+                        Class<?> personClass = personnelVO.getClass();
+                        Field dataField = personClass.getDeclaredField(field);
+                        dataField.setAccessible(true);
+                        reField = dataField.get(personnelVO).toString();
+                        break;
+                    }
+                }
+            }
+        }
+        return reField;
+    }
+
+    //对field部分进行计算
+    public static String distinguishFields(String field, Object[] object, List<DataSource> dataSources, PersonnelVO personnelVO) throws NoSuchFieldException, IllegalAccessException {
+        String reField = "'" + field + "'";
+        //反射获方法的参数值
+        Class<?> jsonClass = object[0].getClass();
+        for (Field field1 : jsonClass.getDeclaredFields()) {
+            if (field1.getName().equals(field)) {     //判断field的值是否和参数名一样,一样的话变为参数值
+                Field dataField = jsonClass.getDeclaredField(field);
+                dataField.setAccessible(true);//设置data属性为可访问的
+                String fie = dataField.get(object[0]).toString();
+                reField = "'" + fie + "'";
+                break;
+            }
+        }
+        //获得登录用户部门列表信息
+        List<PersonnelVO.DP> dps = personnelVO.getDpList();
+        //获得登录用户角色列表信息
+        List<PersonnelVO.PerRole> perRoles = personnelVO.getRList();
+        String tem = "";
+        //遍历字典数据
+        for (DataSource dataSource : dataSources) {
+            // 如果匹配上字典字段则进行处理
+            if (field.equals(dataSource.getDataSourceField())) {
+                // 判断是否是部门信息
+                if (field.contains("DP.")) {
+                    // 分割字符串获得部门字段
+                    String Fields = field.split("\\.")[1];
+                    // 遍历部门信息,用反射将对应字段转换成(*,*,...)格式
+                    for (PersonnelVO.DP dp : dps) {
+                        Class<?> DPClass = dp.getClass();
+                        Field dataField = DPClass.getDeclaredField(Fields);
+                        dataField.setAccessible(true);
+                        tem = dataField.get(dp).toString() + ",";
+
+                    }
+                    reField = tem.substring(0, tem.length() - 1);
+                }
+                //判断是否是角色信息(处理过程同部门信息处理过程)
+                else if (field.contains("PerRole.")) {
+                    String Fields = field.split("\\.")[1];
+                    for (PersonnelVO.PerRole perRole : perRoles) {
+                        Class<?> DPClass = perRole.getClass();
+                        Field dataField = DPClass.getDeclaredField(Fields);
+                        dataField.setAccessible(true);
+                        tem = dataField.get(perRole).toString() + ",";
+                    }
+                    reField = tem.substring(0, tem.length() - 1);
+                } else {
+                    Class<?> personClass = personnelVO.getClass();
+                    Field dataField = personClass.getDeclaredField(field);
+                    dataField.setAccessible(true);
+                    reField = "'" + dataField.get(personnelVO).toString() + "'";
+                    break;
+                }
+            }
+        }
+
+        return reField;
+    }
+
+    //对value部分进行计算
+    public static String distinguishValues(String value, Object[] object) throws NoSuchFieldException, IllegalAccessException {
+        String reValue = "'" + value + "'";
+        //反射获得参数值
+        Class<?> jsonClass = object[0].getClass();
+        for (Field field1 : jsonClass.getDeclaredFields()) {
+            if (field1.getName().equals(value)) {     //判断value的值是否和参数名一样,一样的话变为参数值
+                Field dataField = jsonClass.getDeclaredField(value);
+                dataField.setAccessible(true);//设置data属性为可访问的
+                String fie = dataField.get(object[0]).toString();
+                reValue = "'" + fie + "'";
+                break;
+            }
+        }
+
+        return reValue;
+    }
+
+    //对应改变运算逻辑
+    public static String distinguishLogic(String nodeType, String opr) {
+        if (nodeType.equals("logic")) {
+            switch (opr) {
+                case "=":
+                    opr = "==";
+                    break;
+                case "and":
+                    opr = "&&";
+                    break;
+                case "or":
+                    opr = "||";
+                    break;
+            }
+        }
+
+        return opr;
+    }
+
+    // 将x,y=z,w 形式改为 x=z||x=w||y=z||y=w形式
+    public static String arrayEqlToString(String field, String value, String opr) {
+        StringBuilder reStr = new StringBuilder();
+        String[] fields = field.split(",");
+        String[] values = value.split(",");
+        for (int i = 0; i < fields.length; i++) {
+            for (int t = 0; t < values.length; t++) {
+                reStr.append(i == fields.length - 1 && t == values.length - 1 ? fields[i] + opr + values[t] : fields[i] + opr + values[t] + "||");
+            }
+        }
+
+        return reStr.toString();
+    }
+}

+ 30 - 0
src/main/java/com/cslg/ids/common/core/auth/WxResultStatus.java

@@ -0,0 +1,30 @@
+package com.cslg.ids.common.core.auth;
+
+/**
+ * @author zsq
+ * @version 1.0
+ * @date 2021/3/31 14:19
+ */
+public enum WxResultStatus {
+
+    /**请求成功**/
+    SUCCESS(200, "成功"),
+    /**请求失败**/
+    FAIL(500, "请求失败"),
+    /**返回结果对象解析失败**/
+    FAIL_NULL_RES(510, "返回结果对象解析失败"),
+    /**返回结果为失败状态**/
+    FAIL_STATUS(520, "返回结果为失败状态"),
+    /**读取io流失败**/
+    FAIL_IO_ERR(530, "读取io流失败")
+    ;
+
+    private int status;
+    private String name;
+
+    WxResultStatus(int status, String name){
+        this.status = status;
+        this.name = name;
+    }
+
+}

+ 17 - 0
src/main/java/com/cslg/ids/common/core/auth/checkAuth.java

@@ -0,0 +1,17 @@
+package com.cslg.ids.common.core.auth;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * @author LRJ
+ * @date 2022-8-23
+ * @description 数据权限(增删改)条件判断注解
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface checkAuth {
+    String FunId() default "0";
+}
+

+ 150 - 0
src/main/java/com/cslg/ids/common/core/base/Constants.java

@@ -0,0 +1,150 @@
+package com.cslg.ids.common.core.base;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Constants {
+
+    public static final String ADMIN_USERNAME = "admin";
+
+    public static final String PROJECT_INFO_FILE_NAME = "project.json";
+    public static final String PROJECT_REPORT_DIRECTORY_NAME = "project-report";
+    public static final String PROJECT_REPORT_FILE_NAME = "project-report.json";
+    public static final String PROJECT_FILE_DIRECTORY_NAME = "project-file";
+    public static final String PROJECT_FILE_FILE_NAME = "project-file.json";
+    public static final String PROJECT_PATENT_LINK_FILE_NAME = "project-patent-link.json";
+    public static final String PATENT_IMAGE_DIRECTORY_NAME = "patent-image";
+    public static final String PATENT_IMAGE_FILE_NAME = "patent-image.json";
+    public static final String PATENT_INSTRUCTION_DIRECTORY_NAME = "patent-instruction";
+    public static final String PATENT_INSTRUCTION_FILE_NAME = "patent-instruction.json";
+    public static final String PATENT_APPLICANT_MERGE_LINK_FILE_NAME = "patent-applicant-merge-link.json";
+    public static final String PATENT_APPLICANT_FILE_NAME = "patent-applicant.json";
+    public static final String PATENT_APPLICANT_LINK_FILE_NAME = "patent-applicant-link.json";
+    public static final String PATENT_FILE_NAME = "patent.json";
+    public static final String PATENT_ID_PATENT_NO_FILE_NAME = "patent-id-patentno.json";
+    public static final String PATENT_AFFAIR_FILE_NAME = "patent-affair.json";
+    public static final String PATENT_AGENCY_FILE_NAME = "patent-agency.json";
+    public static final String PATENT_AGENT_LINK_FILE_NAME = "patent-agent-link.json";
+    public static final String PATENT_AGENT_FILE_NAME = "patent-agent.json";
+    public static final String PATENT_INSTRUCTION_TEXT_FILE_NAME = "patent-instruction-text.json";
+    public static final String PATENT_INVENTOR_LINK_FILE_NAME = "patent-inventor-link.json";
+    public static final String PATENT_INVENTOR_MERGE_FILE_NAME = "patent-inventor-merge.json";
+    public static final String PATENT_INVENTOR_FILE_NAME = "patent-inventor.json";
+    public static final String PATENT_LICENSOR_FILE_NAME = "patent-licensor.json";
+    public static final String PATENT_PLEDGE_FILE_NAME = "patent-pledge.json";
+    public static final String PATENT_RIGHT_FILE_NAME = "patent-right.json";
+    public static final String PATENT_FAMILY_LINK_FILE_NAME = "patent-family-link.json";
+    public static final String PATENT_FAMILY_FILE_NAME = "patent-family.json";
+    public static final String PATENT_CLASS_NUMBER_FILE_NAME = "patent-class-number.json";
+    public static final String PATENT_LABEL_FILE_NAME = "patent-label.json";
+    public static final String PROJECT_FIELD_FILE_NAME = "project-field.json";
+    public static final String PROJECT_FIELD_OPTION_FILE_NAME = "project-field-option.json";
+    public static final String PROJECT_FIELD_TREE_FILE_NAME = "project-field-tree.json";
+    public static final String PROJECT_FIELD_TEXT_FILE_NAME = "project-field-text.json";
+    public static final String PROJECT_FIELD_PATENT_LINK_FILE_NAME = "project-field-patent-link.json";
+
+    public static final String API_XiaoSHI = "/api/xiaoshi";
+    public static final String API_PPA = "/api/xiaoshi/ppa";
+    public static final String API_IDS = "/api/xiaoshi/ids";
+
+    public static final Integer PATENT_CLASS_NUMBER_IPC = 1;
+    public static final Integer PATENT_CLASS_NUMBER_CPC = 2;
+    public static final Integer PATENT_CLASS_NUMBER_UPC = 3;
+    public static final Integer PATENT_CLASS_NUMBER_LOC = 4;
+    public static final Integer MAX_IMPORT_TASK_COUNT=5;
+    public static final  Integer IMPORT_PATENT_TO=1;
+    public static final String   IMPORT_TASK_CONFIG="importTaskConfig";
+    /**
+     * 分隔符-竖线
+     */
+    public static final String SEPARATOR_VERTICAL_BAR = " | ";
+
+    /**
+     * 系统字段类型-查询检索
+     */
+    public static final String SYSTEM_FIELD_QUERY = "query";
+
+    /**
+     * 系统字段类型-专利导出
+     */
+    public static final String SYSTEM_FIELD_EXPORT = "export";
+
+    /**
+     * 系统字段类型-专利列表
+     */
+    public static final String SYSTEM_FIELD_PATENT_LIST = "list";
+
+    /**
+     * 系统字段类型-专题库字段
+     */
+    public static final String SYSTEM_FIELD_PROJECT = "project";
+
+    /**
+     * 专题库导入专利任务名称
+     */
+    public static final Integer TASK_IMPORT_PATENT = 1;
+
+    /**
+     * 专利说明书导入任务名称
+     */
+    public static final Integer TASK_IMPORT_PATENT_INSTRUCTION = 3;
+
+    /**
+     * 专利导出任务名称
+     */
+    public static final Integer TASK_EXPORT_PATENT = 2;
+
+    /**
+     * 日期位移值
+     */
+    public static final Map<String, Integer> DATE_OFFSET = new HashMap<String, Integer>() {{
+        put("月", -1);
+        put("季", -3);
+        put("半年", -6);
+        put("年", -12);
+        put("2年", -24);
+        put("3年", -36);
+        put("5年", -60);
+    }};
+
+    /**
+     * 专利类型
+     */
+    public static final String PATENT_TYPE = "PATENT_TYPE";
+
+    /**
+     * 机构类型
+     */
+    public static final String ORGAN_TYPE = "ORGAN_TYPE";
+
+    /**
+     * 许可人/被许可人
+     */
+    public static final String LICENSOR_TYPE = "LICENSOR_TYPE";
+
+    /**
+     * 简单法律状态
+     */
+    public static final String PATENT_SIMPLE_STATUS = "PATENT_SIMPLE_STATUS";
+
+    /**
+     * 国家
+     */
+    public static final String COUNTRIES = "COUNTRIES";
+
+    /**
+     * 法律状态
+     */
+    public static final String PATENT_STATUS = "PATENT_STATUS";
+
+    /**
+     * 企业应用场景
+     */
+    public static final String ENTERPRISE_APPLICATION_SCENARIO = "ENTERPRISE_APPLICATION_SCENARIO";
+
+    /**
+     * 调查类型
+     */
+    public static final String INVESTIGATION_TYPE = "INVESTIGATION_TYPE";
+
+}

+ 27 - 0
src/main/java/com/cslg/ids/common/core/base/MailConstants.java

@@ -0,0 +1,27 @@
+package com.cslg.ids.common.core.base;
+
+public class MailConstants {
+    //消息投递中
+    public static final Integer DELIVERING = 0;
+
+    //消息投成功
+    public static final Integer SUCCESS = 1;
+
+    //消息投递失败
+    public static final Integer FAILURE = 2;
+
+    //最大重试次数
+    public static final Integer MAX_TRY_COUNT = 2;
+
+    //消息超时时间
+    public static final Integer MSG_TIMEOUT = 1;
+
+    //队列
+
+    //交换机
+    public static final String MAIL_EXCHANGE_NAME = "mail.exchange";
+
+    //路由键
+    public static final String MAIL_ROUTING_KEY_NAME = "mail.routing.key";
+
+}

+ 30 - 0
src/main/java/com/cslg/ids/common/core/base/RedisConf.java

@@ -0,0 +1,30 @@
+package com.cslg.ids.common.core.base;
+
+
+/**
+ * Redis常量类
+ */
+public class RedisConf {
+
+    public static final String SYMBOL_COLON = ":";
+    public static final String SYMBOL_LINE = "-";
+    public final static String COMMON_DATA = "common-data";
+    public final static String LOGIN_USER = "login-user";
+    public final static String VERIFY_CODE = "verify-code";
+    public final static String SELECT_PATENT = "select-patent";
+    public final static String ANALYSIS_COUNT = "analysis-count";
+    public final static String AREA_LIST = "area-list";
+    public final static String USER_FIELD = "user-field";
+    public final static String FIELD_ORDER = "field-order";
+    public final static String USER_IMPORT = "user-import";
+    public final static String PROJECT_FIELD_ORDER = "project_field_order";
+    public final static String TASK_FIELD_ORDER = "task_field_order";
+    public final static String PATENT_COUNT = "patent-count";
+    public final static String TASK_FIELD_COUNT = "task_field_count";
+    public final static String PROJECT_FIELD_COUNT = "project_field_count";
+    public final static String FIELD_COUNT = "field_count";
+    public final static String PROJECT = "project";
+    public final static String PRODUCT = "product";
+    public final static String EVIDENCE_REASON = "evidence_reason";
+    public final static String GET_PATENT_SIMILAR_SCORE="get_patent_similar_score";
+}

+ 23 - 0
src/main/java/com/cslg/ids/common/core/log/BusinessLogTypeEnum.java

@@ -0,0 +1,23 @@
+package com.cslg.ids.common.core.log;
+
+public enum BusinessLogTypeEnum {
+	ECOMMERCE("ecommerce","小世电商模块");
+	private String desc;
+	private String type;
+	private BusinessLogTypeEnum(String type, String desc) {
+		this.setType(type);
+		this.setDesc(desc);
+	}
+	public String getType() {
+		return type;
+	}
+	public void setType(String type) {
+		this.type = type;
+	}
+	public String getDesc() {
+		return desc;
+	}
+	public void setDesc(String desc) {
+		this.desc = desc;
+	}
+}

+ 213 - 0
src/main/java/com/cslg/ids/common/core/log/LogHelper.java

@@ -0,0 +1,213 @@
+package com.cslg.ids.common.core.log;
+
+
+import com.cslg.ids.common.exception.BusinessException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * 日志工具类
+ * @author Peach
+ *
+ */
+public class LogHelper {
+	
+	private static Logger logger = null;
+
+	//------------------------------------------系统日志记录-------------------------
+	/**
+	 * @param info
+	 */
+	public static void log(Object...info) {
+		logger = LoggerFactory.getLogger("");
+		logger.info("info={}",info);
+	}
+	
+	public static void log(Throwable e,Object...info) {
+		logger = LoggerFactory.getLogger("");
+		logger.info("exception={} info={}",throwable2String(e),info);
+	}
+	
+	/**
+	 * @param clazz
+	 * @param info
+	 */
+	public static void log(Class clazz, String info) {
+		logger = LoggerFactory.getLogger(clazz);
+		logger.info(info);
+	}
+	
+	/**
+	 * @param clazz
+	 * @param e
+	 */
+	public static void log(Class clazz, Throwable e) {
+		log(clazz,throwable2String(e));
+	}
+	
+	/**
+	 * @param name
+	 * @param info
+	 */
+	@Deprecated
+	public static void log(String name, String info) {
+		logger = LoggerFactory.getLogger(name);
+		logger.info(name+"-"+info);
+	}
+	
+	/**
+	 * @param name
+	 * @param e
+	 */
+	@Deprecated
+	public static void log(String name, Throwable e) {
+		log(name,throwable2String(e));
+	}
+	
+	
+	/**
+	 * @param name
+	 * @param info
+	 * @param e
+	 */
+	@Deprecated
+	public static void log(String name, String info,Throwable e) {
+		log(name,info+"-"+throwable2String(e));
+	}
+	
+	
+	/**
+	 * @param clazz
+	 * @param info
+	 * @param e
+	 */
+	public static void log(Class clazz, String info,Throwable e) {
+		log(clazz,info+"-"+throwable2String(e));
+	}
+	
+	/**
+	 * 将异常信息转为string
+	 * @param e
+	 * @return
+	 */
+	private static String throwable2String(Throwable e){
+		if(checkBaseBusinessException(e)) {
+			BusinessException bbe = (BusinessException)e;
+			return "----->"+bbe.getErrorMessage();
+		}
+		PrintWriter pw = null;
+		StringWriter sw = null;
+		try{
+			sw = new StringWriter();
+			pw = new PrintWriter(sw);
+			e.printStackTrace(pw);
+			pw.flush();
+			sw.flush();
+		}catch (Exception e1) {
+			logger.info(e.getMessage());
+		}finally{
+			if(sw!=null){
+				try{
+					sw.close();
+				}catch (Exception e2) {
+					e2.printStackTrace();
+					return "";
+				}
+			}else{
+				return "";
+			}
+			if(pw!=null){
+				pw.close();
+			}
+			return sw.toString();
+		}
+		
+	}
+	
+	
+	/**
+	* @Title: checkBaseBusinessException
+	* @Description: 判断异常是否为系统异常
+	* @param @param e
+	* @param @return    参数
+	* @return boolean    返回类型
+	* @throws
+	* @author Orange
+	* @date 2019年1月23日
+	*/
+	private static boolean checkBaseBusinessException(Throwable e) {
+		return BusinessException.class.isInstance(e);
+	}
+	
+	
+	//------------------------------------------多业务日志记录-------------------------
+	
+	/**
+	* @Title: log
+	* @Description: 多业务动态日志
+	* @param @param businessLogTypeEnum
+	* @param @param info    参数
+	* @return void    返回类型
+	* @throws
+	* @author Orange
+	* @date 2019年1月21日
+	*/
+	public static void log(BusinessLogTypeEnum businessLogTypeEnum, Object...info) {
+		MDC.put("businessName", businessLogTypeEnum.getType());
+		Logger logger = LoggerFactory.getLogger("business_log");
+		logger.info("businessName={}, info={}", businessLogTypeEnum.getType(), info);
+		MDC.remove(businessLogTypeEnum.getType());
+	}
+	
+	
+	
+	/**
+	* @Title: log
+	* @Description: 多业务动态日志
+	* @param @param businessLogTypeEnum
+	* @param @param e
+	* @param @param info    参数
+	* @return void    返回类型
+	* @throws
+	* @author Orange
+	* @date 2019年1月21日
+	*/
+	public static void log(BusinessLogTypeEnum businessLogTypeEnum, Throwable e, Object...info) {
+		MDC.put("businessName", businessLogTypeEnum.getType());
+		Logger logger = LoggerFactory.getLogger("business_log");
+		logger.info("businessName={}, exception={} ,info={}", businessLogTypeEnum.getType(), throwable2String(e),info);
+		MDC.remove(businessLogTypeEnum.getType());
+	}
+	
+	
+	
+	/**
+	* @Title: warnLog
+	* @Description: 警告日志
+	* @param @param e
+	* @param @param info    参数
+	* @return void    返回类型
+	* @throws
+	* @author Orange
+	* @date 2019年1月26日
+	*/
+	public static void warnLog(Throwable e,Object...info) {
+		//系统级别日志不打印
+		if(checkBaseBusinessException(e)) {
+			log(e,info);
+		}else {
+			Logger logger = LoggerFactory.getLogger("error_log");
+			logger.warn("[System Exception] exception={} ,info={}", throwable2String(e),info);
+		}
+	}
+
+	public static void warnLog(String warnInfo){
+		Logger logger = LoggerFactory.getLogger("error_log");
+		logger.warn(warnInfo);
+	}
+
+}

+ 48 - 0
src/main/java/com/cslg/ids/common/core/redis/CacheTTLEnum.java

@@ -0,0 +1,48 @@
+package com.cslg.ids.common.core.redis;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @ClassName
+ * @Description TODO
+ * @Author 陈凯裕
+ * @Date 2022/7/15 18:08
+ * @Version TODO
+ **/
+public class CacheTTLEnum {
+
+    public static final CacheTTLEnum ONE_MINUTE = new CacheTTLEnum(1L,TimeUnit.MINUTES);
+
+    public static final CacheTTLEnum TEN_MINUTE = new CacheTTLEnum(10L,TimeUnit.MINUTES);
+
+    public static final CacheTTLEnum FIVE_MINUTE = new CacheTTLEnum(5L,TimeUnit.MINUTES);
+
+    public static final CacheTTLEnum FIFTEEN_MINUTE = new CacheTTLEnum(15L,TimeUnit.MINUTES);
+
+    public static final CacheTTLEnum THIRTY_MINUTE = new CacheTTLEnum(30L,TimeUnit.MINUTES);
+
+    public static final CacheTTLEnum ONE_HOUR = new CacheTTLEnum(1L,TimeUnit.HOURS);
+
+    public static final CacheTTLEnum TWELVE_HOUR = new CacheTTLEnum(12L,TimeUnit.HOURS);
+
+    public static final CacheTTLEnum ONE_DAY = new CacheTTLEnum(1L,TimeUnit.DAYS);
+    public static final CacheTTLEnum TWO_HOUR = new CacheTTLEnum(2L,TimeUnit.HOURS);
+
+
+    private Long time;
+
+    private TimeUnit unit;
+
+    protected CacheTTLEnum(Long time, TimeUnit unit) {
+        this.time = time;
+        this.unit = unit;
+    }
+
+    public Long getTime() {
+        return time;
+    }
+
+    public TimeUnit getUnit() {
+        return unit;
+    }
+}

+ 493 - 0
src/main/java/com/cslg/ids/common/core/redis/RedisService.java

@@ -0,0 +1,493 @@
+
+package com.cslg.ids.common.core.redis;
+
+
+import com.cslg.ids.common.utils.DateUtil;
+import jakarta.annotation.Resource;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.support.atomic.RedisAtomicLong;
+import org.springframework.stereotype.Component;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+
+@Component
+public class RedisService {
+
+    @Resource
+    RedisTemplate redisTemplate;
+
+
+/** -------------------key相关操作--------------------- */
+
+
+    /**
+     * 删除key
+     */
+    public void delete(String key) {
+        redisTemplate.delete(key);
+    }
+
+    /**
+     * 批量删除key
+     */
+    public void delete(Collection<String> keys) {
+        redisTemplate.delete(keys);
+    }
+
+
+    /**
+     * 是否存在key
+     */
+    public Boolean hasKey(String key) {
+        return redisTemplate.hasKey(key);
+    }
+
+
+    /**
+     * 设置过期时间
+     */
+    public Boolean expire(String key, CacheTTLEnum ttlEnum) {
+        return redisTemplate.expire(key, ttlEnum.getTime(), ttlEnum.getUnit());
+    }
+
+
+    /**
+     * 移除 key 的过期时间,key 将持久保持
+     */
+    public Boolean persist(String key) {
+        return redisTemplate.persist(key);
+    }
+
+
+    /**
+     * 返回 key 的剩余的过期时间
+     */
+    public Long getExpire(String key, TimeUnit unit) {
+        return redisTemplate.getExpire(key, unit);
+    }
+
+
+    /**
+     * 修改 key 的名称
+     */
+    public void rename(String oldKey, String newKey) {
+        redisTemplate.rename(oldKey, newKey);
+    }
+
+
+/** -------------------string相关操作--------------------- */
+
+
+    /**
+     * 设置指定 key 的值
+     */
+
+    public void set(String key, Object value) {
+        redisTemplate.opsForValue().set(key, value);
+    }
+
+
+    /**
+     * 获取指定 key 的值
+     */
+    public Object get(String key) {
+        return redisTemplate.opsForValue().get(key);
+    }
+
+    public <T> T get(String key, Class<T> clazz) {
+        return (T) get(key);
+    }
+
+
+    /**
+     * 将给定 key 的值设为 value ,并返回 key 的旧值(old value)
+     */
+    public Object getAndSet(String key, Object value) {
+        return redisTemplate.opsForValue().getAndSet(key, value);
+    }
+
+    public <T> T getAndSet(String key, Object value, Class<T> clazz) {
+        return (T) getAndSet(key, value);
+    }
+
+
+    /**
+     * 批量获取
+     */
+    public List<Object> multiGet(Collection<String> keys) {
+        return redisTemplate.opsForValue().multiGet(keys);
+    }
+
+
+    /**
+     * 只有在 key 不存在时设置 key 的值
+     */
+    public boolean setIfAbsent(String key, Object value) {
+        return redisTemplate.opsForValue().setIfAbsent(key, value);
+    }
+
+
+    /**
+     * 设置一个key,值为自增的LONG类型,每调用一次+1并且返回值自增后的值
+     */
+    public Long incrBy(String key) {
+        RedisAtomicLong redisAtomicLong = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
+        return redisAtomicLong.incrementAndGet();
+    }
+
+
+/** -------------------hash相关操作------------------------- */
+
+
+    /**
+     * 获取存储在hash表中指定字段的值
+     */
+    public Object hGet(String key, String field) {
+        return redisTemplate.opsForHash().get(key, field);
+    }
+
+
+    /*
+     * 存储指定键值对至hash表中
+     **/
+    public void hPut(String key, String hashKey, Object value) {
+        redisTemplate.opsForHash().put(key, hashKey, value);
+    }
+
+    /**
+     * 获取hash表中所有的键值对
+     */
+    public Map<String, Object> hGetAll(String key) {
+        return redisTemplate.opsForHash().entries(key);
+    }
+
+
+    /**
+     * 获取hash表中所有给定字段的值
+     */
+    public List<Object> hMultiGet(String key, Collection<String> fields) {
+        return redisTemplate.opsForHash().multiGet(key, fields);
+    }
+
+
+    /*
+     * 批量插入到hash表中
+     * */
+    public void hPutAll(String key, Map<String, Object> maps) {
+        redisTemplate.opsForHash().putAll(key, maps);
+    }
+
+
+    /**
+     * 删除一个或多个hash表字段
+     */
+    public Long hDelete(String key, String... fields) {
+        return redisTemplate.opsForHash().delete(key, fields);
+    }
+
+
+    /**
+     * 查看hash表 key 中,指定的字段是否存在
+     */
+    public boolean hExists(String key, String field) {
+        return redisTemplate.opsForHash().hasKey(key, field);
+    }
+
+
+    /**
+     * 获取所有hash表中的字段
+     */
+    public Set<String> hKeys(String key) {
+        return redisTemplate.opsForHash().keys(key);
+    }
+
+
+    /**
+     * 获取hash表中字段的数量
+     */
+    public Long hSize(String key) {
+        return redisTemplate.opsForHash().size(key);
+    }
+
+
+/** ------------------------list相关操作---------------------------- */
+
+
+    /**
+     * 通过索引获取列表中的元素
+     */
+    public Object lIndex(String key, long index) {
+        return redisTemplate.opsForList().index(key, index);
+    }
+
+
+    /**
+     * 通过索引设置列表元素的值
+     */
+    public void lSet(String key, long index, String value) {
+        redisTemplate.opsForList().set(key, index, value);
+    }
+
+    /**
+     * 列表队列左push
+     */
+    public Long lLeftPush(String key, Object value) {
+        return redisTemplate.opsForList().leftPush(key, value);
+    }
+
+
+    /**
+     * 列表队列批量左push
+     */
+    public Long lLeftPushAll(String key, Object... value) {
+        if (value.length == 0)
+            return 0L;
+        return redisTemplate.opsForList().leftPushAll(key, value);
+    }
+
+
+    /**
+     * 列表队列右push
+     */
+    public Long lRightPush(String key, Object value) {
+        return redisTemplate.opsForList().rightPush(key, value);
+    }
+
+
+    /**
+     * 列表队列批量右push
+     */
+    public Long lRightPushAll(String key, Object... value) {
+        if (value.length == 0)
+            return 0L;
+        return redisTemplate.opsForList().rightPushAll(key, value);
+    }
+
+
+    /**
+     * 弹出列表左侧的第一个元素
+     */
+    public Object lLeftPop(String key) {
+        return redisTemplate.opsForList().leftPop(key);
+    }
+
+    /**
+     * 弹出列表右侧的第一个元素
+     *
+     * @param key
+     * @return 删除的元素
+     */
+    public Object lRightPop(String key) {
+        return redisTemplate.opsForList().rightPop(key);
+    }
+
+
+    /**
+     * 获取列表长度
+     */
+    public Long lLen(String key) {
+        return redisTemplate.opsForList().size(key);
+    }
+
+
+/** --------------------set相关操作-------------------------- */
+
+
+    /**
+     * set添加元素
+     */
+    public Long sAdd(String key, Object... values) {
+        return redisTemplate.opsForSet().add(key, values);
+    }
+
+    /**
+     * set移除元素
+     */
+    public Long sRemove(String key, Object... values) {
+        return redisTemplate.opsForSet().remove(key, values);
+    }
+
+
+    /**
+     * 获取集合的大小
+     *
+     * @param key
+     * @return
+     */
+    public Long sSize(String key) {
+        return redisTemplate.opsForSet().size(key);
+    }
+
+
+    /**
+     * 获取集合所有元素
+     */
+    public Set<String> sGetMembers(String key) {
+        return redisTemplate.opsForSet().members(key);
+    }
+
+
+    /**
+     * 判断集合是否包含元素
+     */
+    public boolean sContains(String key, Object value) {
+        return redisTemplate.opsForSet().isMember(key, value);
+    }
+
+
+/**------------------zSet相关操作--------------------------------*/
+
+
+    /**
+     * 添加元素,有序集合是按照元素的score值由小到大排列
+     */
+    public Boolean zAdd(String key, Object value, double score) {
+        return redisTemplate.opsForZSet().add(key, value, score);
+    }
+
+
+    /**
+     * 移除指定value的值
+     */
+    public Long zRemove(String key, Object... values) {
+        return redisTemplate.opsForZSet().remove(key, values);
+    }
+
+    /**
+     * 增加元素的score值,并返回增加后的值
+     */
+    public Double zIncrementScore(String key, Object value, double delta) {
+        return redisTemplate.opsForZSet().incrementScore(key, value, delta);
+    }
+
+    /**
+     * 返回元素在集合的排名,按Score升序排名
+     */
+    public Long zRank(String key, Object value) {
+        return redisTemplate.opsForZSet().rank(key, value);
+    }
+
+    /**
+     * 返回元素在集合的排名,按Score倒序排名
+     */
+    public Long zReverseRank(String key, Object value) {
+        return redisTemplate.opsForZSet().reverseRank(key, value);
+    }
+
+    /**
+     * 获取集合的元素, 升序
+     */
+    public Set<String> zRange(String key, long start, long end) {
+        return redisTemplate.opsForZSet().range(key, start, end);
+    }
+
+    /**
+     * 获取集合的元素, 倒序
+     */
+    public Set<String> zReverseRange(String key, long start, long end) {
+        return redisTemplate.opsForZSet().reverseRange(key, start, end);
+    }
+
+    /**
+     * 根据Score值查询集合元素,升序
+     */
+    public Set<String> zRangeByScore(String key, double min, double max) {
+        return redisTemplate.opsForZSet().rangeByScore(key, min, max);
+    }
+
+
+    /**
+     * 根据Score值查询集合元素, 倒序
+     */
+    public Set<Object> zReverseRangeByScore(String key, double min,
+                                            double max) {
+        return redisTemplate.opsForZSet().reverseRangeByScore(key, min, max);
+    }
+
+
+    /**
+     * 根据score值获取集合元素数量
+     */
+    public Long zCount(String key, double min, double max) {
+        return redisTemplate.opsForZSet().count(key, min, max);
+    }
+
+
+    /**
+     * 获取集合大小
+     *
+     * @param key
+     * @return
+     */
+    public Long zSize(String key) {
+        return redisTemplate.opsForZSet().size(key);
+    }
+
+
+    /**
+     * 获取集合中value元素的score值
+     */
+    public Double zScore(String key, Object value) {
+        return redisTemplate.opsForZSet().score(key, value);
+    }
+
+
+    /**
+     * 移除指定索引位置的成员
+     */
+    public Long zRemoveRange(String key, long start, long end) {
+        return redisTemplate.opsForZSet().removeRange(key, start, end);
+    }
+
+
+    /**
+     * 根据指定的score值的范围来移除成员
+     */
+    public Long zRemoveRangeByScore(String key, double min, double max) {
+        return redisTemplate.opsForZSet().removeRangeByScore(key, min, max);
+    }
+
+
+    /**
+     * 设置key值在下一天零点过期
+     *
+     * @param key
+     */
+    public void removeKeyBySecond(String key) {
+        Long second = DateUtil.getRemainingSecond();
+        if (second <= 0) {
+            this.delete(key);
+        }
+    }
+
+    /**
+     * 将值 value 关联到 key ,并将 key 的过期时间设为 timeout
+     *
+     * @param key
+     * @param value
+     * @param timeout 过期时间
+     * @param unit    时间单位, 天:TimeUnit.DAYS 小时:TimeUnit.HOURS 分钟:TimeUnit.MINUTES
+     *                秒:TimeUnit.SECONDS 毫秒:TimeUnit.MILLISECONDS
+     */
+    public void setEx(String key, Object value, long timeout, TimeUnit unit) {
+        redisTemplate.opsForValue().set(key, value, timeout, unit);
+    }
+
+    /**
+     * 设置键值并且过期时间是午夜
+     * @param key
+     * @param value
+     */
+    public  void setKeyLastToMidNight(String key ,String value){
+       Long second= DateUtil.getRemainingSecond();
+        redisTemplate.opsForValue().set(key, value, second, TimeUnit.SECONDS);
+    }
+}
+
+
+

+ 47 - 0
src/main/java/com/cslg/ids/common/exception/BusinessException.java

@@ -0,0 +1,47 @@
+package com.cslg.ids.common.exception;
+
+
+import lombok.Getter;
+
+/**
+ * @ClassName
+ * @Description 业务异常
+ * @Version TODO
+ **/
+@Getter
+public class BusinessException extends RuntimeException {
+
+	private String errorCode;// 异常代码
+	private String errorMessage;// 异常信息
+
+	public BusinessException(String errorCode, String errorMessage) {
+		super(errorMessage);
+		this.errorCode = errorCode;
+		this.errorMessage = errorMessage;
+	}
+
+	public BusinessException(ExceptionEnum e) {
+		super(e.getMessage());
+		this.errorMessage = e.getMessage();
+		this.errorCode = e.getCode();
+	}
+
+
+	public String getErrorCode() {
+		return errorCode;
+	}
+
+	public void setErrorCode(String errorCode) {
+		this.errorCode = errorCode;
+	}
+
+	public String getErrorMessage() {
+		return errorMessage;
+	}
+
+	public void setErrorMessage(String errorMessage) {
+		this.errorMessage = errorMessage;
+	}
+
+
+}

+ 100 - 0
src/main/java/com/cslg/ids/common/exception/ExceptionEnum.java

@@ -0,0 +1,100 @@
+package com.cslg.ids.common.exception;
+
+import lombok.Getter;
+
+@Getter
+public enum ExceptionEnum {
+    //400~500  登录相关异常提示
+    LOGIN_NO_LOGIN("401","未登录"),
+    LOGIN_ACCOUNT_MISTAKE("402","账号错误"),
+    LOGIN_PASSWORD_MISTAKE("403","密码错误"),
+    LOGIN_ERROR("405","登录错误"),
+    LOGIN_INVITE_ERROR("406","邀请码错误"),
+    THE_TOKEN_IS_INVALID("407", "token失效"),
+    THE_REQUEST_TIME_OVERTIME("408", "请求时间超时"),
+    THE_SIGN_IS_NOT_SAME("408", "请求SIGN不一致,重新检查"),
+    THE_MACHINE_CODE_IS_NULL("409", "机器码不可为空"),
+    DO_NOT_LOG_IN_TO_MORE_THAN_TWO_NEW_MACHINES_WITH_THE_SAME_ACCOUNT("410", "同一账号新机登录不可超过两个"),
+    THE_PHONE_FORMAT_ERROR("411","手机号格式错误"),
+    THE_PHONE_IS_NOT_EMPTY("412","手机号不可为空"),
+    THE_PHONE_CODE_IS_INVALID("413","手机验证码失效"),
+    THE_PHONE_CODE_IS_NOT_NULL("414","手机验证码不可为空"),
+    THE_PHONE_CODE_IS_INCONFORMITY("415","验证码不一致"),
+    THE_PERSONNEL_IS_NOT_EXIST("416","用户不存在"),
+    THE_PERSONNEL_IS_FORBIDDEN("417","该用户不可用"),
+    THE_VERSION_IS_NULL("418", "版本号不可为空"),
+    THE_PERSONNEL_IS_EXIST("419","用户已存在"),
+    //500~600   业务异常相关
+    THE_SYSTEM_ERROR("500", "系统异常"),
+
+    //600~700  权限相关异常提示
+    PERMISSION_ERROR("601","无权限"),
+    PERMISSION_NO_VIP("606","未开会员"),
+    PERMISSION_BEYOND_USETIME("607","超过使用次数"),
+
+    //700~800  参数相关异常提示
+    BUSINESS_ERROR("708","业务错误"),
+    BUSINESS_CHECK("709","参数校验错误"),
+
+
+    NO_NEED_PAY("901","支付成功"),
+
+
+
+
+
+    /*APP端 100000-300000*/
+    SUCCESS("000000", "调用成功"),
+    PARAMETER_VERIFICATION_ERROR("000001", "数据参数校验异常"),
+    PHONE_FORMAT_ERROR("000002","手机号格式错误"),
+
+    VERIFY_CODE("10001", "校验码失效"),
+    CODE_WRONG("10002","验证码错误"),
+    INIT_GENERICITY_BEAN_ERROR("10003","泛型实例化异常"),
+    THE_PHONE_CANNOT_BE_EXIST("10004","手机号已存在"),
+    THE_LOG_OUT("10004","未登录"),
+    THE_CODE_IS_NOT_NULL("10006","验证码不能为空"),
+
+    //异常20000
+    THE_PARAMETER_EXCEPTION("20001", "参数异常,请传入数据"),
+    THE_GET_INFORMATION_TOKEN_INVALID("20002", "获取用户信息token失效"),
+    THE_FAIL_TO_DELETE("20003", "删除失败"),
+
+    //业务异常
+    THE_PRODUCT_CATEGORY_NAME_IS_EXIST("607", "产品类别名称已存在"),
+    THE_LOG_INVALID_NEED_LOGIN_AGAIN("606","登录失效,请重新登录"),
+
+
+
+
+
+
+
+
+
+    SYSTEM_ERROR("999999", "系统异常");
+
+    private String code;// 异常代码
+    private String message;// 异常信息
+
+    ExceptionEnum(String code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+}

+ 45 - 0
src/main/java/com/cslg/ids/common/exception/GlobalException.java

@@ -0,0 +1,45 @@
+package com.cslg.ids.common.exception;
+
+import cn.dev33.satoken.exception.NotLoginException;
+import com.cslg.ids.common.core.auth.Response;
+import com.cslg.ids.common.core.auth.ResponseEnum;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+
+/**
+ * 全局异常处理
+ */
+@Slf4j
+@RestControllerAdvice // 可指定包前缀,比如:(basePackages = "com.pj.admin")
+public class GlobalException {
+
+    // 全局异常拦截(拦截项目中的所有异常)
+    @ExceptionHandler
+    public String handlerException(Exception e, HttpServletRequest request, HttpServletResponse response) throws Exception {
+        // 打印堆栈,以供调试
+        e.printStackTrace();
+        if (e instanceof NotLoginException) {
+            return Response.error(ResponseEnum.UNAUTHORIZED);
+        } else if (e instanceof PermissionException) {
+            return Response.error(ResponseEnum.NOT_PERMISSION);
+        } else {
+            return Response.error(ResponseEnum.SYSTEM_ERROR);
+        }
+    }
+
+    //小世异常
+    @ExceptionHandler
+    public Response handlerXiaoShiException(XiaoShiException e) {
+        log.info("全局异常处理机制捕获到XiaoShiException,异常信息提示为:{}", e.getErrorCode() + "--" + e.getMessage());
+        if (StringUtils.isNotEmpty(e.getErrorCode())) {
+            return Response.error(e.getErrorCode(), e.getErrorMessage());
+        } else {
+            return Response.error1(e.getMessage());
+        }
+    }
+}

+ 16 - 0
src/main/java/com/cslg/ids/common/exception/PermissionException.java

@@ -0,0 +1,16 @@
+package com.cslg.ids.common.exception;
+
+public class PermissionException extends RuntimeException {
+
+    public PermissionException(String message) {
+        super(message);
+    }
+
+    public PermissionException(Throwable cause) {
+        super(cause);
+    }
+
+    public PermissionException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}

+ 17 - 0
src/main/java/com/cslg/ids/common/exception/ThrowException.java

@@ -0,0 +1,17 @@
+package com.cslg.ids.common.exception;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @Author chenyu
+ * @Date 2023/4/2
+ */
+@Slf4j
+public class ThrowException {
+
+    public static void throwXiaoShiException(String message) {
+        log.info("{}", message);
+        throw new XiaoShiException(message);
+    }
+
+}

+ 45 - 0
src/main/java/com/cslg/ids/common/exception/XiaoShiException.java

@@ -0,0 +1,45 @@
+package com.cslg.ids.common.exception;
+
+/**
+ * 整个项目通用异常类
+ *
+ * @Author chenyu
+ * @Data 2023/2/15
+ */
+public class XiaoShiException extends RuntimeException {
+
+    private String errorCode;// 异常代码
+    private String errorMessage;// 异常信息
+    public XiaoShiException(String message) {
+        super(message);
+    }
+
+    public XiaoShiException(ExceptionEnum e, String errorMessage) {
+        super(errorMessage);
+        this.errorCode = e.getCode();
+        this.errorMessage = errorMessage;
+    }
+
+    public XiaoShiException(ExceptionEnum e) {
+        super(e.getMessage());
+        this.errorMessage = e.getMessage();
+        this.errorCode = e.getCode();
+    }
+
+
+    public String getErrorCode() {
+        return errorCode;
+    }
+
+    public void setErrorCode(String errorCode) {
+        this.errorCode = errorCode;
+    }
+
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+
+    public void setErrorMessage(String errorMessage) {
+        this.errorMessage = errorMessage;
+    }
+}

+ 9 - 0
src/main/java/com/cslg/ids/common/utils/BackupUtils.java

@@ -0,0 +1,9 @@
+package com.cslg.ids.common.utils;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class BackupUtils {
+
+
+}

+ 83 - 0
src/main/java/com/cslg/ids/common/utils/BeanUtil.java

@@ -0,0 +1,83 @@
+package com.cslg.ids.common.utils;
+
+
+import com.cslg.ids.common.core.log.LogHelper;
+import com.cslg.ids.common.exception.BusinessException;
+import com.cslg.ids.common.exception.ExceptionEnum;
+
+public  class BeanUtil {
+
+
+	/**
+	* @Title: copy
+	* @Description: 类属性复制
+	* @param @param source
+	* @param @param target    参数
+	* @return void    返回类型
+	* @throws
+	*/
+	public static void copy(Object source,Object target){
+		org.springframework.beans.BeanUtils.copyProperties(source, target);
+	}
+
+	/**
+	 * @name: 克隆source为新对象
+	 * @author Peach
+	 * @date:2018/9/4
+	 */
+	public static <T> T cloneNewObject(Object source,Class<T> clazz){
+		T t = null;
+		try {
+			t = clazz.newInstance();
+		} catch (Exception e) {
+			LogHelper.log(BeanUtil.class, "泛型实例化异常:" + clazz.getName(), e);
+			throw new BusinessException(ExceptionEnum.INIT_GENERICITY_BEAN_ERROR);
+		}
+		BeanUtil.copy(source,t);
+		return t;
+	}
+
+
+	/**
+	 * @Title: newTclass
+	 * @Description: 实例化泛型类
+	 * @param @param
+	 *            clazz
+	 * @param @return
+	 * @param @throws
+	 *            InstantiationException
+	 * @param @throws
+	 *            IllegalAccessException 参数
+	 * @return T 返回类型
+	 * @throws @author
+	 *             Orange
+	 * @date 2018年1月16日
+	 */
+	public static <T> T newTclass(Class<T> clazz) {
+		T a = null;
+		try {
+			a = clazz.newInstance();
+		} catch (Exception e) {
+			LogHelper.log(BeanUtil.class, "泛型实例化异常:" + clazz.getName(), e);
+			throw new BusinessException(ExceptionEnum.INIT_GENERICITY_BEAN_ERROR);
+		}
+		return a;
+	}
+
+	public static Object[] getEntities(Object target, Class<?>[] objs) {
+		Object[] entities = new Object[objs.length];
+		int count = 0;
+		for (Class<?> o : objs) {
+			Object entity = null;
+			try {
+				entity = o.newInstance();
+			} catch (Exception e) {
+				continue;
+			}
+			if (target != null)
+				copy(target, entity);
+			entities[count ++] = entity;
+		}
+		return entities;
+	}
+}

+ 36 - 0
src/main/java/com/cslg/ids/common/utils/CacheUtils.java

@@ -0,0 +1,36 @@
+package com.cslg.ids.common.utils;
+
+import cn.dev33.satoken.exception.NotLoginException;
+import com.cslg.ids.common.core.base.RedisConf;
+import com.cslg.ids.common.exception.ExceptionEnum;
+import com.cslg.ids.common.exception.XiaoShiException;
+import com.cslg.ids.entity.common.PersonnelVO;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Component;
+
+@Component
+public class CacheUtils {
+
+    @Resource
+    private RedisUtil redisUtil;
+
+
+    public PersonnelVO getLoginUser(Object userId) {
+        String json = redisUtil.get(RedisConf.LOGIN_USER + RedisConf.SYMBOL_COLON + userId);
+        if (Boolean.TRUE.equals(StringUtils.isEmpty(json))) {
+            throw new XiaoShiException(ExceptionEnum.LOGIN_NO_LOGIN,"未登录");
+        } else {
+            return com.alibaba.fastjson2.JSONObject.parseObject(json, PersonnelVO.class);
+        }
+    }
+
+    public PersonnelVO getLoginUserPersonnel(Object userId) {
+        String json = redisUtil.get(RedisConf.LOGIN_USER + RedisConf.SYMBOL_COLON + userId);
+        if (StringUtils.isEmpty(json)) {
+            throw new NotLoginException("无数据", "user", "");
+        } else {
+            return com.alibaba.fastjson2.JSONObject.parseObject(json, PersonnelVO.class);
+        }
+    }
+
+}

+ 244 - 0
src/main/java/com/cslg/ids/common/utils/DataUtils.java

@@ -0,0 +1,244 @@
+package com.cslg.ids.common.utils;
+
+
+import cn.dev33.satoken.secure.SaSecureUtil;
+import org.springframework.stereotype.Component;
+import org.springframework.util.Base64Utils;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.MessageDigest;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+@Component
+public class DataUtils {
+
+    //秘钥
+    public static final String PASSWORD_KEY = "835a9bdc-4f9f-4614-a0cc-493a12454156";
+    public static String[] chars = new String[] { "a", "b", "c", "d", "e", "f",
+            "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
+            "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5",
+            "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I",
+            "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
+            "W", "X", "Y", "Z" };
+
+    /**
+     * 对称加密
+     */
+    public static String aesEncrypt(String password) {
+        return SaSecureUtil.aesEncrypt(PASSWORD_KEY, password);
+    }
+
+    /**
+     * 对称解密
+     */
+    public static String aesDecrypt(String password) {
+        return SaSecureUtil.aesDecrypt(PASSWORD_KEY, password);
+    }
+
+    /**
+     * @return 1.对比数据库内减少了那些数据 2.对比数据库内改变了那些数据(新增 修改) 3.两份数组中不变的数据
+     * @author 沈永艺
+     * @description 计算数据库内已有数据List 和 前台传入新的数据List 之间的比较
+     */
+    public static Map<String, List<Integer>> compareTwoList(List<Integer> dbList, List<Integer> frontList) {
+        //创建一个存放比对结果的Map 数组
+        Map<String, List<Integer>> comparisonResults = new HashMap<>();
+        //减少
+        List<Integer> reduce = dbList.stream().filter(item -> !frontList.contains(item)).collect(Collectors.toList());
+        //改变
+        List<Integer> change = frontList.stream().filter(item -> !dbList.contains(item)).collect(Collectors.toList());
+        //不变
+        List<Integer> unChange = dbList.stream().filter(frontList::contains).collect(Collectors.toList());
+        //填充数据
+        comparisonResults.put("reduce", reduce);
+        comparisonResults.put("change", change);
+        comparisonResults.put("unChange", unChange);
+        return comparisonResults;
+    }
+
+    /**
+     * @return 去重后的数据
+     * @author 沈永艺
+     * @description 在对象数组中按照某一类属性进行去重
+     */
+    //用例:待去重List.stream().filter(DataUtils.distinctByKey(对象::get属性字段)).collect(Collectors.toList());
+    public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
+        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
+        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
+    }
+
+    /**
+     * 比较两个字符串的相识度
+     * 核心算法:用一个二维数组记录每个字符串是否相同,如果相同记为0,不相同记为1,每行每列相同个数累加
+     * 则数组最后一个数为不相同的总数,从而判断这两个字符的相识度
+     *
+     * @param str
+     * @param target
+     * @return
+     */
+    private static int compare(String str, String target) {
+        int d[][];              // 矩阵
+        int n = str.length();
+        int m = target.length();
+        int i;                  // 遍历str的
+        int j;                  // 遍历target的
+        char ch1;               // str的
+        char ch2;               // target的
+        int temp;               // 记录相同字符,在某个矩阵位置值的增量,不是0就是1
+        if (n == 0) {
+            return m;
+        }
+        if (m == 0) {
+            return n;
+        }
+        d = new int[n + 1][m + 1];
+        // 初始化第一列
+        for (i = 0; i <= n; i++) {
+            d[i][0] = i;
+        }
+        // 初始化第一行
+        for (j = 0; j <= m; j++) {
+            d[0][j] = j;
+        }
+        for (i = 1; i <= n; i++) {
+            // 遍历str
+            ch1 = str.charAt(i - 1);
+            // 去匹配target
+            for (j = 1; j <= m; j++) {
+                ch2 = target.charAt(j - 1);
+                if (ch1 == ch2 || ch1 == ch2 + 32 || ch1 + 32 == ch2) {
+                    temp = 0;
+                } else {
+                    temp = 1;
+                }
+                // 左边+1,上边+1, 左上角+temp取最小
+                d[i][j] = min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + temp);
+            }
+        }
+        return d[n][m];
+    }
+
+    /**
+     * 获取最小的值
+     */
+    private static int min(int one, int two, int three) {
+        return (one = one < two ? one : two) < three ? one : three;
+    }
+
+    /**
+     * 获取两字符串的相似度
+     */
+    public static float getSimilarityRatio(String str, String target) {
+        int max = Math.max(str.length(), target.length());
+        return 1 - (float) compare(str, target) / max;
+
+    }
+
+    public static String generateShortUuid() {
+        StringBuffer shortBuffer = new StringBuffer();
+        String uuid = UUID.randomUUID().toString().replace("-", "");
+        for (int i = 0; i < 8; i++) {
+            String str = uuid.substring(i * 4, i * 4 + 4);
+            int x = Integer.parseInt(str, 16);
+            shortBuffer.append(chars[x % 0x3E]);
+        }
+        return shortBuffer.toString();
+    }
+
+    public static <T> List<T> objToList(Object obj, Class<T> cla){
+        List<T> list = new ArrayList<T>();
+        if (obj instanceof ArrayList<?>) {
+            for (Object o : (List<?>) obj) {
+                list.add(cla.cast(o));
+            }
+            return list;
+        }
+        return null;
+    }
+
+    public static String MD5Base64(String s) {
+        if (s == null)
+            return null;
+        String encodeStr = "";
+        byte[] utfBytes = s.getBytes();
+        MessageDigest mdTemp;
+        try {
+            mdTemp = MessageDigest.getInstance("MD5");
+            mdTemp.update(utfBytes);
+            byte[] md5Bytes = mdTemp.digest();
+            byte[] by =  Base64.getEncoder().encode(md5Bytes);
+
+            encodeStr = Base64Utils.encodeToString(by);
+        } catch (Exception e) {
+            throw new Error("Failed to generate MD5 : " + e.getMessage());
+        }
+        return encodeStr;
+    }
+
+    /*
+     * 计算 HMAC-SHA1
+     */
+    public static String HMACSha1(String data, String key) {
+        String result;
+        try {
+            SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), "HmacSHA1");
+            Mac mac = Mac.getInstance("HmacSHA1");
+            mac.init(signingKey);
+            byte[] rawHmac = mac.doFinal(data.getBytes());
+            byte[] by =Base64.getEncoder().encode(rawHmac);
+            result = Base64Utils.encodeToString(by);
+        } catch (Exception e) {
+            throw new Error("Failed to generate HMAC : " + e.getMessage());
+        }
+        return result;
+    }
+
+    //将Unicode代码转为字符
+    public static String unicodeDecode(String string) {
+        Pattern pattern = Pattern.compile("(\\\\u(\\p{XDigit}{4}))");
+        Matcher matcher = pattern.matcher(string);
+        char ch;
+        while (matcher.find()) {
+            ch = (char) Integer.parseInt(matcher.group(2), 16);
+            string = string.replace(matcher.group(1), ch + "");
+        }
+        return string;
+    }
+
+    /**
+     * @return 计算完成度
+     * @author 沈永艺
+     * @description 输入完成数量和全部数量计算完成百分比
+     */
+    public String calculateCompletion(Integer finishNum, Integer allNum) {
+        return finishNum / allNum + "%";
+    }
+
+    /**
+     * @return 拆分出的特征
+     * @author 沈永艺
+     * @description 处理权利要求
+     */
+    // TODO: 2022/11/2 未完成
+    public List<String> processRightToFeatures(List<String> rightList, String patentNo) {
+        List<String> features = new ArrayList<>();
+        if (patentNo != null) {
+            String country = patentNo.substring(0, 2);
+            if (country.equals("CN") || country.equals("JP")) {
+
+            } else {
+
+            }
+        }
+
+        return features;
+    }
+
+}

+ 445 - 0
src/main/java/com/cslg/ids/common/utils/DateUtil.java

@@ -0,0 +1,445 @@
+/**
+ * Copyright (c) 2015-2016, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.cslg.ids.common.utils;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.time.DateFormatUtils;
+
+import java.sql.Timestamp;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.*;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.TemporalAdjusters;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+public class DateUtil {
+
+
+
+	/**
+	 * 获取YYYY格式
+	 *
+	 * @return
+	 */
+
+	public static String getYear() {
+		return formatDate(new Date(), "yyyy");
+	}
+
+
+	/**
+	 * 获取YYYY格式
+	 *
+	 * @return
+	 */
+
+	public static String getYear(Date date) {
+		return formatDate(date, "yyyy");
+	}
+
+	public static String getCurrentServerDate(String format) {
+		return formatDate(new Date(), format);
+	}
+	
+
+	/**
+	 * 获取YYYY-MM-DD格式
+	 *
+	 * @return
+	 */
+
+	public static String getDay() {
+		return formatDate(new Date(), "yyyy-MM-dd");
+	}
+
+
+	/**
+	 * 获取YYYY-MM-DD格式
+	 *
+	 * @return
+	 */
+
+	public static String getDay(Date date) {
+		return formatDate(date, "yyyy-MM-dd");
+	}
+
+
+	/**
+	 * 获取YYYYMMDD格式
+	 *
+	 * @return
+	 */
+
+	public static String getDays() {
+		return formatDate(new Date(), "yyyyMMdd");
+	}
+
+
+	/**
+	 * 获取YYYYMMDD格式
+	 *
+	 * @return
+	 */
+
+	public static String getDays(Date date) {
+		return formatDate(date, "yyyyMMdd");
+	}
+
+	/**
+	 * 获取YYYY-MM-DD HH:mm:ss格式
+	 *
+	 * @return
+	 */
+
+	public static String getTime() {
+		return formatDate(new Date(), "yyyy-MM-dd HH:mm:ss");
+	}
+
+
+ 	/**
+	 * 获取YYYY-MM-DD HH:mm:ss.SSS格式
+	 *
+	 * @return
+	 */
+
+	public static String getMsTime() {
+		return formatDate(new Date(), "yyyy-MM-dd HH:mm:ss.SSS");
+	}
+
+
+	/**
+	 * 获取YYYYMMDDHHmmss格式
+	 *
+	 * @return
+	 */
+
+	public static String getAllTime() {
+		return formatDate(new Date(), "yyyyMMddHHmmss");
+	}
+
+	/**
+	 * 获取YYYY-MM-DD HH:mm:ss格式
+	 *
+	 * @return
+	 */
+
+	public static String getTime(Date date) {
+		return formatDate(date, "yyyy-MM-dd HH:mm:ss");
+	}
+
+	public static String formatDate(Date date, String pattern) {
+		String formatDate = null;
+		if (StringUtils.isNotBlank(pattern)) {
+			formatDate = DateFormatUtils.format(date, pattern);
+		} else {
+			formatDate = DateFormatUtils.format(date, "yyyy-MM-dd");
+		}
+		return formatDate;
+	}
+
+
+	/**
+	 * 格式化日期
+	 *
+	 * @return
+	 */
+
+	public static String format(Date date, String pattern) {
+		return DateFormatUtils.format(date, pattern);
+	}
+
+
+	/**
+	 * 把日期转换为Timestamp
+	 *
+	 * @param date
+	 * @return
+	 */
+
+	public static Timestamp format(Date date) {
+		return new Timestamp(date.getTime());
+	}
+
+
+	public static int getDiffYear(String startTime, String endTime) {
+		DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
+		try {
+			int years = (int) (((fmt.parse(endTime).getTime() - fmt.parse(
+					startTime).getTime()) / (1000 * 60 * 60 * 24)) / 365);
+			return years;
+		} catch (Exception e) {
+			// 如果throw java.text.ParseException或者NullPointerException,就说明格式不对
+			return 0;
+		}
+	}
+
+
+	/**
+	 * <li>功能描述:时间相减得到天数
+	 *
+	 * @param beginDateStr
+	 * @param endDateStr
+	 * @return long
+	 * @author Administrator
+	 */
+
+	public static long getDaySub(String beginDateStr, String endDateStr) {
+		long day = 0;
+		SimpleDateFormat format = new SimpleDateFormat(
+				"yyyy-MM-dd");
+		Date beginDate = null;
+		Date endDate = null;
+
+		try {
+			beginDate = format.parse(beginDateStr);
+			endDate = format.parse(endDateStr);
+		} catch (ParseException e) {
+			e.printStackTrace();
+		}
+		day = (endDate.getTime() - beginDate.getTime()) / (24 * 60 * 60 * 1000);
+		// System.out.println("相隔的天数="+day);
+
+		return day;
+	}
+
+
+	/**
+	 * 得到n天之后的日期
+	 *
+	 * @param days
+	 * @return
+	 */
+
+	public static String getAfterDayDate(String days) {
+		int daysInt = Integer.parseInt(days);
+
+		Calendar canlendar = Calendar.getInstance(); // java.util包
+		canlendar.add(Calendar.DATE, daysInt); // 日期减 如果不够减会将月变动
+		Date date = canlendar.getTime();
+
+		SimpleDateFormat sdfd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+		String dateStr = sdfd.format(date);
+
+		return dateStr;
+	}
+
+
+	/**
+	 * 得到n天之后是周几
+	 *
+	 * @param days
+	 * @return
+	 */
+
+	public static String getAfterDayWeek(String days) {
+		int daysInt = Integer.parseInt(days);
+
+		Calendar canlendar = Calendar.getInstance(); // java.util包
+		canlendar.add(Calendar.DATE, daysInt); // 日期减 如果不够减会将月变动
+		Date date = canlendar.getTime();
+
+		SimpleDateFormat sdf = new SimpleDateFormat("E");
+		String dateStr = sdf.format(date);
+
+		return dateStr;
+	}
+
+
+	/**
+	 * 格式化Oracle Date
+	 * @param value
+	 * @return
+	 */
+
+//	public static String buildDateValue(Object value){
+//		if(Func.isOracle()){
+//			return "to_date('"+ value +"','yyyy-mm-dd HH24:MI:SS')";
+//		}else{
+//			return Func.toStr(value);
+//		}
+//	}
+
+	/**
+	 * @Description: 获取当前时间的周一及周日
+	 * @Param: Date
+	 * @Author: LHX
+	 * @Date: 9:59 2018/11/19
+	 * @return: java.util.Map<java.lang.String,java.lang.String>
+	 */
+
+	public static Map<String,String> getWeekDate(Date date) {
+		Map<String,String> map = new HashMap();
+		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+
+		Calendar cal = Calendar.getInstance();
+		cal.setTime(date);
+		// 设置一个星期的第一天,按中国的习惯一个星期的第一天是星期一
+		cal.setFirstDayOfWeek(Calendar.MONDAY);
+		// 获得当前日期是一个星期的第几天
+		int dayWeek = cal.get(Calendar.DAY_OF_WEEK);
+		if(dayWeek==1){
+			dayWeek = 8;
+		}
+		// 根据日历的规则,给当前日期减去星期几与一个星期第一天的差值
+		cal.add(Calendar.DATE, cal.getFirstDayOfWeek() - dayWeek);
+		Date mondayDate = cal.getTime();
+		String weekBegin = sdf.format(mondayDate);
+		//获取星期日
+		cal.add(Calendar.DATE, 4 +cal.getFirstDayOfWeek());
+		Date sundayDate = cal.getTime();
+		String weekEnd = sdf.format(sundayDate);
+		map.put("mondayDate", weekBegin);
+		map.put("sundayDate", weekEnd);
+		return map;
+	}
+
+	public static void main(String[] args) {
+		System.out.println(getTime(new Date()));
+		System.out.println(getAfterDayWeek("3"));
+	}
+
+	public static Long getRemainingSecond() {
+		// 获取当前时间
+		LocalDateTime now = LocalDateTime.now();
+
+		// 计算当天零点的时间
+		LocalDateTime midnight = now.plusDays(1).truncatedTo(ChronoUnit.DAYS);
+
+		// 转换为ZonedDateTime以获取时区信息
+		ZonedDateTime zonedDateTime = midnight.atZone(ZoneId.systemDefault());
+
+		// 转换为Unix时间戳(秒)
+		long midnightTimestamp = TimeUnit.MILLISECONDS.toSeconds(zonedDateTime.toInstant().toEpochMilli());
+
+		// 获取当前时间的Unix时间戳(秒)
+		long currentTimestamp = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());
+
+		// 计算剩余秒数直到当天零点
+
+//		// 如果已经过了零点,则设置过期时间为0或者重新计算逻辑
+//		if (ttlSeconds <= 0) {
+//			ttlSeconds = 0; // 或者你可以设置为其他逻辑,比如下一个天的零点
+//		}
+		return midnightTimestamp - currentTimestamp;
+	}
+
+	/**
+	 * 获取当前日期减1天的 Date 对象
+	 */
+	public static Date getYesterdayDate() {
+		// 使用 Java 8 的 LocalDate 计算日期
+		LocalDate yesterdayLocalDate = LocalDate.now().minusDays(1);
+
+		// 将 LocalDate 转换为 Date 对象(基于系统默认时区)
+		return Date.from(yesterdayLocalDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
+	}
+
+	/**
+	 * 获取当前日期减1天的 String 对象
+	 */
+	public static String getYesterdayDateStr() {
+		return LocalDate.now().minusDays(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+	}
+
+	/**
+	 * 获取当前日期的 String 对象
+	 */
+	public static String getNowStr() {
+		return LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy年MM月"));
+	}
+
+	/**
+	 * 获取当前日期减1月的 String 对象
+	 */
+	public static String getNowYearStr() {
+		return LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy年"));
+	}
+
+	/**
+	 * 获取当前日期减1月的 String 对象
+	 */
+	public static String getNowMonthStr() {
+		return LocalDate.now().format(DateTimeFormatter.ofPattern("MM"));
+	}
+
+
+	/**
+	 * 获取当前日期减1月的 String 对象
+	 */
+	public static String getLastYearStr() {
+		return LocalDate.now().minusMonths(1).format(DateTimeFormatter.ofPattern("yyyy年"));
+	}
+
+	/**
+	 * 获取当前日期减1月的 String 对象
+	 */
+	public static String getLastMonthStr() {
+		return LocalDate.now().minusMonths(1).format(DateTimeFormatter.ofPattern("MM"));
+	}
+
+	/**
+	 * 获取当前日期 String 对象
+	 */
+	public static String getNowDateStr() {
+		return LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
+	}
+
+	/**
+	 * 获取当前日期的上月第一天 String 对象
+	 */
+	public static String getFirstDayOfMonthStr() {
+		return LocalDate.now().minusMonths(1).with(TemporalAdjusters.firstDayOfMonth()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+	}
+
+	/**
+	 * 获取当前日期的上月最后一天 String 对象
+	 */
+	public static String getLastDayOfMonthStr() {
+		return LocalDate.now().minusMonths(1).with(TemporalAdjusters.lastDayOfMonth()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+	}
+
+	/**
+	 * 判断两个 Date 对象的日期部分是否相等(忽略时间)
+	 */
+	public static boolean isDateEqualIgnoreTime(Date date1, Date date2) {
+		if (date1 == null || date2 == null) {
+			return false;
+		}
+		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+		String str1 = sdf.format(date1);
+		String str2 = sdf.format(date2);
+		return str1.equals(str2);
+	}
+
+	public static String convertTimestamp(long timestamp) {
+		// 将秒级时间戳转换为Instant对象
+		Instant instant = Instant.ofEpochSecond(timestamp);
+		// 创建日期格式化器,并指定UTC时区
+		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")
+				.withZone(ZoneId.of("GMT+8"));
+		// 格式化Instant为字符串
+		return formatter.format(instant);
+	}
+}
+

+ 763 - 0
src/main/java/com/cslg/ids/common/utils/DateUtils.java

@@ -0,0 +1,763 @@
+package com.cslg.ids.common.utils;
+
+
+import com.cslg.ids.entity.common.Calculate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.management.ManagementFactory;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.regex.Pattern;
+
+public class DateUtils {
+    public static final String START_TIME = " 00:00:00";
+    public static final String END_TIME = " 23:59:59";
+    public final static String FORMAT_STRING = "yyyy-MM-dd HH:mm:ss";
+    public final static String[] REPLACE_STRING = new String[]{"GMT+0800", "GMT+08:00"};
+    public final static String SPLIT_STRING = "(中国标准时间)";
+    public static Logger log = LoggerFactory.getLogger(DateUtils.class);
+    public static String YYYY = "yyyy";
+    public static String YYYY_MM = "yyyy-MM";
+    public static String YYYY_MM_DD = "yyyy-MM-dd";
+    public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
+    public static String YYYYMMDD = "yyyyMMdd";
+    public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
+    private static String[] parsePatterns = {
+            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
+            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
+            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
+
+//    public static String getDateSourceName(Date startTime, Date endTime, Integer offset, Integer index) {
+//        String ret = null;
+//        switch (offset) {
+//            //月份
+//            case -1:
+//                ret = DateUtil.format(startTime, "yyyy-MM");
+//                break;
+//            //季度
+//            case -3:
+//                ret = String.format("%s-Q%s", DateUtil.format(startTime, "yyyy"), (index % 4) + 1);
+//                break;
+//            //半年
+//            case -6:
+//                ret = String.format("%s-%s", DateUtil.format(startTime, "yyyy"), index % 2 == 0 ? "H1" : "H2");
+//                break;
+//            //1年
+//            case -12:
+//                ret = DateUtil.format(startTime, "yyyy");
+//                break;
+//            //2年,3年,5年
+//            case -24:
+//            case -36:
+//            case -60:
+//                ret = String.format("%s-%s", DateUtil.format(DateUtil.offsetMonth(endTime, offset / 12 * -1), "yyyy"), DateUtil.format(startTime, "yyyy"));
+//                break;
+//        }
+//        return ret;
+//    }
+//
+//    private DateUtils() {
+//    }
+
+
+
+    public static boolean belongCalendar(Date nowTime, Date beginTime, Date endTime) {
+        Calendar date = Calendar.getInstance();
+        date.setTime(nowTime);
+        Calendar begin = Calendar.getInstance();
+        begin.setTime(beginTime);
+        Calendar end = Calendar.getInstance();
+        end.setTime(endTime);
+        return date.after(begin) && date.before(end);
+    }
+
+    /**
+     * 获取现在的时间 yyyy-MM-dd HH:mm:ss
+     */
+    public static String getNowTime() {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        Date date = new Date(System.currentTimeMillis());
+        return format.format(date);
+    }
+
+    /**
+     * 获取当前Date型日期
+     *
+     * @return Date() 当前日期
+     */
+    public static Date getNowDate() {
+        return new Date();
+    }
+
+    public static Integer getDateTime() {
+        return (int) (new Date().getTime() / 1000);
+    }
+
+//    public static Integer getDateTime(String date) {
+//        int dateTime = 0;
+//        if (date.contains("/")) {
+//            dateTime = Math.toIntExact(strToDateTime(date, parsePatterns[4]).getTime() / 1000);
+//        } else if (date.contains("-")) {
+//            dateTime = Math.toIntExact(strToDateTime(date, YYYY_MM_DD).getTime() / 1000);
+//        }
+//        return dateTime;
+//    }
+
+        public static Date getDateTime(String date) {
+        Date dateTime = null;
+        if (date.contains("/")) {
+            dateTime = strToDateTime(date, parsePatterns[4]);
+        } else if (date.contains("-")) {
+            dateTime = strToDateTime(date, YYYY_MM_DD);
+        }
+        return dateTime;
+    }
+
+    /**
+     * @author 陌溪
+     * @date 2018年6月14日
+     */
+    public static String getNowTimeFormat(String format) {
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
+        Date date = new Date(System.currentTimeMillis());
+        return simpleDateFormat.format(date);
+    }
+
+
+    public static Date str2Date(String dateString) {
+        try {
+            dateString = dateString.split(Pattern.quote(SPLIT_STRING))[0].replace(REPLACE_STRING[0], REPLACE_STRING[1]);
+            SimpleDateFormat sf1 = new SimpleDateFormat("E MMM dd yyyy HH:mm:ss z", Locale.US);
+            return sf1.parse(dateString);
+        } catch (Exception e) {
+            throw new RuntimeException("时间转化格式错误" + "[dateString=" + dateString + "]" + "[FORMAT_STRING=" + FORMAT_STRING + "]");
+        }
+    }
+
+    public static Date strToDate(String dateString) {
+        try {
+            SimpleDateFormat sf1;
+            if (dateString.contains("-")) {
+                sf1 = new SimpleDateFormat("yyyy-MM-dd");
+            } else if (dateString.contains("/")) {
+                sf1 = new SimpleDateFormat("yyyy/MM/dd");
+            } else if (dateString.contains(":")) {
+                sf1 = new SimpleDateFormat("yyyy:MM:dd");
+            } else if (dateString.contains(".")) {
+                sf1 = new SimpleDateFormat("yyyy.MM.dd");
+            } else {
+                sf1 = new SimpleDateFormat("yyyyMMdd");
+            }
+
+            return sf1.parse(dateString);
+        } catch (Exception e) {
+            System.out.println ("时间转化格式错误" + "[dateString=" + dateString + "]" + "[FORMAT_STRING=" + FORMAT_STRING + "]");
+
+            return null;
+        }
+    }
+
+    /**
+     * 获取今天开始的时间
+     */
+    public static String getToDayStartTime() {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
+        Date date = new Date(System.currentTimeMillis());
+        return format.format(date);
+    }
+
+    /**
+     * 获取今天结束的时间
+     */
+    public static String getToDayEndTime() {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
+        Date date = new Date(System.currentTimeMillis());
+        return format.format(date);
+    }
+
+    /**
+     * 获取昨天开始的时间
+     */
+    public static String getYesterdayStartTime() {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
+        Date date = new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000L);
+        return format.format(date);
+    }
+
+    /**
+     * 获取昨天结束的时间
+     */
+    public static String getYesterdayEndTime() {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
+        Date date = new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000L);
+        return format.format(date);
+    }
+
+    /**
+     * 获取某天开始的时间
+     */
+    public static String getOneDayStartTime(String oneDay) {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
+        Date date = new Date(oneDay);
+        return format.format(oneDay);
+    }
+
+    /**
+     * 获取某天开始的日期
+     */
+    public static String getOneDayStartTime(Date oneDay) {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
+        return format.format(oneDay);
+    }
+
+    /**
+     * 获取某天结束的时间
+     */
+    public static String getOneDayEndTime(String oneDay) {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
+        Date date = new Date(oneDay);
+        return format.format(date);
+    }
+
+    /**
+     * 获取某天结束的日期
+     */
+    public static String getOneDayEndTime(Date oneDay) {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
+        return format.format(oneDay);
+    }
+
+    /**
+     * 获取本周开始的时间
+     */
+    public static Date getWeekStartTime() {
+        //获得本周一0点时间
+        Calendar cal = Calendar.getInstance();
+        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
+        cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
+        return cal.getTime();
+    }
+
+    /**
+     * 将 String 转换成 Date
+     */
+    public static Date strToDateTime(String dateTime) {
+        Date date = null;
+        try {
+            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            date = format.parse(dateTime);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return date;
+    }
+
+    /**
+     * 将 String 转换成 Date (转换格式可传入)
+     */
+    public static Date strToDateTime(String dateTime, String fmt) {
+        Date date = null;
+        try {
+            SimpleDateFormat format = new SimpleDateFormat(fmt);
+            date = format.parse(dateTime);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return date;
+    }
+
+    /**
+     * 将 Date 转换成时间戳
+     */
+    public static Long dateToStamp(String s) throws ParseException {
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        Date date = simpleDateFormat.parse(s);
+        return date.getTime();
+    }
+
+    /**
+     * 将 Date 转换成 String
+     */
+    public static String dateTimeToStr(Date dateTime) {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        return format.format(dateTime);
+    }
+
+    public static String dateTimeToStr(Date dateTime, String fmt) {
+
+        SimpleDateFormat format = new SimpleDateFormat(fmt);
+        return format.format(dateTime);
+    }
+
+    /**
+     * 获取本周开始的时间的字符串
+     */
+    public static String getWeekStartTimeStr() {
+        //获得本周一0点时间
+        Calendar cal = Calendar.getInstance();
+        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
+        cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
+        return format.format(cal.getTime());
+    }
+
+    /**
+     * 获取本周结束的时间
+     */
+    public static Date getWeekEndTime() {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(getWeekStartTime());
+        cal.add(Calendar.DAY_OF_WEEK, 7);
+        return cal.getTime();
+    }
+
+    /**
+     * 获取本周结束的时间的字符串
+     */
+    public static String getWeekEndTimeStr() {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(getWeekStartTime());
+        cal.add(Calendar.DAY_OF_WEEK, 7);
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
+        return format.format(cal.getTime());
+    }
+
+    /**
+     * 获取上周开始的时间的字符串
+     */
+    public static String getLastWeekStartTimeStr() {
+        int weeks = -1;
+        int mondayPlus = getMondayPlus();
+        GregorianCalendar currentDate = new GregorianCalendar();
+        currentDate.add(GregorianCalendar.DATE, mondayPlus + 7 * weeks);
+        Date monday = currentDate.getTime();
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
+        return format.format(monday);
+    }
+
+    /**
+     * 获取本月开始的时间
+     */
+    public static Date getMonthStartTime() {
+        Calendar cal = Calendar.getInstance();
+        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
+        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMinimum(Calendar.DAY_OF_MONTH));
+        return cal.getTime();
+    }
+
+    /**
+     * 获取本月开始的时间的字符串
+     */
+    public static String getMonthStartTimeStr() {
+        Calendar cal = Calendar.getInstance();
+        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
+        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMinimum(Calendar.DAY_OF_MONTH));
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
+        return format.format(cal.getTime());
+    }
+
+    /**
+     * 获取本月结束的时间
+     */
+    public static Date getMonthEndTime() {
+        Calendar cal = Calendar.getInstance();
+        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
+        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
+        cal.set(Calendar.HOUR_OF_DAY, 24);
+        return cal.getTime();
+    }
+
+    /**
+     * 获取本月结束的时间的字符串
+     */
+    public static String getMonthEndTimeStr() {
+        Calendar cal = Calendar.getInstance();
+        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
+        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
+        cal.set(Calendar.HOUR_OF_DAY, 24);
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
+        return format.format(cal.getTime());
+    }
+
+    /**
+     * 获取当月的 天数
+     */
+    public static int getCurrentMonthDay() {
+        Calendar a = Calendar.getInstance();
+        a.set(Calendar.DATE, 1);
+        a.roll(Calendar.DATE, -1);
+        return a.get(Calendar.DATE);
+    }
+
+    /**
+     * 得到二个日期间的间隔天数
+     */
+    public static int getDayByTwoDay(String date1, String date2) {
+        SimpleDateFormat myFormatter = new SimpleDateFormat("yyyy-MM-dd");
+        long day;
+        try {
+            Date date = myFormatter.parse(date1);
+            Date myDate = myFormatter.parse(date2);
+            day = (date.getTime() - myDate.getTime()) / (24 * 60 * 60 * 1000);
+        } catch (Exception e) {
+            return 0;
+        }
+        return (int) day;
+    }
+
+    /**
+     * 得到两个日期相差的秒数
+     */
+    public static int getSecondByTwoDay(Date lastDate, Date date) {
+        long second;
+        try {
+            second = (lastDate.getTime() - date.getTime()) / 1000;
+        } catch (Exception e) {
+            return 0;
+        }
+        return (int) second;
+    }
+
+    /**
+     * 判断某个日期属于本周的第几天 (星期一代表第一天)
+     */
+    public static int getDaysByWeek(String dateTime) throws ParseException {
+        Calendar cal = Calendar.getInstance();
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+        Date date = dateFormat.parse(dateTime);
+        cal.setTime(date);
+        int day = cal.get(Calendar.DAY_OF_WEEK);
+        day = day - 1;
+        if (day == 0) {
+            day = 7;
+        }
+        return day;
+    }
+
+    /**
+     * 判断某个日期属于本月的第几天
+     */
+    public static int getDaysByMonth(String dateTime) throws ParseException {
+        Calendar cal = Calendar.getInstance();
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+        Date date = dateFormat.parse(dateTime);
+        cal.setTime(date);
+        return cal.get(Calendar.DAY_OF_MONTH);
+    }
+
+    /**
+     * 根据年 月 获取对应的月份 天数
+     */
+    public static int getDaysByYearMonth(int year, int month) {
+        Calendar a = Calendar.getInstance();
+        a.set(Calendar.YEAR, year);
+        a.set(Calendar.MONTH, month - 1);
+        a.set(Calendar.DATE, 1);
+        a.roll(Calendar.DATE, -1);
+        return a.get(Calendar.DATE);
+    }
+
+
+    /**
+     * 获取当前的年
+     */
+    public static Integer getYears() {
+        Calendar calendar = new GregorianCalendar(TimeZone
+                .getDefault());
+        return calendar.get(Calendar.YEAR);
+    }
+
+    /**
+     * 获取当前的月
+     */
+    public static Integer getMonth() {
+        Calendar calendar = new GregorianCalendar(TimeZone
+                .getDefault());
+        return calendar.get(Calendar.MONTH) + 1;
+    }
+
+    /**
+     * 获取当前天
+     */
+    public static Integer getDay() {
+        Calendar calendar = new GregorianCalendar(TimeZone
+                .getDefault());
+        return calendar.get(Calendar.DAY_OF_MONTH);
+    }
+
+    /**
+     * wx支付的过期时间
+     */
+    public static String getTime(double hour) {
+        long time = (long) (System.currentTimeMillis() + hour * 60 * 60 * 1000L);
+        Date date = new Date(time);
+        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
+        return format.format(date);
+    }
+
+    /**
+     * 获得当前日期与本周日相差的天数
+     */
+    private static int getMondayPlus() {
+        Calendar cd = Calendar.getInstance();
+        // 获得今天是一周的第几天,星期日是第一天,星期二是第二天......
+        // 因为按中国礼拜一作为第一天所以这里减1
+        int dayOfWeek = cd.get(Calendar.DAY_OF_WEEK) - 1;
+        if (dayOfWeek == 1) {
+            return 0;
+        } else {
+            return 1 - dayOfWeek;
+        }
+    }
+
+    /**
+     * 获取几天之后的日期
+     *
+     * @param date yyyy-MM-dd HH:mm:ss
+     * @param day  加减的天数
+     */
+    public static Date getDate(String date, int day) {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        Calendar cal = Calendar.getInstance();
+        Date beforeDate;
+        try {
+            beforeDate = format.parse(date);
+            cal.setTime(beforeDate);
+            cal.add(Calendar.DAY_OF_MONTH, day);
+            return cal.getTime();
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 获取几天之后的日期
+     *
+     * @param date yyyy-MM-dd HH:mm:ss
+     * @param day  加减的天数
+     */
+    public static Date getDate(Date date, int day) {
+        Calendar cal = Calendar.getInstance();
+            cal.setTime(date);
+            cal.add(Calendar.DAY_OF_MONTH, day);
+            return cal.getTime();
+    }
+
+    /**
+     * 获取某个日期 在加上 秒数的时间
+     *
+     * @param beforeDate yyyy-MM-dd HH:mm:ss
+     * @param timeSecond 加减的秒数
+     */
+    public static String getDateStr(Date beforeDate, Long timeSecond) {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        try {
+            // 返回毫秒数 + 添加的毫秒数
+            Long time = beforeDate.getTime() + timeSecond * 1000;
+            return format.format(time);
+        } catch (Exception e) {
+            log.error(e.getMessage());
+        }
+        return "";
+    }
+
+    /**
+     * 把date转换成字符串
+     */
+    public static String formatDate(Date date, String code) {
+        SimpleDateFormat format = new SimpleDateFormat(code);
+        return format.format(date);
+    }
+
+    public static String formatDate(Integer timestamp, String code) {
+        if (timestamp == null || timestamp == 0) {
+            return "";
+        }
+        return formatDate(new Date(timestamp * 1000L), code);
+    }
+
+    /**
+     * 获取过去N天内的日期数组
+     *
+     * @param intervals intervals天内
+     * @param formatStr 格式化字符串   yyyy-MM-dd
+     * @return 日期数组
+     */
+    public static ArrayList<String> getDaysByN(int intervals, String formatStr) {
+        ArrayList<String> pastDaysList = new ArrayList<>();
+        for (int i = intervals - 1; i >= 0; i--) {
+            pastDaysList.add(getPastDate(i, formatStr));
+        }
+        return pastDaysList;
+    }
+
+    /**
+     * 获取过去第几天的日期
+     */
+    public static String getPastDate(int past, String formatStr) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) - past);
+        Date today = calendar.getTime();
+        SimpleDateFormat format = new SimpleDateFormat(formatStr);
+        return format.format(today);
+    }
+
+    /**
+     * 获取某个时间段内所有日期
+     */
+    public static List<String> getDayBetweenDates(String begin, String end) {
+        Date dBegin = strToDateTime(begin);
+        Date dEnd = strToDateTime(end);
+        List<String> lDate = new ArrayList<>();
+        SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");
+        lDate.add(sd.format(dBegin));
+        Calendar calBegin = Calendar.getInstance();
+        // 使用给定的 Date 设置此 Calendar 的时间
+        calBegin.setTime(dBegin);
+        Calendar calEnd = Calendar.getInstance();
+        // 使用给定的 Date 设置此 Calendar 的时间
+        calEnd.setTime(dEnd);
+        // 测试此日期是否在指定日期之后
+        while (dEnd.after(calBegin.getTime())) {
+            // 根据日历的规则,为给定的日历字段添加或减去指定的时间量
+            calBegin.add(Calendar.DAY_OF_MONTH, 1);
+            lDate.add(sd.format(calBegin.getTime()));
+        }
+        return lDate;
+    }
+
+    /**
+     * 获取服务器启动时间
+     */
+    public static Date getServerStartDate() {
+        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
+        return new Date(time);
+    }
+
+    /**
+     * 计算两个时间差
+     */
+    public static String getDatePoor(Date endDate, Date nowDate) {
+        long nd = 1000 * 24 * 60 * 60;
+        long nh = 1000 * 60 * 60;
+        long nm = 1000 * 60;
+        // 获得两个时间的毫秒时间差异
+        long diff = endDate.getTime() - nowDate.getTime();
+        // 计算差多少天
+        long day = diff / nd;
+        // 计算差多少小时
+        long hour = diff % nd / nh;
+        // 计算差多少分钟
+        long min = diff % nd % nh / nm;
+        return day + "天" + hour + "小时" + min + "分钟";
+    }
+
+    public static long getTimeDiff(Date date) {
+        long NTime = date.getTime();
+        long OTime = getNowDate().getTime();
+        return (NTime - OTime) / 1000 / 60;
+    }
+
+    public static Date setDateHourAndMinute(Date date, int hour, int minute) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        calendar.set(Calendar.HOUR_OF_DAY, hour);
+        calendar.set(Calendar.MINUTE, minute);
+        calendar.set(Calendar.SECOND, 0);
+        return calendar.getTime();
+    }
+
+
+    /**
+     * 根据起止条数计算开始页数、开始页数的开始位置、结束页数、结束页数的结束位置
+     *
+     * @param startNumber 起始条数
+     * @param endNumber   终止条数
+     * @return 返回计算结果对象(开始页数、开始页数的开始位置、结束页数、结束页数的结束位置)
+     */
+    public static Calculate calculateFromStartAndEndNumber(Integer startNumber, Integer endNumber, Integer pageSize) {
+        int startPage;  //检索开始页数
+        int startNum;  //检索开始页数的开始专利位置
+        int endPage;  //检索结束页数
+        int endNum;  //检索结束页数的结束专利位置
+        if (startNumber % pageSize != 0) {
+            startPage = startNumber / pageSize;
+            startNum = startNumber % pageSize;
+        } else {
+            startPage = startNumber / pageSize;
+            startNum = pageSize;
+        }
+        if (endNumber % pageSize != 0) {
+            endPage = endNumber / pageSize + 1;
+            endNum = endNumber % pageSize;
+        } else {
+            endPage = endNumber / pageSize;
+            endNum = pageSize;
+        }
+
+        Calculate calculate = new Calculate()
+                .setStartPage(startPage)
+                .setStartNum(startNum)
+                .setEndPage(endPage)
+                .setEndNum(endNum);
+
+        return calculate;
+    }
+    /**
+     * 专利之星返回日期格式为字符串 yyyyMMdd,如 "20230713",本方法将其转成10位数字时间戳
+     *
+     * @param dateStr yyyyMMdd格式字符串日期
+     * @return 返回10位数字时间戳
+     */
+    public static int  stringDateToTimeStamp(String dateStr) {
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
+        Date date;
+        try {
+            date = dateFormat.parse(dateStr);
+        } catch (ParseException e) {
+            //日期格式转换异常
+            e.printStackTrace();
+            return Integer.parseInt(dateStr);
+        }
+        long timeStamp = date.getTime() / 1000;
+        return (int) timeStamp;
+    }
+
+    public static String strToStr(String dateString,String dateForm) {
+        try {
+            SimpleDateFormat sf1;
+            if (dateString.contains("-")) {
+                sf1 = new SimpleDateFormat("yyyy-MM-dd");
+            } else if (dateString.contains("/")) {
+                sf1 = new SimpleDateFormat("yyyy/MM/dd");
+            } else if (dateString.contains(":")) {
+                sf1 = new SimpleDateFormat("yyyy:MM:dd");
+            } else if (dateString.contains(".")) {
+                sf1 = new SimpleDateFormat("yyyy.MM.dd");
+            } else {
+                sf1 = new SimpleDateFormat("yyyyMMdd");
+            }
+
+
+            SimpleDateFormat format = new SimpleDateFormat(dateForm);
+            Date a= sf1.parse(dateString);
+           String reDate= format.format(a);
+            return reDate;
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+
+    /*
+     * 获取时间
+     */
+    public static String toGMTString(Date date) {
+        SimpleDateFormat df = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z", Locale.UK);
+        df.setTimeZone(new SimpleTimeZone(0, "GMT"));
+        return df.format(date);
+    }
+}

+ 180 - 0
src/main/java/com/cslg/ids/common/utils/ExcelUtils.java

@@ -0,0 +1,180 @@
+package com.cslg.ids.common.utils;
+
+import org.apache.poi.hssf.usermodel.*;
+import org.apache.poi.ooxml.POIXMLDocumentPart;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.xssf.usermodel.*;
+import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
+
+import java.awt.*;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ExcelUtils {
+
+    public static Map<String, PictureData> getDataFromExcel(String filePath) throws IOException {
+        //判断是否为excel类型文件
+        if (!filePath.endsWith(".xls") && !filePath.endsWith(".xlsx") && !filePath.endsWith(".XLS") && !filePath.endsWith(".XLSX")) {
+            System.out.println("文件不是excel类型");
+        }
+
+        FileInputStream fis = null;
+        Workbook wookbook = null;
+        Sheet sheet = null;
+        try {
+            //获取一个绝对地址的流
+            fis = new FileInputStream(filePath);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        try {
+            //2003版本的excel,用.xls结尾
+            wookbook = new HSSFWorkbook(fis);//得到工作簿
+        } catch (Exception ex) {
+            //ex.printStackTrace();
+            try {
+                //2007版本的excel,用.xlsx结尾
+                fis = new FileInputStream(filePath);
+                wookbook = new XSSFWorkbook(fis);//得到工作簿
+            } catch (IOException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
+        Map<String, PictureData> maplist = null;
+        //拿到excel表格的第一个sheet工作簿
+        sheet = wookbook.getSheetAt(0);
+        // 判断用07还是03的方法获取图片
+        if (filePath.endsWith(".xls") || filePath.endsWith(".XLS")) {
+            maplist = getPictures1((HSSFSheet) sheet);
+        } else if (filePath.endsWith(".xlsx") || filePath.endsWith(".XLSX")) {
+            maplist = getPictures2((XSSFSheet) sheet);
+        }
+        wookbook.close();
+        return maplist;
+    }
+
+    /**
+     * 获取图片和位置 (xls)
+     *
+     * @param sheet
+     * @return
+     * @throws IOException
+     */
+    public static Map<String, PictureData> getPictures1(HSSFSheet sheet) throws IOException {
+        Map<String, PictureData> map = new HashMap();
+        if (sheet.getDrawingPatriarch() != null) {
+            List<HSSFShape> list = sheet.getDrawingPatriarch().getChildren();
+            for (HSSFShape shape : list) {
+                if (shape instanceof HSSFPicture) {
+                    HSSFPicture picture = (HSSFPicture) shape;
+                    HSSFClientAnchor cAnchor = (HSSFClientAnchor) picture.getAnchor();
+                    PictureData pdata = picture.getPictureData();
+                    String key = String.valueOf(cAnchor.getRow1());
+                    map.put(key, pdata);
+                }
+            }
+        }
+        return map;
+    }
+
+    /**
+     * 获取图片和位置 (xlsx)
+     *
+     * @param sheet
+     * @return
+     * @throws IOException
+     */
+    public static Map<String, PictureData> getPictures2(XSSFSheet sheet) throws IOException {
+        Map<String, PictureData> map = new HashMap();
+        List<POIXMLDocumentPart> list = sheet.getRelations();
+        for (POIXMLDocumentPart part : list) {
+            if (part instanceof XSSFDrawing) {
+                XSSFDrawing drawing = (XSSFDrawing) part;
+                List<XSSFShape> shapes = drawing.getShapes();
+                for (XSSFShape shape : shapes) {
+                    XSSFPicture picture = (XSSFPicture) shape;
+                    Dimension d = picture.getImageDimension();
+                    //解决图片空指针报错问题 lig  2021-06-03
+                    XSSFClientAnchor anchor = (XSSFClientAnchor) shape.getAnchor();
+                    //XSSFClientAnchor anchor = picture.getPreferredSize();
+                    CTMarker marker = anchor.getFrom();
+                    String key = String.valueOf(marker.getRow());
+                    map.put(key, picture.getPictureData());
+                }
+            }
+        }
+        return map;
+    }
+
+//    /**
+//     * @param pictureData 图片
+//     * @return 返回图片的文件路径和文件名称
+//     */
+//    public static Map<String, String> savePicture(PictureData pictureData) throws IOException {
+//        FileUtils fileUtils = SpringUtils.getBean(FileUtils.class);
+//        Map<String, String> result = new HashMap<>();
+//        String ext = pictureData.suggestFileExtension();
+//        byte[] data = pictureData.getData();
+//        String picName = IdUtil.simpleUUID() + "." + ext;
+//        String date = DateUtils.getNowTimeFormat("yyyyMMdd");
+//        String folderPath = fileUtils.getSavePath(date);
+//        String filePath = FileUtils.FILE_SEPARATOR + date + FileUtils.FILE_SEPARATOR + picName;
+//        File directory = new File(folderPath);
+//        if (!directory.exists()) {
+//            directory.mkdir();
+//        }
+//        FileOutputStream out = new FileOutputStream(folderPath + picName);
+//        out.write(data);
+//        out.close();
+//        result.put("path", filePath);
+//        result.put("name", picName);
+//        return result;
+//    }
+
+    /**
+     * @param
+     * @param x           单元格x轴坐标
+     * @param y           单元格y轴坐标
+     * @param pictureData 图片二进制数据
+     * @param picType     图片格式
+     */
+    public static void writePicture(Sheet sheet, int x, int y, byte[] pictureData, int picType) {
+        Drawing drawingPatriarch = sheet.createDrawingPatriarch();
+        //设置图片单元格位置
+        ClientAnchor anchor = drawingPatriarch.createAnchor(0, 0, 0, 0, x, y, x + 1, y + 1);
+        //随单元格改变位置和大小
+        anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);
+        //添加图片
+        int pictureIndex = sheet.getWorkbook().addPicture(pictureData, picType);
+        drawingPatriarch.createPicture(anchor, pictureIndex);
+    }
+
+    public static void setExcelCellStyle(HSSFCellStyle cellStyle) {
+        cellStyle.setBorderBottom(BorderStyle.THIN);
+        cellStyle.setBorderLeft(BorderStyle.THIN);
+        cellStyle.setBorderRight(BorderStyle.THIN);
+        cellStyle.setBorderTop(BorderStyle.THIN);
+    }
+
+    public static String getValue(Cell cell) {
+        if (cell != null) {
+            if (cell.getCellType() == CellType.NUMERIC && HSSFDateUtil.isCellDateFormatted(cell)) {
+                Date date = cell.getDateCellValue();
+                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+                String dateString = dateFormat.format(date);
+                return dateString;
+            } else {
+                return cell.toString();
+            }
+        }
+        return "";
+    }
+
+
+}

+ 304 - 0
src/main/java/com/cslg/ids/common/utils/FileUtils.java

@@ -0,0 +1,304 @@
+package com.cslg.ids.common.utils;
+
+
+import cn.hutool.core.util.IdUtil;
+import com.alibaba.fastjson.JSON;
+import com.cslg.ids.IdsApplication;
+import org.springframework.boot.system.ApplicationHome;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.*;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+
+@Service
+public class FileUtils {
+
+    public static final String FILE_SEPARATOR = System.getProperty("file.separator");
+    public static final String COMMON_FILE = "file";
+    public static final String BACKUP_FILE = "backup";
+
+    public static String getStaticPath(String fileName) {
+        //ApplicationHome类 返回target目录层级
+        ApplicationHome ah = new ApplicationHome(IdsApplication.class);
+        //获取 applicationHome 内的路径 ...\target\classes 到这一层级下
+        File file = ah.getSource();
+        //获取 file的parentFile 即最后一级之前的所有层级路径(包括盘符) 这里能获得到的最终层级为  ...\target 后续用FILE_SEPARATOR(系统路径分割通配符 即 "\") 以及fileName拼接生成存放文件的目录层级 即为根目录 root
+        String rootPath = null;
+
+        if (fileName != null && !fileName.equals("")) {
+            rootPath = file.getParentFile().toString() + FILE_SEPARATOR + fileName;
+        } else {
+            rootPath = file.getParentFile().toString();
+        }
+        //根据上方生成的根目录路径 生成对应文件夹 没有就新建
+        File root = new File(rootPath);
+        if (!root.exists()) {
+            root.mkdir();
+        }
+        //返回的最终形式为 盘符:\项目层级\target\file
+        return rootPath;
+    }
+
+    public static File getFileByBytes(byte[] bytes, String prefix, String suffix) {
+        BufferedOutputStream bos = null;
+        FileOutputStream fos = null;
+        File file = null;
+        try {
+
+            file = File.createTempFile(prefix, suffix);
+
+            //输出流
+            fos = new FileOutputStream(file);
+
+            //缓冲流
+            bos = new BufferedOutputStream(fos);
+
+            //将字节数组写出
+            bos.write(bytes);
+            return file;
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            if (bos != null) {
+                try {
+                    bos.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            if (fos != null) {
+                try {
+                    fos.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            return file;
+        }
+    }
+
+    public static File getFileByUrl(String dataUrl) throws IOException {
+
+        URL url = new URL(dataUrl);  //想要读取的url地址
+        InputStream in = url.openStream();
+        File file = File.createTempFile("new_url", ".pdf");  //创建文件
+        OutputStream os = new FileOutputStream(file);  //创建文件输出流
+        int bytesRead;
+        byte[] buffer = new byte[8192];
+        int len = 8192;
+        while ((bytesRead = in.read(buffer, 0, len)) != -1) {
+            os.write(buffer, 0, bytesRead);
+        }
+        //关闭释放流
+        os.close();
+        in.close();
+        return file;
+    }
+
+    public static File getPictureFileByUrl(String dataUrl) throws IOException {
+
+        URL url = new URL(dataUrl);  //想要读取的url地址
+        InputStream in = url.openStream();
+        File file = File.createTempFile("new_url", ".jpg");  //创建文件
+        OutputStream os = new FileOutputStream(file);  //创建文件输出流
+        int bytesRead;
+        byte[] buffer = new byte[8192];
+        int len = 8192;
+        while ((bytesRead = in.read(buffer, 0, len)) != -1) {
+            os.write(buffer, 0, bytesRead);
+        }
+        //关闭释放流
+        os.close();
+        in.close();
+        return file;
+    }
+
+    public static FileInputStream byteToFile(byte[] bytes) {
+        String fileName = IdUtil.simpleUUID() + ".png";
+        File file = new File(fileName);
+        FileInputStream fileInputStream = null;
+        try {
+            OutputStream output = new FileOutputStream(file);
+            BufferedOutputStream bufferedOutput = new BufferedOutputStream(output);
+            bufferedOutput.write(bytes);
+            fileInputStream = new FileInputStream(file);
+            file.deleteOnExit();
+            return fileInputStream;
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return fileInputStream;
+    }
+
+    public static String getSystemPath2(String url) {
+        return getStaticPath(COMMON_FILE) + FILE_SEPARATOR + url;
+    }
+
+    public static void writeFile(String json, String FilePath) {
+
+        try {
+            File file = new File(FilePath);
+
+            // if file doesnt exists, then create it
+            if (!file.exists()) {
+                file.createNewFile();
+            } else {
+                file.delete();
+                file.createNewFile();
+            }
+
+            // true = append file
+            FileWriter fileWritter = new FileWriter(file, false);
+            BufferedWriter bufferWritter = new BufferedWriter(fileWritter);
+            bufferWritter.write(json);
+            bufferWritter.close();
+
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static File getFileByName(File file, String name) {
+        for (File file1 : file.listFiles()) {
+            if (file1.getName().equals(name)) {
+                return file1;
+            }
+        }
+        return null;
+    }
+
+    public static void writeFile(Object object, File file) {
+        String json = JSON.toJSONString(object);
+        try {
+            // if file doesnt exists, then create it
+            if (!file.exists()) {
+                file.createNewFile();
+            } else {
+                file.delete();
+                file.createNewFile();
+            }
+            // true = append file
+            FileWriter fileWritter = new FileWriter(file, false);
+            BufferedWriter bufferWritter = new BufferedWriter(fileWritter);
+            bufferWritter.write(json);
+            bufferWritter.close();
+
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static File multipartFileToFile(MultipartFile file) throws Exception {
+        File toFile = null;
+        if (file == null || file.equals("") || file.getSize() <= 0) {
+            file = null;
+        } else {
+            InputStream ins = null;
+            ins = file.getInputStream();
+            toFile = new File(file.getOriginalFilename());
+            inputStreamToFile(ins, toFile);
+            ins.close();
+        }
+        return toFile;
+    }
+
+    //获取流文件
+    private static void inputStreamToFile(InputStream ins, File file) {
+        try {
+            OutputStream os = new FileOutputStream(file);
+            int bytesRead = 0;
+            byte[] buffer = new byte[8192];
+            while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
+                os.write(buffer, 0, bytesRead);
+            }
+            os.close();
+            ins.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public String analysisJsonFile() {
+        ApplicationHome ah = new ApplicationHome(BackupUtils.class);
+        File file = ah.getSource();
+//        String settingFilePath = file.getParentFile().toString() + FileUtils.FILE_SEPARATOR + "\\jsons\\" + "uploadSetting.json";
+        String settingFilePath = file.getParentFile().toString() + FileUtils.FILE_SEPARATOR + "uploadSetting.json";
+        BufferedReader reader = null;
+        StringBuilder last = new StringBuilder();
+        InputStreamReader inputStreamReader;
+        try (FileInputStream fileInputStream = new FileInputStream(settingFilePath)) {
+            inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8);
+
+            reader = new BufferedReader(inputStreamReader);
+            String tempString;
+            while ((tempString = reader.readLine()) != null) {
+                last.append(tempString);
+            }
+            reader.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return last.toString();
+    }
+
+    public String getPath(String url) {
+        return getStaticPath(COMMON_FILE) + url;
+    }
+
+    public String getDirectoryName() {
+        return DateUtils.getNowTimeFormat("yyyyMMdd");
+    }
+
+    public String getSavePath(String directoryName) {
+        return getStaticPath(COMMON_FILE) + FILE_SEPARATOR + directoryName + FILE_SEPARATOR;
+    }
+
+    public String createDirectory() {
+        String directoryName = this.getDirectoryName();
+        String savePath = this.getSavePath(directoryName);
+        File directory = new File(savePath);
+        if (!directory.exists()) {
+            directory.mkdir();
+        }
+        return directoryName;
+    }
+
+    public String createRandomDirectory() {
+        String directoryName = IdUtil.simpleUUID();
+        String savePath = this.getSavePath(directoryName);
+        File directory = new File(savePath);
+        if (!directory.exists()) {
+            directory.mkdir();
+        }
+        return directoryName;
+    }
+
+    public String getTempPath(String fileName) {
+        String tempPath = getStaticPath(COMMON_FILE) + FILE_SEPARATOR + "temp";
+        File file = new File(tempPath);
+        if (!file.exists()) {
+            file.mkdir();
+        }
+        return tempPath + FILE_SEPARATOR + fileName;
+    }
+
+    public String getDirectory(String fileName) {
+        return FILE_SEPARATOR + this.createDirectory() + FILE_SEPARATOR + fileName;
+    }
+
+    public String getSystemPath(String url) {
+        return getStaticPath(COMMON_FILE) + FILE_SEPARATOR + url;
+    }
+}

+ 381 - 0
src/main/java/com/cslg/ids/common/utils/JsonUtils.java

@@ -0,0 +1,381 @@
+package com.cslg.ids.common.utils;
+
+import com.alibaba.fastjson.JSONObject;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonSyntaxException;
+import com.google.gson.reflect.TypeToken;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * json解析的工具类
+ */
+public class JsonUtils {
+
+    // 定义jackson对象
+    public static Logger log = LoggerFactory.getLogger(JsonUtils.class);
+    private static ObjectMapper MAPPER;
+
+    static {
+        MAPPER = new ObjectMapper();
+        MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
+    }
+
+    /**
+     * 把对象转换为json数据
+     *
+     * @param obj
+     * @return 2018年5月7日  下午5:27:16
+     */
+    public static String objectToJson(Object obj) {
+        Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
+        try {
+            String json = gson.toJson(obj);
+            return json;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 将Object转换成Map
+     *
+     * @param obj
+     * @return
+     */
+    public static Map<String, Object> objectToMap(Object obj) {
+
+        try {
+            Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
+            String json = gson.toJson(obj);
+            return jsonToMap(json);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 将Object类型的map转换成String类型
+     *
+     * @param map
+     * @return
+     */
+    public static Map<String, String> mapToMap(Map<String, Object> map) {
+        Map<String, String> returnMap = new HashMap<>();
+        for (String key : map.keySet()) {
+            returnMap.put(key, String.valueOf(map.get(key)));
+        }
+        return returnMap;
+    }
+
+    /**
+     * 任意类型转换成Map
+     * @return
+     */
+    public static Map<String, String> object2Map(Object obj) {
+        Map<String, String> hashMap = new HashMap();
+        try {
+            Class c = obj.getClass();
+            Method m[] = c.getDeclaredMethods();
+            for (int i = 0; i < m.length; i++) {
+                if (m[i].getName().indexOf("get")==0) {
+                    // 得到Map的key
+                    String suffixKey = m[i].getName().substring(4);
+                    String prefixKey = m[i].getName().substring(3,4).toLowerCase();
+                    hashMap.put(prefixKey + suffixKey, String.valueOf(m[i].invoke(obj, new Object[0])));
+                }
+            }
+        } catch (Throwable e) {
+            log.error(e.getMessage());
+        }
+        return hashMap;
+    }
+
+
+    /**
+     * 把json字符串转化为对象
+     *
+     * @param jsonString
+     * @param clazz
+     * @return
+     */
+    public static Object jsonToObject(String jsonString, Class<?> clazz) {
+
+        Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
+        Object obj = null;
+        try {
+            obj = gson.fromJson(jsonString, clazz);
+        } catch (JsonSyntaxException e) {
+            e.printStackTrace();
+        }
+        return obj;
+    }
+
+    /**
+     * josn转arrayList
+     *
+     * @param jsonArray
+     * @return
+     */
+    public static ArrayList<?> jsonArrayToArrayList(String jsonArray) {
+
+        Gson gson = new GsonBuilder()
+                .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC)
+                .setDateFormat("yyyy-MM-dd HH:mm:ss")
+                .serializeNulls()
+                .create();
+        ArrayList<?> list = null;
+        try {
+            Type listType = new TypeToken<ArrayList<?>>() {
+            }.getType();
+
+            list = gson.fromJson(jsonArray, listType);
+        } catch (JsonSyntaxException e) {
+            e.printStackTrace();
+        }
+        return list;
+    }
+
+    /**
+     * JSON 转 ArrayList
+     */
+    public static ArrayList<?> jsonArrayToArrayList(String jsonArray, Class<?> clazz) {
+
+        Gson gson = new GsonBuilder()
+                .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC)
+                .setDateFormat("yyyy-MM-dd HH:mm:ss")
+                .serializeNulls()
+                .create();
+        ArrayList<?> list = null;
+        try {
+
+            list = (ArrayList<?>) gson.fromJson(jsonArray, clazz);
+        } catch (JsonSyntaxException e) {
+            e.printStackTrace();
+        }
+        return list;
+    }
+
+    /**
+     * 把json转换为map类型的数据
+     *
+     * @param json
+     * @return
+     */
+    public static Map<String, Object> jsonToMap(String json) {
+
+        Gson gson = new GsonBuilder()
+                .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC)
+                .setDateFormat("yyyy-MM-dd HH:mm:ss")
+                .serializeNulls()
+                .create();
+        Map<String, Object> map = null;
+        try {
+            Type type = new TypeToken<Map<String, Object>>() {
+            }.getType();
+
+            map = gson.fromJson(json, type);
+        } catch (JsonSyntaxException e) {
+            e.printStackTrace();
+        }
+        return map;
+    }
+
+    /**
+     * 将Json转换成Map<String, ?>
+     *
+     * @param json
+     * @param clazz
+     * @return
+     */
+    public static Map<String, ?> jsonToMap(String json, Class<?> clazz) {
+
+        Gson gson = new GsonBuilder()
+                .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC)
+                .setDateFormat("yyyy-MM-dd HH:mm:ss")
+                .serializeNulls()
+                .create();
+        Map<String, ?> map = null;
+        try {
+            Type type = new TypeToken<Map<String, ?>>() {
+            }.getType();
+
+            map = gson.fromJson(json, type);
+        } catch (JsonSyntaxException e) {
+            e.printStackTrace();
+        }
+        return map;
+    }
+
+    /**
+     * 将map转换成pojo
+     *
+     * @param map
+     * @param beanType
+     * @param <T>
+     * @return
+     */
+    public static <T> T mapToPojo(Map<String, Object> map, Class<T> beanType) {
+
+        Gson gson = new GsonBuilder()
+                .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC)
+                .setDateFormat("yyyy-MM-dd HH:mm:ss")
+                .serializeNulls()
+                .create();
+
+        JsonElement jsonElement = gson.toJsonTree(map);
+        T pojo = gson.fromJson(jsonElement, beanType);
+
+        return pojo;
+    }
+
+    /**
+     * 将json结果集转化为对象
+     *
+     * @param jsonData
+     * @param beanType
+     * @param <T>
+     * @return
+     */
+    public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {
+        try {
+            T t = MAPPER.readValue(jsonData, beanType);
+            return t;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 将json数据转换成pojo对象list
+     *
+     * @param jsonData
+     * @param beanType
+     * @return
+     */
+    public static <T> List<T> jsonToList(String jsonData, Class<T> beanType) {
+        JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
+        try {
+            List<T> list = MAPPER.readValue(jsonData, javaType);
+            return list;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+
+    /**
+     * 将任意pojo转化成map
+     *
+     * @param t pojo对象
+     * @return
+     */
+    public static <T> Map<String, Object> pojoToMap(T t) {
+        Map<String, Object> result = new HashMap<String, Object>();
+        Method[] methods = t.getClass().getMethods();
+        try {
+            for (Method method : methods) {
+                Class<?>[] paramClass = method.getParameterTypes();
+                // 如果方法带参数,则跳过
+                if (paramClass.length > 0) {
+                    continue;
+                }
+                String methodName = method.getName();
+                if (methodName.startsWith("get")) {
+                    Object value = method.invoke(t);
+                    result.put(methodName, value);
+                }
+            }
+        } catch (IllegalArgumentException e) {
+            e.printStackTrace();
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+        } catch (InvocationTargetException e) {
+            e.printStackTrace();
+        } catch (SecurityException e) {
+            e.printStackTrace();
+        }
+        return result;
+    }
+
+
+    /**
+     * 将二叉树json对象转为sql where后的条件语句
+     *liRJ
+     * @param jsonObject jsaonObject
+     * @return
+     */
+    public static String reSql(JSONObject jsonObject){
+        String str1 = "";
+        String str2 = "";
+        JSONObject jsonLeft =jsonObject.getJSONObject("left");
+        JSONObject jsonRight =jsonObject.getJSONObject("right");
+        if(jsonLeft.containsKey("left")){
+            str1 = reSql(jsonLeft);
+        }
+        else{
+            str1 = jsonLeft.get("field").toString()+jsonLeft.get("opr").toString()+jsonLeft.get("value").toString();
+        }
+        if(jsonRight.containsKey("right")){
+            str2= reSql( jsonRight);
+        }
+        else{
+            str2 =jsonRight.get("field").toString()+jsonRight.get("opr").toString()+jsonRight.get("value").toString();
+        }
+        String sql ="("+ str1+") "+ jsonObject.get("logicOpr")+" ("+str2+")";
+
+        return sql;
+    }
+
+    /**
+     * json转对象
+     * @param jsonStr
+     * @param clazz
+     * @param <T>
+     * @return
+     */
+    public static <T> T jsonToObj(String jsonStr, Class<T> clazz) {
+        try {
+            return MAPPER.readValue(jsonStr, clazz);
+        } catch (IOException e) {
+            throw new RuntimeException("json转换出错", e);
+        }
+    }
+
+    /**
+     * json转对象
+     * @param jsonStr
+     * @param typeReference
+     * @param <T>
+     * @return
+     */
+    public static <T> T jsonToObj(String jsonStr, TypeReference<T> typeReference) {
+        try {
+            return MAPPER.readValue(jsonStr, typeReference);
+        } catch (IOException e) {
+            throw new RuntimeException("json转换出错", e);
+        }
+    }
+
+}

+ 66 - 0
src/main/java/com/cslg/ids/common/utils/LoginUtils.java

@@ -0,0 +1,66 @@
+package com.cslg.ids.common.utils;
+
+import com.cslg.ids.common.exception.ExceptionEnum;
+import com.cslg.ids.common.exception.XiaoShiException;
+import jakarta.annotation.Resource;
+import jakarta.servlet.http.HttpServletRequest;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import java.util.List;
+
+@Component
+public class LoginUtils {
+    @Resource
+    private RedisUtil redisUtil;
+
+    public static String getToken() {
+        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
+        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
+        HttpServletRequest httpRequest = sra.getRequest();
+        String tem = httpRequest.getHeader("Cookie");
+        List<String> lst = StringUtils.changeStringToString(tem, ";");
+        final String[] token = {null};
+        lst.forEach(item -> {
+            if (item.contains("token")) {
+                token[0] = item;
+            }
+        });
+        return token[0].replaceAll(" ", "");
+    }
+
+    public static String getTokenByFixedAttribute() {
+        RequestAttributes ra =RequestContextHolder.getRequestAttributes();
+        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
+        HttpServletRequest httpRequest = sra.getRequest();
+        String tem = httpRequest.getHeader("FixedAttribute");
+        final String[] token = {null};
+        if (org.apache.commons.lang3.StringUtils.isNotEmpty(tem)) {
+            List<String> lst = StringUtils.changeStringToString(tem, ";");
+            lst.forEach(item -> {
+                if (item.contains("token")) {
+                    token[0] = item;
+                }
+            });
+            return token[0].replaceAll(" ", "");
+        } else
+            return null;
+    }
+
+    public Integer getId() {
+        String oriToken = null;
+        try {
+            oriToken = LoginUtils.getToken();
+        } catch (Exception e) {
+            throw new XiaoShiException(ExceptionEnum.LOGIN_NO_LOGIN, "未登录");
+        }
+        String q = "token:login:" + oriToken.replace("=", ":");
+        String IdS = redisUtil.get(q);
+        if (IdS == null) {
+            throw new XiaoShiException(ExceptionEnum.LOGIN_NO_LOGIN, "未登录");
+        }
+        return Integer.parseInt(IdS);
+    }
+}

+ 25 - 0
src/main/java/com/cslg/ids/common/utils/RabbitMQUtils.java

@@ -0,0 +1,25 @@
+package com.cslg.ids.common.utils;
+
+import com.cslg.ids.common.core.base.MailConstants;
+import org.springframework.amqp.rabbit.connection.CorrelationData;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+@Component
+public class RabbitMQUtils {
+
+    @Autowired
+    private RabbitTemplate rabbitTemplate;
+
+    /**
+     * 向用户邮箱发送短信
+     *
+     * @param map 所需参数
+     */
+    public void sendEmailMessage(Map<String, Object> map) {
+        rabbitTemplate.convertAndSend(MailConstants.MAIL_EXCHANGE_NAME, MailConstants.MAIL_ROUTING_KEY_NAME, map, new CorrelationData("1"));
+    }
+}

+ 58 - 0
src/main/java/com/cslg/ids/common/utils/RandomUtil.java

@@ -0,0 +1,58 @@
+package com.cslg.ids.common.utils;
+
+import java.security.SecureRandom;
+import java.util.Random;
+
+public class RandomUtil {
+
+    // 定义可用来生成邀请码的字符集
+    private static final String CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+    // 定义邀请码的长度
+    private static final int CODE_LENGTH = 8;
+
+    private static String[] STR_ARR = new String[] { "a", "b", "c", "d", "e",
+            "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r",
+            "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E",
+            "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
+            "S", "T", "U", "V", "W", "X", "Y", "Z", "1", "2", "3", "4", "5",
+            "6", "7", "8", "9", "0"};
+
+    /**
+     * 随机验证码
+     * @return
+     */
+    public static String getSixRandom(){
+        return String.valueOf((int) ((Math.random() * 9 + 1) * Math.pow(10, 5)));
+    }
+
+    /**
+     * 随机生成code码的方法
+     * @param length
+     * @return
+     */
+    public static String generateRandomString(int length) {
+        StringBuilder sb = new StringBuilder();
+        Random rand = new Random();
+        for (int i = 0; i < length; i++) {
+            sb.append(STR_ARR[rand.nextInt(STR_ARR.length)]);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 生成随机邀请码的方法
+     *
+     * @return 生成的邀请码
+     */
+    public static String generateInvitationCode() {
+        SecureRandom random = new SecureRandom();
+        StringBuilder codeBuilder = new StringBuilder(CODE_LENGTH);
+
+        for (int i = 0; i < CODE_LENGTH; i++) {
+            int index = random.nextInt(CHARACTERS.length());
+            codeBuilder.append(CHARACTERS.charAt(index));
+        }
+
+        return codeBuilder.toString();
+    }
+}

+ 323 - 0
src/main/java/com/cslg/ids/common/utils/ReadExcelUtils.java

@@ -0,0 +1,323 @@
+package com.cslg.ids.common.utils;
+
+import com.cslg.ids.common.exception.ThrowException;
+import com.cslg.ids.entity.common.PatentData;
+import org.apache.poi.hssf.usermodel.*;
+import org.apache.poi.ooxml.POIXMLDocumentPart;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.xssf.usermodel.*;
+import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
+import org.springframework.stereotype.Service;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * @Author xiexiang
+ * @Date 2023/5/30
+ */
+@Service
+public class ReadExcelUtils {
+    /**
+     * 检测Excel文件合法性
+     *
+     * @param tempFile 临时文件
+     * @return 返回文件总行数
+     */
+    public static Integer textExcel(File tempFile, String sourceId) throws IOException {
+        //判断文件是否存在
+        if (!tempFile.exists() || tempFile.getPath().trim().equals("")) {
+            ThrowException.throwXiaoShiException("文件上传失败,服务器忙请稍后再试!");
+        }
+
+        // 检测是否为excel文件
+        String suffix = tempFile.getPath().substring(tempFile.getPath().lastIndexOf("."));
+        if (!suffix.equals(".xls") && !suffix.equals(".xlsx") && !suffix.equals(".XLS") && !suffix.equals(".XLSX")) {
+            //删除临时文件tempFile
+            new File(tempFile.getPath()).delete();
+            ThrowException.throwXiaoShiException("文件格式错误,请上传Excel文件!");
+        }
+
+        InputStream fis = new FileInputStream(tempFile);
+        //使用poi框架解析处理Excel文件
+        Workbook workbook = null;
+        //区分不同版本Excel,使用各自对应的工具类
+        if (suffix.equals(".xls") || suffix.equals(".XLS")) {
+            workbook = new HSSFWorkbook(fis);
+        } else if (suffix.equals(".xlsx") || suffix.equals(".XLSX")) {
+            workbook = new XSSFWorkbook(fis);
+        }
+        //读取第几个sheet
+        Sheet sheet = workbook.getSheetAt(0);
+        //读取总行数
+        int rows = sheet.getPhysicalNumberOfRows();
+        if (rows <= 1) {
+            //删除临时文件tempFile
+            fis.close();
+            new File(tempFile.getPath()).delete();
+            ThrowException.throwXiaoShiException("文件内容格式不正确,请检查总行数是否有专利内容");
+        }
+
+        //获取第一行抬头
+        Row firstRow = sheet.getRow(0);
+        boolean flag1 = false;  //是否有 "公开(公告)号"
+        boolean flag2 = false;  //是否有 "申请号"
+        //遍历第一行单元格抬头,检查合法性
+        String title = "", source = "";
+        if (sourceId.equals("1")) {
+            source = "智慧芽";
+            title = "公开(公告)号";
+        } else if (sourceId.equals("2")) {
+            source = "合享";
+            title = "公开(公告)号";
+        } else {
+            source = "Patentics";
+            title = "公开号";
+        }
+        for (Cell cell : firstRow) {
+            if (cell.getStringCellValue().equals(title)) {
+                flag1 = true;
+            }
+            if (cell.getStringCellValue().equals("申请号")) {
+                flag2 = true;
+            }
+        }
+        if (!flag1 || !flag2) {
+            //删除临时文件tempFile
+            fis.close();
+            new File(tempFile.getPath()).delete();
+            ThrowException.throwXiaoShiException("文件内容格式不正确,您选择【" + source + "】来源,Excel第一行抬头必须有【" + title + "】和【申请号】");
+        }
+        //关闭流
+        fis.close();
+        //返回文件总行数-1(即专利总数量)
+        return rows - 1;
+    }
+
+    /**
+     * 获取一行专利的全部数据(专利内容数据 + 摘要附图)
+     *
+     * @param tempFile Excel临时文件
+     * @param row      行数
+     * @return 返回装载专利数据(专利内容数据 + 摘要附图)的对象
+     */
+    public static PatentData readExcelOneRow(File tempFile, Sheet sheet, int row) throws IOException {
+        //创建返回最终结果的对象 patentData
+        PatentData patentData = new PatentData();
+        //装载专利数据(除了摘要附图)的map:(key:表头如 "公开(公告)号"  value:表头对应内容如 "CN1307082B")
+        Map<Object, Object> map = new HashMap<>();
+        //装载摘要附图的对象
+        PictureData pictureData = null;
+
+        //开始装载专利数据
+        Row firstRow = sheet.getRow(0);
+        Row needRow = sheet.getRow(row);
+        //获得总列数
+        int columns = firstRow.getLastCellNum();
+        for (int i = 0; i < columns; i++) {
+            map.put(firstRow.getCell(i) + "", ExcelUtils.getValue(needRow.getCell(i)) + "");
+        }
+
+        //开始装载专利摘要附图(判断用07还是03的方法获取图片)
+        String suffix = tempFile.getName().substring(tempFile.getName().lastIndexOf("."));
+        if (suffix.equals(".xls") || suffix.equals(".XLS")) {
+            pictureData = getPictures1((HSSFSheet) sheet, row);
+        } else if (suffix.equals(".xlsx") || suffix.equals(".XLSX")) {
+            pictureData = getPictures2((XSSFSheet) sheet, row);
+        }
+
+        //返回结果对象装载结果
+        patentData.setMap(map);
+        patentData.setPictureData(pictureData);
+
+        return patentData;
+    }
+
+    /**
+     * 获取一行专利的全部数据(专利内容数据 + 摘要附图)
+     *
+     * @param tempFile Excel临时文件
+     * @param row      行数
+     * @return 返回装载专利数据(专利内容数据 + 摘要附图)的对象
+     */
+    public static PatentData readExcelTwoRow(File tempFile, Sheet sheet, int row) throws IOException {
+        //创建返回最终结果的对象 patentData
+        PatentData patentData = new PatentData();
+        //装载专利数据(除了摘要附图)的map:(key:表头如 "公开(公告)号"  value:表头对应内容如 "CN1307082B")
+        Map<Object, Object> map = new HashMap<>();
+        //装载摘要附图的对象
+        PictureData pictureData = null;
+
+        //开始装载专利数据
+        Row firstRow = sheet.getRow(1);
+        Row needRow = sheet.getRow(row);
+        //获得总列数
+        int columns = firstRow.getLastCellNum();
+        for (int i = 0; i < columns; i++) {
+            map.put(firstRow.getCell(i) + "", ExcelUtils.getValue(needRow.getCell(i)) + "");
+        }
+
+        //开始装载专利摘要附图(判断用07还是03的方法获取图片)
+        String suffix = tempFile.getName().substring(tempFile.getName().lastIndexOf("."));
+        if (suffix.equals(".xls") || suffix.equals(".XLS")) {
+            pictureData = getPictures1((HSSFSheet) sheet, row);
+        } else if (suffix.equals(".xlsx") || suffix.equals(".XLSX")) {
+            pictureData = getPictures2((XSSFSheet) sheet, row);
+        }
+
+        //返回结果对象装载结果
+        patentData.setMap(map);
+        patentData.setPictureData(pictureData);
+
+        return patentData;
+    }
+
+    public static Sheet readExcel(File tempFile) {
+        Sheet sheet = null;
+
+        try {
+            InputStream inputStream = new FileInputStream(tempFile);
+            //POI可以处理Excel文件
+            Workbook workbook = null;
+            //当文件以.xls结尾时
+            String suffix = tempFile.getName().substring(tempFile.getName().lastIndexOf("."));
+            if (suffix.equals(".xls") || suffix.equals(".XLS")) {
+                workbook = new HSSFWorkbook(inputStream);
+            } else if (suffix.equals(".xlsx") || suffix.equals(".XLSX")) {
+                workbook = new XSSFWorkbook(inputStream);
+            }
+
+            //读取第几个sheet
+            sheet = workbook.getSheetAt(0);
+
+            //关闭流
+            inputStream.close();
+
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        return sheet;
+    }
+
+    /**
+     * 03版本Excel取附图
+     *
+     * @param sheet Excel工作簿
+     * @return 返回附图map
+     */
+    public static PictureData getPictures1(HSSFSheet sheet, Integer row) throws IOException {
+        if (sheet.getDrawingPatriarch() != null) {
+            List<HSSFShape> list = sheet.getDrawingPatriarch().getChildren();
+            for (HSSFShape shape : list) {
+                if (shape instanceof HSSFPicture) {
+                    HSSFPicture picture = (HSSFPicture) shape;
+                    HSSFClientAnchor cAnchor = (HSSFClientAnchor) picture.getAnchor();
+                    int row1 = cAnchor.getRow1();
+                    if (row1 == row) {
+                        return picture.getPictureData();
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 07版本Excel取附图
+     *
+     * @param sheet Excel工作簿
+     * @return 返回附图map
+     */
+    public static PictureData getPictures2(XSSFSheet sheet, Integer row) throws IOException {
+        List<POIXMLDocumentPart> list = sheet.getRelations();
+        for (POIXMLDocumentPart part : list) {
+            if (part instanceof XSSFDrawing) {
+                XSSFDrawing drawing = (XSSFDrawing) part;
+                List<XSSFShape> shapes = drawing.getShapes();
+                for (XSSFShape shape : shapes) {
+                    //解决图片空指针报错问题 lig  2021-06-03
+                    XSSFClientAnchor anchor = (XSSFClientAnchor) shape.getAnchor();
+                    //XSSFClientAnchor anchor = picture.getPreferredSize();
+                    CTMarker marker = anchor.getFrom();
+                    int excelRow = marker.getRow();
+                    if (excelRow == row) {
+                        XSSFPicture picture = (XSSFPicture) shape;
+                        return picture.getPictureData();
+                    }
+                }
+            }
+        }
+
+        return null;
+    }
+
+    public static String getValue(Cell cell) {
+        if (cell != null) {
+            if (cell.getCellType() == CellType.NUMERIC && HSSFDateUtil.isCellDateFormatted(cell)) {
+                Date date = cell.getDateCellValue();
+                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+                String dateString = dateFormat.format(date);
+                return dateString;
+            } else {
+                return cell.toString();
+            }
+        }
+        return "";
+    }
+
+
+    /**
+     * @param sheet
+     * @return
+     * @throws IOException
+     */
+    public static List<String> getPatentNoFromExcel(Sheet sheet) throws IOException {
+        List<String> patentNos = new ArrayList<>();
+        int rows = sheet.getPhysicalNumberOfRows();
+        Integer cellId = null;
+        //开始装载专利数据
+        Row firstRow = sheet.getRow(0);
+
+        //查找列
+        int columns = firstRow.getLastCellNum();
+        for (int t = 0; t < columns; t++) {
+            if (firstRow.getCell(t).toString().equals("专利号")) {
+                cellId = t;
+            }
+        }
+        for (int i = 1; i < rows; i++) {
+            Row row = sheet.getRow(i);
+            String patentNo = row.getCell(cellId).toString();
+            patentNos.add(patentNo);
+        }
+        return patentNos;
+    }
+
+
+    public static Integer testNoImport(Sheet sheet) throws IOException {
+        int rows = sheet.getPhysicalNumberOfRows();
+        Integer cellId = null;
+        //开始装载专利数据
+        Row firstRow = sheet.getRow(0);
+
+        //查找列
+        int columns = firstRow.getLastCellNum();
+        for (int t = 0; t < columns; t++) {
+            if (firstRow.getCell(t).toString().equals("专利号")) {
+                cellId = t;
+            }
+        }
+
+        if(cellId!=null&&rows==1){
+            cellId=-1;
+        }
+        return cellId;
+    }
+
+
+}

Dosya farkı çok büyük olduğundan ihmal edildi
+ 1325 - 0
src/main/java/com/cslg/ids/common/utils/RedisUtil.java


+ 99 - 0
src/main/java/com/cslg/ids/common/utils/RegexUtil.java

@@ -0,0 +1,99 @@
+package com.cslg.ids.common.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+/**
+  * 正则工具类
+ */
+public class RegexUtil {
+
+    private static final Pattern DATE_PATTERN = Pattern.compile("(?<!\\d)(\\d{4}-\\d{2}-\\d{2})(?!\\d)");
+
+    /**
+     * 大陆号码或香港号码均可
+     */
+    public static boolean isPhoneLegal(String str) throws PatternSyntaxException {
+        return isChinaPhoneLegal(str) || isHKPhoneLegal(str);
+    }
+
+    /**
+     * 手机号验证,1开头,后面10位随机0-9数字
+     */
+    public static boolean isChinaPhoneLegal(String str) throws PatternSyntaxException {
+        if (str == null) {
+            return false;
+        }
+        String regExp = "^[1][0-9]{10}$";
+        Pattern p = Pattern.compile(regExp);
+        Matcher m = p.matcher(str);
+        return m.matches();
+    }
+
+    /**
+     * 香港手机号码8位数,5|6|8|9开头+7位任意数
+     */
+    public static boolean isHKPhoneLegal(String str) throws PatternSyntaxException {
+        if (str == null) {
+            return false;
+        }
+        String regExp = "^(5|6|8|9)\\d{7}$";
+        Pattern p = Pattern.compile(regExp);
+        Matcher m = p.matcher(str);
+        return m.matches();
+    }
+
+    public static boolean isRegExpReplace(String str) throws PatternSyntaxException {
+        if (str == null) {
+            return false;
+        }
+        String regExp = "[,。、;,./;]";
+        Pattern p = Pattern.compile(regExp);
+        Matcher m = p.matcher(str);
+        return m.matches();
+    }
+
+    //split By分隔符忽略引号
+    public static List<String> splitByDelimiters(String input) {
+        List<String> result = new ArrayList<>();
+        // 正则表达式匹配分隔符,但忽略引号内的内容
+        // 注意:这里使用了Unicode转义序列来表示中文引号
+        Pattern pattern = Pattern.compile("\"([^\"]*)\"|’([^’]*)’|‘([^’]*)’|“([^\"]*)”|([^,。、;,./;\\s+]+)");
+        Matcher matcher = pattern.matcher(input);
+
+        while (matcher.find()) {
+            if (matcher.group(1) != null) { // 英文双引号
+                result.add(matcher.group(1));
+            } else if (matcher.group(2) != null) { // 中文单引号
+                result.add(matcher.group(2));
+            } else if (matcher.group(3) != null) { // 中文单引号(另一种可能的形式)
+                result.add(matcher.group(3));
+            } else if (matcher.group(4) != null) { // 中文双引号
+                result.add(matcher.group(4));
+            } else { // 其他内容(即分隔符外的部分)
+                result.add(matcher.group(5));
+            }
+        }
+        return result;
+
+    }
+
+    public static String extractDate(String input) {
+        if (input == null || input.trim().isEmpty()) {
+            return null;
+        }
+
+        Matcher matcher = DATE_PATTERN.matcher(input);
+        String lastMatch = null;
+
+        // 查找所有匹配项并记录最后一个
+        while (matcher.find()) {
+            lastMatch = matcher.group(1);
+        }
+
+        return lastMatch;
+    }
+}

+ 563 - 0
src/main/java/com/cslg/ids/common/utils/StringUtils.java

@@ -0,0 +1,563 @@
+package com.cslg.ids.common.utils;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.UUID;
+
+@Slf4j
+public class StringUtils {
+
+    private final static int NUM_32 = 32;
+    /**
+     * 下划线
+     */
+    private static final char SEPARATOR = '_';
+    //集群号
+    private static int machineId = 1;
+
+    /**
+     * 下划线转驼峰命名
+     */
+    public static String toUnderScoreCase(String str) {
+        if (str == null) {
+            return null;
+        }
+        StringBuilder sb = new StringBuilder();
+        // 前置字符是否大写
+        boolean preCharIsUpperCase = true;
+        // 当前字符是否大写
+        boolean curreCharIsUpperCase = true;
+        // 下一字符是否大写
+        boolean nexteCharIsUpperCase = true;
+        for (int i = 0; i < str.length(); i++) {
+            char c = str.charAt(i);
+            if (i > 0) {
+                preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
+            } else {
+                preCharIsUpperCase = false;
+            }
+
+            curreCharIsUpperCase = Character.isUpperCase(c);
+
+            if (i < (str.length() - 1)) {
+                nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
+            }
+
+            if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) {
+                sb.append(SEPARATOR);
+            } else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) {
+                sb.append(SEPARATOR);
+            }
+            sb.append(Character.toLowerCase(c));
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * * 判断一个对象是否非空
+     *
+     * @param object Object
+     * @return true:非空 false:空
+     */
+    public static boolean isNotNull(Object object) {
+        return !isNull(object);
+    }
+
+    public static boolean isNull(Object object) {
+        return object == null;
+    }
+
+
+    /**
+     * 把String 转换为 long
+     *
+     * @param str
+     * @param defaultData
+     * @return
+     */
+    public static long getLong(String str, Long defaultData) {
+        Long lnum = defaultData;
+
+        if (isEmpty(str)) {
+            return lnum;
+        }
+        try {
+            lnum = Long.valueOf(str.trim()).longValue();
+        } catch (NumberFormatException e) {
+            log.warn("把String 转换为 long======== " + str);
+        }
+        return lnum;
+
+    }
+
+    /**
+     * 转换成Boolean类型
+     *
+     * @param str
+     * @param defaultData
+     * @return
+     */
+    public static Boolean getBoolean(String str, Boolean defaultData) {
+        Boolean lnum = defaultData;
+
+        if (isEmpty(str)) {
+            return lnum;
+        }
+        try {
+            lnum = Boolean.valueOf(str.trim()).booleanValue();
+        } catch (NumberFormatException e) {
+            log.warn("把String 转换为 long======== " + str);
+        }
+        return lnum;
+
+    }
+
+    /**
+     * 把String转换成int数据
+     *
+     * @param str
+     * @param defaultData
+     * @return
+     */
+    public static int getInt(String str, Integer defaultData) {
+        int inum = defaultData;
+        if (isEmpty(str)) {
+            return inum;
+        }
+        try {
+            inum = Integer.valueOf(str.trim()).intValue();
+        } catch (NumberFormatException e) {
+            log.warn("把String转换成int数据========== " + str);
+        }
+        return inum;
+    }
+
+    /**
+     * 把String转换成double数据
+     *
+     * @param str
+     * @param defaultData
+     * @return
+     */
+    public static double getDouble(String str, Double defaultData) {
+        double dnum = defaultData;
+        if (isEmpty(str)) {
+            return dnum;
+        }
+        try {
+            dnum = Double.valueOf(str.trim()).doubleValue();
+        } catch (NumberFormatException e) {
+            log.error("把String转换成double数据: {}", str);
+        }
+        return dnum;
+    }
+
+    /**
+     * 把String转换成float数据
+     *
+     * @param str
+     * @param defaultData
+     * @return
+     */
+    public static float getFloat(String str, Float defaultData) {
+        float dnum = defaultData;
+        if (isEmpty(str)) {
+            return dnum;
+        }
+        try {
+            dnum = Float.valueOf(str.trim()).floatValue();
+        } catch (NumberFormatException e) {
+            log.error("把String转换成float数据: {}", str);
+        }
+        return dnum;
+    }
+
+    /**
+     * 判断字符串是否为空
+     *
+     * @param s
+     * @return
+     */
+    public static Boolean isEmpty(String s) {
+        if (s == null || s.length() <= 0) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * 判断字符串是否为空
+     *
+     * @param str
+     * @return
+     */
+    public static boolean isNotEmpty(String str) {
+        return !StringUtils.isEmpty(str);
+    }
+
+    /**
+     * 按code截取字符串
+     *
+     * @return
+     */
+    public static String[] split(String str, String code) {
+        String[] split;
+        if (isEmpty(str)) {
+            split = null;
+        } else {
+            split = str.split(code);
+        }
+        return split;
+    }
+
+    /**
+     * 把字符串按code 转换为List<Long>
+     *
+     * @param str
+     * @return
+     */
+    public static List<Long> changeStringToLong(String str, String code) {
+        String[] split = split(str, code);
+        List<Long> lnums = new ArrayList<>();
+        for (String s : split) {
+            if (!isEmpty(s)) {
+                long lnum = getLong(s, 0L);
+                lnums.add(lnum);
+            }
+
+        }
+        return lnums;
+    }
+
+    /**
+     * 把字符串按code 转换为List<String>
+     *
+     * @param str
+     * @return
+     */
+    public static List<String> changeStringToString(String str, String code) {
+        String[] split = split(str, code);
+        List<String> lnums = new ArrayList<>();
+        for (String s : split) {
+            String trim = s.trim();
+            lnums.add(trim);
+        }
+        return lnums;
+    }
+
+    /**
+     * 把字符串按code 转换为List<Long>
+     *
+     * @param str
+     * @return
+     */
+    public static List<Integer> changeStringToInteger(String str, String code) {
+        if (isEmpty(str)) {
+            return new ArrayList<>();
+        }
+        String[] split = split(str, code);
+        List<Integer> inums = new ArrayList<>();
+        for (String s : split) {
+            int inum = getInt(s, 0);
+            inums.add(inum);
+        }
+        return inums;
+    }
+
+
+    /**
+     * 生成唯一订单号
+     *
+     * @return
+     */
+    public static String getOrderNumberByUUID() {
+
+        int hashCodeV = UUID.randomUUID().toString().hashCode();
+        //有可能是负数
+        if (hashCodeV < 0) {
+            hashCodeV = -hashCodeV;
+        }
+        String orderNumber = machineId + String.format("%015d", hashCodeV);
+        return orderNumber;
+    }
+
+    /**
+     * 生成唯一商户退款单号
+     *
+     * @return
+     */
+    public static String getOutRefundNoByUUID() {
+
+        int hashCodeV = UUID.randomUUID().toString().hashCode();
+        //有可能是负数
+        if (hashCodeV < 0) {
+            hashCodeV = -hashCodeV;
+        }
+        String out_refund_no = "BACK" + machineId + String.format("%015d", hashCodeV);
+        return out_refund_no;
+
+    }
+
+    /**
+     * 获取UUID,去掉了-
+     *
+     * @return
+     */
+    public static String getUUID() {
+        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
+        log.debug("获取32位的UUID的调试日志-->>" + uuid);
+        return uuid;
+    }
+
+    /**
+     * 获取雪花UID
+     *
+     * @return
+     */
+//    public static Long getSnowflakeId() {
+//        SnowflakeIdWorker snowflakeIdWorker = new SnowflakeIdWorker(0, 0);
+//        return snowflakeIdWorker.nextId();
+//    }
+
+    /**
+     * list小于0的数据就过滤了
+     * 把list的数组变成1,3,4,5,6
+     *
+     * @param list
+     * @param code
+     * @return
+     */
+    public static String listToString(List<Long> list, String code) {
+        String s = "";
+        if (list == null || list.size() <= 0) {
+            return s;
+        }
+        for (Long l : list) {
+            if (l.longValue() > 0) {
+                s = s + l + code;
+            }
+        }
+        return s;
+    }
+
+    /**
+     * 按code把list的数组转换成字符串
+     *
+     * @param list
+     * @param code
+     * @return
+     */
+    public static String listTranformString(List<String> list, String code) {
+        String s = "";
+        if (list == null || list.size() <= 0) {
+            return s;
+        }
+        s = String.join(code, list);
+        return s;
+    }
+
+    /**
+     * 判断是否为非空字符串
+     *
+     * @param str
+     * @return
+     */
+    public static boolean isNotBlank(String str) {
+        return !StringUtils.isBlank(str);
+    }
+
+    /**
+     * 校验uid列表,检查里面元素是否满足限定长度为32
+     *
+     * @param collection
+     * @return
+     */
+    public static boolean checkUidList(Collection<String> collection) {
+        if (collection.size() == 0) {
+            return false;
+        }
+        for (String uid : collection) {
+            if (uid.trim().length() != NUM_32) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 判断是否为空字符串
+     *
+     * @param str
+     * @return
+     */
+    public static boolean isBlank(String str) {
+        int strLen;
+        if (str == null || (strLen = str.length()) == 0) {
+            return true;
+        }
+        for (int i = 0; i < strLen; i++) {
+            if ((Character.isWhitespace(str.charAt(i)) == false)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 判断一个字符串是否为数字
+     *
+     * @param str
+     * @return
+     */
+    public static boolean isNumeric(String str) {
+        try {
+            //把字符串强制转换为数字
+            Integer.valueOf(str);
+            //如果是数字,返回True
+            return true;
+        } catch (Exception e) {
+            //如果抛出异常,返回False
+            return false;
+        }
+    }
+
+    /**
+     * 判断是不是整数数字
+     * @param s
+     * @return
+     */
+    public static boolean isInteger(String s) {
+        if (s == null) {
+            return false;
+        }
+        return s.matches("-?\\d+"); // 匹配整数,包括负数
+    }
+
+    /**
+     * 判断是不是正整数数字
+     * @param s
+     * @return
+     */
+    public static boolean isPositiveInteger(String s) {
+        if (s == null) {
+            return false;
+        }
+        // 正则表达式匹配一个或多个正整数
+        return s.matches("\\d+"); // "\\d+" 匹配一个或多个数字,但不包括负数和小数点
+    }
+
+    /**
+     * 某个子串是否在字符串内
+     *
+     * @param str
+     * @param searchChar
+     * @return
+     */
+    public static boolean contains(String str, String searchChar) {
+        if (isEmpty(str)) {
+            return false;
+        }
+        return str.indexOf(searchChar) >= 0;
+    }
+
+    /**
+     * 切割字符串
+     *
+     * @param str
+     * @param start
+     * @return
+     */
+    public static String substring(String str, int start) {
+        if (str == null) {
+            return null;
+        }
+        // handle negatives, which means last n characters
+        if (start < 0) {
+            start = str.length() + start;
+        }
+        if (start < 0) {
+            start = 0;
+        }
+        if (start > str.length()) {
+            return "";
+        }
+        return str.substring(start);
+    }
+
+    /**
+     * 判断评论是否为垃圾评论(仅通过单一字符重复出现来判断,以后可以扩展更多的检测方法)
+     *
+     * @param content
+     * @return
+     */
+    public static Boolean isCommentSpam(String content) {
+        if (content == null) {
+            return true;
+        }
+        char[] chars = content.toCharArray();
+        // 最大重复次数
+        Integer maxCount = 4;
+        for (int a = 0; a < chars.length; a++) {
+            Integer count = 1;
+            for (int b = a; b < chars.length - 1; b++) {
+                if (chars[b + 1] == chars[b]) {
+                    count++;
+                    // 判断字符重复的次数是否大于阈值
+                    if (count >= maxCount) {
+                        return true;
+                    }
+                    continue;
+                } else {
+                    break;
+                }
+            }
+        }
+        return false;
+    }
+
+    public static <T> String join(List<T> list, String separator) {
+        return org.apache.commons.lang3.StringUtils.join(list, separator);
+    }
+
+    public static <T> String join(String[] list, String separator) {
+        return org.apache.commons.lang3.StringUtils.join(list, separator);
+    }
+
+
+    public static List<String> splitChineseText(String text,Integer textNum) {
+        List<String> chunks = new ArrayList<>();
+        int start = 0;
+        int textLength = text.length();
+        if (text.length() < textNum) {
+            chunks.add(text);
+            return chunks;
+        }
+        while (start < textLength) {
+            // 计算当前块的最大可能结束位置
+            int end = Math.min(start + textNum, textLength);
+            int lastSentenceEnd = -1;
+
+            // 从后向前查找最后一个句号
+            for (int i = end - 1; i >= start; i--) {
+                if (text.charAt(i) == '。') {
+                    lastSentenceEnd = i;
+                    break;
+                }
+            }
+
+            if (lastSentenceEnd != -1) {
+                // 切割文本并添加到结果集
+                chunks.add(text.substring(start, lastSentenceEnd + 1));
+                start = lastSentenceEnd + 1;
+            } else {
+                // 异常处理:当前2000字符范围内没有句号
+                throw new RuntimeException("文本位置 " + start + " 至 " + end + " 之间未找到句号,请检查输入文本格式");
+            }
+        }
+        return chunks;
+    }
+}

+ 20 - 0
src/main/java/com/cslg/ids/config/MybatisPlusConfig.java

@@ -0,0 +1,20 @@
+package com.cslg.ids.config;
+
+
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@MapperScan("com.cslg.ids.mapper")
+public class MybatisPlusConfig {
+    @Bean
+    public MybatisPlusInterceptor mybatisPlusInterceptor() {
+        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
+        return interceptor;
+    }
+}

+ 68 - 0
src/main/java/com/cslg/ids/config/RabbitMQConfig.java

@@ -0,0 +1,68 @@
+package com.cslg.ids.config;
+
+import com.cslg.ids.common.core.base.MailConstants;
+import org.springframework.amqp.core.*;
+import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
+import org.springframework.amqp.rabbit.connection.CorrelationData;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+
+@Component
+public class RabbitMQConfig {
+    @Value("${queueName}")
+    private String queueName;
+    @Autowired
+    private CachingConnectionFactory cachingConnectionFactory;
+
+    @Bean
+    public RabbitTemplate rabbitTemplate() {
+        RabbitTemplate rabbitTemplate = new RabbitTemplate(cachingConnectionFactory);
+        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
+            /**
+             * 消息确认回调
+             * @param data 消息唯一标识
+             * @param ack  确认结果
+             * @param cause  失败原因
+             */
+            @Override
+            public void confirm(CorrelationData data, boolean ack, String cause) {
+                String msgId = data.getId();
+                if (ack) {
+//                    LOGGER.info("{}======>消息发送成功",msgId);
+//                    mailLogService.update(new UpdateWrapper<MailLog>()
+//                            .set("status",MailConstants.SUCCESS)
+//                            .eq("msgId",msgId));
+                } else {
+//                    LOGGER.error("{}======>消息发送失败",msgId);
+                }
+            }
+        });
+        rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {
+
+            @Override
+            public void returnedMessage(ReturnedMessage returnedMessage) {
+//                LOGGER.error("{}======>消息发送queue时失败",message.getBody());
+            }
+        });
+        return rabbitTemplate;
+    }
+
+
+    @Bean
+    public Queue queue() {
+        return new Queue(queueName);
+    }
+
+    @Bean
+    public DirectExchange directExchange() {
+        return new DirectExchange(MailConstants.MAIL_EXCHANGE_NAME);
+    }
+
+    @Bean
+    public Binding binding() {
+        return BindingBuilder.bind(queue()).to(directExchange()).with(MailConstants.MAIL_ROUTING_KEY_NAME);
+    }
+}

+ 11 - 0
src/main/java/com/cslg/ids/config/WebSocketConfig.java

@@ -0,0 +1,11 @@
+package com.cslg.ids.config;
+
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class WebSocketConfig {
+//    @Bean
+//    public ServerEndpointExporter serverEndpointExporter() {
+//        return new ServerEndpointExporter();
+//    }
+}

+ 78 - 0
src/main/java/com/cslg/ids/controller/TranslateController.java

@@ -0,0 +1,78 @@
+package com.cslg.ids.controller;
+
+import com.cslg.ids.common.core.auth.Response;
+import com.cslg.ids.common.core.base.Constants;
+import com.cslg.ids.common.utils.FileUtils;
+import com.cslg.ids.dto.FileInfoIdDTO;
+import com.cslg.ids.dto.TaskIdDTO;
+import com.cslg.ids.service.FileInfoService;
+import com.cslg.ids.service.TranslateService;
+import com.cslg.ids.vo.FileTranslateVO;
+import com.cslg.ids.vo.SelectFileInfoVO;
+import com.cslg.ids.vo.SelectTranslatePlanVO;
+import io.swagger.v3.oas.annotations.Operation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.IOException;
+
+@RequestMapping(Constants.API_IDS + "/translate")
+@RestController
+@RequiredArgsConstructor(onConstructor_ = {@Lazy})
+public class TranslateController {
+
+    @Autowired
+    private TranslateService translateService;
+
+    @Autowired
+    private FileInfoService fileInfoService;
+
+    @Operation(summary = "文件翻译")
+    @PostMapping("/fileTranslate2")
+    public String fileTranslate2(@RequestParam(value = "multipartFile", required = false) MultipartFile multipartFile) throws Exception {
+        File file = FileUtils.multipartFileToFile(multipartFile);
+        translateService.fileTranslate2(file);
+        return Response.success("");
+    }
+
+    @Operation(summary = "上传IDS文件")
+    @PostMapping("/fileTranslate")
+    public String fileTranslate(@RequestParam(value = "multipartFile", required = false) MultipartFile multipartFile,
+                                @RequestParam(value = "type",required = false) Integer type) throws Exception {
+        File file = FileUtils.multipartFileToFile(multipartFile);
+        FileTranslateVO translateVO = translateService.fileTranslate(file, type);
+        return Response.success(translateVO);
+    }
+
+    @Operation(summary = "查询文件")
+    @PostMapping("/selectFileInfo")
+    public String selectFileInfo(@RequestBody FileInfoIdDTO infoIdDTO) {
+        SelectFileInfoVO infoVO = fileInfoService.selectFileInfo(infoIdDTO);
+        return Response.success(infoVO);
+    }
+
+    @Operation(summary = "查询翻译进度")
+    @PostMapping("/selectTranslatePlan")
+    public String selectTranslatePlan(@RequestBody TaskIdDTO taskIdDTO) throws IOException {
+        SelectTranslatePlanVO translatePlanVO = translateService.selectTranslatePlan(taskIdDTO);
+        return Response.success(translatePlanVO);
+    }
+
+    @Operation(summary = "生成翻译文件")
+    @PostMapping("/generateTranslateFile")
+    public String generateTranslateFile(@RequestBody TaskIdDTO taskIdDTO) throws IOException {
+        String guid = translateService.generateTranslateFile(taskIdDTO);
+        return Response.success(guid);
+    }
+
+    @Operation(summary = "重新翻译")
+    @PostMapping("/againTranslate")
+    public String againTranslate(@RequestBody FileInfoIdDTO infoIdDTO) throws Exception {
+        FileTranslateVO translateVO = translateService.againTranslate(infoIdDTO);
+        return Response.success(translateVO);
+    }
+}

+ 24 - 0
src/main/java/com/cslg/ids/dto/FMSDeleteFileDTO.java

@@ -0,0 +1,24 @@
+package com.cslg.ids.dto;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 调用FMS系统删除文件接口
+ *
+ * @Author xiexiang
+ * @Date 2023/8/14
+ */
+@Data
+public class FMSDeleteFileDTO {
+    /**
+     * 文件ids
+     */
+    private List<String> guids;
+
+    /**
+     * 删除类型(2物理删除 1逻辑删除)
+     */
+    private Integer type;
+}

+ 28 - 0
src/main/java/com/cslg/ids/dto/FileInfoDTO.java

@@ -0,0 +1,28 @@
+package com.cslg.ids.dto;
+
+import lombok.Data;
+
+@Data
+public class FileInfoDTO {
+    private Integer fileInfoId;
+
+    //原文名称
+    private String oldFileName;
+
+    //原文guid
+    private String oldFileGuid;
+
+    //任务id
+    private String taskId;
+
+    //译文名称
+    private String newFileName;
+
+    //译文guid
+    private String newFileGuid;
+
+    //文件类型 1专利 2文献 3审查意见书 4检索报告
+    private Integer type;
+
+    private Integer status;
+}

+ 8 - 0
src/main/java/com/cslg/ids/dto/FileInfoIdDTO.java

@@ -0,0 +1,8 @@
+package com.cslg.ids.dto;
+
+import lombok.Data;
+
+@Data
+public class FileInfoIdDTO {
+    private Integer fileInfoId;
+}

+ 9 - 0
src/main/java/com/cslg/ids/dto/SelectTranslatePlanDTO.java

@@ -0,0 +1,9 @@
+package com.cslg.ids.dto;
+
+import lombok.Data;
+
+@Data
+public class SelectTranslatePlanDTO {
+
+    private String taskId;
+}

+ 9 - 0
src/main/java/com/cslg/ids/dto/TaskIdDTO.java

@@ -0,0 +1,9 @@
+package com.cslg.ids.dto;
+
+import lombok.Data;
+
+@Data
+public class TaskIdDTO {
+
+    private String taskId;
+}

+ 13 - 0
src/main/java/com/cslg/ids/dto/TranslateFileDTO.java

@@ -0,0 +1,13 @@
+package com.cslg.ids.dto;
+
+import lombok.Data;
+
+@Data
+public class TranslateFileDTO {
+
+    private String file_name;
+
+    private String file_content;
+
+    private TranslateFilePayLoadDTO payload;
+}

+ 38 - 0
src/main/java/com/cslg/ids/dto/TranslateFilePayLoadDTO.java

@@ -0,0 +1,38 @@
+package com.cslg.ids.dto;
+
+import lombok.Data;
+
+@Data
+public class TranslateFilePayLoadDTO {
+    private Boolean skip_translate;
+    private String base_url;
+    private String api_key;
+    private String model_id;
+    private String to_lang;
+    private String thinking;
+    private Long chunk_size;
+    private Long concurrent;
+    private Float temperature;
+    private Long retry;
+    private String custom_prompt;
+    private String glossary_dict;
+    private Boolean system_proxy_enable;
+    private Boolean glossary_generate_enable;
+    private String glossary_agent_config;
+    private String workflow_type;
+    private String convert_engine;
+    private String mineru_deploy_backend;
+    private String mineru_deploy_base_url;
+    private Long mineru_deploy_end_page_id;
+    private Boolean mineru_deploy_formula_enable;
+    private Long mineru_deploy_start_page_id;
+    private String mineru_token;
+    private Boolean formula_ocr;
+    private Boolean code_ocr;
+    private Boolean force_json;
+    private String model_version;
+
+
+    private String insert_mode;
+    private String separator;
+}

+ 48 - 0
src/main/java/com/cslg/ids/entity/FileInfo.java

@@ -0,0 +1,48 @@
+package com.cslg.ids.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.cslg.ids.entity.common.BaseEntity;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@TableName("file_info")
+public class FileInfo extends BaseEntity<FileInfo> {
+
+    //原文名称
+    @TableField(value = "old_file_name")
+    private String oldFileName;
+
+    //原文guid
+    @TableField(value = "old_file_guid")
+    private String oldFileGuid;
+
+    //任务id
+    @TableField(value = "task_id")
+    private String taskId;
+
+    //译文名称
+    @TableField(value = "new_file_name")
+    private String newFileName;
+
+    //译文guid
+    @TableField(value = "new_file_guid")
+    private String newFileGuid;
+
+    //文件类型 1专利 2文献 3审查意见书 4检索报告
+    @TableField(value = "type")
+    private Integer type;
+
+    //文件状态 1未完成 2翻译完成 3译文已生成 4翻译失败
+    @TableField(value = "status")
+    private Integer status;
+
+    @TableField(value = "retry")
+    private Integer retry;
+
+    //创建时间
+    @TableField(value = "create_time")
+    private Date createTime;
+}

+ 28 - 0
src/main/java/com/cslg/ids/entity/common/BaseEntity.java

@@ -0,0 +1,28 @@
+package com.cslg.ids.entity.common;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+
+
+/**
+ * Entity基类
+ *
+ */
+@Data
+@SuppressWarnings("rawtypes")
+public class BaseEntity<T extends Model> extends Model {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = -4851055162892178225L;
+
+    /**
+     * 唯一ID
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+}

+ 30 - 0
src/main/java/com/cslg/ids/entity/common/BaseVO.java

@@ -0,0 +1,30 @@
+package com.cslg.ids.entity.common;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * @author 沈永艺
+ * @date 2022-8-3
+ * @description VO基类
+ */
+
+@Data
+@Accessors(chain = true)
+public class BaseVO {
+    /**
+     * 每页条数
+     */
+    private Integer size;
+
+    /**
+     * 当前页数
+     */
+    private Integer current;
+
+    /**
+     * 数据总数
+     */
+    private Integer total;
+
+}

+ 35 - 0
src/main/java/com/cslg/ids/entity/common/Calculate.java

@@ -0,0 +1,35 @@
+package com.cslg.ids.entity.common;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 根据起止条数计算开始页数、开始页数的开始位置、结束页数、结束页数的结束位置
+ *
+ * @Author chenyu
+ * @Date 2023/7/14
+ */
+@Accessors(chain = true)
+@Data
+public class Calculate implements Serializable {
+    /**
+     * 检索开始页数
+     */
+    private Integer startPage;
+    /**
+     * 检索开始页数的开始专利位置
+     */
+    private Integer startNum;
+    /**
+     * 检索结束页数
+     */
+    private Integer endPage;
+    /**
+     * 检索结束页数的结束专利位置
+     */
+    private Integer endNum;
+
+
+}

+ 45 - 0
src/main/java/com/cslg/ids/entity/common/DataSource.java

@@ -0,0 +1,45 @@
+package com.cslg.ids.entity.common;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * @author 沈永艺
+ * @date 2022-8-12
+ * @description 数据权限类 数据库对应实体
+ */
+
+@Data
+@Accessors(chain = true)
+
+public class DataSource {
+    /**
+     * 数据字典名字
+     */
+    private String dataSourceName;
+
+    /**
+     * 数据字典描述
+     */
+    private String dataSourceDescription;
+
+    /**
+     * 数据字典数据库
+     */
+    private String dataSourceDataBase;
+
+    /**
+     * 数据字典表格
+     */
+    private String dataSourceTable;
+
+    /**
+     * 数据字典字段
+     */
+    private String dataSourceField;
+
+    private  Integer id;
+    private Integer isDelete;
+
+
+}

+ 15 - 0
src/main/java/com/cslg/ids/entity/common/DifyFile.java

@@ -0,0 +1,15 @@
+package com.cslg.ids.entity.common;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+
+@Data
+public class DifyFile {
+    private String type;
+    @SerializedName("transfer_method")
+    private String transferMethod;
+    private String url;
+    @JsonProperty("upload_file_id")
+    private String uploadFileId;
+}

+ 25 - 0
src/main/java/com/cslg/ids/entity/common/PatentData.java

@@ -0,0 +1,25 @@
+package com.cslg.ids.entity.common;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+import org.apache.poi.ss.usermodel.PictureData;
+
+import java.util.Map;
+
+/**
+ * @Author chenyu
+ * @Date 2023/5/31
+ */
+@Accessors(chain = true)
+@Data
+public class PatentData {
+    /**
+     * 专利内容数据(除了摘要附图, key:表头如 "公开(公告)号"  value:表头对应内容如 "CN1307082B")
+     */
+    private Map<Object, Object> map;
+    /**
+     * 专利摘要附图
+     */
+    private PictureData pictureData;
+
+}

+ 168 - 0
src/main/java/com/cslg/ids/entity/common/PersonnelVO.java

@@ -0,0 +1,168 @@
+package com.cslg.ids.entity.common;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.List;
+
+/**
+ * @author 沈永艺
+ * @date 2022-8-4
+ * @description 人员类 前台对应实体
+ */
+
+@Data
+@Accessors(chain = true)
+public class PersonnelVO {
+    /**
+     * ID
+     */
+    private String id;
+
+
+    /**
+     * Front:姓名
+     * Back:人员名称
+     */
+    private String name;
+
+    /**
+     * Front:性别
+     * Back:人员性别
+     */
+    private Integer gender;
+
+    /**
+     * Front:邮箱
+     * Back:人员邮箱
+     */
+    private String email;
+
+    /**
+     * Front:联系方式
+     * Back:人员联系电话
+     */
+    private String mobile;
+
+    /**
+     * Front:所属租户
+     * Back:租户ID
+     */
+    private Integer tenant;
+
+    /**
+     * Front:状态
+     * Back:人员账号状态(1启用0停用)
+     */
+    private Integer state;
+
+    /**
+     * Front:账号
+     * Back:人员账号
+     */
+    private String username;
+
+    /**
+     * Front:密码
+     * Back:人员密码
+     */
+    private String password;
+
+    /**
+     * Front:备注
+     * Back:人员描述
+     */
+    private String remark;
+
+    /**
+     * Front:QQ号
+     * Back:人员QQ号
+     */
+    private String qqNumber;
+
+    /**
+     * Front:微信号
+     * Back:人员微信号
+     */
+    private String wechat;
+
+    /**
+     * Front:钉钉号
+     * Back:人员钉钉号
+     */
+    private String nail;
+
+    /**
+     * Front:
+     * Back:租户名称
+     */
+    private String tenantName;
+
+    /**
+     * Front:
+     * Back:租户ID
+     */
+    private Integer tenantId;
+
+    /**
+     * 登陆成功后生成的Token
+     */
+    private String token;
+
+    /**
+     * 角色List
+     */
+    private List<PerRole> rList;
+
+    /**
+     * 部门职位List
+     */
+    private List<DP> dpList;
+    /**
+     * 角色类型(是否为管理角色)
+     */
+    private Integer roleType;
+    /**
+     * 租户类型
+     */
+    private String tenantType;
+
+    /**
+     * 部门职位绑定关系
+     */
+    @Data
+    public static class DP {
+        /**
+         * 部门名称
+         */
+        private String departmentName;
+        /**
+         * 部门ID
+         */
+        private Integer departmentId;
+        /**
+         * 职位名称
+         */
+        private String positionName;
+        /**
+         * 职位ID
+         */
+        private Integer positionId;
+    }
+
+    /**
+     * 角色信息
+     */
+    @Data
+    public static class PerRole {
+        /**
+         * 角色名称
+         */
+        private String roleName;
+        /**
+         * 角色ID
+         */
+        private Integer roleId;
+    }
+
+}

+ 11 - 0
src/main/java/com/cslg/ids/entity/common/Records.java

@@ -0,0 +1,11 @@
+package com.cslg.ids.entity.common;
+
+import lombok.Data;
+
+@Data
+public class Records {
+    private Long current;
+    private Long size;
+    private Long total;
+    private Object data;
+}

+ 33 - 0
src/main/java/com/cslg/ids/entity/common/SystemFile.java

@@ -0,0 +1,33 @@
+package com.cslg.ids.entity.common;
+
+import lombok.Data;
+
+/**
+ * 系统文件实体类
+ *
+ * @Author xiexiang
+ * @Date 2023/6/1
+ */
+@Data
+
+public class SystemFile {
+    /**
+     * 文件guid
+     */
+    private String guid;
+
+    /**
+     * 文件名称
+     */
+    private String fileName;
+
+    /**
+     * 原始名称
+     */
+    private String originalName;
+
+    /**
+     * 文件类型
+     */
+    private String type;
+}

+ 9 - 0
src/main/java/com/cslg/ids/mapper/FileInfoMapper.java

@@ -0,0 +1,9 @@
+package com.cslg.ids.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cslg.ids.entity.FileInfo;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface FileInfoMapper extends BaseMapper<FileInfo> {
+}

+ 62 - 0
src/main/java/com/cslg/ids/service/FileInfoService.java

@@ -0,0 +1,62 @@
+package com.cslg.ids.service;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.cslg.ids.dto.FileInfoDTO;
+import com.cslg.ids.dto.FileInfoIdDTO;
+import com.cslg.ids.entity.FileInfo;
+import com.cslg.ids.mapper.FileInfoMapper;
+import com.cslg.ids.vo.SelectFileInfoVO;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor(onConstructor_ = {@Lazy})
+public class FileInfoService extends ServiceImpl<FileInfoMapper, FileInfo> {
+    @Autowired
+    private FileInfoMapper fileInfoMapper;
+
+    public SelectFileInfoVO selectFileInfo(FileInfoIdDTO vo) {
+        Integer fileInfoId = vo.getFileInfoId();
+        SelectFileInfoVO infoVO = new SelectFileInfoVO();
+        FileInfo fileInfo = fileInfoMapper.selectById(fileInfoId);
+        if (ObjectUtils.isNotEmpty(fileInfo)) {
+            BeanUtils.copyProperties(fileInfo, infoVO);
+            infoVO.setFileInfoId(fileInfo.getId());
+        }
+        return infoVO;
+    }
+
+    public Integer addOrEditFileInfo(FileInfoDTO vo) {
+        Integer id = null;
+        if (vo.getFileInfoId() != null) {
+            FileInfo info = fileInfoMapper.selectById(vo.getFileInfoId());
+            info.setTaskId(vo.getTaskId());
+            info.setOldFileName(vo.getOldFileName());
+            info.setOldFileGuid(vo.getOldFileGuid());
+            info.setType(vo.getType());
+            info.setStatus(vo.getStatus());
+            info.setNewFileName(vo.getNewFileName());
+            info.setNewFileGuid(vo.getNewFileGuid());
+            info.updateById();
+            id = info.getId();
+        } else {
+            FileInfo info = new FileInfo();
+            info.setTaskId(vo.getTaskId());
+            info.setOldFileName(vo.getOldFileName());
+            info.setOldFileGuid(vo.getOldFileGuid());
+            info.setType(vo.getType());
+            info.setStatus(vo.getStatus());
+            info.setNewFileName(vo.getNewFileName());
+            info.setNewFileGuid(vo.getNewFileGuid());
+            info.insert();
+            id = info.getId();
+        }
+        return id;
+    }
+}

+ 864 - 0
src/main/java/com/cslg/ids/service/TranslateService.java

@@ -0,0 +1,864 @@
+package com.cslg.ids.service;
+
+import cn.hutool.core.codec.Base64;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.cslg.ids.common.exception.ExceptionEnum;
+import com.cslg.ids.common.exception.XiaoShiException;
+import com.cslg.ids.dto.*;
+import com.cslg.ids.entity.FileInfo;
+import com.cslg.ids.service.common.FileManagerService;
+import com.cslg.ids.vo.*;
+import com.google.gson.Gson;
+import com.itextpdf.html2pdf.HtmlConverter;
+import com.vladsch.flexmark.ast.*;
+import com.vladsch.flexmark.ext.tables.TableBlock;
+import com.vladsch.flexmark.ext.tables.TableCell;
+import com.vladsch.flexmark.ext.tables.TableRow;
+import com.vladsch.flexmark.html.HtmlRenderer;
+import com.vladsch.flexmark.parser.Parser;
+import com.vladsch.flexmark.util.ast.Node;
+import com.vladsch.flexmark.util.data.MutableDataSet;
+import com.vladsch.flexmark.util.sequence.BasedSequence;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.PDPage;
+import org.apache.pdfbox.pdmodel.PDPageContentStream;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.pdmodel.font.PDType0Font;
+import org.apache.pdfbox.pdmodel.font.PDType1Font;
+import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
+import org.apache.pdfbox.text.PDFTextStripper;
+import org.apache.poi.util.Units;
+import org.apache.poi.xwpf.usermodel.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.io.*;
+import java.net.ConnectException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor(onConstructor_ = {@Lazy})
+public class TranslateService {
+    private static final String BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1";
+    private static final String API_KEY = "sk-4f9fdd48c67a41d18d2817aed393e854";
+//    private static final String MODEL_ID = "qwen3-max";
+    private static final String MODEL_ID = "qwen-plus";
+    private static final String TARGET_LANGUAGE = "English";
+    private static final String THINKING_MODE = "disable";
+    private static final String CONVERT_ENGINE = "mineru";
+    private static final long CHUNK_SIZE = 5000L;
+    private static final long CONCURRENT = 40L;
+    private static final float TEMPERATURE = 0.8f;
+    private static final long RETRY_COUNT = 2L;
+    private static final String CUSTOM_PROMPT = "你是一位资深专业的英文翻译者,擅长根据文件内容将非英文文件内容翻译成英文文件内容,翻译误差率仅有1%。\\n\\n**翻译规则**\\n- 先根据文件内容判断出是否为英文文件内容,如果不是才需要翻译,反之不需要翻译。\\n- 翻译内容需要符合原文内容以及格式\\n- 翻译内容必须为英文";
+    private static final String MINERU_TOKEN = "eyJ0eXBlIjoiSldUIiwiYWxnIjoiSFM1MTIifQ.eyJqdGkiOiI2OTgwMDQyMSIsInJvbCI6IlJPTEVfUkVHSVNURVIiLCJpc3MiOiJPcGVuWExhYiIsImlhdCI6MTc2NDcyOTQ2OSwiY2xpZW50SWQiOiJsa3pkeDU3bnZ5MjJqa3BxOXgydyIsInBob25lIjoiMTU3MDUyMjA1MzMiLCJvcGVuSWQiOm51bGwsInV1aWQiOiIwZDlkYmUwZS04MjI0LTQyMWQtOGM5My0yOTlhNGFhNjA2YTgiLCJlbWFpbCI6IiIsImV4cCI6MTc2NTkzOTA2OX0.nAOIssRaG5HSYDvbxtH0CtAjCf7nNWaJImA2EdwkDxkTK3_6Gh7Kl_3wldfrOoNvik9h33bOUspXSiFiz1meaw";
+    private static final String DOCUTRANSLATE_URL = "http://192.168.2.24:8010";
+
+    @Autowired
+    private FileManagerService fileManagerService;
+    @Autowired
+    private FileInfoService fileInfoService;
+
+    /**
+     * 递归处理 Markdown 节点并添加到 Word 文档
+     */
+    private static void processNode(Node node, XWPFDocument document) {
+        if (node instanceof Heading) {
+            Heading heading = (Heading) node;
+            XWPFParagraph paragraph = document.createParagraph();
+            XWPFRun run = paragraph.createRun();
+            run.setText(heading.getText().toString());
+            run.setBold(true);
+            run.setFontSize(20 - (2 * heading.getLevel()));
+        } else if (node instanceof Paragraph) {
+            XWPFParagraph paragraph = document.createParagraph();
+            processChildren(node, document, paragraph);
+        } else if (node instanceof Text) {
+            Text text = (Text) node;
+            XWPFParagraph paragraph = document.createParagraph();
+            XWPFRun run = paragraph.createRun();
+            run.setText(text.getChars().toString());
+        } else if (node instanceof StrongEmphasis) {
+            StrongEmphasis strong = (StrongEmphasis) node;
+            XWPFParagraph paragraph = document.createParagraph();
+            XWPFRun run = paragraph.createRun();
+            run.setText(strong.getText().toString());
+            run.setBold(true);
+        } else if (node instanceof Emphasis) {
+            Emphasis emphasis = (Emphasis) node;
+            XWPFParagraph paragraph = document.createParagraph();
+            XWPFRun run = paragraph.createRun();
+            run.setText(emphasis.getText().toString());
+            run.setItalic(true);
+        } else if (node instanceof Image) {
+            // 处理图片(示例:占位符,实际需下载图片)
+            Image image = (Image) node;
+            processImage(image.getUrl().toString(), document, null);
+        } else if (node instanceof HtmlInline) {
+            HtmlInline htmlInline = (HtmlInline) node;
+            String htmlContent = htmlInline.getChars().toString();
+            processHtmlContent(htmlContent, document, null);
+        } else if (node instanceof BulletList) {
+            node.getChildren().forEach(child -> {
+                if (child instanceof ListItem) {
+                    XWPFParagraph paragraph = document.createParagraph();
+                    paragraph.setStyle("ListBullet");
+                    processChildren(child, document, paragraph);
+                }
+            });
+        } else if (node instanceof OrderedList) {
+            node.getChildren().forEach(child -> {
+                if (child instanceof ListItem) {
+                    XWPFParagraph paragraph = document.createParagraph();
+                    paragraph.setStyle("ListNumber");
+                    processChildren(child, document, paragraph);
+                }
+            });
+        } else if (node instanceof HtmlBlock) {
+            HtmlBlock htmlBlock = (HtmlBlock) node;
+            processHtmlContent(htmlBlock.getContentChars().toString(), document, null);
+        }
+    }
+
+    private static void processChildren(Node node, XWPFDocument document, XWPFParagraph paragraph) {
+        node.getChildren().forEach(child -> {
+            if (child instanceof Text) {
+                XWPFRun run = paragraph.createRun();
+                run.setText(((Text) child).getChars().toString());
+            } else if (child instanceof StrongEmphasis) {
+                XWPFRun run = paragraph.createRun();
+                run.setText(((StrongEmphasis) child).getText().toString());
+                run.setBold(true);
+            } else if (child instanceof Emphasis) {
+                XWPFRun run = paragraph.createRun();
+                run.setText(((Emphasis) child).getText().toString());
+                run.setItalic(true);
+            } else if (child instanceof HtmlInline) {
+                HtmlInline htmlInline = (HtmlInline) child;
+                processHtmlContent(htmlInline.getChars().toString(), document, paragraph);
+            } else if (child instanceof Image) {
+                // 处理图片(示例:占位符,实际需下载图片)
+                Image image = (Image) child;
+                // 居中对齐
+                processImage(image.getUrl().toString(), document, paragraph);
+            } else {
+                processChildren(child, document, paragraph);
+            }
+        });
+    }
+
+    private static void processImage(String imageUrl, XWPFDocument document, XWPFParagraph paragraph) {
+        if (paragraph == null) {
+            paragraph = document.createParagraph();
+            paragraph.setAlignment(ParagraphAlignment.CENTER);
+        }
+        XWPFRun run = paragraph.createRun();
+        // 检查是否是base64编码的图片
+        if (imageUrl.startsWith("data:image")) {
+            try {
+                // 提取base64数据
+                String base64Data = imageUrl.substring(imageUrl.indexOf(",") + 1);
+                byte[] imageBytes = Base64.decode(base64Data);
+
+                // 确定图片类型
+                int pictureType = org.apache.poi.xwpf.usermodel.Document.PICTURE_TYPE_PNG;
+                String extension = "png";
+                if (imageUrl.startsWith("data:image/jpeg") || imageUrl.startsWith("data:image/jpg")) {
+                    pictureType = org.apache.poi.xwpf.usermodel.Document.PICTURE_TYPE_JPEG;
+                    extension = "jpg";
+                } else if (imageUrl.startsWith("data:image/gif")) {
+                    pictureType = org.apache.poi.xwpf.usermodel.Document.PICTURE_TYPE_GIF;
+                    extension = "gif";
+                } else if (imageUrl.startsWith("data:image/bmp")) {
+                    pictureType = org.apache.poi.xwpf.usermodel.Document.PICTURE_TYPE_BMP;
+                    extension = "bmp";
+                }
+
+                // 将图片添加到Word文档
+                run.addPicture(new ByteArrayInputStream(imageBytes),
+                        pictureType,
+                        "image." + extension,
+                        Units.toEMU(400), // 宽度
+                        Units.toEMU(300)); // 高度
+            } catch (Exception e) {
+                log.error("处理图片时发生错误: ", e);
+                run.setText("[图片]");
+            }
+        } else {
+            run.setText("[图片: " + imageUrl + "]");
+        }
+    }
+
+    private static void processHtmlContent(String htmlContent, XWPFDocument document, XWPFParagraph paragraph) {
+        // 处理HTML表格,包括带有colspan属性的情况
+        if (htmlContent.startsWith("<table>")) {
+            if (paragraph != null) {
+                paragraph.createRun().setText("[表格内容]");
+                return;
+            }
+            XWPFTable table = document.createTable();
+            // 使用正则表达式或HTML解析器来更准确地解析HTML表格
+            // 这里简化处理,假设表格结构相对简单且colspan值已知或可推断
+            String[] rows = htmlContent.split("<tr>|</tr>");
+            boolean firstRow = true;
+            int maxColumns = 0; // 用于记录最大列数,以处理colspan
+
+            // 第一遍遍历确定最大列数
+            for (String row : rows) {
+                if (row.trim().isEmpty() || !row.contains("<td")) continue;
+                String[] cells = row.split("<td[^>]*>|</td>"); // 匹配<td>及其属性(如colspan)和</td>
+                int columnCount = 0;
+                for (String cell : cells) {
+                    if (cell.trim().isEmpty() || cell.trim().equalsIgnoreCase("<td>") || cell.trim().equalsIgnoreCase("</td>")) continue;
+                    // 检查是否有colspan属性
+                    if (cell.contains("colspan=")) {
+                        Pattern pattern = Pattern.compile("colspan\\s*=\\s*[\"']?(\\d+)[\"']?");
+                        Matcher matcher = pattern.matcher(cell);
+                        if (matcher.find()) {
+                            columnCount += Integer.parseInt(matcher.group(1)) - 1; // 减去1,因为下面的循环会加1
+                        }
+                    }
+                    columnCount++;
+                }
+                if (columnCount > maxColumns) {
+                    maxColumns = columnCount;
+                }
+            }
+
+            // 第二遍遍历创建表格行和单元格
+            int currentColumn = 0;
+            for (String row : rows) {
+                if (row.trim().isEmpty() || !row.contains("<td")) continue;
+                XWPFTableRow tableRow = firstRow ? table.getRow(0) : table.createRow();
+                if (firstRow && tableRow.getTableCells().size() < maxColumns) {
+                    // 如果第一行单元格数不足,则补充
+                    for (int i = tableRow.getTableCells().size(); i < maxColumns; i++) {
+                        tableRow.addNewTableCell();
+                    }
+                } else if (!firstRow && tableRow.getTableCells().isEmpty()) {
+                    // 对于非第一行,如果单元格为空,则根据maxColumns创建
+                    for (int i = 0; i < maxColumns; i++) {
+                        tableRow.createCell();
+                    }
+                }
+                String[] cells = row.split("<td[^>]*>|</td>"); // 重新分割以处理单元格内容
+                currentColumn = 0;
+                for (String cell : cells) {
+                    if (cell.trim().isEmpty() || cell.trim().equalsIgnoreCase("<td>") || cell.trim().equalsIgnoreCase("</td>")) continue;
+                    int colspan = 1; // 默认colspan为1
+                    if (cell.contains("colspan=")) {
+                        Pattern pattern = Pattern.compile("colspan\\s*=\\s*[\"']?(\\d+)[\"']?");
+                        Matcher matcher = pattern.matcher(cell);
+                        if (matcher.find()) {
+                            colspan = Integer.parseInt(matcher.group(1));
+                        }
+                    }
+                    // 确保不超出当前行的单元格范围(考虑colspan)
+                    if (currentColumn < tableRow.getTableCells().size()) {
+                        XWPFTableCell xwpfTableCell = currentColumn < tableRow.getTableCells().size() ?
+                                tableRow.getTableCells().get(currentColumn) : tableRow.createCell();
+                        // 处理colspan,可能需要合并单元格(这里简化处理,不实际合并,只是跳过后续单元格)
+                        processHtmlCellContent(cell.replaceAll("<[^>]*>", ""), xwpfTableCell); // 移除HTML标签后处理内容
+                        currentColumn += colspan; // 跳过被colspan覆盖的单元格
+                    } else {
+                        // 如果超出范围,则忽略(或根据需要处理)
+                        break;
+                    }
+                }
+                firstRow = false;
+            }
+        } else {
+            // 处理非表格HTML内容
+            if (paragraph == null) {
+                paragraph = document.createParagraph();
+            }
+            processHtmlInlineContent(htmlContent, paragraph);
+        }
+    }
+
+    private static void processHtmlCellContent(String cellContent, XWPFTableCell cell) {
+        XWPFParagraph paragraph = cell.getParagraphs().isEmpty() ?
+                cell.addParagraph() : cell.getParagraphs().get(0);
+        processHtmlInlineContent(cellContent, paragraph);
+    }
+
+    private static void processHtmlInlineContent(String htmlContent, XWPFParagraph paragraph) {
+        if (htmlContent.contains("<img") && htmlContent.contains("data:image")) {
+            try {
+                Pattern pattern = Pattern.compile("src\\s*=\\s*[\"']?(data:image[^\"'>]+)[\"']?");
+                Matcher matcher = pattern.matcher(htmlContent);
+                if (matcher.find()) {
+                    String imageUrl = matcher.group(1);
+                    if (imageUrl.startsWith("data:image")) {
+                        XWPFRun run = paragraph.createRun();
+                        String base64Data = imageUrl.substring(imageUrl.indexOf(",") + 1);
+                        byte[] imageBytes = Base64.decode(base64Data);
+                        int pictureType = Document.PICTURE_TYPE_PNG;
+                        String extension = "png";
+                        if (imageUrl.startsWith("data:image/jpeg") || imageUrl.startsWith("data:image/jpg")) {
+                            pictureType = Document.PICTURE_TYPE_JPEG;
+                            extension = "jpg";
+                        } else if (imageUrl.startsWith("data:image/gif")) {
+                            pictureType = Document.PICTURE_TYPE_GIF;
+                            extension = "gif";
+                        } else if (imageUrl.startsWith("data:image/bmp")) {
+                            pictureType = Document.PICTURE_TYPE_BMP;
+                            extension = "bmp";
+                        }
+                        run.addPicture(new ByteArrayInputStream(imageBytes),
+                                pictureType,
+                                "image." + extension,
+                                Units.toEMU(400),
+                                Units.toEMU(300));
+                        return;
+                    }
+                }
+            } catch (Exception e) {
+                paragraph.createRun().setText("[图片处理错误]");
+            }
+        }
+        // 如果不是图片或者处理失败,按普通文本处理(移除HTML标签)
+        String textContent = htmlContent.replaceAll("<[^>]*>", "");
+        paragraph.createRun().setText(textContent);
+    }
+
+    private static File convertHtmlToPdf(String htmlContent, String outputPdfPath) throws IOException {
+        try (OutputStream outputStream = new FileOutputStream(outputPdfPath)) {
+            HtmlConverter.convertToPdf(htmlContent, outputStream);
+        }
+        return new File(outputPdfPath);
+    }
+
+    private static File convertHtmlToDocx(String htmlContent, String outputPdfPath) throws IOException {
+        XWPFDocument document = new XWPFDocument();
+        XWPFParagraph paragraph = document.createParagraph();
+        XWPFRun run = paragraph.createRun();
+        run.setText(htmlContent);
+        FileOutputStream out = new FileOutputStream(outputPdfPath);
+        document.write(out);
+        out.close();
+        document.close();
+        return new File(outputPdfPath);
+    }
+
+    //提交翻译任务
+    public String translate(TranslateFileDTO fileDTO) throws IOException {
+        String param = new Gson().toJson(fileDTO);
+        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), param);
+        OkHttpClient okHttpClient = new OkHttpClient.Builder()
+                .connectTimeout(60, TimeUnit.SECONDS)
+                .writeTimeout(60, TimeUnit.SECONDS)
+                .readTimeout(60, TimeUnit.SECONDS)
+                .build();
+        Request request = new Request.Builder()
+                .url(DOCUTRANSLATE_URL + "/service/translate")
+                .post(requestBody)
+                .build();
+        return Objects.requireNonNull(okHttpClient.newCall(request).execute().body()).string();
+    }
+
+    //获取翻译状态
+    public String getTranslateStatus(String taskId) throws IOException {
+        OkHttpClient okHttpClient = new OkHttpClient.Builder()
+                .connectTimeout(60, TimeUnit.SECONDS)
+                .writeTimeout(60, TimeUnit.SECONDS)
+                .readTimeout(60, TimeUnit.SECONDS)
+                .build();
+        Request request = new Request.Builder()
+                .url(DOCUTRANSLATE_URL + "/service/status/" + taskId)
+                .get()
+                .build();
+        return Objects.requireNonNull(okHttpClient.newCall(request).execute().body()).string();
+    }
+
+    //获取翻译任务日志
+    public String getTranslateLogs(String taskId) throws IOException {
+        OkHttpClient okHttpClient = new OkHttpClient.Builder()
+                .connectTimeout(60, TimeUnit.SECONDS)
+                .writeTimeout(60, TimeUnit.SECONDS)
+                .readTimeout(60, TimeUnit.SECONDS)
+                .build();
+        Request request = new Request.Builder()
+                .url(DOCUTRANSLATE_URL + "/service/logs/" + taskId)
+                .get()
+                .build();
+        return Objects.requireNonNull(okHttpClient.newCall(request).execute().body()).string();
+    }
+
+    //翻译文件下载
+    public String translateFileDownload(String taskId, String type) throws IOException {
+        OkHttpClient okHttpClient = new OkHttpClient.Builder()
+                .connectTimeout(60, TimeUnit.SECONDS)
+                .writeTimeout(60, TimeUnit.SECONDS)
+                .readTimeout(60, TimeUnit.SECONDS)
+                .build();
+        Request request = new Request.Builder()
+                .url(DOCUTRANSLATE_URL + "/service/download/" + taskId + "/" + type)
+                .get()
+                .build();
+        return Objects.requireNonNull(okHttpClient.newCall(request).execute().body()).string();
+    }
+
+    //释放文件资源
+    public String release(String taskId) throws IOException {
+        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), "");
+        OkHttpClient okHttpClient = new OkHttpClient.Builder()
+                .connectTimeout(60, TimeUnit.SECONDS)
+                .writeTimeout(60, TimeUnit.SECONDS)
+                .readTimeout(60, TimeUnit.SECONDS)
+                .build();
+        Request request = new Request.Builder()
+                .url(DOCUTRANSLATE_URL + "/service/release/" + taskId)
+                .post(requestBody)
+                .build();
+        return Objects.requireNonNull(okHttpClient.newCall(request).execute().body()).string();
+    }
+
+    /**
+     * 删除固定的image标签
+     */
+    private String removeFixedImages(String markdownContent) {
+//        markdownContent = markdownContent.replaceAll("!\\[.*?\\]\\(data:image/[^)]+\\)", "");
+        // 使用正则表达式匹配并删除特定的base64图片标签
+//        markdownContent = markdownContent.replaceAll("!\\[Image\\]\\(data:image/png;base64,iVBORw0KGgoAAA[a-zA-Z0-9+/=]*\\)", "");
+
+        // 使用正则表达式匹配并删除特定的base64图片标签
+        markdownContent = markdownContent.replaceAll("!\\[Image\\]\\(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA[a-zA-Z0-9+/=]*\\)", "");
+
+        // 清理多余的空行
+//        markdownContent = markdownContent.replaceAll("\n\\s*\n\\s*", "\n\n");
+
+        return markdownContent;
+    }
+
+    public TranslateFilePayLoadDTO load() {
+        TranslateFilePayLoadDTO loadDTO = new TranslateFilePayLoadDTO();
+        loadDTO.setApi_key(API_KEY);
+        loadDTO.setBase_url(BASE_URL);
+        loadDTO.setChunk_size(CHUNK_SIZE);
+        loadDTO.setCode_ocr(true);
+        loadDTO.setConcurrent(CONCURRENT);
+        loadDTO.setConvert_engine(CONVERT_ENGINE);
+        loadDTO.setCustom_prompt(CUSTOM_PROMPT);
+        loadDTO.setForce_json(false);
+        loadDTO.setFormula_ocr(true);
+        loadDTO.setGlossary_generate_enable(false);
+        loadDTO.setMineru_deploy_backend("pipeline");
+        loadDTO.setMineru_deploy_base_url("http://127.0.0.1:8000");
+        loadDTO.setMineru_deploy_end_page_id(99999L);
+        loadDTO.setMineru_deploy_formula_enable(true);
+        loadDTO.setMineru_deploy_start_page_id(0L);
+        loadDTO.setMineru_token(MINERU_TOKEN);
+        loadDTO.setModel_version("vlm");
+        loadDTO.setModel_id(MODEL_ID);
+        loadDTO.setRetry(RETRY_COUNT);
+        loadDTO.setSkip_translate(false);
+        loadDTO.setSystem_proxy_enable(false);
+        loadDTO.setTemperature(TEMPERATURE);
+        loadDTO.setThinking(THINKING_MODE);
+        loadDTO.setTo_lang(TARGET_LANGUAGE);
+        loadDTO.setWorkflow_type("markdown_based");
+        return loadDTO;
+    }
+
+    public void fileTranslate2(File file) throws Exception {
+        TranslateFileDTO fileDTO = new TranslateFileDTO();
+        String fileName = file.getName();
+        fileDTO.setFile_name(fileName);
+        fileDTO.setFile_content(Base64.encode(file));
+        TranslateFilePayLoadDTO loadDTO = new TranslateFilePayLoadDTO();
+        loadDTO.setApi_key(API_KEY);
+        loadDTO.setBase_url(BASE_URL);
+        loadDTO.setChunk_size(CHUNK_SIZE);
+        loadDTO.setCode_ocr(true);
+        loadDTO.setConcurrent(CONCURRENT);
+        loadDTO.setConvert_engine(CONVERT_ENGINE);
+        loadDTO.setCustom_prompt(CUSTOM_PROMPT);
+        loadDTO.setForce_json(false);
+        loadDTO.setFormula_ocr(true);
+        loadDTO.setGlossary_generate_enable(false);
+        loadDTO.setMineru_deploy_backend("pipeline");
+        loadDTO.setMineru_deploy_base_url("http://127.0.0.1:8000");
+        loadDTO.setMineru_deploy_end_page_id(99999L);
+        loadDTO.setMineru_deploy_formula_enable(true);
+        loadDTO.setMineru_deploy_start_page_id(0L);
+        loadDTO.setMineru_token(MINERU_TOKEN);
+        loadDTO.setModel_version("vlm");
+        loadDTO.setModel_id(MODEL_ID);
+        loadDTO.setRetry(RETRY_COUNT);
+        loadDTO.setSkip_translate(false);
+        loadDTO.setSystem_proxy_enable(false);
+        loadDTO.setTemperature(TEMPERATURE);
+        loadDTO.setThinking(THINKING_MODE);
+        loadDTO.setTo_lang(TARGET_LANGUAGE);
+        loadDTO.setWorkflow_type("markdown_based");
+        fileDTO.setPayload(loadDTO);
+        String str = this.translate(fileDTO);
+        TranslateFileVO translateFileVO = JSONObject.parseObject(str, TranslateFileVO.class);
+        boolean status = false;
+        String taskId = "";
+        if (ObjectUtils.isNotEmpty(translateFileVO) && StringUtils.isNotEmpty(translateFileVO.getTask_id())) {
+            taskId = translateFileVO.getTask_id();
+            while (true) {
+                try {
+                    String res = this.getTranslateStatus(taskId);
+                    JSONObject jsonObject = JSONObject.parseObject(res);
+                    Boolean bool = jsonObject.getBoolean("download_ready");
+                    if (bool) {
+                        status = true;
+                        break;
+                    }
+                    Thread.sleep(2000);
+                } catch (Exception e) {
+                    break;
+                }
+            }
+        }
+        if (status && StringUtils.isNotEmpty(taskId)) {
+            String outputPdfPath = "output.docx";
+            String result = translateFileDownload(taskId, "markdown");
+            System.out.println("--------------");
+
+            MutableDataSet options = new MutableDataSet();
+            Parser parser = Parser.builder(options).build();
+            Node document = parser.parse(result);
+
+            // 2. 创建 Word 文档
+            XWPFDocument wordDocument = new XWPFDocument();
+
+            // 3. 遍历 Markdown AST (抽象语法树) 并转换为 Word 内容
+            document.getChildren().forEach(node -> processNode(node, wordDocument));
+            // 4. 保存到临时文件
+            try (FileOutputStream out = new FileOutputStream(outputPdfPath)) {
+                wordDocument.write(out);
+            }
+            wordDocument.close();
+            File pdfFile = new File(outputPdfPath);
+            System.out.println(pdfFile.getAbsolutePath());
+            file.deleteOnExit();
+        }
+    }
+
+    /**
+     * 预处理HTML中的图片标签,为图片添加适当的宽度属性以确保自适应
+     */
+    private String preprocessImages(String htmlContent) {
+        // 使用正则表达式查找所有<img>标签并添加宽度属性
+        // 设置图片最大宽度为页面宽度的90%,保持宽高比
+        String processedContent = htmlContent.replaceAll(
+                "<img([^>]*?)src=\"([^\"]*?)\"([^>]*?)>",
+                "<img$1src=\"$2\" width=\"100%\" style=\"max-width: 100%; height: auto; display: block; margin: 0 auto;\"$3>"
+        );
+
+        return processedContent;
+    }
+
+    /**
+     * 为HTML内容添加CSS样式,使图片自适应页面大小并居中,保持原始宽高比
+     */
+    private String addImageStyles(String htmlContent) {
+        // 添加CSS样式到HTML头部,确保图片按原始宽高比缩放以适应页面
+        String cssStyles = "<style>\n" +
+                "img {\n" +
+                "    max-width: 100% !important;\n" +
+                "    height: auto !important;\n" +
+                "    display: block !important;\n" +
+                "    margin-left: auto !important;\n" +
+                "    margin-right: auto !important;\n" +
+                "    object-fit: contain;\n" +  // 保持宽高比
+                "    page-break-inside: avoid;\n" +  // 避免图片跨页分割
+                "}\n" +
+                // 添加页面大小设置,确保内容适应页面
+                "@page {\n" +
+                "    size: A4;\n" +
+                "    margin: 1cm;\n" +  // 减小页边距以增加可用空间
+                "}\n" +
+                "body {\n" +
+                "    margin: 0;\n" +
+                "    padding: 0.5cm;\n" +
+                "}\n" +
+                "</style>\n";
+
+        // 如果HTML已有<head>标签,则在其中添加样式
+        if (htmlContent.contains("<head>")) {
+            htmlContent = htmlContent.replace("<head>", "<head>\n" + cssStyles);
+        } else {
+            // 否则在<html>标签后添加<head>和样式
+            htmlContent = htmlContent.replace("<html>", "<html>\n<head>\n" + cssStyles + "</head>");
+        }
+
+        return htmlContent;
+    }
+
+    public FileTranslateVO fileTranslate(File file, Integer type) throws IOException {
+        String fileName = file.getName();
+        if (!fileName.endsWith(".pdf")) {
+            throw new XiaoShiException(ExceptionEnum.BUSINESS_ERROR, "请上传pdf文件");
+        }
+
+        List<String> guids = null;
+        try {
+            guids = fileManagerService.uploadFileGetGuid2(Collections.singletonList(file));
+        } catch (Exception e) {
+            throw new XiaoShiException(ExceptionEnum.BUSINESS_ERROR, "上传pdf文件失败");
+        }
+
+        if (CollectionUtils.isEmpty(guids)) {
+            throw new XiaoShiException(ExceptionEnum.BUSINESS_ERROR, "上传pdf文件失败");
+        }
+        String guid = guids.get(0);
+
+        TranslateFileDTO fileDTO = new TranslateFileDTO();
+        fileDTO.setFile_name(fileName);
+        fileDTO.setFile_content(Base64.encode(file));
+
+        TranslateFilePayLoadDTO loadDTO = this.load();
+        fileDTO.setPayload(loadDTO);
+        FileTranslateVO translateVO = new FileTranslateVO();
+        try {
+            String str = this.translate(fileDTO);
+            TranslateFileVO translateFileVO = JSONObject.parseObject(str, TranslateFileVO.class);
+
+            FileInfoDTO infoDTO = new FileInfoDTO();
+            infoDTO.setType(type);
+            infoDTO.setStatus(1);
+            infoDTO.setOldFileName(fileName);
+            infoDTO.setOldFileGuid(guid);
+            if (ObjectUtils.isNotEmpty(translateFileVO) && StringUtils.isNotEmpty(translateFileVO.getTask_id())) {
+                String taskId = translateFileVO.getTask_id();
+                infoDTO.setTaskId(taskId);
+                Integer fileInfoId = fileInfoService.addOrEditFileInfo(infoDTO);
+                translateVO.setFileInfoId(fileInfoId);
+                translateVO.setTaskId(taskId);
+                translateVO.setOldFileName(fileName);
+                translateVO.setOldFileGuid(guid);
+                translateVO.setType(type);
+            }
+        } catch (Exception e) {
+            throw new XiaoShiException(ExceptionEnum.BUSINESS_ERROR, "请求翻译服务失败");
+        } finally {
+            file.delete();
+        }
+        return translateVO;
+    }
+
+    public SelectTranslatePlanVO selectTranslatePlan(TaskIdDTO vo) throws IOException {
+        String taskId = vo.getTaskId();
+        SelectTranslatePlanVO planVO = new SelectTranslatePlanVO();
+
+        try {
+            // 获取日志和状态
+            String translateLogs = this.getTranslateLogs(taskId);
+            String translateStatus = this.getTranslateStatus(taskId);
+
+            // 处理日志
+            JSONObject logsObject = JSONObject.parseObject(translateLogs);
+            List<String> logs = JSON.parseArray(logsObject.getJSONArray("logs").toJSONString(), String.class);
+            SelectTranslateLogsVO logsVO = new SelectTranslateLogsVO();
+            logsVO.setLogs(logs);
+            planVO.setTranslateLogsVO(logsVO);
+
+            // 处理状态
+            SelectTranslateStatusVO statusVO = JSONObject.parseObject(translateStatus, SelectTranslateStatusVO.class);
+            planVO.setTranslateStatusVO(statusVO);
+
+            // 更新状态逻辑
+            if (statusVO != null && Boolean.FALSE.equals(statusVO.getIs_processing())) {
+                if (Boolean.TRUE.equals(statusVO.getDownload_ready())) {
+                    updateStatus(taskId, 2);
+                } else if (Boolean.TRUE.equals(statusVO.getError_flag())) {
+                    updateStatus(taskId, 4);
+                    this.release(taskId);
+                }
+            }
+
+        } catch (Exception e) {
+            // 异常处理
+            updateStatus(taskId, 4);
+            this.release(taskId);
+            SelectTranslateStatusVO statusVO = new SelectTranslateStatusVO();
+            statusVO.setIs_processing(false);
+            planVO.setTranslateStatusVO(statusVO);
+            planVO.setTranslateLogsVO(new SelectTranslateLogsVO());
+        }
+
+        return planVO;
+    }
+
+    public void updateStatus(String taskId, Integer status) {
+        LambdaQueryWrapper<FileInfo> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(FileInfo::getTaskId, taskId);
+        FileInfo fileInfo = fileInfoService.getOne(queryWrapper, false);
+        fileInfo.setStatus(status);
+        fileInfo.setId(fileInfo.getId());
+        fileInfo.updateById();
+    }
+
+    public String generateTranslateFile(TaskIdDTO vo) throws IOException {
+        String taskId = vo.getTaskId();
+        LambdaQueryWrapper<FileInfo> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(FileInfo::getTaskId, taskId);
+        FileInfo fileInfo = fileInfoService.getOne(queryWrapper, false);
+        String oldFileName = fileInfo.getOldFileName();
+        String fileName = null;
+        if (oldFileName.contains(".")) {
+            fileName = oldFileName.substring(0, oldFileName.indexOf("."));
+        } else {
+            fileName = oldFileName;
+        }
+        String outputPdfPath = fileName + "-译文.docx";
+        String result = translateFileDownload(taskId, "markdown");
+
+        MutableDataSet options = new MutableDataSet();
+        Parser parser = Parser.builder(options).build();
+        Node document = parser.parse(result);
+
+        // 2. 创建 Word 文档
+        XWPFDocument wordDocument = new XWPFDocument();
+
+        // 3. 遍历 Markdown AST (抽象语法树) 并转换为 Word 内容
+        document.getChildren().forEach(node -> processNode(node, wordDocument));
+        // 4. 保存到临时文件
+        try (FileOutputStream out = new FileOutputStream(outputPdfPath)) {
+            wordDocument.write(out);
+        }
+        wordDocument.close();
+        File pdfFile = new File(outputPdfPath);
+        List<String> guids = fileManagerService.uploadFileGetGuid2(Collections.singletonList(pdfFile));
+        if (CollectionUtils.isEmpty(guids)) {
+            throw new XiaoShiException(ExceptionEnum.BUSINESS_ERROR, "翻译文件保存失败");
+        }
+        String guid = guids.get(0);
+
+        fileInfo.setNewFileGuid(guid);
+        fileInfo.setNewFileName(outputPdfPath);
+        fileInfo.setStatus(3);
+        fileInfo.setId(fileInfo.getId());
+        fileInfo.updateById();
+
+        pdfFile.delete();
+
+        this.release(taskId);
+
+        return guid;
+    }
+
+    public String generateTranslatePDFFile(TaskIdDTO vo) throws IOException {
+        String taskId = vo.getTaskId();
+        LambdaQueryWrapper<FileInfo> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(FileInfo::getTaskId, taskId);
+        FileInfo fileInfo = fileInfoService.getOne(queryWrapper, false);
+        String oldFileName = fileInfo.getOldFileName();
+        String fileName = null;
+        if (oldFileName.contains(".")) {
+            fileName = oldFileName.substring(0, oldFileName.indexOf("."));
+        } else {
+            fileName = oldFileName;
+        }
+        String outputPdfPath = fileName + "-译文.pdf";
+        String result = translateFileDownload(taskId, "markdown");
+
+        if (fileInfo.getType() == 3) {
+            // 1. 删除特定的image标签
+            result = removeFixedImages(result);
+        }
+
+        // 2. 解析Markdown并转换为HTML
+        Parser parser = Parser.builder().build();
+        HtmlRenderer renderer = HtmlRenderer.builder().build();
+        Node document = parser.parse(result);
+
+        // 3. 转换为HTML并应用CSS样式使图片自适应和居中
+        String htmlContent = renderer.render(document);
+
+        // 4. 预处理HTML中的图片标签,添加宽度和高度属性以确保自适应
+        String processedHtmlContent = preprocessImages(htmlContent);
+
+        // 5. 添加CSS样式使图片自适应页面大小并居中,保持原始宽高比
+        String styledHtmlContent = addImageStyles(processedHtmlContent);
+
+        // 6. 将HTML转换为PDF
+        File pdfFile = convertHtmlToPdf(styledHtmlContent, outputPdfPath);
+        List<String> guids = fileManagerService.uploadFileGetGuid2(Collections.singletonList(pdfFile));
+        if (CollectionUtils.isEmpty(guids)) {
+            throw new XiaoShiException(ExceptionEnum.BUSINESS_ERROR, "翻译文件保存失败");
+        }
+        String guid = guids.get(0);
+
+        fileInfo.setNewFileGuid(guid);
+        fileInfo.setNewFileName(outputPdfPath);
+        fileInfo.setStatus(3);
+        fileInfo.setId(fileInfo.getId());
+        fileInfo.updateById();
+
+        pdfFile.delete();
+
+        this.release(taskId);
+
+        return guid;
+    }
+
+    public FileTranslateVO againTranslate(FileInfoIdDTO infoIdDTO) throws IOException {
+        Integer fileInfoId = infoIdDTO.getFileInfoId();
+        FileInfo fileInfo = fileInfoService.getById(fileInfoId);
+        if (ObjectUtils.isEmpty(fileInfo)) {
+            throw new XiaoShiException(ExceptionEnum.BUSINESS_ERROR, "当前任务不存在");
+        }
+        Integer retry = fileInfo.getRetry();
+        if (retry > 5) {
+            throw new XiaoShiException(ExceptionEnum.BUSINESS_ERROR, "该文件无法翻译");
+        }
+        String fileName = fileInfo.getOldFileName();
+        String guid = fileInfo.getOldFileGuid();
+        File file = fileManagerService.getTempFileByGuid(guid);
+
+        TranslateFileDTO fileDTO = new TranslateFileDTO();
+        fileDTO.setFile_name(fileName);
+        fileDTO.setFile_content(Base64.encode(file));
+
+        TranslateFilePayLoadDTO loadDTO = this.load();
+        fileDTO.setPayload(loadDTO);
+        FileTranslateVO translateVO = new FileTranslateVO();
+        try {
+            String str = this.translate(fileDTO);
+            TranslateFileVO translateFileVO = JSONObject.parseObject(str, TranslateFileVO.class);
+
+            if (ObjectUtils.isNotEmpty(translateFileVO) && StringUtils.isNotEmpty(translateFileVO.getTask_id())) {
+                String taskId = translateFileVO.getTask_id();
+                fileInfo.setStatus(1);
+                fileInfo.setTaskId(taskId);
+                fileInfo.setRetry(retry + 1);
+                fileInfo.updateById();
+                translateVO.setFileInfoId(fileInfoId);
+                translateVO.setTaskId(taskId);
+                translateVO.setOldFileName(fileName);
+                translateVO.setOldFileGuid(guid);
+                translateVO.setType(fileInfo.getType());
+            }
+        } catch (Exception e) {
+            throw new XiaoShiException(ExceptionEnum.BUSINESS_ERROR, "请求翻译失败");
+        } finally {
+            file.delete();
+        }
+        return translateVO;
+    }
+}

+ 248 - 0
src/main/java/com/cslg/ids/service/common/FileManagerService.java

@@ -0,0 +1,248 @@
+package com.cslg.ids.service.common;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.cslg.ids.dto.FMSDeleteFileDTO;
+import com.cslg.ids.entity.common.SystemFile;
+import com.google.gson.Gson;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.*;
+import org.apache.commons.compress.utils.IOUtils;
+import org.apache.commons.io.FileUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.util.FileCopyUtils;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.*;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+import static cn.hutool.core.io.FileUtil.getMimeType;
+
+/**
+ * Okhttp调用FMS上传文件接口
+ *
+ * @Author xiexiang
+ * @Date 2023/8/10
+ */
+@RequiredArgsConstructor
+@Slf4j
+@Service
+public class FileManagerService {
+    @Value("${FMSUrl}")
+    private String FMSUrl;
+    @Value("${FileSource}")
+    private String FileSource;
+    /**
+     * 调用文件系统上传文件接口
+     *
+     * @param multipartFiles 文件
+     */
+    public String uploadFile(List<MultipartFile> multipartFiles) throws IOException {
+        List<File> files = new ArrayList<>();
+        for (MultipartFile multipartFile : multipartFiles) {
+            File file = new File(multipartFile.getOriginalFilename());
+            FileCopyUtils.copy(multipartFile.getBytes(), file);
+            files.add(file);
+        }
+        MultipartBody.Builder multipartBodyBuilder = new MultipartBody.Builder()
+                .setType(MultipartBody.FORM);
+        for (File file : files) {
+            //根据文件名获取文件的MIME类型
+            String mimeType = getMimeType(file.getPath());
+            multipartBodyBuilder.addFormDataPart("files", file.getName(), RequestBody.create(MediaType.parse(mimeType), file));
+        }
+        RequestBody requestBody = multipartBodyBuilder
+                .addFormDataPart("sourceId", String.valueOf(FileSource))
+                .build();
+        OkHttpClient okHttpClient = new OkHttpClient.Builder()
+                .connectTimeout(60, TimeUnit.SECONDS)
+                .writeTimeout(60, TimeUnit.SECONDS)
+                .readTimeout(60, TimeUnit.SECONDS)
+                .build();
+        Request request = new Request.Builder()
+                .url(FMSUrl + "/fileManager/uploadNormalFile")
+                .post(requestBody)
+                .build();
+        Response response = null;
+        response = okHttpClient.newCall(request).execute();
+        // 最后记得删除临时文件
+        for (File file : files) {
+            FileUtils.deleteQuietly(file);
+        }
+        return Objects.requireNonNull(response.body()).string();
+    }
+
+    public List<String> uploadFileGetGuid(List<MultipartFile> multipartFiles) throws IOException {
+        String res = this.uploadFile(multipartFiles);
+        JSONObject jsonObject = JSONObject.parseObject(res);
+        List<String> guids = JSONArray.parseArray(jsonObject.get("data").toString(), String.class);
+        return guids;
+    }
+
+    /**
+     * 调用文件系统取出文件接口(获得文件流)
+     * @param fieldId 文件id
+     */
+    public byte[] downloadSystemFileFromFMS(String fieldId) throws IOException {
+        OkHttpClient okHttpClient = new OkHttpClient.Builder()
+                .connectTimeout(60000, TimeUnit.SECONDS)
+                .writeTimeout(60000, TimeUnit.SECONDS)
+                .readTimeout(60000, TimeUnit.SECONDS)
+                .build();
+        Request request = new Request.Builder()
+                .url(FMSUrl + "/fileManager/downloadFile?fileId=" + fieldId)
+                .get()
+                .build();
+        return Objects.requireNonNull(okHttpClient.newCall(request).execute().body()).bytes();
+    }
+
+    /**
+     * 调用文件系统获取文件信息接口
+     *
+     * @param fileIds 文件ids
+     */
+    public String getSystemFileFromFMS(List<String> fileIds) throws IOException {
+        String param = new Gson().toJson(fileIds);
+        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), param);
+        OkHttpClient okHttpClient = new OkHttpClient.Builder()
+                .connectTimeout(60, TimeUnit.SECONDS)
+                .writeTimeout(60, TimeUnit.SECONDS)
+                .readTimeout(60, TimeUnit.SECONDS)
+                .build();
+        Request request = new Request.Builder()
+                .url(FMSUrl + "/fileManager/getFileData")
+                .post(requestBody)
+                .build();
+        return Objects.requireNonNull(okHttpClient.newCall(request).execute().body()).string();
+    }
+
+    /**
+     * 调用文件系统删除文件接口
+     *
+     * @param ids 需要删除的文件ids
+     */
+    public String deleteFileFromFMS(List<String> ids) throws IOException {
+        FMSDeleteFileDTO fmsDeleteFileDTO = new FMSDeleteFileDTO();
+        fmsDeleteFileDTO.setGuids(ids);
+        fmsDeleteFileDTO.setType(2);
+        String param = new Gson().toJson(fmsDeleteFileDTO);
+        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), param);
+        OkHttpClient okHttpClient = new OkHttpClient.Builder()
+                .connectTimeout(60, TimeUnit.SECONDS)
+                .writeTimeout(60, TimeUnit.SECONDS)
+                .readTimeout(60, TimeUnit.SECONDS)
+                .build();
+        Request request = new Request.Builder()
+                .url(FMSUrl + "/fileManager/deleteSystemFile")
+                .post(requestBody)
+                .build();
+        return Objects.requireNonNull(okHttpClient.newCall(request).execute().body()).string();
+    }
+
+    public String uploadFileWithGuid(File file, String guid) throws IOException {
+        MultipartBody.Builder multipartBodyBuilder = new MultipartBody.Builder()
+                .setType(MultipartBody.FORM);
+        //根据文件名获取文件的MIME类型
+        String mimeType = getMimeType(file.getPath());
+        multipartBodyBuilder.addFormDataPart("file", file.getName(), RequestBody.create(MediaType.parse(mimeType), file));
+        RequestBody requestBody = multipartBodyBuilder
+                .addFormDataPart("sourceId", String.valueOf(FileSource))
+                .addFormDataPart("fileGuid", guid)
+                .build();
+        OkHttpClient okHttpClient = new OkHttpClient.Builder()
+                .connectTimeout(60, TimeUnit.SECONDS)
+                .writeTimeout(60, TimeUnit.SECONDS)
+                .readTimeout(60, TimeUnit.SECONDS)
+                .build();
+        Request request = new Request.Builder()
+                .url(FMSUrl + "/fileManager/replaceFile")
+                .post(requestBody)
+                .build();
+        Response response = null;
+        response = okHttpClient.newCall(request).execute();
+        // 最后记得删除临时文件
+//        FileUtils.deleteQuietly(file);
+
+        return Objects.requireNonNull(response.body()).string();
+    }
+
+    /**
+     * 调用文件系统上传文件接口
+     */
+    public String uploadFile2(List<File> files) throws IOException {
+
+        MultipartBody.Builder multipartBodyBuilder = new MultipartBody.Builder()
+                .setType(MultipartBody.FORM);
+        for (File file : files) {
+            //根据文件名获取文件的MIME类型
+            String mimeType = getMimeType(file.getPath());
+            multipartBodyBuilder.addFormDataPart("files", file.getName(), RequestBody.create(MediaType.parse(mimeType), file));
+        }
+        RequestBody requestBody = multipartBodyBuilder
+                .addFormDataPart("sourceId", String.valueOf(FileSource))
+                .build();
+        OkHttpClient okHttpClient = new OkHttpClient.Builder()
+                .connectTimeout(60, TimeUnit.SECONDS)
+                .writeTimeout(60, TimeUnit.SECONDS)
+                .readTimeout(60, TimeUnit.SECONDS)
+                .build();
+        Request request = new Request.Builder()
+                .url(FMSUrl + "/fileManager/uploadNormalFile")
+                .post(requestBody)
+                .build();
+        Response response = null;
+        response = okHttpClient.newCall(request).execute();
+        // 最后记得删除临时文件
+        for (File file : files) {
+//            FileUtils.deleteQuietly(file);
+        }
+        return Objects.requireNonNull(response.body()).string();
+    }
+
+    public List<String> uploadFileGetGuid2(List<File> files) throws IOException {
+        String res = this.uploadFile2(files);
+        JSONObject jsonObject = JSONObject.parseObject(res);
+        List<String> guids = JSONArray.parseArray(jsonObject.get("data").toString(), String.class);
+        return guids;
+    }
+
+    /**
+     * 调用文件系统获得专利图片的guid
+     *
+     * @param appNo 申请号
+     */
+    public String getPatentPictureGuids(String appNo) throws IOException {
+        OkHttpClient okHttpClient = new OkHttpClient.Builder()
+                .connectTimeout(60, TimeUnit.SECONDS)
+                .writeTimeout(60, TimeUnit.SECONDS)
+                .readTimeout(60, TimeUnit.SECONDS)
+                .build();
+        Request request = new Request.Builder()
+                .url(FMSUrl + "/fileManager/getPatentPictureGuids?appNo=" + appNo)
+                .get()
+                .build();
+        return Objects.requireNonNull(okHttpClient.newCall(request).execute().body()).string();
+    }
+
+    public File getTempFileByGuid(String guid)throws IOException{
+        String res = this.getSystemFileFromFMS(Collections.singletonList(guid));
+        List<SystemFile> systemFiles = JSONArray.parseArray(res, SystemFile.class);
+        SystemFile systemFile = systemFiles.get(0);
+        String suffix = systemFile.getFileName().substring(systemFile.getFileName().lastIndexOf("."));
+        //调用文件系统取出文件接口,获得文件流
+        byte[] bytes = this.downloadSystemFileFromFMS(guid);
+        //创建临时文件tempFile,并将文件读取到tempFile
+        File tempFile = File.createTempFile(systemFile.getFileName() + "temp", suffix);
+        try (
+                InputStream inputStream = new ByteArrayInputStream(bytes);
+                FileOutputStream outputStream = new FileOutputStream(tempFile);
+        ) {
+            IOUtils.copy(inputStream, outputStream); // 将输入流复制到临时文件
+        }
+        return  tempFile;
+    }
+
+}

+ 12 - 0
src/main/java/com/cslg/ids/vo/FileTranslateVO.java

@@ -0,0 +1,12 @@
+package com.cslg.ids.vo;
+
+import lombok.Data;
+
+@Data
+public class FileTranslateVO {
+    private Integer fileInfoId;
+    private String taskId;
+    private String oldFileName;
+    private String oldFileGuid;
+    private Integer type;
+}

+ 32 - 0
src/main/java/com/cslg/ids/vo/SelectFileInfoVO.java

@@ -0,0 +1,32 @@
+package com.cslg.ids.vo;
+
+import lombok.Data;
+
+@Data
+public class SelectFileInfoVO {
+
+    private Integer fileInfoId;
+
+    //原文名称
+    private String oldFileName;
+
+    //原文guid
+    private String oldFileGuid;
+
+    //任务id
+    private String taskId;
+
+    //译文名称
+    private String newFileName;
+
+    //译文guid
+    private String newFileGuid;
+
+    //文件类型 1专利 2文献 3审查意见书 4检索报告
+    private Integer type;
+
+    //文件状态 1未完成 2翻译完成 3译文已生成
+    private Integer status;
+
+    private Integer retry;
+}

+ 10 - 0
src/main/java/com/cslg/ids/vo/SelectTranslateLogsVO.java

@@ -0,0 +1,10 @@
+package com.cslg.ids.vo;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class SelectTranslateLogsVO {
+    private List<String> logs;
+}

+ 11 - 0
src/main/java/com/cslg/ids/vo/SelectTranslatePlanVO.java

@@ -0,0 +1,11 @@
+package com.cslg.ids.vo;
+
+import lombok.Data;
+
+@Data
+public class SelectTranslatePlanVO {
+
+    private SelectTranslateStatusVO translateStatusVO;
+
+    private SelectTranslateLogsVO translateLogsVO;
+}

+ 18 - 0
src/main/java/com/cslg/ids/vo/SelectTranslateStatusVO.java

@@ -0,0 +1,18 @@
+package com.cslg.ids.vo;
+
+import lombok.Data;
+
+@Data
+public class SelectTranslateStatusVO {
+    private String task_id;
+    private Boolean is_processing;
+    private String status_message;
+    private Boolean error_flag;
+    private Boolean download_ready;
+    private String original_filename_stem;
+    private String original_filename;
+    private Long task_start_time;
+    private Long task_end_time;
+    private TranslateDownloadVO downloads;
+    private TranslateAttachmentVO attachment;
+}

+ 10 - 0
src/main/java/com/cslg/ids/vo/TranslateAttachmentVO.java

@@ -0,0 +1,10 @@
+package com.cslg.ids.vo;
+
+import lombok.Data;
+
+@Data
+public class TranslateAttachmentVO {
+    private String html;
+    private String markdown;
+    private String markdown_zip;
+}

+ 8 - 0
src/main/java/com/cslg/ids/vo/TranslateDownloadVO.java

@@ -0,0 +1,8 @@
+package com.cslg.ids.vo;
+
+import lombok.Data;
+
+@Data
+public class TranslateDownloadVO {
+    private String md_cached;
+}

+ 10 - 0
src/main/java/com/cslg/ids/vo/TranslateFileVO.java

@@ -0,0 +1,10 @@
+package com.cslg.ids.vo;
+
+import lombok.Data;
+
+@Data
+public class TranslateFileVO {
+    private Boolean task_started;
+    private String task_id;
+    private String message;
+}

+ 70 - 0
src/main/resources/application-dev.yml

@@ -0,0 +1,70 @@
+spring:
+  rabbitmq:
+    host: 192.168.2.24
+    port: 5672
+    username: admin
+    password: 123456
+  data:
+   redis:
+     host: 192.168.2.24
+     port: 6379
+     database: 3
+     password: Xx0GWxdWQJxx6Swe
+     lettuce:
+       pool:
+         max-active: 20
+         max-idle: 20
+         min-idle: 0
+         max-wait: -1ms
+     timeout: 2000ms
+  datasource:
+    url: jdbc:mysql://192.168.2.24:3306/ids?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=GMT%2B8
+    username: root
+    password: rrzTwWAYX8Gxh5JH
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    type: com.alibaba.druid.pool.DruidDataSource
+    druid:
+      stat-view-servlet:
+        login-username: admin
+        login-password: Cslg2022+
+      web-stat-filter:
+        exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
+  quartz:
+    #相关属性配置
+#    properties:
+#      org:
+#        quartz:
+#          scheduler:
+#            instanceName: DefaultQuartzScheduler
+#            instanceId: AUTO
+#          jobStore:
+#            class: org.springframework.scheduling.quartz.LocalDataSourceJobStore
+#            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
+#            tablePrefix: QRTZ_
+#            isClustered: false
+#            clusterCheckinInterval: 10000
+#            useProperties: false
+#          threadPool:
+#            class: org.quartz.simpl.SimpleThreadPool
+#            threadCount: 10
+#            threadPriority: 5
+#            threadsInheritContextClassLoaderOfInitializingThread: true
+#          dataSource:
+#            default:
+#              URL: jdbc:mysql://192.168.2.24:3306/pas_prod2?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=GMT%2B8
+#              user: root
+#              password: rrzTwWAYX8Gxh5JH
+#              driver: com.mysql.jdbc.Driver
+
+    #数据库方式
+    job-store-type: memory
+    #初始化表结构
+
+authorUrl: http://192.168.2.24:8871
+PCSUrl: http://192.168.2.24:8871
+FMSUrl: http://192.168.2.24:8803
+FileDownloadUrl: http://192.168.2.24:8803/fileManager/downloadFile?fileId=
+FileSource: 1
+DIFY:
+  ecigaretteSummaryKey: app-iuvXti6Wma2vwQUuiBJ2u6Yh
+  url: http://192.168.2.24/v1/

+ 43 - 0
src/main/resources/application.yml

@@ -0,0 +1,43 @@
+server:
+  servlet:
+    context-path: /
+  port: 8907
+spring:
+  thymeleaf:
+    cache: false
+    mode: HTML5
+  aop:
+    auto: true
+    proxy-target-class: true
+  application:
+    name: IDS
+  servlet:
+    multipart:
+      max-file-size: 1000MB
+      max-request-size: 1000MB
+  profiles:
+    active: dev
+  jackson:
+    default-property-inclusion: non_null
+    serialization:
+      INDENT_OUTPUT: true
+    date-format: yyyy-MM-dd HH:mm:ss
+    time-zone: Asia/Shanghai
+logging:
+  config: classpath:config/logback-spring.xml
+  level:
+    com.cslg.ids.mapper: debug
+mybatis-plus:
+  typeAliasesPackage: com.cslg.ids.entity
+  global-config:
+    db-config:
+      id-type: AUTO
+      logic-delete-value: 0
+      logic-not-delete-value: 1
+      update-strategy: ignored
+  configuration:
+    map-underscore-to-camel-case: true
+    cache-enabled: false
+  mapper-locations: classpath:mapper/*.xml
+queueName: emailProd.queue
+

+ 2 - 0
src/main/resources/config/cron.setting

@@ -0,0 +1,2 @@
+[com.cslg.ids.common.utils]
+BackupUtils.run = 00 03 * * *

+ 110 - 0
src/main/resources/config/logback-spring.xml

@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <contextName>${APP_NAME}</contextName>
+
+    <springProperty name="APP_NAME" scope="context" source="spring.application.name"/>
+    <springProperty name="LOG_FILE" scope="context" source="logging.file" defaultValue="./logs/${APP_NAME}"/>
+    <springProperty name="LOG_POINT_FILE" scope="context" source="logging.file" defaultValue="./logs/point"/>
+    <springProperty name="LOG_MAXFILESIZE" scope="context" source="logback.filesize" defaultValue="50MB"/>
+    <springProperty name="LOG_FILEMAXDAY" scope="context" source="logback.filemaxday" defaultValue="7"/>
+    <springProperty name="ServerIP" scope="context" source="server.address" defaultValue="0.0.0.0"/>
+    <springProperty name="ServerPort" scope="context" source="server.port" defaultValue="0000"/>
+
+    <!-- 彩色日志 -->
+    <!-- 彩色日志依赖的渲染类 -->
+    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
+    <conversionRule conversionWord="wex"
+                    converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
+    <conversionRule conversionWord="wEx"
+                    converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
+
+    <!-- 彩色日志格式 -->
+    <property name="CONSOLE_LOG_PATTERN"
+              value="[${APP_NAME}:${ServerIP}:${ServerPort}] [%clr(%X{traceid}){yellow},%clr(%X{X-B3-TraceId}){yellow}] %clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%level){blue} %clr(${PID}){magenta} %clr([%thread]){orange} %clr(%logger){cyan} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
+    <property name="CONSOLE_LOG_PATTERN_NO_COLOR"
+              value="[${APP_NAME}:${ServerIP}:${ServerPort}] [%X{traceid},%X{X-B3-TraceId}] %d{yyyy-MM-dd HH:mm:ss.SSS} %level ${PID} [%thread] %logger %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
+
+
+    <!-- 控制台日志 -->
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <withJansi>true</withJansi>
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+    </appender>
+
+    <!-- 按照每天生成常规日志文件 -->
+    <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_FILE}/${APP_NAME}-error.log</file>
+        <!-- 基于时间的分包策略 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_FILE}/${APP_NAME}-error.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <maxFileSize>100MB</maxFileSize>
+            <!--保留时间,单位:天-->
+            <maxHistory>7</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN_NO_COLOR}</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+            <MaxFileSize>100MB</MaxFileSize>
+        </triggeringPolicy>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter"><!-- 只打印错误日志 -->
+            <level>ERROR</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <!-- 按照每天生成常规日志文件 -->
+    <appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_FILE}/${APP_NAME}-info.log</file>
+        <!-- 基于时间的分包策略 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_FILE}/${APP_NAME}-info.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <maxFileSize>100MB</maxFileSize>
+            <!--保留时间,单位:天-->
+            <maxHistory>7</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN_NO_COLOR}</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>INFO</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <!-- 按照每天生成常规日志文件 -->
+    <appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_FILE}/${APP_NAME}-debug.log</file>
+        <!-- 基于时间的分包策略 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_FILE}/${APP_NAME}-debug.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <maxFileSize>100MB</maxFileSize>
+            <!--保留时间,单位:天-->
+            <maxHistory>7</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN_NO_COLOR}</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>DEBUG</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <root level="INFO">
+        <appender-ref ref="STDOUT"/>
+        <appender-ref ref="ERROR"/>
+        <appender-ref ref="INFO"/>
+        <appender-ref ref="DEBUG"/>
+    </root>
+
+</configuration>

+ 21 - 0
src/test/java/com/cslg/ids/IdsApplicationTests.java

@@ -0,0 +1,21 @@
+package com.cslg.ids;
+
+import com.cslg.ids.service.TranslateService;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import java.io.IOException;
+
+@SpringBootTest
+class IdsApplicationTests {
+
+    @Autowired
+    private TranslateService translateService;
+    @Test
+    void contextLoads() throws IOException {
+        final String s = translateService.release("ca987747");
+        System.out.println(s);
+    }
+
+}