Эх сурвалжийг харах

Merge branch 'dev' of licailing/uwip into master

licailing 4 жил өмнө
parent
commit
ce462d3c79
64 өөрчлөгдсөн 4020 нэмэгдсэн , 235 устгасан
  1. 14 0
      src/main/java/com/izouma/uwip/annotations/OperLog.java
  2. 188 0
      src/main/java/com/izouma/uwip/aspect/OperLogAspect.java
  3. 17 4
      src/main/java/com/izouma/uwip/domain/CountryPatent.java
  4. 2 0
      src/main/java/com/izouma/uwip/domain/DomesticPatent.java
  5. 71 0
      src/main/java/com/izouma/uwip/domain/ExceptionLog.java
  6. 1 0
      src/main/java/com/izouma/uwip/domain/InternationalPatent.java
  7. 6 1
      src/main/java/com/izouma/uwip/domain/Message.java
  8. 63 0
      src/main/java/com/izouma/uwip/domain/OperationLog.java
  9. 3 1
      src/main/java/com/izouma/uwip/domain/Patent.java
  10. 6 1
      src/main/java/com/izouma/uwip/dto/AttachmentDTO.java
  11. 174 0
      src/main/java/com/izouma/uwip/dto/CountryPatentDTO.java
  12. 42 0
      src/main/java/com/izouma/uwip/dto/PatentDTO.java
  13. 3 3
      src/main/java/com/izouma/uwip/enums/ApplyRoute.java
  14. 2 2
      src/main/java/com/izouma/uwip/enums/CaseStage.java
  15. 34 14
      src/main/java/com/izouma/uwip/enums/CountryWorkflow.java
  16. 23 0
      src/main/java/com/izouma/uwip/repo/CountryPatentRepo.java
  17. 8 0
      src/main/java/com/izouma/uwip/repo/ExceptionLogRepo.java
  18. 3 1
      src/main/java/com/izouma/uwip/repo/LogoPatentRepo.java
  19. 3 0
      src/main/java/com/izouma/uwip/repo/MaintenanceRepo.java
  20. 8 0
      src/main/java/com/izouma/uwip/repo/OperationLogRepo.java
  21. 11 3
      src/main/java/com/izouma/uwip/service/AttachmentService.java
  22. 131 0
      src/main/java/com/izouma/uwip/service/CountryPatentService.java
  23. 13 34
      src/main/java/com/izouma/uwip/service/DomesticPatentService.java
  24. 13 0
      src/main/java/com/izouma/uwip/service/ExceptionLogService.java
  25. 5 32
      src/main/java/com/izouma/uwip/service/InternationalPatentService.java
  26. 33 9
      src/main/java/com/izouma/uwip/service/LogoPatentService.java
  27. 13 0
      src/main/java/com/izouma/uwip/service/OperationLogService.java
  28. 11 2
      src/main/java/com/izouma/uwip/service/PartnerService.java
  29. 181 2
      src/main/java/com/izouma/uwip/service/PatentService.java
  30. 71 0
      src/main/java/com/izouma/uwip/utils/IPUtils.java
  31. 9 2
      src/main/java/com/izouma/uwip/web/AttachmentController.java
  32. 75 0
      src/main/java/com/izouma/uwip/web/CountryPatentController.java
  33. 4 0
      src/main/java/com/izouma/uwip/web/DomesticPatentController.java
  34. 63 0
      src/main/java/com/izouma/uwip/web/ExceptionLogController.java
  35. 6 3
      src/main/java/com/izouma/uwip/web/InternationalPatentController.java
  36. 63 0
      src/main/java/com/izouma/uwip/web/OperationLogController.java
  37. 0 0
      src/main/resources/genjson/CountryPatent.json
  38. 34 0
      src/main/vue/src/components/Workflow.vue
  39. 1 1
      src/main/vue/src/components/domesticPatent/BaseInfo.vue
  40. 1 1
      src/main/vue/src/components/fee/FeeList.vue
  41. 313 0
      src/main/vue/src/components/internationalPatent/BaseInfo.vue
  42. 86 0
      src/main/vue/src/components/internationalPatent/MaintainCase.vue
  43. 140 0
      src/main/vue/src/components/internationalPatent/OfficeAttachment.vue
  44. 103 0
      src/main/vue/src/components/internationalPatent/Reply.vue
  45. 85 0
      src/main/vue/src/components/internationalPatent/ReplyResult.vue
  46. 72 0
      src/main/vue/src/components/internationalPatent/replySubmissions.vue
  47. 84 0
      src/main/vue/src/mixins/internationalPatent.js
  48. 2 2
      src/main/vue/src/plugins/http.js
  49. 43 0
      src/main/vue/src/router.js
  50. 8 0
      src/main/vue/src/styles/app.less
  51. 237 0
      src/main/vue/src/views/CountryPatentEdit.vue
  52. 226 0
      src/main/vue/src/views/CountryPatentList.vue
  53. 4 1
      src/main/vue/src/views/DomesticPatentEdit.vue
  54. 194 0
      src/main/vue/src/views/ExceptionLogList.vue
  55. 313 0
      src/main/vue/src/views/InternationalPatentAdd.vue
  56. 273 83
      src/main/vue/src/views/InternationalPatentEdit.vue
  57. 145 0
      src/main/vue/src/views/InternationalPatentEdit1.vue
  58. 80 30
      src/main/vue/src/views/InternationalPatentList.vue
  59. 2 0
      src/main/vue/src/views/LogoPatentAdd.vue
  60. 138 0
      src/main/vue/src/views/OperationLogList.vue
  61. 44 0
      src/test/java/com/izouma/uwip/service/CountryPatentServiceTest.java
  62. 2 2
      src/test/java/com/izouma/uwip/service/InternationalPatentServiceTest.java
  63. 1 1
      src/test/java/com/izouma/uwip/service/LogoPatentServiceTest.java
  64. 16 0
      src/test/java/com/izouma/uwip/service/PatentServiceTest.java

+ 14 - 0
src/main/java/com/izouma/uwip/annotations/OperLog.java

@@ -0,0 +1,14 @@
+package com.izouma.uwip.annotations;
+
+import java.lang.annotation.*;
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface OperLog {
+    String value() default "";
+
+    String type() default "";
+
+    String desc() default "";
+}

+ 188 - 0
src/main/java/com/izouma/uwip/aspect/OperLogAspect.java

@@ -0,0 +1,188 @@
+package com.izouma.uwip.aspect;
+
+import com.alibaba.fastjson.JSON;
+import com.izouma.uwip.annotations.OperLog;
+import com.izouma.uwip.domain.ExceptionLog;
+import com.izouma.uwip.domain.OperationLog;
+import com.izouma.uwip.domain.User;
+import com.izouma.uwip.repo.ExceptionLogRepo;
+import com.izouma.uwip.repo.OperationLogRepo;
+import com.izouma.uwip.utils.IPUtils;
+import com.izouma.uwip.utils.SecurityUtils;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.AfterThrowing;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+
+import javax.servlet.http.HttpServletRequest;
+import java.lang.reflect.Method;
+import java.time.LocalDateTime;
+import java.util.HashMap;
+import java.util.Map;
+
+@Aspect
+@Component
+public class OperLogAspect {
+
+    @Autowired
+    private OperationLogRepo operationLogRepo;
+
+    @Autowired
+    private ExceptionLogRepo exceptionLogRepo;
+
+    /**
+     * 设置操作日志切入点 记录操作日志 在注解的位置切入代码
+     */
+    @Pointcut("@annotation(com.izouma.uwip.annotations.OperLog)")
+    public void operLogPointCut() {
+    }
+
+    /**
+     * 设置操作异常切入点记录异常日志 扫描所有controller包下操作
+     */
+    @Pointcut("execution(* com.izouma.uwip.web..*.*(..))")
+    public void operExceptionLogPointCut() {
+    }
+
+    /**
+     * 正常返回通知,拦截用户操作日志,连接点正常执行完成后执行, 如果连接点抛出异常,则不会执行
+     *
+     * @param joinPoint 切入点
+     * @param keys      返回结果
+     */
+    @AfterReturning(value = "operLogPointCut()", returning = "keys")
+    public void saveOperLog(JoinPoint joinPoint, Object keys) {
+        // 获取RequestAttributes
+        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
+        // 从获取RequestAttributes中获取HttpServletRequest的信息
+        HttpServletRequest request = (HttpServletRequest) requestAttributes
+                .resolveReference(RequestAttributes.REFERENCE_REQUEST);
+
+        OperationLog operationLog = new OperationLog();
+        try {
+            // 从切面织入点处通过反射机制获取织入点处的方法
+            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
+            // 获取切入点所在的方法
+            Method method = signature.getMethod();
+            // 获取操作
+            OperLog operLog = method.getAnnotation(OperLog.class);
+            if (operLog != null) {
+                operationLog.setName(operLog.value()); // 操作模块
+                operationLog.setType(operLog.type()); // 操作类型
+                operationLog.setDesc(operLog.desc()); // 操作描述
+            }
+            // 获取请求的类名
+            String className = joinPoint.getTarget().getClass().getName();
+            // 获取请求的方法名
+            String methodName = method.getName();
+            methodName = className + "." + methodName;
+
+            operationLog.setReqMethod(methodName);
+
+            // 请求的参数
+            Map<String, String> rtnMap = null;
+            String params = null;
+            if (request != null) {
+                rtnMap = convertMap(request.getParameterMap());
+                params = JSON.toJSONString(rtnMap);
+            }
+
+            operationLog.setReqParams(params);
+            operationLog.setResp(JSON.toJSONString(keys));
+
+            User user = SecurityUtils.getAuthenticatedUser();
+            if (user != null) {
+                operationLog.setUserId(String.valueOf(user.getId()));
+                operationLog.setUsername(user.getUsername());
+            }
+            operationLog.setReqIp(IPUtils.getIpAddr(request));
+            operationLog.setReqUrl(request != null ? request.getRequestURI() : null);
+            operationLog.setTime(LocalDateTime.now());
+            operationLogRepo.save(operationLog);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 异常返回通知,用于拦截异常日志信息 连接点抛出异常后执行
+     *
+     * @param joinPoint 切入点
+     * @param e         异常信息
+     */
+    @AfterThrowing(pointcut = "operExceptionLogPointCut()", throwing = "e")
+    public void saveExceptionLog(JoinPoint joinPoint, Throwable e) {
+        // 获取RequestAttributes
+        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
+        // 从获取RequestAttributes中获取HttpServletRequest的信息
+        HttpServletRequest request = (HttpServletRequest) requestAttributes
+                .resolveReference(RequestAttributes.REFERENCE_REQUEST);
+
+        ExceptionLog exceptionLog = new ExceptionLog();
+        try {
+            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
+            Method method = signature.getMethod();
+            String className = joinPoint.getTarget().getClass().getName();
+            String methodName = method.getName();
+            methodName = className + "." + methodName;
+            exceptionLog.setReqMethod(methodName);
+
+            Map<String, String> rtnMap = convertMap(request.getParameterMap());
+            String params = JSON.toJSONString(rtnMap);
+            exceptionLog.setReqParams(params);
+
+            exceptionLog.setName(e.getClass().getName());
+            exceptionLog.setMessage(stackTraceToString(e.getClass().getName(), e.getMessage(), e
+                    .getStackTrace()));
+            User user = SecurityUtils.getAuthenticatedUser();
+            if (user != null) {
+                exceptionLog.setUserId(String.valueOf(user.getId()));
+                exceptionLog.setUsername(user.getUsername());
+            }
+
+            exceptionLog.setReqUrl(request.getRequestURI());
+            exceptionLog.setReqIp(IPUtils.getIpAddr(request));
+            exceptionLog.setTime(LocalDateTime.now());
+
+            exceptionLogRepo.save(exceptionLog);
+
+        } catch (Exception e2) {
+            e2.printStackTrace();
+        }
+
+    }
+
+    /**
+     * 转换request 请求参数
+     *
+     * @param paramMap request获取的参数数组
+     */
+    public Map<String, String> convertMap(Map<String, String[]> paramMap) {
+        Map<String, String> rtnMap = new HashMap<>();
+        for (String key : paramMap.keySet()) {
+            rtnMap.put(key, paramMap.get(key)[0]);
+        }
+        return rtnMap;
+    }
+
+    /**
+     * 转换异常信息为字符串
+     *
+     * @param exceptionName    异常名称
+     * @param exceptionMessage 异常信息
+     * @param elements         堆栈信息
+     */
+    public String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) {
+        StringBuilder strBuff = new StringBuilder();
+        for (StackTraceElement stet : elements) {
+            strBuff.append(stet).append("\n");
+        }
+        return exceptionName + ":" + exceptionMessage + "\n\t" + strBuff;
+    }
+}

+ 17 - 4
src/main/java/com/izouma/uwip/domain/CountryPatent.java

@@ -1,5 +1,7 @@
 package com.izouma.uwip.domain;
 
+import cn.hutool.core.bean.BeanUtil;
+import com.izouma.uwip.dto.CountryPatentDTO;
 import com.izouma.uwip.enums.ApplyRoute;
 import com.izouma.uwip.enums.CountryWorkflow;
 import io.swagger.annotations.ApiModel;
@@ -8,24 +10,27 @@ import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
+import org.hibernate.annotations.Where;
 
-import javax.persistence.Entity;
-import javax.persistence.EnumType;
-import javax.persistence.Enumerated;
+import javax.persistence.*;
 import java.math.BigDecimal;
 import java.time.LocalDate;
 
 @AllArgsConstructor
 @Data
 @Builder
-//@Entity
+@Entity
 @NoArgsConstructor
+@Where(clause = "del = 0")
 @ApiModel(value = "国家申请")
 public class CountryPatent extends BaseEntity {
 
+    private Long patentId;
+
     @ApiModelProperty(value = "流程")
     private CountryWorkflow workflow;
 
+    @ApiModelProperty(value = "进入国家")
     private String country;
 
     @Enumerated(EnumType.STRING)
@@ -87,4 +92,12 @@ public class CountryPatent extends BaseEntity {
     @ApiModelProperty(value = "办登缴费期限")
     private LocalDate registerPayPeriod;
 
+    @ManyToOne(fetch = FetchType.LAZY)
+    @JoinColumn(name = "patentId", insertable = false, updatable = false, foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
+    private Patent patent;
+
+    public CountryPatent(CountryPatentDTO dto) {
+        BeanUtil.copyProperties(dto, this);
+    }
+
 }

+ 2 - 0
src/main/java/com/izouma/uwip/domain/DomesticPatent.java

@@ -9,6 +9,7 @@ import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
+import org.hibernate.annotations.Where;
 
 import javax.persistence.*;
 import java.math.BigDecimal;
@@ -19,6 +20,7 @@ import java.time.LocalDate;
 @Builder
 @Entity
 @NoArgsConstructor
+@Where(clause = "del = 0")
 @ApiModel(value = "国内申请")
 public class DomesticPatent extends BaseEntity {
     private Long patentId;

+ 71 - 0
src/main/java/com/izouma/uwip/domain/ExceptionLog.java

@@ -0,0 +1,71 @@
+package com.izouma.uwip.domain;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.*;
+import java.time.LocalDateTime;
+
+@Data
+@Entity
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonIgnoreProperties(value = {"hibernateLazyInitializer"}, ignoreUnknown = true)
+@ApiModel("异常日志")
+public class ExceptionLog {
+    @Id
+    @GeneratedValue(strategy = GenerationType.AUTO)
+    private Long id;
+
+    @ApiModelProperty("异常名称")
+    private String name;
+
+    @ApiModelProperty("操作类型")
+    private String type;
+
+    @ApiModelProperty("用户ID")
+    private String userId;
+
+    @ApiModelProperty("用户名")
+    private String username;
+
+    @ApiModelProperty("描述")
+    @Column(name = "description")
+    private String desc;
+
+    @ApiModelProperty("调用方法")
+    private String reqMethod;
+
+    @ApiModelProperty("请求地址")
+    private String reqUrl;
+
+    @ApiModelProperty("请求参数")
+    @Lob
+    private String reqParams;
+
+    @ApiModelProperty("请求ip")
+    private String reqIp;
+
+    @ApiModelProperty("返回结果")
+    @Lob
+    private String resp;
+
+    @ApiModelProperty("操作时间")
+    private LocalDateTime time;
+
+    @ApiModelProperty("异常消息")
+    @Lob
+    private String message;
+
+    @ApiModelProperty("错误追踪")
+    @Lob
+    private String stackTrace;
+}

+ 1 - 0
src/main/java/com/izouma/uwip/domain/InternationalPatent.java

@@ -20,6 +20,7 @@ import java.time.LocalDate;
 @Builder
 @NoArgsConstructor
 @Entity
+@Where(clause = "del = 0")
 @ApiModel(value = "国际申请")
 public class InternationalPatent extends BaseEntity {
     private Long patentId;

+ 6 - 1
src/main/java/com/izouma/uwip/domain/Message.java

@@ -1,5 +1,6 @@
 package com.izouma.uwip.domain;
 
+import com.izouma.uwip.converter.LongArrayConverter;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.AllArgsConstructor;
@@ -8,6 +9,9 @@ import lombok.Data;
 import lombok.NoArgsConstructor;
 import org.hibernate.annotations.Where;
 
+import javax.persistence.Convert;
+import java.util.List;
+
 @Data
 @AllArgsConstructor
 @NoArgsConstructor
@@ -16,7 +20,8 @@ import org.hibernate.annotations.Where;
 @Where(clause = "del = 0")
 public class Message extends BaseEntity {
     @ApiModelProperty(value = "接收人")
-    private Long receiveUserId;
+    @Convert(converter = LongArrayConverter.class)
+    private List<Long> receiveUserId;
 
     @ApiModelProperty(value = "是否已读")
     private boolean read;

+ 63 - 0
src/main/java/com/izouma/uwip/domain/OperationLog.java

@@ -0,0 +1,63 @@
+package com.izouma.uwip.domain;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.*;
+import java.time.LocalDateTime;
+
+@Data
+@Entity
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonIgnoreProperties(value = {"hibernateLazyInitializer"}, ignoreUnknown = true)
+@ApiModel("操作日志")
+public class OperationLog {
+    @Id
+    @GeneratedValue(strategy = GenerationType.AUTO)
+    private Long id;
+
+    @ApiModelProperty("操作名称")
+    private String name;
+
+    @ApiModelProperty("操作类型")
+    private String type;
+
+    @ApiModelProperty("用户ID")
+    private String userId;
+
+    @ApiModelProperty("用户名")
+    private String username;
+
+    @ApiModelProperty("描述")
+    @Column(name = "description")
+    private String desc;
+
+    @ApiModelProperty("调用方法")
+    private String reqMethod;
+
+    @ApiModelProperty("请求地址")
+    private String reqUrl;
+
+    @ApiModelProperty("请求参数")
+    @Lob
+    private String reqParams;
+
+    @ApiModelProperty("请求ip")
+    private String reqIp;
+
+    @ApiModelProperty("返回结果")
+    @Lob
+    private String resp;
+
+    @ApiModelProperty("操作时间")
+    private LocalDateTime time;
+}

+ 3 - 1
src/main/java/com/izouma/uwip/domain/Patent.java

@@ -11,6 +11,7 @@ import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
+import org.hibernate.annotations.Where;
 
 import javax.persistence.*;
 import java.time.LocalDate;
@@ -23,6 +24,7 @@ import java.util.List;
 @NoArgsConstructor
 @Entity
 @ApiModel(value = "专利申请")
+@Where(clause = "del = 0")
 @JsonIgnoreProperties(value = {"hibernateLazyInitializer"}, ignoreUnknown = true)
 public class Patent extends BaseEntity {
 //    private String workflow;
@@ -103,5 +105,5 @@ public class Patent extends BaseEntity {
 
     @Column(columnDefinition = "TEXT")
     @Convert(converter = HandleListConverter.class)
-    private List<Handle> handle = new ArrayList<>();
+    private List<Handle> handle;
 }

+ 6 - 1
src/main/java/com/izouma/uwip/dto/AttachmentDTO.java

@@ -1,12 +1,13 @@
 package com.izouma.uwip.dto;
 
 import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
+import java.math.BigDecimal;
+
 @AllArgsConstructor
 @Data
 @Builder
@@ -24,4 +25,8 @@ public class AttachmentDTO {
 
     private String remark;
 
+    private String size;
+
+    private int version;
+
 }

+ 174 - 0
src/main/java/com/izouma/uwip/dto/CountryPatentDTO.java

@@ -0,0 +1,174 @@
+package com.izouma.uwip.dto;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.izouma.uwip.domain.CountryPatent;
+import com.izouma.uwip.domain.Handle;
+import com.izouma.uwip.domain.Patent;
+import com.izouma.uwip.enums.ApplyRoute;
+import com.izouma.uwip.enums.ApplyStatus;
+import com.izouma.uwip.enums.CountryWorkflow;
+import com.izouma.uwip.enums.PatentType;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.List;
+
+@AllArgsConstructor
+@Data
+@Builder
+@NoArgsConstructor
+@ApiModel(value = "国家申请")
+public class CountryPatentDTO {
+    private Long cid;
+
+    private Long patentId;
+
+    @ApiModelProperty(value = "流程")
+    private CountryWorkflow workflow;
+
+    private String country;
+
+    @ApiModelProperty(value = "申请途径")
+    private ApplyRoute applyRoute;
+
+    /*
+    选择pct时必填
+    */
+    @ApiModelProperty(value = "pct申请号")
+    private String pctApplyNo;
+
+    @ApiModelProperty(value = "pct申请日")
+    private String pctApplyDate;
+
+    @ApiModelProperty(value = "pct公开号")
+    private String pctPublicNo;
+
+    @ApiModelProperty(value = "pct公开日")
+    private String pctPublicDate;
+
+    @ApiModelProperty(value = "授权号")
+    private String grantNo;
+
+    @ApiModelProperty(value = "授权日")
+    private LocalDate grantDate;
+
+    /*
+    翻译
+     */
+    @ApiModelProperty(value = "翻译字数")
+    private long translateWord;
+
+    @ApiModelProperty(value = "翻译语种")
+    private String translationLanguage;
+
+    @ApiModelProperty(value = "单价/千字")
+    private BigDecimal unitPrice;
+
+    @ApiModelProperty(value = "总价")
+    private BigDecimal totalPrice;
+
+    @ApiModelProperty(value = "翻译交期")
+    private LocalDate translationPeriod;
+
+    @ApiModelProperty(value = "是否决定答复")
+    private Boolean decideReply;
+
+    /*
+    true 客户准备
+    false 律师准备
+     */
+    @ApiModelProperty(value = "准备答复意见")
+    private Boolean isClientReady;
+
+    @ApiModelProperty(value = "是否通过答复")
+    private Boolean replyPassed;
+
+    @ApiModelProperty(value = "办登缴费期限")
+    private LocalDate registerPayPeriod;
+
+    @ApiModelProperty(value = "专利名称")
+    private String name;
+
+    private ApplyStatus applyStatus;
+
+    @ApiModelProperty(value = "专利类型")
+    private PatentType type;
+
+    /*
+    客户编码(由客户经理填写)+年份+案件类型+连接符+案件阶段[+国家]+序列号
+     */
+    @ApiModelProperty(value = "寰球案号")
+    private String uwNo;
+
+    @ApiModelProperty(value = "客户id")
+    private Long clientPartnerId;
+
+    @ApiModelProperty(value = "供应商")
+    private Long supplierPartnerId;
+
+    @ApiModelProperty(value = "供应商案号")
+    private String supplierNo;
+
+    @ApiModelProperty(value = "供应商提交期限")
+    private LocalDate supplierSubmitPeriod;
+
+    @ApiModelProperty(value = "申请人名称")
+    private String applicantName;
+
+    @ApiModelProperty(value = "申请人英文名称")
+    private String applicantEnName;
+
+    @ApiModelProperty(value = "申请人地址")
+    private String applicantAddress;
+
+    @ApiModelProperty(value = "申请人英文地址")
+    private String applicantEnAddress;
+
+    @ApiModelProperty(value = "发明人名称")
+    private String inventorName;
+
+    @ApiModelProperty(value = "发明人英文名称")
+    private String inventorEnName;
+
+    @ApiModelProperty(value = "优先权号")
+    private String priorityNo;
+
+    @ApiModelProperty(value = "优先权日")
+    private LocalDate priorityDate;
+
+    @ApiModelProperty(value = "优先权国别")
+    private String priorityCountry;
+
+    @ApiModelProperty(value = "提交期限/内部期限")
+    private LocalDate submitPeriod;
+
+    /*
+    =优先权日+30个月
+     */
+    @ApiModelProperty(value = "官方期限")
+    private LocalDate officialPeriod;
+
+    @ApiModelProperty(value = "申请号")
+    private String applyNo;
+
+    @ApiModelProperty(value = "申请日")
+    private LocalDate applyDate;
+
+    private List<Handle> handle = new ArrayList<>();
+
+    public List<AttachmentDTO> attachments;
+
+    public CountryPatentDTO(CountryPatent cPatent, Patent patent) {
+        BeanUtil.copyProperties(cPatent, this);
+        BeanUtil.copyProperties(patent, this);
+        this.cid = cPatent.getId();
+    }
+
+}

+ 42 - 0
src/main/java/com/izouma/uwip/dto/PatentDTO.java

@@ -0,0 +1,42 @@
+package com.izouma.uwip.dto;
+
+import com.izouma.uwip.domain.LogoPatent;
+import com.izouma.uwip.domain.Patent;
+import com.izouma.uwip.enums.ApplyStatus;
+import com.izouma.uwip.enums.CountryWorkflow;
+import com.izouma.uwip.enums.DomesticWorkflow;
+import com.izouma.uwip.enums.LogoWorkflow;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDate;
+
+@Data
+@NoArgsConstructor
+public class PatentDTO {
+    private String name;
+
+    private String uwNo;
+
+    private ApplyStatus applyStatus;
+
+    private String workflow;
+
+    private LocalDate date;
+
+    public PatentDTO(Patent patent) {
+        this.name = patent.getName();
+        this.uwNo = patent.getUwNo();
+        this.applyStatus = patent.getApplyStatus();
+    }
+
+    public PatentDTO(LogoPatent patent) {
+        this.name = patent.getName();
+        this.uwNo = patent.getUwNo();
+        this.applyStatus = patent.getApplyStatus();
+        this.workflow = patent.getLogoWorkflow().getDescription();
+        if (LogoWorkflow.PALINDROME_CORRECTION.equals(patent.getLogoWorkflow())) {
+            this.date = patent.getCorrectionPeriod();
+        }
+    }
+}

+ 3 - 3
src/main/java/com/izouma/uwip/enums/ApplyRoute.java

@@ -2,11 +2,11 @@ package com.izouma.uwip.enums;
 
 public enum ApplyRoute {
     /*
-    pct
+    pct国家阶段
      */
-    PCT,
+    COUNTRY,
     /*
-    单一国申请
+    巴黎公约
      */
     SINGLE
 }

+ 2 - 2
src/main/java/com/izouma/uwip/enums/CaseStage.java

@@ -10,11 +10,11 @@ public enum CaseStage {
      */
     PCT(2),
     /*
-    国家
+    PCT国家
      */
     COUNTRY(3),
     /*
-    单一国
+    单一国/巴黎公约
      */
     SINGLE(4);
 

+ 34 - 14
src/main/java/com/izouma/uwip/enums/CountryWorkflow.java

@@ -2,30 +2,50 @@ package com.izouma.uwip.enums;
 
 /*
 国家申请流程
+1 客户经理
+2 项目经理
+3 翻译经理
  */
 public enum CountryWorkflow {
-    APPLY_TRANSLATION("待申请翻译文稿"),
-    TRANSLATION_DOCUMENTS("待上传翻译文稿"),
-    FINALIZED_TRANSLATION("待上传翻译定稿"),
-    ADD_SUPPLIERS("待添加供应商"),
-    SUPPLIER_MATERIALS("待提交供应商材料"),
-    MAINTAIN_CASE("待维护案件信息"),
-    REPLY_NOTIFICATION("待上传答复通知"),
-    DETERMINED_REPLY("待确定答复意向"),
-    UPLOADED_REPLY("待上传答复意见书"),
-    RESPONSE_RESULT("待确定答复结果"),
-    AUTHORIZE_REGISTER("授权办登"),
-    AUTHORIZATION_INFORMATION("待维护授权信息"),
-    COMPLETED("已完成"),
+    APPLY_TRANSLATION("待申请翻译文稿", 3),
+    TRANSLATION_DOCUMENTS("待上传翻译文稿", 3),
+    FINALIZED_TRANSLATION("待上传翻译定稿", 1),
+    ADD_SUPPLIERS("待添加供应商", 2),
+    SUPPLIER_MATERIALS("待提交供应商材料", 2),
+    MAINTAIN_CASE("待维护案件信息", 1),
+    REPLY_NOTIFICATION("待上传答复通知", 2),
+    DETERMINED_REPLY("待确定答复意向", 1),
+    NO_REPLY("不答复终止", 1),
+    UPLOADED_REPLY("待上传答复意见书", 1),
+    RESPONSE_RESULT("待确定答复结果", 2),
+    /*
+    授权办登通知日
+    */
+    PENDING_REGISTER("待办登", 1),
+    /*
+    办登凭证/证书扫描件
+     */
+    AUTHORIZE_REGISTER("授权办登", 1),
+    /*
+    授权号/授权日
+     */
+    AUTHORIZATION_INFORMATION("待维护授权信息", 1),
+    COMPLETED("已完成", 1),
     ;
 
     private final String description;
+    private final int    authority;
 
     public String getDescription() {
         return description;
     }
 
-    CountryWorkflow(String description) {
+    public int getAuthority() {
+        return authority;
+    }
+
+    CountryWorkflow(String description, int authority) {
         this.description = description;
+        this.authority = authority;
     }
 }

+ 23 - 0
src/main/java/com/izouma/uwip/repo/CountryPatentRepo.java

@@ -0,0 +1,23 @@
+package com.izouma.uwip.repo;
+
+import com.izouma.uwip.domain.CountryPatent;
+import com.izouma.uwip.dto.CountryPatentDTO;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+
+import javax.transaction.Transactional;
+import java.util.Optional;
+
+public interface CountryPatentRepo extends JpaRepository<CountryPatent, Long>, JpaSpecificationExecutor<CountryPatent> {
+    @Query("update CountryPatent t set t.del = true where t.id = ?1")
+    @Modifying
+    @Transactional
+    void softDelete(Long id);
+
+    @Query("select new com.izouma.uwip.dto.CountryPatentDTO(c,p) " +
+            "from CountryPatent c join Patent p on c.patentId = p.id " +
+            "where c.id = ?1 and p.del = false and c.del = false")
+    Optional<CountryPatentDTO> findCountryDTO(Long id);
+}

+ 8 - 0
src/main/java/com/izouma/uwip/repo/ExceptionLogRepo.java

@@ -0,0 +1,8 @@
+package com.izouma.uwip.repo;
+
+import com.izouma.uwip.domain.ExceptionLog;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+
+public interface ExceptionLogRepo extends JpaRepository<ExceptionLog, Long>, JpaSpecificationExecutor<ExceptionLog> {
+}

+ 3 - 1
src/main/java/com/izouma/uwip/repo/LogoPatentRepo.java

@@ -14,6 +14,8 @@ public interface LogoPatentRepo extends JpaRepository<LogoPatent, Long>, JpaSpec
     @Transactional
     void softDelete(Long id);
 
-    @Query(nativeQuery = true, value = "select ifnull(max(sort + 1),1) from  logo_patent where del = true")
+    @Query(nativeQuery = true, value = "select ifnull(max(sort + 1),1) from  logo_patent where del = false")
     int findMax();
+
+
 }

+ 3 - 0
src/main/java/com/izouma/uwip/repo/MaintenanceRepo.java

@@ -7,6 +7,7 @@ import org.springframework.data.jpa.repository.Modifying;
 import org.springframework.data.jpa.repository.Query;
 
 import javax.transaction.Transactional;
+import javax.validation.constraints.Size;
 import java.util.List;
 
 public interface MaintenanceRepo extends JpaRepository<Maintenance, Long>, JpaSpecificationExecutor<Maintenance> {
@@ -17,5 +18,7 @@ public interface MaintenanceRepo extends JpaRepository<Maintenance, Long>, JpaSp
 
     List<Maintenance> findAllByFlag(String description);
 
+    Maintenance findByFlagAndName(@Size(min = 1, max = 50) String flag, String name);
+
 
 }

+ 8 - 0
src/main/java/com/izouma/uwip/repo/OperationLogRepo.java

@@ -0,0 +1,8 @@
+package com.izouma.uwip.repo;
+
+import com.izouma.uwip.domain.OperationLog;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+
+public interface OperationLogRepo extends JpaRepository<OperationLog, Long>, JpaSpecificationExecutor<OperationLog> {
+}

+ 11 - 3
src/main/java/com/izouma/uwip/service/AttachmentService.java

@@ -1,5 +1,7 @@
 package com.izouma.uwip.service;
 
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
 import com.izouma.uwip.domain.Attachment;
 import com.izouma.uwip.dto.AttachmentDTO;
 import com.izouma.uwip.dto.PageQuery;
@@ -41,7 +43,7 @@ public class AttachmentService {
         }
         if (size > 1024) {
             BigDecimal bigDecimal = new BigDecimal(size / 1024);
-            return bigDecimal.setScale(2,BigDecimal.ROUND_UP) + "KB";
+            return bigDecimal.setScale(2, BigDecimal.ROUND_UP) + "KB";
         }
         return size + "B";
     }
@@ -58,9 +60,15 @@ public class AttachmentService {
                     .fileName(dto.getFileName())
                     .url(dto.getUrl())
                     .remark(dto.getRemark())
-                    .size(getSize(dto.getUrl()))
-                    .version(attachmentRepo.findVersion(dto.getAttachmentName(), patentId))
+                    .size(dto.getSize())
+                    .version(dto.getVersion())
                     .build();
+            if (StrUtil.isBlank(dto.getSize())) {
+                build.setSize(getSize(dto.getUrl()));
+            }
+            if (dto.getVersion() == 0) {
+                build.setVersion(attachmentRepo.findVersion(dto.getAttachmentName(), patentId));
+            }
             attachmentRepo.save(build);
         });
 

+ 131 - 0
src/main/java/com/izouma/uwip/service/CountryPatentService.java

@@ -0,0 +1,131 @@
+package com.izouma.uwip.service;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.izouma.uwip.domain.CountryPatent;
+import com.izouma.uwip.domain.Handle;
+import com.izouma.uwip.domain.InternationalPatent;
+import com.izouma.uwip.domain.Patent;
+import com.izouma.uwip.dto.CountryPatentDTO;
+import com.izouma.uwip.dto.PageQuery;
+import com.izouma.uwip.enums.ApplyStatus;
+import com.izouma.uwip.enums.CaseStage;
+import com.izouma.uwip.enums.CaseType;
+import com.izouma.uwip.enums.CountryWorkflow;
+import com.izouma.uwip.exception.BusinessException;
+import com.izouma.uwip.repo.CountryPatentRepo;
+import com.izouma.uwip.repo.PatentRepo;
+import com.izouma.uwip.utils.JpaUtils;
+import com.izouma.uwip.utils.ObjUtils;
+import lombok.AllArgsConstructor;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.data.domain.Page;
+import org.springframework.stereotype.Service;
+
+import javax.persistence.criteria.Predicate;
+import java.util.ArrayList;
+import java.util.List;
+
+@Service
+@AllArgsConstructor
+public class CountryPatentService {
+
+    private final CountryPatentRepo countryPatentRepo;
+    private final PatentRepo        patentRepo;
+    private final PartnerService    partnerService;
+    private final AttachmentService attachmentService;
+    private final PatentService     patentService;
+
+
+    public Page<CountryPatent> all(PageQuery pageQuery) {
+        return countryPatentRepo.findAll(JpaUtils.toSpecification(pageQuery, CountryPatent.class), JpaUtils.toPageRequest(pageQuery));
+    }
+
+    public CountryPatent saveDTO(CountryPatentDTO record, Long userId) {
+        if (record.getCid() != null) {
+            CountryPatent orig = countryPatentRepo.findById(record.getCid())
+                    .orElseThrow(new BusinessException("无记录"));
+            CountryPatent cPatent = new CountryPatent(record);
+            ObjUtils.merge(orig, cPatent);
+            orig = countryPatentRepo.save(orig);
+
+            Patent orig1 = patentRepo.findById(record.getPatentId()).orElseThrow(new BusinessException("无记录"));
+            Patent patent = new Patent();
+            BeanUtil.copyProperties(record, patent);
+            ObjUtils.mergePatent(orig1, patent);
+            // 流程
+            List<Handle> handleList = orig1.getHandle();
+            if (handleList == null) {
+                handleList = new ArrayList<>();
+            }
+            patentService.saveHandle(record.getWorkflow().toString(), userId, handleList);
+            orig1.setHandle(handleList);
+
+            if (ObjectUtil.isNull(record.getApplyStatus()) || !ApplyStatus.COMPLETED.equals(record.getApplyStatus())) {
+                orig1.setApplyStatus(this.getApplyStatus(record.getWorkflow()));
+            }
+            patentRepo.save(orig1);
+
+            // 保存附件
+            if (CollectionUtils.isNotEmpty(record.getAttachments())) {
+                attachmentService.batchSave(record.getAttachments(), userId, record.getCid());
+            }
+            return orig;
+        }
+
+        Patent patent = new Patent();
+        BeanUtil.copyProperties(record, patent);
+        patent.setSort(patentRepo.findMax());
+
+        // 寰球案号
+        String type = patent.getType().name();
+        // pct国家申请专利 + 巴黎公约
+        String applyRoute = record.getApplyRoute().name();
+        patent.setUwNo(partnerService.getUwNo(patent.getClientPartnerId(), CaseType.valueOf(type), CaseStage.valueOf(applyRoute), record
+                .getCountry(), patent
+                .getSort()));
+        patent.setApplyStatus(ApplyStatus.APPLY_STAGE);
+        patent = patentRepo.save(patent);
+
+        CountryPatent cPatent = new CountryPatent(record);
+        cPatent.setPatentId(patent.getId());
+        cPatent = countryPatentRepo.save(cPatent);
+
+        // 保存附件
+        if (CollectionUtils.isNotEmpty(record.getAttachments())) {
+            attachmentService.batchSave(record.getAttachments(), userId, record.getCid());
+        }
+        return cPatent;
+    }
+
+    public ApplyStatus getApplyStatus(CountryWorkflow workflow) {
+        switch (workflow) {
+            case APPLY_TRANSLATION://申请翻译文稿
+            case TRANSLATION_DOCUMENTS://上传翻译文稿
+            case FINALIZED_TRANSLATION://上传翻译定稿
+            case ADD_SUPPLIERS://供应商
+            case SUPPLIER_MATERIALS://供应商材料
+            case MAINTAIN_CASE://案件信息
+                return ApplyStatus.APPLY_STAGE;//申请阶段
+            case REPLY_NOTIFICATION://答复通知
+            case DETERMINED_REPLY://答复意向
+            case UPLOADED_REPLY://答复意见书
+            case RESPONSE_RESULT://答复结果
+                return ApplyStatus.SUBSTANTIVE_STAGE;//审查
+            case PENDING_REGISTER://办登通知日
+            case AUTHORIZE_REGISTER://办登凭证
+            case AUTHORIZATION_INFORMATION://授权号
+                return ApplyStatus.GRANT_STAGE;
+            default://不答复终止
+                return ApplyStatus.COMPLETED;
+        }
+    }
+
+    public Page<CountryPatent> allDTO(PageQuery pageQuery) {
+        return countryPatentRepo.findAll(((root, criteriaQuery, criteriaBuilder) -> {
+            List<Predicate> and = patentService.getPredicate(pageQuery, InternationalPatent.class, root, criteriaBuilder);
+
+            return criteriaBuilder.and(and.toArray(new Predicate[0]));
+        }), JpaUtils.toPageRequest(pageQuery));
+    }
+}

+ 13 - 34
src/main/java/com/izouma/uwip/service/DomesticPatentService.java

@@ -2,7 +2,6 @@ package com.izouma.uwip.service;
 
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
 import com.izouma.uwip.domain.DomesticPatent;
 import com.izouma.uwip.domain.Handle;
 import com.izouma.uwip.domain.Patent;
@@ -18,12 +17,10 @@ import lombok.AllArgsConstructor;
 import org.apache.commons.collections.CollectionUtils;
 import org.springframework.data.domain.Page;
 import org.springframework.stereotype.Service;
-import javax.persistence.criteria.Path;
+
 import javax.persistence.criteria.Predicate;
-import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 
 @Service
 @AllArgsConstructor
@@ -33,6 +30,7 @@ public class DomesticPatentService {
     private final AttachmentService  attachmentService;
     private final PatentRepo         patentRepo;
     private final PartnerService     partnerService;
+    private final PatentService      patentService;
 
     public Page<DomesticPatent> all(PageQuery pageQuery) {
         return domesticPatentRepo.findAll(JpaUtils.toSpecification(pageQuery, DomesticPatent.class), JpaUtils.toPageRequest(pageQuery));
@@ -51,11 +49,13 @@ public class DomesticPatentService {
             BeanUtil.copyProperties(record, patent);
             ObjUtils.mergePatent(orig1, patent);
 
-            orig1.getHandle().add(Handle.builder()
-                    .workflow(record.getWorkflow().toString())
-                    .userId(userId)
-                    .checkAt(LocalDateTime.now())
-                    .build());
+            // 流程信息
+            List<Handle> handleList = orig1.getHandle();
+            if (handleList == null) {
+                handleList = new ArrayList<>();
+            }
+            patentService.saveHandle(record.getWorkflow().toString(), userId, handleList);
+
             if (ObjectUtil.isNull(record.getApplyStatus()) || !ApplyStatus.COMPLETED.equals(record.getApplyStatus())) {
                 orig1.setApplyStatus(this.getApplyStatus(record.getWorkflow()));
             }
@@ -75,7 +75,7 @@ public class DomesticPatentService {
 
         //寰球案号
         PatentType type = patent.getType();
-        patent.setUwNo(partnerService.getUwNo(patent.getClientPartnerId(), CaseType.valueOf(type.name()), CaseStage.DOMESTIC, patent
+        patent.setUwNo(partnerService.getUwNo(patent.getClientPartnerId(), CaseType.valueOf(type.name()), CaseStage.DOMESTIC, null, patent
                 .getSort()));
         patent.setApplyStatus(ApplyStatus.APPLY_STAGE);
         patent = patentRepo.save(patent);
@@ -114,30 +114,9 @@ public class DomesticPatentService {
     }
 
     public Page<DomesticPatent> allDTO(PageQuery pageQuery) {
-       return domesticPatentRepo.findAll(((root, criteriaQuery, criteriaBuilder) -> {
-            List<Predicate> and = new ArrayList<>();
-            Path<Object> patent = root.get("patent");
-            if (StrUtil.isNotBlank(pageQuery.getSearch())) {
-                List<Predicate> or = new ArrayList<>();
-                or.add(criteriaBuilder.like(patent.get("name"), "%" + pageQuery.getSearch() + "%"));
-                or.add(criteriaBuilder.like(patent.get("uwNo"), "%" + pageQuery.getSearch() + "%"));
-                and.add(criteriaBuilder.or(or.toArray(new Predicate[0])));
-            }
-            Map<String, Object> query = pageQuery.getQuery();
-            query.keySet().forEach(key -> {
-                if (JpaUtils.isExistField(key, DomesticPatent.class)) {
-                    Predicate predicate = JpaUtils.getPredicate(key, query.get(key), DomesticPatent.class, root, criteriaBuilder,false);
-                    if (ObjectUtil.isNotNull(predicate)){
-                        and.add(predicate);
-                    }
-                } else {
-                    Predicate predicate = JpaUtils.getPredicate(key, query.get(key), Patent.class, root, criteriaBuilder,true);
-                    if (ObjectUtil.isNotNull(predicate)){
-                        and.add(predicate);
-                    }
-                }
-            });
+        return domesticPatentRepo.findAll(((root, criteriaQuery, criteriaBuilder) -> {
+            List<Predicate> and = patentService.getPredicate(pageQuery, DomesticPatent.class, root, criteriaBuilder);
             return criteriaBuilder.and(and.toArray(new Predicate[0]));
-        }),JpaUtils.toPageRequest(pageQuery));
+        }), JpaUtils.toPageRequest(pageQuery));
     }
 }

+ 13 - 0
src/main/java/com/izouma/uwip/service/ExceptionLogService.java

@@ -0,0 +1,13 @@
+package com.izouma.uwip.service;
+
+import com.izouma.uwip.repo.ExceptionLogRepo;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Service;
+
+@Service
+@AllArgsConstructor
+public class ExceptionLogService {
+
+    private ExceptionLogRepo exceptionLogRepo;
+
+}

+ 5 - 32
src/main/java/com/izouma/uwip/service/InternationalPatentService.java

@@ -2,7 +2,6 @@ package com.izouma.uwip.service;
 
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
 import com.izouma.uwip.domain.Handle;
 import com.izouma.uwip.domain.InternationalPatent;
 import com.izouma.uwip.domain.Patent;
@@ -19,12 +18,9 @@ import org.apache.commons.collections.CollectionUtils;
 import org.springframework.data.domain.Page;
 import org.springframework.stereotype.Service;
 
-import javax.persistence.criteria.Path;
 import javax.persistence.criteria.Predicate;
-import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 
 @Service
 @AllArgsConstructor
@@ -34,6 +30,7 @@ public class InternationalPatentService {
     private final PatentRepo              patentRepo;
     private final AttachmentService       attachmentService;
     private final PartnerService          partnerService;
+    private final PatentService           patentService;
 
     public Page<InternationalPatent> all(PageQuery pageQuery) {
         return internationalPatentRepo.findAll(JpaUtils.toSpecification(pageQuery, InternationalPatent.class), JpaUtils.toPageRequest(pageQuery));
@@ -55,11 +52,7 @@ public class InternationalPatentService {
             if (handleList == null) {
                 handleList = new ArrayList<>();
             }
-            handleList.add(Handle.builder()
-                    .workflow(record.getWorkflow().toString())
-                    .userId(userId)
-                    .checkAt(LocalDateTime.now())
-                    .build());
+            patentService.saveHandle(record.getWorkflow().toString(), userId, handleList);
             orig1.setHandle(handleList);
             if (ObjectUtil.isNull(record.getApplyStatus()) || !ApplyStatus.COMPLETED.equals(record.getApplyStatus())) {
                 orig1.setApplyStatus(this.getApplyStatus(record.getWorkflow()));
@@ -79,7 +72,7 @@ public class InternationalPatentService {
 
         //寰球案号
         PatentType type = patent.getType();
-        patent.setUwNo(partnerService.getUwNo(patent.getClientPartnerId(), CaseType.valueOf(type.name()), CaseStage.PCT, patent
+        patent.setUwNo(partnerService.getUwNo(patent.getClientPartnerId(), CaseType.valueOf(type.name()), CaseStage.PCT, null, patent
                 .getSort()));
         patent.setApplyStatus(ApplyStatus.APPLY_STAGE);
         patent = patentRepo.save(patent);
@@ -113,28 +106,8 @@ public class InternationalPatentService {
 
     public Page<InternationalPatent> allDTO(PageQuery pageQuery) {
         return internationalPatentRepo.findAll(((root, criteriaQuery, criteriaBuilder) -> {
-            List<Predicate> and = new ArrayList<>();
-            Path<Object> patent = root.get("patent");
-            if (StrUtil.isNotBlank(pageQuery.getSearch())) {
-                List<Predicate> or = new ArrayList<>();
-                or.add(criteriaBuilder.like(patent.get("name"), "%" + pageQuery.getSearch() + "%"));
-                or.add(criteriaBuilder.like(patent.get("uwNo"), "%" + pageQuery.getSearch() + "%"));
-                and.add(criteriaBuilder.or(or.toArray(new Predicate[0])));
-            }
-            Map<String, Object> query = pageQuery.getQuery();
-            query.keySet().forEach(key -> {
-                if (JpaUtils.isExistField(key, InternationalPatent.class)) {
-                    Predicate predicate = JpaUtils.getPredicate(key, query.get(key), InternationalPatent.class, root, criteriaBuilder, false);
-                    if (ObjectUtil.isNotNull(predicate)) {
-                        and.add(predicate);
-                    }
-                } else {
-                    Predicate predicate = JpaUtils.getPredicate(key, query.get(key), Patent.class, root, criteriaBuilder, true);
-                    if (ObjectUtil.isNotNull(predicate)) {
-                        and.add(predicate);
-                    }
-                }
-            });
+            List<Predicate> and = patentService.getPredicate(pageQuery, InternationalPatent.class, root, criteriaBuilder);
+
             return criteriaBuilder.and(and.toArray(new Predicate[0]));
         }), JpaUtils.toPageRequest(pageQuery));
     }

+ 33 - 9
src/main/java/com/izouma/uwip/service/LogoPatentService.java

@@ -4,7 +4,10 @@ import cn.hutool.core.util.ObjectUtil;
 import com.izouma.uwip.domain.Handle;
 import com.izouma.uwip.domain.LogoPatent;
 import com.izouma.uwip.dto.PageQuery;
-import com.izouma.uwip.enums.*;
+import com.izouma.uwip.enums.ApplyStatus;
+import com.izouma.uwip.enums.CaseStage;
+import com.izouma.uwip.enums.CaseType;
+import com.izouma.uwip.enums.LogoWorkflow;
 import com.izouma.uwip.exception.BusinessException;
 import com.izouma.uwip.repo.LogoPatentRepo;
 import com.izouma.uwip.utils.JpaUtils;
@@ -15,6 +18,9 @@ import org.springframework.data.domain.Page;
 import org.springframework.stereotype.Service;
 
 import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
 
 @Service
 @AllArgsConstructor
@@ -28,12 +34,27 @@ public class LogoPatentService {
         return logoPatentRepo.findAll(JpaUtils.toSpecification(pageQuery, LogoPatent.class), JpaUtils.toPageRequest(pageQuery));
     }
 
-    public Handle saveHandle(LogoWorkflow workflow, Long userId) {
-        return Handle.builder()
-                .workflow(workflow.toString())
-                .userId(userId)
-                .checkAt(LocalDateTime.now())
-                .build();
+    public void saveHandle(LogoWorkflow workflow, Long userId, List<Handle> handles) {
+//        if (handles == null) {
+//            handles = new ArrayList<>();
+//            handles.add(Handle.builder()
+//                    .workflow(workflow.toString())
+//                    .userId(userId)
+//                    .checkAt(LocalDateTime.now())
+//                    .build());
+//            return handles;
+//        }
+        handles.sort(Comparator.comparing(Handle::getCheckAt));
+        int size = handles.size();
+
+        if (size == 0 || !workflow.toString().equals(handles.get(size - 1).getWorkflow())) {
+            handles.add(Handle.builder()
+                    .workflow(workflow.toString())
+                    .userId(userId)
+                    .checkAt(LocalDateTime.now())
+                    .build());
+        }
+//        return handles;
     }
 
     public LogoPatent save(LogoPatent record, Long userId) {
@@ -48,7 +69,9 @@ public class LogoPatentService {
                 attachmentService.batchSave(record.getAttachments(), userId, record.getId());
             }
             ObjUtils.merge(orig, record);
-            orig.getHandle().add(this.saveHandle(workflow, userId));
+            // 流程记录
+            this.saveHandle(workflow, userId, orig.getHandle());
+
             if (ObjectUtil.isNull(record.getApplyStatus()) || !ApplyStatus.COMPLETED.equals(record.getApplyStatus())) {
                 orig.setApplyStatus(this.getApplyStatus(workflow));
             }
@@ -57,7 +80,8 @@ public class LogoPatentService {
         if (record.getSort() == 0) {
             record.setSort(logoPatentRepo.findMax());
         }
-        record.setUwNo(partnerService.getUwNo(record.getClientPartnerId(), CaseType.LOGO, CaseStage.DOMESTIC, record.getSort()));
+        record.setUwNo(partnerService.getUwNo(record.getClientPartnerId(), CaseType.LOGO, CaseStage.DOMESTIC, null, record
+                .getSort()));
         record.setLogoWorkflow(LogoWorkflow.IS_CONTRACT);
         record.setApplyStatus(ApplyStatus.APPLY_STAGE);
         record = logoPatentRepo.save(record);

+ 13 - 0
src/main/java/com/izouma/uwip/service/OperationLogService.java

@@ -0,0 +1,13 @@
+package com.izouma.uwip.service;
+
+import com.izouma.uwip.repo.OperationLogRepo;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Service;
+
+@Service
+@AllArgsConstructor
+public class OperationLogService {
+
+    private OperationLogRepo operationLogRepo;
+
+}

+ 11 - 2
src/main/java/com/izouma/uwip/service/PartnerService.java

@@ -1,10 +1,13 @@
 package com.izouma.uwip.service;
 
+import cn.hutool.core.util.StrUtil;
+import com.izouma.uwip.domain.Maintenance;
 import com.izouma.uwip.domain.Partner;
 import com.izouma.uwip.dto.PageQuery;
 import com.izouma.uwip.enums.CaseStage;
 import com.izouma.uwip.enums.CaseType;
 import com.izouma.uwip.exception.BusinessException;
+import com.izouma.uwip.repo.MaintenanceRepo;
 import com.izouma.uwip.repo.PartnerRepo;
 import com.izouma.uwip.utils.JpaUtils;
 import lombok.AllArgsConstructor;
@@ -17,16 +20,22 @@ import java.time.LocalDate;
 @AllArgsConstructor
 public class PartnerService {
 
-    private final PartnerRepo partnerRepo;
+    private final PartnerRepo     partnerRepo;
+    private final MaintenanceRepo maintenanceRepo;
 
     public Page<Partner> all(PageQuery pageQuery) {
         return partnerRepo.findAll(JpaUtils.toSpecification(pageQuery, Partner.class), JpaUtils.toPageRequest(pageQuery));
     }
 
-    public String getUwNo(Long partnerId, CaseType type, CaseStage stage, int sort) {
+    public String getUwNo(Long partnerId, CaseType type, CaseStage stage, String country, int sort) {
 //        客户编码(由客户经理填写)+年份+案件类型+连接符+案件阶段[+国家]+序列号
         Partner partner = partnerRepo.findById(partnerId).orElseThrow(new BusinessException("客户不存在"));
         int y = LocalDate.now().getYear() - 2000;
+        if (StrUtil.isNotBlank(country)) {
+            Maintenance maintenance = maintenanceRepo.findByFlagAndName("Country", country);
+            return partner.getCode() + y + type.getValue() + "——" + stage.getValue() + maintenance.getDescription() + String
+                    .format("%03d", sort);
+        }
         return partner.getCode() + y + type.getValue() + "——" + stage.getValue() + String.format("%03d", sort);
     }
 }

+ 181 - 2
src/main/java/com/izouma/uwip/service/PatentService.java

@@ -1,20 +1,199 @@
 package com.izouma.uwip.service;
 
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.izouma.uwip.domain.Handle;
+import com.izouma.uwip.domain.LogoPatent;
 import com.izouma.uwip.domain.Patent;
 import com.izouma.uwip.dto.PageQuery;
-import com.izouma.uwip.repo.PatentRepo;
+import com.izouma.uwip.dto.PatentDTO;
+import com.izouma.uwip.enums.ApplyStatus;
+import com.izouma.uwip.repo.*;
 import com.izouma.uwip.utils.JpaUtils;
 import lombok.AllArgsConstructor;
 import org.springframework.data.domain.Page;
 import org.springframework.stereotype.Service;
 
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.Path;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.stream.Collectors;
+
 @Service
 @AllArgsConstructor
 public class PatentService {
 
-    private final PatentRepo patentRepo;
+    private final PatentRepo              patentRepo;
+    private final LogoPatentRepo          logoPatentRepo;
+    private final DomesticPatentRepo      domesticPatentRepo;
+    private final InternationalPatentRepo internationalPatentRepo;
+    private final CountryPatentRepo       countryPatentRepo;
 
     public Page<Patent> all(PageQuery pageQuery) {
         return patentRepo.findAll(JpaUtils.toSpecification(pageQuery, Patent.class), JpaUtils.toPageRequest(pageQuery));
     }
+
+    public void saveHandle(String workflow, Long userId, List<Handle> handles) {
+        handles.sort(Comparator.comparing(Handle::getCheckAt));
+        int size = handles.size();
+
+        if (size == 0 || !workflow.equals(handles.get(size - 1).getWorkflow())) {
+            handles.add(Handle.builder()
+                    .workflow(workflow)
+                    .userId(userId)
+                    .checkAt(LocalDateTime.now())
+                    .build());
+        }
+    }
+
+    public <T> List<Predicate> getPredicate(PageQuery pageQuery, Class<?> queryClass, Root<T> root,
+                                            CriteriaBuilder criteriaBuilder) {
+        List<Predicate> and = new ArrayList<>();
+        Path<Object> patent = root.get("patent");
+        if (StrUtil.isNotBlank(pageQuery.getSearch())) {
+            List<Predicate> or = new ArrayList<>();
+            or.add(criteriaBuilder.like(patent.get("name"), "%" + pageQuery.getSearch() + "%"));
+            or.add(criteriaBuilder.like(patent.get("uwNo"), "%" + pageQuery.getSearch() + "%"));
+            and.add(criteriaBuilder.or(or.toArray(new Predicate[0])));
+        }
+        Map<String, Object> query = pageQuery.getQuery();
+        query.keySet().forEach(key -> {
+            if (JpaUtils.isExistField(key, queryClass)) {
+                Predicate predicate = JpaUtils.getPredicate(key, query.get(key), queryClass, root, criteriaBuilder, false);
+                if (ObjectUtil.isNotNull(predicate)) {
+                    and.add(predicate);
+                }
+            } else {
+                Predicate predicate = JpaUtils.getPredicate(key, query.get(key), Patent.class, root, criteriaBuilder, true);
+                if (ObjectUtil.isNotNull(predicate)) {
+                    and.add(predicate);
+                }
+            }
+        });
+        return and;
+    }
+
+    public Map<String, Object> total() {
+        Map<String, Object> map = new HashMap<>();
+
+        List<Patent> patents = patentRepo.findAll();
+        List<LogoPatent> logoPatents = logoPatentRepo.findAll();
+
+        //总数
+        int total = patents.size() + logoPatents.size();
+        map.put("total", total);
+
+        //今天
+        LocalDate now = LocalDate.now();
+        long pToday = patents.stream().filter(patent -> patent.getCreatedAt().toLocalDate().equals(now)).count();
+        long lToday = logoPatents.stream().filter(patent -> patent.getCreatedAt().toLocalDate().equals(now)).count();
+        int today = (int) (pToday + lToday);
+        map.put("today", today);
+
+        //进行中
+        List<Patent> pInProgress = patents.stream()
+                .filter(patent -> !ApplyStatus.COMPLETED.equals(patent.getApplyStatus()))
+                .collect(Collectors.toList());
+        List<LogoPatent> lInProgress = logoPatents.stream()
+                .filter(patent -> !ApplyStatus.COMPLETED.equals(patent.getApplyStatus()))
+                .collect(Collectors.toList());
+        int inProgress = pInProgress.size() + lInProgress.size();
+        map.put("inProgress", inProgress);
+
+        //已结束
+        int end = total - inProgress;
+        map.put("end", end);
+
+        //代办案件列表
+        List<PatentDTO> lAgent = lInProgress.stream().map(PatentDTO::new).collect(Collectors.toList());
+//        List<PatentDTO> pAgent = pInProgress.stream().map(PatentDTO::new).collect(Collectors.toList());
+
+        //数据统计
+        Map<ApplyStatus, List<Patent>> byPStatus = patents.stream()
+                .collect(Collectors.groupingBy(Patent::getApplyStatus));
+
+        Map<ApplyStatus, List<LogoPatent>> byLStatus = logoPatents.stream()
+                .collect(Collectors.groupingBy(LogoPatent::getApplyStatus));
+        List<LogoPatent> applyLPatent = byLStatus.get(ApplyStatus.APPLY_STAGE);
+        List<Patent> applyPatent = byPStatus.get(ApplyStatus.APPLY_STAGE);
+        int apply = CollUtil.isEmpty(applyLPatent) ? 0 : applyLPatent.size() +
+                ((CollUtil.isEmpty(applyPatent)) ? 0 : applyPatent.size());
+
+        List<LogoPatent> grantLPatent = byLStatus.get(ApplyStatus.GRANT_STAGE);
+        List<Patent> grantPatent = byPStatus.get(ApplyStatus.GRANT_STAGE);
+        int grant = CollUtil.isEmpty(grantLPatent) ? 0 : grantLPatent.size() +
+                ((CollUtil.isEmpty(grantPatent)) ? 0 : grantPatent.size());
+
+        List<LogoPatent> reviewLPatent = byLStatus.get(ApplyStatus.REVIEW_STAGE);
+        List<Patent> reviewPatent = byPStatus.get(ApplyStatus.REVIEW_STAGE);
+        int review = CollUtil.isEmpty(reviewLPatent) ? 0 : reviewLPatent.size() +
+                ((CollUtil.isEmpty(reviewPatent)) ? 0 : reviewPatent.size());
+
+        List<LogoPatent> substantiveLPatent = byLStatus.get(ApplyStatus.SUBSTANTIVE_STAGE);
+        List<Patent> substantivePatent = byPStatus.get(ApplyStatus.SUBSTANTIVE_STAGE);
+        int substantive = CollUtil.isEmpty(substantiveLPatent) ? 0 : substantiveLPatent.size() +
+                ((CollUtil.isEmpty(substantivePatent)) ? 0 : substantivePatent.size());
+
+        map.put("apply", apply);
+        map.put("grant", grant);
+        map.put("review", review);
+        map.put("substantive", substantive);
+
+
+        //本周数据对比
+        int dayOfWeek = now.getDayOfWeek().getValue() % 7;
+        Map<LocalDate, Integer> weekMap = getData(patents, logoPatents, now, dayOfWeek);
+        map.put("weekMap", weekMap);
+
+        //本月数据对比
+        int dayOfMonth = now.getDayOfMonth() - 1;
+        Map<LocalDate, Integer> monthMap = getData(patents, logoPatents, now, dayOfMonth);
+        map.put("monthMap", monthMap);
+
+        return map;
+    }
+
+    /*
+    趋势
+    1 周
+    2 月
+    3 年
+     */
+    public Map<Integer, Integer> getTrend(int type) {
+        Map<Integer, Integer> map = new HashMap<>();
+        switch (type) {
+
+            case 3:
+
+        }
+
+
+        return map;
+    }
+
+    private Map<LocalDate, Integer> getData(List<Patent> patents, List<LogoPatent> logoPatents,
+                                            LocalDate now, int day) {
+        Map<LocalDate, Integer> map = new HashMap<>();
+        while (day >= 0) {
+            LocalDate weekStart = now.minusDays(day);
+
+            long pWeek = patents.stream()
+                    .filter(patent -> patent.getCreatedAt().toLocalDate().equals(weekStart))
+                    .count();
+            long lWeek = logoPatents.stream()
+                    .filter(patent -> patent.getCreatedAt().toLocalDate().equals(weekStart))
+                    .count();
+            day--;
+
+            map.put(weekStart, (int) (pWeek + lWeek));
+        }
+        return map;
+    }
+
+
 }

+ 71 - 0
src/main/java/com/izouma/uwip/utils/IPUtils.java

@@ -0,0 +1,71 @@
+package com.izouma.uwip.utils;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.util.StringUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+@Slf4j
+public class IPUtils {
+    private static final String IP_UTILS_FLAG = ",";
+    private static final String UNKNOWN       = "unknown";
+    private static final String LOCALHOST_IP  = "0:0:0:0:0:0:0:1";
+    private static final String LOCALHOST_IP1 = "127.0.0.1";
+
+    /**
+     * 获取IP地址
+     * <p>
+     * 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址
+     * 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址
+     */
+    public static String getIpAddr(HttpServletRequest request) {
+        String ip = null;
+        try {
+            //以下两个获取在k8s中,将真实的客户端IP,放到了x-Original-Forwarded-For。而将WAF的回源地址放到了 x-Forwarded-For了。
+            ip = request.getHeader("X-Original-Forwarded-For");
+            if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
+                ip = request.getHeader("X-Forwarded-For");
+            }
+            //获取nginx等代理的ip
+            if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
+                ip = request.getHeader("x-forwarded-for");
+            }
+            if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
+                ip = request.getHeader("Proxy-Client-IP");
+            }
+            if (StringUtils.isEmpty(ip) || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+                ip = request.getHeader("WL-Proxy-Client-IP");
+            }
+            if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
+                ip = request.getHeader("HTTP_CLIENT_IP");
+            }
+            if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
+                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
+            }
+            //兼容k8s集群获取ip
+            if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
+                ip = request.getRemoteAddr();
+                if (LOCALHOST_IP1.equalsIgnoreCase(ip) || LOCALHOST_IP.equalsIgnoreCase(ip)) {
+                    //根据网卡取本机配置的IP
+                    InetAddress iNet = null;
+                    try {
+                        iNet = InetAddress.getLocalHost();
+                        ip = iNet.getHostAddress();
+                    } catch (UnknownHostException e) {
+                        log.error("getClientIp error", e);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            log.error("IPUtils ERROR ", e);
+        }
+        //使用代理,则获取第一个IP地址
+        if (!StringUtils.isEmpty(ip) && ip.indexOf(IP_UTILS_FLAG) > 0) {
+            ip = ip.substring(0, ip.indexOf(IP_UTILS_FLAG));
+        }
+
+        return ip;
+    }
+}

+ 9 - 2
src/main/java/com/izouma/uwip/web/AttachmentController.java

@@ -1,5 +1,6 @@
 package com.izouma.uwip.web;
 
+import cn.hutool.core.util.StrUtil;
 import com.izouma.uwip.domain.Attachment;
 import com.izouma.uwip.domain.User;
 import com.izouma.uwip.repo.UserRepo;
@@ -37,8 +38,14 @@ public class AttachmentController extends BaseController {
             return attachmentRepo.save(orig);
         }
         record.setAttachmentName(record.getAttachmentName().trim());
-        record.setVersion(attachmentRepo.findVersion(record.getAttachmentName(), record.getPatentId()));
-        record.setSize(attachmentService.getSize(record.getUrl()));
+
+        if (StrUtil.isBlank(record.getSize())) {
+            record.setSize(attachmentService.getSize(record.getUrl()));
+        }
+        if (record.getVersion() == 0) {
+            record.setVersion(attachmentRepo.findVersion(record.getAttachmentName(), record.getPatentId()));
+        }
+//        record.setSize(attachmentService.getSize(record.getUrl()));
         return attachmentRepo.save(record);
     }
 

+ 75 - 0
src/main/java/com/izouma/uwip/web/CountryPatentController.java

@@ -0,0 +1,75 @@
+package com.izouma.uwip.web;
+
+import com.izouma.uwip.domain.CountryPatent;
+import com.izouma.uwip.dto.CountryPatentDTO;
+import com.izouma.uwip.dto.PageQuery;
+import com.izouma.uwip.exception.BusinessException;
+import com.izouma.uwip.repo.CountryPatentRepo;
+import com.izouma.uwip.repo.PatentRepo;
+import com.izouma.uwip.service.CountryPatentService;
+import com.izouma.uwip.utils.ObjUtils;
+import com.izouma.uwip.utils.excel.ExcelUtils;
+import lombok.AllArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+
+@RestController
+@RequestMapping("/countryPatent")
+@AllArgsConstructor
+public class CountryPatentController extends BaseController {
+    private final CountryPatentService countryPatentService;
+    private final CountryPatentRepo    countryPatentRepo;
+    private final PatentRepo           patentRepo;
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/save")
+    public CountryPatent save(@RequestBody CountryPatent record) {
+        if (record.getId() != null) {
+            CountryPatent orig = countryPatentRepo.findById(record.getId()).orElseThrow(new BusinessException("无记录"));
+            ObjUtils.merge(orig, record);
+            return countryPatentRepo.save(orig);
+        }
+        return countryPatentRepo.save(record);
+    }
+
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/all")
+    public Page<CountryPatent> all(@RequestBody PageQuery pageQuery) {
+        return countryPatentService.all(pageQuery);
+    }
+
+    @PostMapping("/allDTO")
+    public Page<CountryPatent> allDTO(@RequestBody PageQuery pageQuery) {
+        return countryPatentService.allDTO(pageQuery);
+    }
+
+    @GetMapping("/get/{id}")
+    public CountryPatent get(@PathVariable Long id) {
+        return countryPatentRepo.findById(id).orElseThrow(new BusinessException("无记录"));
+    }
+
+    @GetMapping("/getDTO/{id}")
+    public CountryPatentDTO getDTO(@PathVariable Long id) {
+        return countryPatentRepo.findCountryDTO(id).orElseThrow(new BusinessException("无记录"));
+    }
+
+    @PostMapping("/del/{id}")
+    public void del(@PathVariable Long id) {
+        CountryPatent cPatent = countryPatentRepo.findById(id).orElseThrow(new BusinessException("无记录"));
+        patentRepo.softDelete(cPatent.getPatentId());
+        countryPatentRepo.softDelete(id);
+    }
+
+    @GetMapping("/excel")
+    @ResponseBody
+    public void excel(HttpServletResponse response, PageQuery pageQuery) throws IOException {
+        List<CountryPatent> data = all(pageQuery).getContent();
+        ExcelUtils.export(response, data);
+    }
+}
+

+ 4 - 0
src/main/java/com/izouma/uwip/web/DomesticPatentController.java

@@ -2,6 +2,7 @@ package com.izouma.uwip.web;
 
 import com.izouma.uwip.domain.DomesticPatent;
 import com.izouma.uwip.dto.DomesticPatentDTO;
+import com.izouma.uwip.repo.PatentRepo;
 import com.izouma.uwip.service.DomesticPatentService;
 import com.izouma.uwip.dto.PageQuery;
 import com.izouma.uwip.exception.BusinessException;
@@ -23,6 +24,7 @@ import java.util.List;
 public class DomesticPatentController extends BaseController {
     private final DomesticPatentService domesticPatentService;
     private final DomesticPatentRepo    domesticPatentRepo;
+    private final PatentRepo            patentRepo;
 
     //@PreAuthorize("hasRole('ADMIN')")
     @PostMapping("/save")
@@ -64,6 +66,8 @@ public class DomesticPatentController extends BaseController {
 
     @PostMapping("/del/{id}")
     public void del(@PathVariable Long id) {
+        DomesticPatent dPatent = domesticPatentRepo.findById(id).orElseThrow(new BusinessException("无记录"));
+        patentRepo.softDelete(dPatent.getPatentId());
         domesticPatentRepo.softDelete(id);
     }
 

+ 63 - 0
src/main/java/com/izouma/uwip/web/ExceptionLogController.java

@@ -0,0 +1,63 @@
+package com.izouma.uwip.web;
+
+import com.izouma.uwip.domain.ExceptionLog;
+import com.izouma.uwip.dto.PageQuery;
+import com.izouma.uwip.exception.BusinessException;
+import com.izouma.uwip.repo.ExceptionLogRepo;
+import com.izouma.uwip.service.ExceptionLogService;
+import com.izouma.uwip.utils.ObjUtils;
+import com.izouma.uwip.utils.excel.ExcelUtils;
+import lombok.AllArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+
+import static com.izouma.uwip.utils.JpaUtils.toPageRequest;
+import static com.izouma.uwip.utils.JpaUtils.toSpecification;
+
+@RestController
+@RequestMapping("/exceptionLog")
+@AllArgsConstructor
+public class ExceptionLogController extends BaseController {
+    private ExceptionLogService exceptionLogService;
+    private ExceptionLogRepo    exceptionLogRepo;
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/save")
+    public ExceptionLog save(@RequestBody ExceptionLog record) {
+        if (record.getId() != null) {
+            ExceptionLog orig = exceptionLogRepo.findById(record.getId()).orElseThrow(new BusinessException("无记录"));
+            ObjUtils.merge(orig, record);
+            return exceptionLogRepo.save(orig);
+        }
+        return exceptionLogRepo.save(record);
+    }
+
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/all")
+    public Page<ExceptionLog> all(@RequestBody PageQuery pageQuery) {
+        return exceptionLogRepo.findAll(toSpecification(pageQuery, ExceptionLog.class), toPageRequest(pageQuery));
+    }
+
+    @GetMapping("/get/{id}")
+    public ExceptionLog get(@PathVariable Long id) {
+        return exceptionLogRepo.findById(id).orElseThrow(new BusinessException("无记录"));
+    }
+
+    @PostMapping("/del/{id}")
+    public void del(@PathVariable Long id) {
+        exceptionLogRepo.deleteById(id);
+    }
+
+    @GetMapping("/excel")
+    @ResponseBody
+    public void excel(HttpServletResponse response, PageQuery pageQuery) throws IOException {
+        List<ExceptionLog> data = all(pageQuery).getContent();
+        ExcelUtils.export(response, data);
+    }
+}
+

+ 6 - 3
src/main/java/com/izouma/uwip/web/InternationalPatentController.java

@@ -2,16 +2,16 @@ package com.izouma.uwip.web;
 
 import com.izouma.uwip.domain.InternationalPatent;
 import com.izouma.uwip.dto.InternationalPatentDTO;
-import com.izouma.uwip.service.InternationalPatentService;
 import com.izouma.uwip.dto.PageQuery;
 import com.izouma.uwip.exception.BusinessException;
 import com.izouma.uwip.repo.InternationalPatentRepo;
+import com.izouma.uwip.repo.PatentRepo;
+import com.izouma.uwip.service.InternationalPatentService;
 import com.izouma.uwip.utils.ObjUtils;
 import com.izouma.uwip.utils.SecurityUtils;
 import com.izouma.uwip.utils.excel.ExcelUtils;
 import lombok.AllArgsConstructor;
 import org.springframework.data.domain.Page;
-import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletResponse;
@@ -24,6 +24,7 @@ import java.util.List;
 public class InternationalPatentController extends BaseController {
     private final InternationalPatentService internationalPatentService;
     private final InternationalPatentRepo    internationalPatentRepo;
+    private final PatentRepo                 patentRepo;
 
     //@PreAuthorize("hasRole('ADMIN')")
     @PostMapping("/save")
@@ -49,7 +50,7 @@ public class InternationalPatentController extends BaseController {
     }
 
     @PostMapping("/allDTO")
-    public Page<InternationalPatent> allDTO(PageQuery pageQuery) {
+    public Page<InternationalPatent> allDTO(@RequestBody PageQuery pageQuery) {
         return internationalPatentService.allDTO(pageQuery);
     }
 
@@ -65,6 +66,8 @@ public class InternationalPatentController extends BaseController {
 
     @PostMapping("/del/{id}")
     public void del(@PathVariable Long id) {
+        InternationalPatent iPatent = internationalPatentRepo.findById(id).orElseThrow(new BusinessException("无记录"));
+        patentRepo.softDelete(iPatent.getPatentId());
         internationalPatentRepo.softDelete(id);
     }
 

+ 63 - 0
src/main/java/com/izouma/uwip/web/OperationLogController.java

@@ -0,0 +1,63 @@
+package com.izouma.uwip.web;
+
+import com.izouma.uwip.domain.OperationLog;
+import com.izouma.uwip.dto.PageQuery;
+import com.izouma.uwip.exception.BusinessException;
+import com.izouma.uwip.repo.OperationLogRepo;
+import com.izouma.uwip.service.OperationLogService;
+import com.izouma.uwip.utils.ObjUtils;
+import com.izouma.uwip.utils.excel.ExcelUtils;
+import lombok.AllArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+
+import static com.izouma.uwip.utils.JpaUtils.toPageRequest;
+import static com.izouma.uwip.utils.JpaUtils.toSpecification;
+
+@RestController
+@RequestMapping("/operationLog")
+@AllArgsConstructor
+public class OperationLogController extends BaseController {
+    private OperationLogService operationLogService;
+    private OperationLogRepo operationLogRepo;
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/save")
+    public OperationLog save(@RequestBody OperationLog record) {
+        if (record.getId() != null) {
+            OperationLog orig = operationLogRepo.findById(record.getId()).orElseThrow(new BusinessException("无记录"));
+            ObjUtils.merge(orig, record);
+            return operationLogRepo.save(orig);
+        }
+        return operationLogRepo.save(record);
+    }
+
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/all")
+    public Page<OperationLog> all(@RequestBody PageQuery pageQuery) {
+        return operationLogRepo.findAll(toSpecification(pageQuery,OperationLog.class), toPageRequest(pageQuery));
+    }
+
+    @GetMapping("/get/{id}")
+    public OperationLog get(@PathVariable Long id) {
+        return operationLogRepo.findById(id).orElseThrow(new BusinessException("无记录"));
+    }
+
+    @PostMapping("/del/{id}")
+    public void del(@PathVariable Long id) {
+        operationLogRepo.deleteById(id);
+    }
+
+    @GetMapping("/excel")
+    @ResponseBody
+    public void excel(HttpServletResponse response, PageQuery pageQuery) throws IOException {
+        List<OperationLog> data = all(pageQuery).getContent();
+        ExcelUtils.export(response, data);
+    }
+}
+

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
src/main/resources/genjson/CountryPatent.json


+ 34 - 0
src/main/vue/src/components/Workflow.vue

@@ -0,0 +1,34 @@
+<template>
+    <div class="workflow-box">
+        <div class="workflow">
+            <div class="top">
+                <div class="name">国内申请</div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+export default {
+    name: 'Workflow',
+    props: {
+        info: {
+            type: Object,
+            default: () => {
+                return {};
+            }
+        }
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.workflow-box {
+    flex-grow: 1;
+    padding: 20px;
+    display: flex;
+}
+.workflow {
+    background-color: #fff;
+}
+</style>

+ 1 - 1
src/main/vue/src/components/domesticPatent/BaseInfo.vue

@@ -40,7 +40,7 @@
                         </el-select>
                     </el-form-item>
                     <el-form-item prop="uwNo" label="寰球案号">
-                        <el-input v-model="formData.uwNo" disabledÎ></el-input>
+                        <el-input v-model="formData.uwNo" disabled></el-input>
                     </el-form-item>
                     <el-form-item prop="clientPartnerId" label="客户">
                         <el-select

+ 1 - 1
src/main/vue/src/components/fee/FeeList.vue

@@ -23,7 +23,7 @@
             <el-table-column prop="patentPartner" label="专利权人" min-width="120px"> </el-table-column>
             <el-table-column prop="payPartner" label="支付对象" min-width="120px"> </el-table-column>
             <el-table-column prop="amount" label="金额" min-width="120px"> </el-table-column>
-            <el-table-column prop="currencyMaintenanceId" label="币种" min-width="100px"> </el-table-column>
+            <el-table-column prop="currency" label="币种" min-width="100px"> </el-table-column>
             <el-table-column prop="paymentDeadline" label="支付期限" min-width="100px"> </el-table-column>
             <el-table-column prop="bill" label="账单" min-width="100px"> </el-table-column>
             <el-table-column prop="billImg" label="账单图片" min-width="100px">

+ 313 - 0
src/main/vue/src/components/internationalPatent/BaseInfo.vue

@@ -0,0 +1,313 @@
+<template>
+    <div class="edit-view__content-wrapper">
+        <div class="edit-view__content-section" :class="{ bottomPad: otherShow }">
+            <divider collapse :showMore.sync="baseShow" />
+            <el-form
+                :model="formData"
+                :rules="rules"
+                ref="form"
+                label-width="200px"
+                label-position="right"
+                size="small"
+                style="width: 100%"
+                inline
+                center
+            >
+                <div class="base-item" v-show="baseShow">
+                    <el-form-item prop="name" label="专利名称">
+                        <el-input v-model="formData.name" style="width: 600px" @change="submit"></el-input>
+                    </el-form-item>
+                    <el-form-item prop="applyStatus" label="案件状态">
+                        <el-select v-model="formData.applyStatus" disabled clearable filterable placeholder="请选择">
+                            <el-option
+                                v-for="item in statusOptions"
+                                :key="item.value"
+                                :label="item.label"
+                                :value="item.value"
+                            >
+                            </el-option>
+                        </el-select>
+                    </el-form-item>
+                    <el-form-item prop="type" label="专利类型">
+                        <el-select v-model="formData.type" clearable filterable placeholder="请选择">
+                            <el-option
+                                v-for="item in typeOptions"
+                                :key="item.value"
+                                :label="item.label"
+                                :value="item.value"
+                            >
+                            </el-option>
+                        </el-select>
+                    </el-form-item>
+                    <el-form-item prop="uwNo" label="寰球案号">
+                        <el-input v-model="formData.uwNo" disabled></el-input>
+                    </el-form-item>
+                    <el-form-item prop="clientPartnerId" label="客户">
+                        <el-select
+                            style="width: 200px"
+                            v-model="formData.clientPartnerId"
+                            clearable
+                            filterable
+                            placeholder="请选择"
+                        >
+                            <el-option
+                                v-for="item in clientPartnerIdOptions"
+                                :key="item.value"
+                                :label="item.label"
+                                :value="item.value"
+                            >
+                            </el-option>
+                        </el-select>
+                    </el-form-item>
+
+                    <el-form-item prop="supplierNo" label="供应商案号">
+                        <el-input v-model="formData.supplierNo"></el-input>
+                    </el-form-item>
+
+                    <el-form-item prop="supplierPartnerId" label="供应商">
+                        <el-select
+                            style="width: 200px"
+                            v-model="formData.supplierPartnerId"
+                            clearable
+                            filterable
+                            placeholder="请选择"
+                        >
+                            <el-option
+                                v-for="item in supplierPartnerIdOptions"
+                                :key="item.value"
+                                :label="item.label"
+                                :value="item.value"
+                            >
+                            </el-option>
+                        </el-select>
+                    </el-form-item>
+
+                    <el-form-item prop="pctApplyNo" label="PCT申请号">
+                        <el-input v-model="formData.pctApplyNo"></el-input>
+                    </el-form-item>
+
+                    <el-form-item prop="pctApplyDate" label="PCT申请日">
+                        <el-date-picker
+                            v-model="formData.pctApplyDate"
+                            type="date"
+                            value-format="yyyy-MM-dd"
+                            placeholder="选择日期"
+                        >
+                        </el-date-picker>
+                    </el-form-item>
+
+                    <el-form-item prop="supplierSubmitPeriod" label="供应商提交期限">
+                        <el-date-picker
+                            v-model="formData.supplierSubmitPeriod"
+                            type="date"
+                            value-format="yyyy-MM-dd"
+                            placeholder="选择日期"
+                        >
+                        </el-date-picker>
+                    </el-form-item>
+
+                    <el-form-item prop="officialPeriod" label="官方期限">
+                        <el-date-picker
+                            v-model="formData.officialPeriod"
+                            type="date"
+                            value-format="yyyy-MM-dd"
+                            placeholder="选择日期"
+                        >
+                        </el-date-picker>
+                    </el-form-item>
+
+                    <el-form-item prop="actualOfficialAmount" label="官费实际金额">
+                        <el-input type="number" v-model="formData.actualOfficialAmount"></el-input>
+                    </el-form-item>
+                </div>
+
+                <divider collapse topLine :showMore.sync="personShow">申请人及发明人 </divider>
+                <div class="base-item" v-show="personShow">
+                    <el-form-item prop="applicantName" label="申请人名称" class="input-pre-zh">
+                        <el-input style="width: 236px;" v-model="formData.applicantName" placeholder="请输入中文名称">
+                            <template #prepend>中</template></el-input
+                        >
+                    </el-form-item>
+                    <el-form-item prop="applicantEnName" label="英文名称" label-width="125px" class="input-pre-en">
+                        <el-input style="width: 236px;" v-model="formData.applicantEnName" placeholder="请输入英文名称">
+                            <template #prepend>英</template></el-input
+                        >
+                    </el-form-item>
+
+                    <el-form-item
+                        style="margin-bottom:10px;"
+                        prop="applicantAddress"
+                        label="申请人地址"
+                        class="input-pre-zh error-end"
+                    >
+                        <el-input style="width:600px;" v-model="formData.applicantAddress" placeholder="请输入中文地址">
+                            <template #prepend>中</template>
+                        </el-input>
+                    </el-form-item>
+                    <el-form-item prop="applicantEnAddress" label=" " class="input-pre-en  error-end">
+                        <el-input
+                            style="width:600px;"
+                            v-model="formData.applicantEnAddress"
+                            placeholder="请输入英文地址"
+                        >
+                            <template #prepend>英</template>
+                        </el-input>
+                    </el-form-item>
+                    <el-form-item
+                        style="margin-bottom:10px;"
+                        prop="inventorName"
+                        label="发明人姓名"
+                        class="input-pre-zh  error-end"
+                    >
+                        <el-input style="width:600px;" v-model="formData.inventorName" placeholder="请输入中文名称">
+                            <template #prepend>中</template>
+                        </el-input>
+                    </el-form-item>
+                    <el-form-item prop="inventorEnName" label=" " class="input-pre-en  error-end">
+                        <el-input style="width:600px;" v-model="formData.inventorEnName" placeholder="请输入英文名称">
+                            <template #prepend>英</template>
+                        </el-input>
+                    </el-form-item>
+                </div>
+                <divider collapse topLine :showMore.sync="otherShow">优先权信息 </divider>
+                <div class="base-item" v-show="otherShow">
+                    <el-form-item prop="priorityNo" label="优先权号">
+                        <el-input v-model="formData.priorityNo" placeholder="请输入..."></el-input>
+                    </el-form-item>
+
+                    <el-form-item prop="priorityDate" label="优先权日">
+                        <el-date-picker
+                            v-model="formData.priorityDate"
+                            type="date"
+                            value-format="yyyy-MM-dd"
+                            placeholder="选择日期"
+                        >
+                        </el-date-picker>
+                    </el-form-item>
+                    <el-form-item prop="priorityCountry" label="优先权国别">
+                        <el-input v-model="formData.priorityCountry" placeholder="请输入..."></el-input>
+                    </el-form-item>
+                </div>
+            </el-form>
+        </div>
+    </div>
+</template>
+<script>
+import domesticPatent from '@/mixins/domesticPatent';
+
+export default {
+    name: 'DomesticPatentEdit',
+    mixins: [domesticPatent],
+    created() {
+        this.$http
+            .post('/partner/all', { size: 1000, query: { del: false } }, { body: 'json' })
+            .then(res => {
+                if (res.content.length > 0) {
+                    this.clientPartnerIdOptions = res.content
+                        .filter(item => {
+                            return item.type === 'CLIENT';
+                        })
+                        .map(item => {
+                            return {
+                                label: item.name,
+                                value: item.id
+                            };
+                        });
+                    this.supplierPartnerIdOptions = res.content
+                        .filter(item => {
+                            return item.type === 'SUPPLIER';
+                        })
+                        .map(item => {
+                            return {
+                                label: item.name,
+                                value: item.id
+                            };
+                        });
+                }
+            })
+            .catch(e => {
+                console.log(e);
+                this.$message.error(e.error);
+            });
+    },
+    props: {
+        info: {
+            type: Object,
+            default: () => {
+                return {};
+            }
+        }
+    },
+    data() {
+        return {
+            saving: false,
+            formData: {},
+            rules: {},
+            clientPartnerIdOptions: [],
+            supplierPartnerIdOptions: [],
+            personShow: true,
+            baseShow: true,
+            otherShow: true,
+            boolOptions: [
+                {
+                    label: '是',
+                    value: true
+                },
+                {
+                    label: '否',
+                    value: false
+                }
+            ]
+        };
+    },
+    methods: {
+        init() {
+            this.formData = { ...this.info };
+        },
+        onSave() {
+            this.$refs.form.validate(valid => {
+                if (valid) {
+                    this.submit();
+                } else {
+                    return false;
+                }
+            });
+        },
+        submit() {
+            let data = { ...this.formData };
+
+            this.$emit('submit', data);
+        },
+        onDelete() {
+            this.$alert('删除将无法恢复,确认要删除么?', '警告', { type: 'error' })
+                .then(() => {
+                    return this.$http.post(`/domesticPatent/del/${this.formData.id}`);
+                })
+                .then(() => {
+                    this.$message.success('删除成功');
+                    this.$router.go(-1);
+                })
+                .catch(e => {
+                    if (e !== 'cancel') {
+                        console.log(e);
+                        this.$message.error((e || {}).error || '删除失败');
+                    }
+                });
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+.base-item {
+    width: 800px;
+    padding-right: 200px;
+    margin: 0 auto;
+}
+
+.edit-view .edit-view__content-wrapper .edit-view__content-section {
+    padding-bottom: 0px;
+    &.bottomPad {
+        padding-bottom: 20px;
+    }
+}
+</style>

+ 86 - 0
src/main/vue/src/components/internationalPatent/MaintainCase.vue

@@ -0,0 +1,86 @@
+<template>
+    <el-dialog title="维护案件信息" :visible.sync="show" destroy-on-close center width="600px">
+        <el-form
+            hide-required-asterisk
+            :model="form"
+            :rules="rules"
+            ref="form"
+            label-width="140px"
+            style="padding-right: 130px"
+        >
+            <el-form-item prop="pctApplyNo" label="PCT申请号">
+                <el-input v-model="form.pctApplyNo" placeholder="请输入..."></el-input>
+            </el-form-item>
+
+            <el-form-item prop="pctApplyDate" label="PCT申请日">
+                <el-date-picker
+                    v-model="form.pctApplyDate"
+                    type="date"
+                    value-format="yyyy-MM-dd"
+                    placeholder="选择日期"
+                >
+                </el-date-picker>
+            </el-form-item>
+            <el-form-item prop="actualOfficialAmount" label="官费实际金额">
+                <el-input type="number" v-model="form.actualOfficialAmount" placeholder="请输入..."></el-input>
+            </el-form-item>
+
+            <el-form-item>
+                <el-button style="width: 150px" size="normal" type="primary" @click="onSubmit">提交</el-button>
+                <el-button style="width: 120px" size="normal" @click="show = false">取消</el-button>
+            </el-form-item>
+        </el-form>
+    </el-dialog>
+</template>
+
+<script>
+import logoPatent from '@/mixins/logoPatent';
+export default {
+    mixins: [logoPatent],
+    props: {
+        info: {}
+    },
+    data() {
+        return {
+            form: {},
+            show: false,
+            rules: {
+                pctApplyNo: { required: true, message: '请输入PCT申请号', trigger: 'blur' },
+                pctApplyDate: { required: true, message: '请选择PCT申请日', trigger: 'change' },
+                actualOfficialAmount: { required: true, message: '请选择官费实际金额', trigger: 'change' }
+            },
+            supplierPartnerIdOptions: []
+        };
+    },
+    methods: {
+        onSubmit() {
+            this.$refs.form.validate(valid => {
+                if (valid) {
+                    this.submit();
+                } else {
+                    return false;
+                }
+            });
+        },
+        submit() {
+            let info = { ...this.info };
+            info.pctApplyNo = this.form.pctApplyNo;
+            info.pctApplyDate = this.form.pctApplyDate;
+            info.actualOfficialAmount = this.form.actualOfficialAmount;
+
+            info.workflow = 'OFFICIAL_CIRCULATION';
+
+            this.$emit('submit', info);
+            this.show = false;
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+.el-select {
+    width: 100%;
+}
+.el-date-editor.el-input {
+    width: 100%;
+}
+</style>

+ 140 - 0
src/main/vue/src/components/internationalPatent/OfficeAttachment.vue

@@ -0,0 +1,140 @@
+/* eslint-disable vue/valid-v-model */
+<template>
+    <el-dialog title="上传官文流转附件" :visible.sync="show" destroy-on-close center width="600px">
+        <el-form
+            hide-required-asterisk
+            :model="form"
+            :rules="rules"
+            ref="form"
+            label-width="140px"
+            style="padding-right: 130px"
+        >
+            <template v-for="(item, index) in attachments">
+                <el-form-item :label="`附件${index + 1}`" :prop="`attachment${index + 1}`" :key="index">
+                    <el-input
+                        size="mini"
+                        v-model="item.attachmentName"
+                        placeholder="请输入附件名称"
+                        clearable
+                    ></el-input>
+
+                    <attachment-upload :value="item" @input="changeVal" :fileSize.sync="item.size"></attachment-upload>
+
+                    <div style="margin-top:20px" v-if="index !== 0">
+                        <el-button type="danger" size="mini" @click="del(index)">删除</el-button>
+                    </div>
+                </el-form-item>
+            </template>
+            <el-form-item label=" ">
+                <el-button type="primary" size="mini" plain @click="add">新增</el-button>
+            </el-form-item>
+
+            <el-form-item>
+                <el-button style="width: 150px" size="normal" type="primary" @click="onSubmit">提交</el-button>
+                <el-button style="width: 120px" size="normal" @click="show = false">取消</el-button>
+            </el-form-item>
+        </el-form>
+    </el-dialog>
+</template>
+
+<script>
+import logoPatent from '@/mixins/logoPatent';
+import { th } from 'date-fns/locale';
+export default {
+    mixins: [logoPatent],
+    props: {
+        info: {}
+    },
+    data() {
+        return {
+            attachments: [{ attachmentName: '', fileName: '', url: '', remark: '', size: '', index: 0 }],
+            show: false
+        };
+    },
+    computed: {
+        form() {
+            const list = [...this.attachments];
+            let form = {};
+            list.forEach((item, index) => {
+                let info = { ...item };
+                delete info.index;
+                form[`attachment${index + 1}`] = info;
+            });
+            return form;
+        },
+        rules() {
+            const list = [...this.attachments];
+            let form = {};
+            list.forEach((item, index) => {
+                form[`attachment${index + 1}`] = {
+                    validator: (rule, value, callback) => {
+                        if (!value.url) {
+                            callback(new Error('请上传附件' + (index + 1)));
+                        } else {
+                            callback();
+                        }
+                    },
+                    trigger: 'change'
+                };
+            });
+            return form;
+        }
+    },
+    methods: {
+        onSubmit() {
+            this.$refs.form.validate(valid => {
+                if (valid) {
+                    this.submit();
+                } else {
+                    return false;
+                }
+            });
+        },
+        submit() {
+            let info = { ...this.info };
+            let list = [...this.attachments];
+
+            list.forEach(item => {
+                let _item = { ...item };
+                delete item.index;
+                this.$emit('uploadAttement', _item);
+            });
+
+            info.workflow = 'SUPPLEMENTARY_REPLY';
+            this.$emit('submit', info);
+            this.show = false;
+        },
+        changeVal(val) {
+            let list = [...this.attachments];
+            list[val.index] = val;
+            this.attachments = list;
+        },
+        add() {
+            this.$refs.form.validate(valid => {
+                if (valid) {
+                    let list = [...this.attachments];
+                    list.push({ attachmentName: '', fileName: '', url: '', remark: '', size: '', index: list.length });
+                    this.attachments = list;
+                } else {
+                    return false;
+                }
+            });
+        },
+        del(index) {
+            this.$alert('删除将无法恢复,确认要删除么?', '警告', { type: 'error' }).then(() => {
+                let list = [...this.attachments];
+                list.splice(index, 1);
+                this.attachments = list;
+            });
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+.el-select {
+    width: 100%;
+}
+.el-date-editor.el-input {
+    width: 100%;
+}
+</style>

+ 103 - 0
src/main/vue/src/components/internationalPatent/Reply.vue

@@ -0,0 +1,103 @@
+<template>
+    <el-dialog title="上传补正答复信息" :visible.sync="show" destroy-on-close center width="600px">
+        <el-form
+            hide-required-asterisk
+            :model="form"
+            :rules="rules"
+            ref="form"
+            label-width="140px"
+            style="padding-right: 130px"
+        >
+            <el-form-item prop="officialPeriod" label="官方期限">
+                <el-date-picker
+                    v-model="form.officialPeriod"
+                    type="date"
+                    value-format="yyyy-MM-dd"
+                    placeholder="选择日期"
+                >
+                </el-date-picker>
+            </el-form-item>
+            <el-form-item prop="submitPeriod" label="内部期限">
+                <el-date-picker
+                    v-model="form.submitPeriod"
+                    type="date"
+                    value-format="yyyy-MM-dd"
+                    placeholder="选择日期"
+                >
+                </el-date-picker>
+            </el-form-item>
+            <el-form-item label="通知书官文" prop="attachment1">
+                <attachment-upload
+                    v-model="form.attachment1"
+                    :fileSize.sync="form.attachment1.size"
+                ></attachment-upload>
+            </el-form-item>
+
+            <el-form-item>
+                <el-button style="width: 150px" size="normal" type="primary" @click="onSubmit">提交</el-button>
+                <el-button style="width: 120px" size="normal" @click="show = false">取消</el-button>
+            </el-form-item>
+        </el-form>
+    </el-dialog>
+</template>
+
+<script>
+import logoPatent from '@/mixins/logoPatent';
+export default {
+    mixins: [logoPatent],
+    props: {
+        info: {}
+    },
+    data() {
+        return {
+            form: {
+                attachment1: { attachmentName: '通知书官文', fileName: '', url: '', remark: '', size: '' }
+            },
+            show: false,
+            rules: {
+                attachment1: {
+                    validator: (rule, value, callback) => {
+                        if (!value.url) {
+                            callback(new Error('请上传通知书官文'));
+                        } else {
+                            callback();
+                        }
+                    },
+                    trigger: 'change'
+                },
+                officialPeriod: { required: true, message: '请选择官方期限', trigger: 'change' },
+                submitPeriod: { required: true, message: '请选择内部期限', trigger: 'change' }
+            }
+        };
+    },
+    methods: {
+        onSubmit() {
+            this.$refs.form.validate(valid => {
+                if (valid) {
+                    this.submit();
+                } else {
+                    return false;
+                }
+            });
+        },
+        submit() {
+            let info = { ...this.info };
+
+            this.$emit('uploadAttement', this.form.attachment1);
+            info.officialPeriod = this.form.officialPeriod;
+            info.submitPeriod = this.form.submitPeriod;
+            info.workflow = 'REPLY_SUBMISSION';
+            this.$emit('submit', info);
+            this.show = false;
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+.el-select {
+    width: 100%;
+}
+.el-date-editor.el-input {
+    width: 100%;
+}
+</style>

+ 85 - 0
src/main/vue/src/components/internationalPatent/ReplyResult.vue

@@ -0,0 +1,85 @@
+<template>
+    <el-dialog title="确认答复状态" :visible.sync="show" destroy-on-close center width="600px">
+        <el-form
+            hide-required-asterisk
+            :model="form"
+            :rules="rules"
+            ref="form"
+            label-width="140px"
+            style="padding-right: 130px"
+        >
+            <el-form-item prop="replyStatus" label="答复意见状态">
+                <el-input v-model="form.replyStatus"></el-input>
+            </el-form-item>
+
+            <el-form-item label="是否继续官文流转" prop="officialCirculation">
+                <el-radio-group v-model="form.officialCirculation">
+                    <el-radio :label="true"> 是 </el-radio>
+                    <el-radio :label="false"> 否 </el-radio>
+                </el-radio-group>
+            </el-form-item>
+
+            <el-form-item>
+                <el-button style="width: 150px" size="normal" type="primary" @click="onSubmit">提交</el-button>
+                <el-button style="width: 120px" size="normal" @click="show = false">取消</el-button>
+            </el-form-item>
+        </el-form>
+    </el-dialog>
+</template>
+
+<script>
+import logoPatent from '@/mixins/logoPatent';
+export default {
+    mixins: [logoPatent],
+    props: {
+        info: {}
+    },
+    data() {
+        return {
+            form: {
+                officialCirculation: false
+            },
+            show: false,
+            rules: {
+                replyStatus: { required: true, message: '请选择授权办登通知日', trigger: 'blur' },
+                officialCirculation: { required: true, message: '请选择授权办登通知日', trigger: 'change' }
+            }
+        };
+    },
+    methods: {
+        onSubmit() {
+            this.$refs.form.validate(valid => {
+                if (valid) {
+                    this.submit();
+                } else {
+                    return false;
+                }
+            });
+        },
+        submit() {
+            let info = { ...this.info };
+
+            info.replyStatus = this.form.replyStatus;
+            info.officialCirculation = this.form.officialCirculation;
+
+            if (info.officialCirculation) {
+                info.workflow = 'OFFICIAL_CIRCULATION';
+            } else {
+                info.workflow = 'COMPLETED';
+                //否回答复通知
+            }
+
+            this.$emit('submit', info);
+            this.show = false;
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+.el-form-tips {
+    font-size: 12px;
+    color: #d75e41;
+    line-height: 17px;
+    margin-top: 18px;
+}
+</style>

+ 72 - 0
src/main/vue/src/components/internationalPatent/replySubmissions.vue

@@ -0,0 +1,72 @@
+<template>
+    <el-dialog title="上传答复意见书" :visible.sync="show" destroy-on-close center width="600px">
+        <el-form
+            hide-required-asterisk
+            :model="form"
+            :rules="rules"
+            ref="form"
+            label-width="140px"
+            style="padding-right: 130px"
+        >
+            <el-form-item label="答复意见书" prop="attachment1">
+                <attachment-upload
+                    v-model="form.attachment1"
+                    :fileSize.sync="form.attachment1.size"
+                ></attachment-upload>
+            </el-form-item>
+
+            <el-form-item>
+                <el-button style="width: 150px" size="normal" type="primary" @click="onSubmit">提交</el-button>
+                <el-button style="width: 120px" size="normal" @click="show = false">取消</el-button>
+            </el-form-item>
+        </el-form>
+    </el-dialog>
+</template>
+
+<script>
+import logoPatent from '@/mixins/logoPatent';
+export default {
+    mixins: [logoPatent],
+    props: {
+        info: {}
+    },
+    data() {
+        return {
+            form: {
+                attachment1: { attachmentName: '答复意见书', fileName: '', url: '', remark: '', size: '' }
+            },
+            show: false,
+            rules: {
+                attachment1: {
+                    validator: (rule, value, callback) => {
+                        if (!value.url) {
+                            callback(new Error('请上传答复意见书'));
+                        } else {
+                            callback();
+                        }
+                    },
+                    trigger: 'change'
+                }
+            }
+        };
+    },
+    methods: {
+        onSubmit() {
+            this.$refs.form.validate(valid => {
+                if (valid) {
+                    this.submit();
+                } else {
+                    return false;
+                }
+            });
+        },
+        submit() {
+            let info = { ...this.info };
+            this.$emit('uploadAttement', this.form.attachment1);
+            info.workflow = 'CONFIRM_REPLY';
+            this.$emit('submit', info);
+            this.show = false;
+        }
+    }
+};
+</script>

+ 84 - 0
src/main/vue/src/mixins/internationalPatent.js

@@ -0,0 +1,84 @@
+export default {
+    data() {
+        return {
+            statusOptions: [
+                {
+                    label: '申请阶段',
+                    value: 'APPLY_STAGE',
+                    type: '',
+                    workflows: [
+                        { label: '待添加供应商', value: 'ADD_SUPPLIERS' },
+                        { label: '待提交供应商材料', value: 'SUPPLIER_MATERIALS' },
+                        { label: '维护案件信息', value: 'MAINTAIN_CASE' },
+                        { label: '待官文流转', value: 'OFFICIAL_CIRCULATION' }
+                    ]
+                },
+                {
+                    label: '实审阶段',
+                    value: 'SUBSTANTIVE_STAGE',
+                    type: 'warning',
+                    workflows: [
+                        { label: '待补正答复', value: 'SUPPLEMENTARY_REPLY' },
+                        { label: '待上传答复意见书', value: 'REPLY_SUBMISSION' }
+                    ]
+                },
+                {
+                    label: '复审阶段',
+                    value: 'REVIEW_STAGE',
+                    type: 'warning',
+                    workflows: [{ label: '待确认答复状态', value: 'CONFIRM_REPLY' }]
+                },
+                {
+                    label: '已完成',
+                    value: 'COMPLETED',
+                    type: 'end',
+                    workflows: [{ label: '已完成', value: 'COMPLETED' }]
+                }
+            ],
+            typeOptions: [
+                { label: '发明专利', value: 'INVENTION' },
+                { label: '实用新型专利', value: 'UTILITY_MODEL' },
+                { label: '外观设计专利', value: 'APPEARANCE_DESIGN' }
+            ]
+        };
+    },
+    computed: {
+        workflowOptions() {
+            return [...this.statusOptions]
+                .map(item => {
+                    return item.workflows;
+                })
+                .flat();
+        }
+    },
+    methods: {
+        applyStatusFormatter(row, column, cellValue, index) {
+            let selectedOption = this.statusOptions.find(i => i.value === cellValue);
+            if (selectedOption) {
+                return selectedOption.label;
+            }
+            return '';
+        },
+        typeFormatter(row, column, cellValue, index) {
+            let selectedOption = this.typeOptions.find(i => i.value === cellValue);
+            if (selectedOption) {
+                return selectedOption.label;
+            }
+            return '';
+        },
+        statusFormatter(row, column, cellValue, index) {
+            let selectedOption = this.statusOptions.find(i => i.value === cellValue);
+            if (selectedOption) {
+                return selectedOption.label;
+            }
+            return '';
+        },
+        workflowFormatter(row, column, cellValue, index) {
+            let selectedOption = this.workflowOptions.find(i => i.value === cellValue);
+            if (selectedOption) {
+                return selectedOption.label;
+            }
+            return '';
+        }
+    }
+};

+ 2 - 2
src/main/vue/src/plugins/http.js

@@ -5,8 +5,8 @@ import qs from 'qs';
 let baseUrl = 'http://localhost:8080';
 switch (process.env.NODE_ENV) {
     case 'development':
-        // baseUrl = 'http://uwip.izouma.com';
-        baseUrl = 'http://localhost:8080';
+        baseUrl = 'http://uwip.izouma.com';
+        // baseUrl = 'http://192.168.50.190:8080';
         break;
     case 'test':
         baseUrl = 'http://localhost:8080';

+ 43 - 0
src/main/vue/src/router.js

@@ -258,6 +258,15 @@ const router = new Router({
                         title: '国内专利申请'
                     }
                 },
+                {
+                    path: '/internationalPatentAdd',
+                    name: 'internationalPatentAdd',
+                    component: () =>
+                        import(/* webpackChunkName: "internationalPatentEdit" */ '@/views/InternationalPatentAdd.vue'),
+                    meta: {
+                        title: '新增国际申请专利'
+                    }
+                },
                 {
                     path: '/internationalPatentEdit',
                     name: 'InternationalPatentEdit',
@@ -275,6 +284,40 @@ const router = new Router({
                     meta: {
                         title: '国际专利申请'
                     }
+                },
+                {
+                    path: '/countryPatentEdit',
+                    name: 'CountryPatentEdit',
+                    component: () =>
+                        import(/* webpackChunkName: "countryPatentEdit" */ '@/views/CountryPatentEdit.vue'),
+                    meta: {
+                        title: '国家专利申请编辑'
+                    }
+                },
+                {
+                    path: '/countryPatentList',
+                    name: 'CountryPatentList',
+                    component: () =>
+                        import(/* webpackChunkName: "countryPatentList" */ '@/views/CountryPatentList.vue'),
+                    meta: {
+                        title: '国家专利申请'
+                    }
+                },
+                {
+                    path: '/operationLogList',
+                    name: 'OperationLogList',
+                    component: () => import(/* webpackChunkName: "operationLogList" */ '@/views/OperationLogList.vue'),
+                    meta: {
+                        title: '操作日志'
+                    }
+                },
+                {
+                    path: '/exceptionLogList',
+                    name: 'ExceptionLogList',
+                    component: () => import(/* webpackChunkName: "exceptionLogList" */ '@/views/ExceptionLogList.vue'),
+                    meta: {
+                        title: '异常日志'
+                    }
                 }
                 /**INSERT_LOCATION**/
             ]

+ 8 - 0
src/main/vue/src/styles/app.less

@@ -422,6 +422,14 @@ li {
         color: #eead81;
     }
 }
+
+.error-end {
+    .el-form-item__error {
+        top: 11px;
+        left: calc(100% + 10px);
+        white-space: nowrap;
+    }
+}
 .edit-tabs {
     flex-grow: 1;
     .flex-col();

+ 237 - 0
src/main/vue/src/views/CountryPatentEdit.vue

@@ -0,0 +1,237 @@
+<template>
+    <div class="edit-view">
+        <page-title>
+            <el-button @click="$router.go(-1)">取消</el-button>
+            <el-button @click="del" :loading="$store.state.fetchingData" type="danger" v-if="formData.id">
+                删除
+            </el-button>
+            <el-button @click="onSave" :loading="$store.state.fetchingData" type="primary">保存</el-button>
+        </page-title>
+        <div class="edit-view__content-wrapper">
+            <div class="edit-view__content-section">
+                <divider />
+                <el-form
+                    :model="formData"
+                    :rules="rules"
+                    ref="form"
+                    label-width="108px"
+                    label-position="right"
+                    size="small"
+                    style="max-width: 500px;"
+                >
+                    <el-form-item prop="workflow" label="流程">
+                        <el-select v-model="formData.workflow" clearable filterable placeholder="请选择">
+                            <el-option
+                                v-for="item in workflowOptions"
+                                :key="item.value"
+                                :label="item.label"
+                                :value="item.value"
+                            >
+                            </el-option>
+                        </el-select>
+                    </el-form-item>
+                    <el-form-item prop="country" label="进入国家">
+                        <el-select v-model="formData.country" clearable filterable placeholder="请选择">
+                            <el-option
+                                v-for="item in countryOptions"
+                                :key="item.value"
+                                :label="item.label"
+                                :value="item.value"
+                            >
+                            </el-option>
+                        </el-select>
+                    </el-form-item>
+                    <el-form-item prop="applyRoute" label="申请途径">
+                        <el-select v-model="formData.applyRoute" clearable filterable placeholder="请选择">
+                            <el-option
+                                v-for="item in applyRouteOptions"
+                                :key="item.value"
+                                :label="item.label"
+                                :value="item.value"
+                            >
+                            </el-option>
+                        </el-select>
+                    </el-form-item>
+                    <el-form-item prop="pctApplyNo" label="pct申请号" v-if="formData.applyRoute == 'COUNTRY'">
+                        <el-input v-model="formData.pctApplyNo"></el-input>
+                    </el-form-item>
+                    <el-form-item prop="pctApplyDate" label="pct申请日" v-if="formData.applyRoute == 'COUNTRY'">
+                        <el-input v-model="formData.pctApplyDate"></el-input>
+                    </el-form-item>
+                    <el-form-item prop="pctPublicNo" label="pct公开号" v-if="formData.applyRoute == 'COUNTRY'">
+                        <el-input v-model="formData.pctPublicNo"></el-input>
+                    </el-form-item>
+                    <el-form-item prop="pctPublicDate" label="pct公开日" v-if="formData.applyRoute == 'COUNTRY'">
+                        <el-input v-model="formData.pctPublicDate"></el-input>
+                    </el-form-item>
+                    <el-form-item prop="grantNo" label="授权号">
+                        <el-input v-model="formData.grantNo"></el-input>
+                    </el-form-item>
+                    <el-form-item prop="grantDate" label="授权日">
+                        <el-date-picker
+                            v-model="formData.grantDate"
+                            type="date"
+                            value-format="yyyy-MM-dd"
+                            placeholder="选择日期"
+                        >
+                        </el-date-picker>
+                    </el-form-item>
+                    <el-form-item prop="translateWord" label="翻译字数">
+                        <el-input v-model="formData.translateWord"></el-input>
+                    </el-form-item>
+                    <el-form-item prop="translationLanguage" label="翻译语种">
+                        <el-input v-model="formData.translationLanguage"></el-input>
+                    </el-form-item>
+                    <el-form-item prop="unitPrice" label="单价/千字">
+                        <el-input-number type="number" v-model="formData.unitPrice"></el-input-number>
+                    </el-form-item>
+                    <el-form-item prop="totalPrice" label="总价">
+                        <el-input-number type="number" v-model="formData.totalPrice"></el-input-number>
+                    </el-form-item>
+                    <el-form-item prop="translationPeriod" label="翻译交期">
+                        <el-date-picker
+                            v-model="formData.translationPeriod"
+                            type="date"
+                            value-format="yyyy-MM-dd"
+                            placeholder="选择日期"
+                        >
+                        </el-date-picker>
+                    </el-form-item>
+                    <el-form-item prop="decideReply" label="是否决定答复">
+                        <el-switch v-model="formData.decideReply"></el-switch>
+                    </el-form-item>
+                    <el-form-item prop="isClientReady" label="准备答复意见">
+                        <el-switch v-model="formData.isClientReady"></el-switch>
+                    </el-form-item>
+                    <el-form-item prop="replyPassed" label="是否通过答复">
+                        <el-switch v-model="formData.replyPassed"></el-switch>
+                    </el-form-item>
+                    <el-form-item prop="registerPayPeriod" label="办登缴费期限">
+                        <el-date-picker
+                            v-model="formData.registerPayPeriod"
+                            type="date"
+                            value-format="yyyy-MM-dd"
+                            placeholder="选择日期"
+                        >
+                        </el-date-picker>
+                    </el-form-item>
+                    <el-form-item class="form-submit">
+                        <el-button @click="onSave" :loading="saving" size="default" type="primary">保存 </el-button>
+                        <el-button @click="onDelete" :loading="saving" size="default" type="danger" v-if="formData.id"
+                            >删除
+                        </el-button>
+                        <el-button @click="$router.go(-1)" size="default">取消</el-button>
+                    </el-form-item>
+                </el-form>
+            </div>
+        </div>
+    </div>
+</template>
+<script>
+export default {
+    name: 'CountryPatentEdit',
+    created() {
+        if (this.$route.query.id) {
+            this.$http
+                .get('countryPatent/get/' + this.$route.query.id)
+                .then(res => {
+                    this.formData = res;
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.$message.error(e.error);
+                });
+        }
+        this.$http
+            .post('/maintenance/byDesc', { description: 'Country' })
+            .then(res => {
+                if (res[0].children.length > 0) {
+                    res[0].children.forEach(item => {
+                        this.countryOptions.push({
+                            label: item.name,
+                            value: item.name
+                        });
+                    });
+                }
+            })
+            .catch(e => {
+                console.log(e);
+                this.$message.error(e.error);
+            });
+    },
+    data() {
+        return {
+            saving: false,
+            formData: {},
+            rules: {},
+            workflowOptions: [
+                { label: '待申请翻译文稿', value: 'APPLY_TRANSLATION' },
+                { label: '待上传翻译文稿', value: 'TRANSLATION_DOCUMENTS' },
+                { label: '待上传翻译定稿', value: 'FINALIZED_TRANSLATION' },
+                { label: '待添加供应商', value: 'ADD_SUPPLIERS' },
+                { label: '待提交供应商材料', value: 'SUPPLIER_MATERIALS' },
+                { label: '待维护案件信息', value: 'MAINTAIN_CASE' },
+                { label: '待上传答复通知', value: 'REPLY_NOTIFICATION' },
+                { label: '待确定答复意向', value: 'DETERMINED_REPLY' },
+                { label: '不答复终止', value: 'NO_REPLY' },
+                { label: '待上传答复意见书', value: 'UPLOADED_REPLY' },
+                { label: '待确定答复结果', value: 'RESPONSE_RESULT' },
+                { label: '待办登', value: 'PENDING_REGISTER' },
+                { label: '授权办登', value: 'AUTHORIZE_REGISTER' },
+                { label: '待维护授权信息', value: 'AUTHORIZATION_INFORMATION' },
+                { label: '已完成', value: 'COMPLETED' }
+            ],
+            countryOptions: [],
+            applyRouteOptions: [
+                { label: 'PCT国家阶段', value: 'COUNTRY' },
+                { label: '巴黎公约', value: 'SINGLE' }
+            ]
+        };
+    },
+    methods: {
+        onSave() {
+            this.$refs.form.validate(valid => {
+                if (valid) {
+                    this.submit();
+                } else {
+                    return false;
+                }
+            });
+        },
+        submit() {
+            let data = { ...this.formData };
+
+            this.saving = true;
+            this.$http
+                .post('/countryPatent/save', data, { body: 'json' })
+                .then(res => {
+                    this.saving = false;
+                    this.$message.success('成功');
+                    this.$router.go(-1);
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.saving = false;
+                    this.$message.error(e.error);
+                });
+        },
+        onDelete() {
+            this.$alert('删除将无法恢复,确认要删除么?', '警告', { type: 'error' })
+                .then(() => {
+                    return this.$http.post(`/countryPatent/del/${this.formData.id}`);
+                })
+                .then(() => {
+                    this.$message.success('删除成功');
+                    this.$router.go(-1);
+                })
+                .catch(e => {
+                    if (e !== 'cancel') {
+                        console.log(e);
+                        this.$message.error((e || {}).error || '删除失败');
+                    }
+                });
+        }
+    }
+};
+</script>
+<style lang="less" scoped></style>

+ 226 - 0
src/main/vue/src/views/CountryPatentList.vue

@@ -0,0 +1,226 @@
+<template>
+    <div class="list-view">
+        <page-title>
+            <el-button @click="addRow" type="primary" icon="el-icon-plus" :loading="downloading" class="filter-item">
+                新增
+            </el-button>
+            <el-button @click="download" icon="el-icon-upload2" :loading="downloading" class="filter-item">
+                导出
+            </el-button>
+        </page-title>
+        <div class="filters-container">
+            <el-input
+                placeholder="搜索..."
+                v-model="search"
+                clearable
+                class="filter-item search"
+                @keyup.enter.native="getData"
+            >
+                <el-button @click="getData" slot="append" icon="el-icon-search"> </el-button>
+            </el-input>
+        </div>
+        <el-table
+            :data="tableData"
+            row-key="id"
+            ref="table"
+            header-row-class-name="table-header-row"
+            header-cell-class-name="table-header-cell"
+            row-class-name="table-row"
+            cell-class-name="table-cell"
+            :height="tableHeight"
+        >
+            <el-table-column v-if="multipleMode" align="center" type="selection" width="50"> </el-table-column>
+            <el-table-column prop="id" label="ID" width="100"> </el-table-column>
+            <el-table-column prop="workflow" label="流程" :formatter="workflowFormatter"> </el-table-column>
+            <el-table-column prop="country" label="进入国家"> </el-table-column>
+            <el-table-column prop="applyRoute" label="申请途径" :formatter="applyRouteFormatter"> </el-table-column>
+            <el-table-column prop="pctApplyNo" label="pct申请号"> </el-table-column>
+            <el-table-column prop="pctApplyDate" label="pct申请日"> </el-table-column>
+            <el-table-column prop="pctPublicNo" label="pct公开号"> </el-table-column>
+            <el-table-column prop="pctPublicDate" label="pct公开日"> </el-table-column>
+            <el-table-column prop="grantNo" label="授权号"> </el-table-column>
+            <el-table-column prop="grantDate" label="授权日"> </el-table-column>
+            <el-table-column prop="translateWord" label="翻译字数"> </el-table-column>
+            <el-table-column prop="translationLanguage" label="翻译语种"> </el-table-column>
+            <el-table-column prop="unitPrice" label="单价/千字"> </el-table-column>
+            <el-table-column prop="totalPrice" label="总价"> </el-table-column>
+            <el-table-column prop="translationPeriod" label="翻译交期"> </el-table-column>
+            <el-table-column prop="decideReply" label="是否决定答复">
+                <template slot-scope="{ row }">
+                    <el-tag :type="row.decideReply ? '' : 'info'">{{ row.decideReply }}</el-tag>
+                </template>
+            </el-table-column>
+            <el-table-column prop="isClientReady" label="准备答复意见">
+                <template slot-scope="{ row }">
+                    <el-tag :type="row.isClientReady ? '' : 'info'">{{ row.isClientReady }}</el-tag>
+                </template>
+            </el-table-column>
+            <el-table-column prop="replyPassed" label="是否通过答复">
+                <template slot-scope="{ row }">
+                    <el-tag :type="row.replyPassed ? '' : 'info'">{{ row.replyPassed }}</el-tag>
+                </template>
+            </el-table-column>
+            <el-table-column prop="registerPayPeriod" label="办登缴费期限"> </el-table-column>
+            <el-table-column label="操作" align="center" fixed="right" min-width="150">
+                <template slot-scope="{ row }">
+                    <el-button @click="editRow(row)" type="primary" size="mini" plain>编辑</el-button>
+                    <el-button @click="deleteRow(row)" type="danger" size="mini" plain>删除</el-button>
+                </template>
+            </el-table-column>
+        </el-table>
+        <div class="pagination-wrapper">
+            <!-- <div class="multiple-mode-wrapper">
+                <el-button v-if="!multipleMode" @click="toggleMultipleMode(true)">批量编辑</el-button>
+                <el-button-group v-else>
+                    <el-button @click="operation1">批量操作1</el-button>
+                    <el-button @click="operation2">批量操作2</el-button>
+                    <el-button @click="toggleMultipleMode(false)">取消</el-button>
+                </el-button-group>
+            </div> -->
+            <el-pagination
+                background
+                @size-change="onSizeChange"
+                @current-change="onCurrentChange"
+                :current-page="page"
+                :page-sizes="[10, 20, 30, 40, 50]"
+                :page-size="pageSize"
+                layout="total, sizes, prev, pager, next, jumper"
+                :total="totalElements"
+            >
+            </el-pagination>
+        </div>
+    </div>
+</template>
+<script>
+import { mapState } from 'vuex';
+import pageableTable from '@/mixins/pageableTable';
+
+export default {
+    name: 'CountryPatentList',
+    mixins: [pageableTable],
+    data() {
+        return {
+            multipleMode: false,
+            search: '',
+            url: '/countryPatent/all',
+            downloading: false,
+            workflowOptions: [
+                { label: '待申请翻译文稿', value: 'APPLY_TRANSLATION' },
+                { label: '待上传翻译文稿', value: 'TRANSLATION_DOCUMENTS' },
+                { label: '待上传翻译定稿', value: 'FINALIZED_TRANSLATION' },
+                { label: '待添加供应商', value: 'ADD_SUPPLIERS' },
+                { label: '待提交供应商材料', value: 'SUPPLIER_MATERIALS' },
+                { label: '待维护案件信息', value: 'MAINTAIN_CASE' },
+                { label: '待上传答复通知', value: 'REPLY_NOTIFICATION' },
+                { label: '待确定答复意向', value: 'DETERMINED_REPLY' },
+                { label: '不答复终止', value: 'NO_REPLY' },
+                { label: '待上传答复意见书', value: 'UPLOADED_REPLY' },
+                { label: '待确定答复结果', value: 'RESPONSE_RESULT' },
+                { label: '待办登', value: 'PENDING_REGISTER' },
+                { label: '授权办登', value: 'AUTHORIZE_REGISTER' },
+                { label: '待维护授权信息', value: 'AUTHORIZATION_INFORMATION' },
+                { label: '已完成', value: 'COMPLETED' }
+            ],
+            applyRouteOptions: [
+                { label: 'COUNTRY', value: 'PCT国家阶段' },
+                { label: 'SINGLE', value: '巴黎公约' }
+            ]
+        };
+    },
+    computed: {
+        selection() {
+            return this.$refs.table.selection.map(i => i.id);
+        }
+    },
+    methods: {
+        workflowFormatter(row, column, cellValue, index) {
+            let selectedOption = this.workflowOptions.find(i => i.value === cellValue);
+            if (selectedOption) {
+                return selectedOption.label;
+            }
+            return '';
+        },
+        applyRouteFormatter(row, column, cellValue, index) {
+            let selectedOption = this.applyRouteOptions.find(i => i.value === cellValue);
+            if (selectedOption) {
+                return selectedOption.label;
+            }
+            return '';
+        },
+        beforeGetData() {
+            return { search: this.search };
+        },
+        toggleMultipleMode(multipleMode) {
+            this.multipleMode = multipleMode;
+            if (!multipleMode) {
+                this.$refs.table.clearSelection();
+            }
+        },
+        addRow() {
+            this.$router.push({
+                path: '/countryPatentEdit',
+                query: {
+                    ...this.$route.query
+                }
+            });
+        },
+        editRow(row) {
+            this.$router.push({
+                path: '/countryPatentEdit',
+                query: {
+                    id: row.id
+                }
+            });
+        },
+        download() {
+            this.downloading = true;
+            this.$axios
+                .get('/countryPatent/excel', {
+                    responseType: 'blob',
+                    params: { size: 10000 }
+                })
+                .then(res => {
+                    console.log(res);
+                    this.downloading = false;
+                    const downloadUrl = window.URL.createObjectURL(new Blob([res.data]));
+                    const link = document.createElement('a');
+                    link.href = downloadUrl;
+                    link.setAttribute('download', res.headers['content-disposition'].split('filename=')[1]);
+                    document.body.appendChild(link);
+                    link.click();
+                    link.remove();
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.downloading = false;
+                    this.$message.error(e.error);
+                });
+        },
+        operation1() {
+            this.$notify({
+                title: '提示',
+                message: this.selection
+            });
+        },
+        operation2() {
+            this.$message('操作2');
+        },
+        deleteRow(row) {
+            this.$alert('删除将无法恢复,确认要删除么?', '警告', { type: 'error' })
+                .then(() => {
+                    return this.$http.post(`/countryPatent/del/${row.id}`);
+                })
+                .then(() => {
+                    this.$message.success('删除成功');
+                    this.getData();
+                })
+                .catch(e => {
+                    if (e !== 'cancel') {
+                        this.$message.error(e.error);
+                    }
+                });
+        }
+    }
+};
+</script>
+<style lang="less" scoped></style>

+ 4 - 1
src/main/vue/src/views/DomesticPatentEdit.vue

@@ -42,7 +42,9 @@
             <el-tab-pane label="费用信息" name="third">
                 <fee-list ref="feeList" :info="formData"></fee-list>
             </el-tab-pane>
-            <!-- <el-tab-pane label="流程信息" name="fourth"></el-tab-pane> -->
+            <!-- <el-tab-pane label="流程信息" name="fourth">
+                <workflow ref="workflow" :info="formData"></workflow>
+            </el-tab-pane> -->
         </el-tabs>
         <attachment-add ref="attachmentAdd" :info="formData" @refreash="init"></attachment-add>
         <fee-add ref="feeAdd" isLogoPatent :info="formData" @refreash="init"></fee-add>
@@ -111,6 +113,7 @@ import Register from '../components/domesticPatent/Register.vue';
 import RegisterPayment from '../components/domesticPatent/RegisterPayment.vue';
 import RegisterComplate from '../components/domesticPatent/RegisterComplate.vue';
 import AnnualFee from '../components/domesticPatent/AnnualFee.vue';
+import Workflow from '../components/Workflow.vue';
 export default {
     name: 'DomesticPatentEdit',
     mixins: [domesticPatent],

+ 194 - 0
src/main/vue/src/views/ExceptionLogList.vue

@@ -0,0 +1,194 @@
+<template>
+    <div class="list-view">
+        <page-title name="异常日志">
+            <el-button @click="addRow" type="primary" icon="el-icon-plus" :loading="downloading" class="filter-item">
+                新增
+            </el-button>
+            <el-button @click="download" icon="el-icon-upload2" :loading="downloading" class="filter-item">
+                导出
+            </el-button>
+        </page-title>
+        <div class="filters-container">
+            <el-input
+                placeholder="搜索..."
+                v-model="search"
+                clearable
+                class="filter-item search"
+                @keyup.enter.native="getData"
+            >
+                <el-button @click="getData" slot="append" icon="el-icon-search"> </el-button>
+            </el-input>
+        </div>
+        <el-table
+            :data="tableData"
+            row-key="id"
+            ref="table"
+            header-row-class-name="table-header-row"
+            header-cell-class-name="table-header-cell"
+            row-class-name="table-row"
+            cell-class-name="table-cell"
+            :height="tableHeight"
+        >
+            <el-table-column v-if="multipleMode" align="center" type="selection" width="50"> </el-table-column>
+            <el-table-column prop="id" label="ID" width="100"> </el-table-column>
+            <el-table-column prop="name" label="异常名称"> </el-table-column>
+            <el-table-column prop="type" label="操作类型"> </el-table-column>
+            <el-table-column prop="userId" label="用户ID"> </el-table-column>
+            <el-table-column prop="username" label="用户名"> </el-table-column>
+            <el-table-column prop="desc" label="描述"> </el-table-column>
+            <el-table-column prop="reqMethod" label="调用方法"> </el-table-column>
+            <el-table-column prop="reqUrl" label="请求地址"> </el-table-column>
+            <el-table-column prop="reqParams" label="请求参数"> </el-table-column>
+            <el-table-column prop="reqIp" label="请求IP"> </el-table-column>
+            <el-table-column prop="resp" label="返回结果"> </el-table-column>
+            <el-table-column prop="time" label="操作时间"> </el-table-column>
+            <el-table-column prop="message" label="异常消息"> </el-table-column>
+            <el-table-column prop="stackTrace" label="错误追踪"> </el-table-column>
+            <el-table-column label="操作" align="center" fixed="right" min-width="150">
+                <template slot-scope="{ row }">
+                    <el-button @click="editRow(row)" type="primary" size="mini" plain>编辑</el-button>
+                    <el-button @click="deleteRow(row)" type="danger" size="mini" plain>删除</el-button>
+                </template>
+            </el-table-column>
+        </el-table>
+        <div class="pagination-wrapper">
+            <!-- <div class="multiple-mode-wrapper">
+                <el-button v-if="!multipleMode" @click="toggleMultipleMode(true)">批量编辑</el-button>
+                <el-button-group v-else>
+                    <el-button @click="operation1">批量操作1</el-button>
+                    <el-button @click="operation2">批量操作2</el-button>
+                    <el-button @click="toggleMultipleMode(false)">取消</el-button>
+                </el-button-group>
+            </div> -->
+            <el-pagination
+                background
+                @size-change="onSizeChange"
+                @current-change="onCurrentChange"
+                :current-page="page"
+                :page-sizes="[10, 20, 30, 40, 50]"
+                :page-size="pageSize"
+                layout="total, sizes, prev, pager, next, jumper"
+                :total="totalElements"
+            >
+            </el-pagination>
+        </div>
+        <el-dialog :visible.sync="showResp" title="返回结果">
+            <pre
+                >{{ resp }}
+           </pre
+            >
+        </el-dialog>
+    </div>
+</template>
+<script>
+import { mapState } from 'vuex';
+import pageableTable from '@/mixins/pageableTable';
+
+export default {
+    name: 'ExceptionLogList',
+    mixins: [pageableTable],
+    data() {
+        return {
+            multipleMode: false,
+            search: '',
+            url: '/exceptionLog/all',
+            downloading: false,
+            sortStr: '',
+            resp: '',
+            showResp: false
+        };
+    },
+    computed: {
+        selection() {
+            return this.$refs.table.selection.map(i => i.id);
+        }
+    },
+    methods: {
+        beforeGetData() {
+            if (this.search) {
+                return { search: this.search };
+            }
+        },
+        toggleMultipleMode(multipleMode) {
+            this.multipleMode = multipleMode;
+            if (!multipleMode) {
+                this.$refs.table.clearSelection();
+            }
+        },
+        addRow() {
+            this.$router.push({
+                path: '/exceptionLogEdit',
+                query: {
+                    ...this.$route.query
+                }
+            });
+        },
+        editRow(row) {
+            this.$router.push({
+                path: '/exceptionLogEdit',
+                query: {
+                    id: row.id
+                }
+            });
+        },
+        download() {
+            this.downloading = true;
+            this.$axios
+                .get('/exceptionLog/excel', {
+                    responseType: 'blob',
+                    params: { size: 10000 }
+                })
+                .then(res => {
+                    console.log(res);
+                    this.downloading = false;
+                    const downloadUrl = window.URL.createObjectURL(new Blob([res.data]));
+                    const link = document.createElement('a');
+                    link.href = downloadUrl;
+                    link.setAttribute('download', res.headers['content-disposition'].split('filename=')[1]);
+                    document.body.appendChild(link);
+                    link.click();
+                    link.remove();
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.downloading = false;
+                    this.$message.error(e.error);
+                });
+        },
+        operation1() {
+            this.$notify({
+                title: '提示',
+                message: this.selection
+            });
+        },
+        operation2() {
+            this.$message('操作2');
+        },
+        deleteRow(row) {
+            this.$alert('删除将无法恢复,确认要删除么?', '警告', { type: 'error' })
+                .then(() => {
+                    return this.$http.post(`/exceptionLog/del/${row.id}`);
+                })
+                .then(() => {
+                    this.$message.success('删除成功');
+                    this.getData();
+                })
+                .catch(e => {
+                    if (e !== 'cancel') {
+                        this.$message.error(e.error);
+                    }
+                });
+        },
+        viewResp(row) {
+            try {
+                this.resp = JSON.stringify(JSON.parse(row.resp), null, 4);
+            } catch (e) {
+                console.log(e);
+                this.resp = row.resp;
+            }
+            this.showResp = true;
+        }
+    }
+};
+</script>
+<style lang="less" scoped></style>

+ 313 - 0
src/main/vue/src/views/InternationalPatentAdd.vue

@@ -0,0 +1,313 @@
+<template>
+    <div class="edit-view">
+        <page-title> </page-title>
+        <div class="edit-view__content-wrapper">
+            <div class="edit-view__content-section">
+                <divider />
+                <el-form
+                    :model="formData"
+                    :rules="rules"
+                    ref="form"
+                    label-width="116px"
+                    label-position="right"
+                    size="small"
+                    style="width: 600px;"
+                    hide-required-asterisk
+                    inline
+                >
+                    <el-form-item prop="name" label="专利名称">
+                        <el-input style="width: 300px;" v-model="formData.name" placeholder="请输入"></el-input>
+                    </el-form-item>
+                    <el-form-item prop="type" label="专利类型">
+                        <el-radio-group v-model="formData.type">
+                            <el-radio :label="item.value" v-for="(item, index) in typeOptions" :key="index">
+                                {{ item.label }}
+                            </el-radio>
+                        </el-radio-group>
+                    </el-form-item>
+
+                    <el-form-item prop="clientPartnerId" label="选择客户">
+                        <el-select
+                            style="width: 300px;"
+                            v-model="formData.clientPartnerId"
+                            clearable
+                            filterable
+                            placeholder="请选择"
+                        >
+                            <el-option
+                                v-for="item in clientPartnerIdOptions"
+                                :key="item.value"
+                                :label="item.label"
+                                :value="item.value"
+                            >
+                            </el-option>
+                        </el-select>
+                    </el-form-item>
+
+                    <el-form-item prop="applicantName" label="申请人名称" class="input-pre-zh">
+                        <el-input style="width: 236px;" v-model="formData.applicantName" placeholder="请输入中文名称">
+                            <template #prepend>中</template></el-input
+                        >
+                    </el-form-item>
+                    <el-form-item prop="applicantEnName" label=" " label-width="10px" class="input-pre-en">
+                        <el-input style="width: 236px;" v-model="formData.applicantEnName" placeholder="请输入英文名称">
+                            <template #prepend>英</template></el-input
+                        >
+                    </el-form-item>
+
+                    <el-form-item
+                        style="margin-bottom:10px;"
+                        prop="applicantAddress"
+                        label="申请人地址"
+                        class="input-pre-zh error-end"
+                    >
+                        <el-input style="width:480px;" v-model="formData.applicantAddress" placeholder="请输入中文地址">
+                            <template #prepend>中</template>
+                        </el-input>
+                    </el-form-item>
+                    <el-form-item prop="applicantEnAddress" label=" " class="input-pre-en  error-end">
+                        <el-input
+                            style="width:480px;"
+                            v-model="formData.applicantEnAddress"
+                            placeholder="请输入英文地址"
+                        >
+                            <template #prepend>英</template>
+                        </el-input>
+                    </el-form-item>
+
+                    <el-form-item
+                        style="margin-bottom:10px;"
+                        prop="inventorName"
+                        label="发明人姓名"
+                        class="input-pre-zh  error-end"
+                    >
+                        <el-input style="width:480px;" v-model="formData.inventorName" placeholder="请输入中文名称">
+                            <template #prepend>中</template>
+                        </el-input>
+                    </el-form-item>
+                    <el-form-item prop="inventorEnName" label=" " class="input-pre-en  error-end">
+                        <el-input style="width:480px;" v-model="formData.inventorEnName" placeholder="请输入英文名称">
+                            <template #prepend>英</template>
+                        </el-input>
+                    </el-form-item>
+                    <el-form-item prop="priorityNo" label="优先权号">
+                        <el-input v-model="formData.priorityNo" placeholder="请输入..."></el-input>
+                    </el-form-item>
+
+                    <el-form-item prop="priorityDate" label="优先权日">
+                        <el-date-picker
+                            v-model="formData.priorityDate"
+                            type="date"
+                            value-format="yyyy-MM-dd"
+                            placeholder="选择日期"
+                        >
+                        </el-date-picker>
+                    </el-form-item>
+                    <el-form-item prop="priorityCountry" label="优先权国别">
+                        <el-input v-model="formData.priorityCountry" placeholder="请输入..."></el-input>
+                    </el-form-item>
+                    <el-form-item label="PCT申请信息表单" prop="attachment1">
+                        <attachment-upload
+                            v-model="formData.attachment1"
+                            :fileSize.sync="formData.attachment1.size"
+                        ></attachment-upload>
+                    </el-form-item>
+                    <el-form-item label="总委托书" prop="attachment2">
+                        <attachment-upload
+                            v-model="formData.attachment2"
+                            :fileSize.sync="formData.attachment2.size"
+                        ></attachment-upload>
+                    </el-form-item>
+                    <el-form-item label="申请文稿" prop="attachment3">
+                        <attachment-upload
+                            v-model="formData.attachment3"
+                            :fileSize.sync="formData.attachment3.size"
+                        ></attachment-upload>
+                    </el-form-item>
+                    <el-form-item label="自定义附件" prop="attachment4">
+                        <el-input
+                            size="mini"
+                            v-model="formData.attachment4.attachmentName"
+                            placeholder="请输入附件名称"
+                        ></el-input>
+
+                        <attachment-upload
+                            v-model="formData.attachment4"
+                            :fileSize.sync="formData.attachment4.size"
+                        ></attachment-upload>
+                    </el-form-item>
+
+                    <el-form-item class="form-submit" label=" ">
+                        <el-button @click="onSave" :loading="saving" size="default" type="primary">保存 </el-button>
+                        <el-button @click="onDelete" :loading="saving" size="default" type="danger" v-if="formData.id"
+                            >删除
+                        </el-button>
+                        <el-button @click="$router.go(-1)" size="default">取消</el-button>
+                    </el-form-item>
+                </el-form>
+            </div>
+        </div>
+    </div>
+</template>
+<script>
+export default {
+    name: 'InternationalPatentEdit',
+    created() {
+        this.$http
+            .post('/partner/all', { size: 1000, query: { del: false, type: 'CLIENT' } }, { body: 'json' })
+            .then(res => {
+                if (res.content.length > 0) {
+                    res.content.forEach(item => {
+                        this.clientPartnerIdOptions.push({
+                            label: item.name,
+                            value: item.id
+                        });
+                    });
+                }
+            })
+            .catch(e => {
+                console.log(e);
+                this.$message.error(e.error);
+            });
+    },
+    data() {
+        return {
+            saving: false,
+            formData: {
+                attachment1: { attachmentName: 'PCT申请信息表单', fileName: '', url: '', remark: '', size: '' },
+                attachment2: { attachmentName: '总委托书', fileName: '', url: '', remark: '', size: '' },
+                attachment3: { attachmentName: '申请文稿', fileName: '', url: '', remark: '', size: '' },
+                attachment4: { attachmentName: '', fileName: '', url: '', remark: '', size: '' }
+            },
+            rules: {
+                name: { required: true, message: '请输入专利名称', trigger: 'blur' },
+                type: { required: true, message: '请选择专利类型', trigger: 'change' },
+                clientPartnerId: { required: true, message: '请选择选择客户', trigger: 'change' },
+                applicantName: { required: true, message: '请输入申请人名称', trigger: 'blur' },
+                applicantEnName: { required: true, message: '请输入申请人英文名称', trigger: 'blur' },
+                applicantAddress: { required: true, message: '请输入申请人地址', trigger: 'blur' },
+                applicantEnAddress: { required: true, message: '请输入申请人英文地址', trigger: 'blur' },
+                inventorName: { required: true, message: '请输入发明人姓名', trigger: 'blur' },
+                inventorEnName: { required: true, message: '请输入发明人英文名称', trigger: 'blur' },
+                priorityNo: { required: true, message: '请输入优先权号', trigger: 'blur' },
+                priorityDate: { required: true, message: '请选择优先权日', trigger: 'change' },
+                priorityCountry: { required: true, message: '请输入优先权国别', trigger: 'blur' },
+                attachment1: {
+                    validator: (rule, value, callback) => {
+                        if (!value.url) {
+                            callback(new Error('请上传PCT申请信息表单'));
+                        } else {
+                            callback();
+                        }
+                    },
+                    trigger: 'change'
+                },
+                attachment2: {
+                    validator: (rule, value, callback) => {
+                        if (!value.url) {
+                            callback(new Error('请上传总委托书'));
+                        } else {
+                            callback();
+                        }
+                    },
+                    trigger: 'change'
+                },
+                attachment3: {
+                    validator: (rule, value, callback) => {
+                        if (!value.url) {
+                            callback(new Error('请上传申请文稿'));
+                        } else {
+                            callback();
+                        }
+                    },
+                    trigger: 'change'
+                },
+                attachment4: {
+                    validator: (rule, value, callback) => {
+                        if (!value.url && value.name) {
+                            callback(new Error('请上传' + value.name));
+                        } else if (value.url && !value.name) {
+                            callback(new Error('请输入附件名称'));
+                        } else {
+                            callback();
+                        }
+                    },
+                    trigger: 'change'
+                }
+            },
+            workflowOptions: [
+                { label: '待添加供应商', value: 'ADD_SUPPLIERS' },
+                { label: '待提交供应商材料', value: 'SUPPLIER_MATERIALS' },
+                { label: '待维护案件', value: 'MAINTAIN_CASE' },
+                { label: '待官文流转', value: 'OFFICIAL_CIRCULATION' },
+                { label: '待补正答复', value: 'SUPPLEMENTARY_REPLY' },
+                { label: '待上传答复意见书', value: 'REPLY_SUBMISSION' },
+                { label: '待确认答复状态', value: 'CONFIRM_REPLY' },
+                { label: '已完成', value: 'COMPLETED' }
+            ],
+            typeOptions: [
+                { label: '发明专利', value: 'INVENTION' },
+                { label: '实用新型专利', value: 'UTILITY_MODEL' },
+                { label: '外观设计专利', value: 'APPEARANCE_DESIGN' }
+            ],
+            clientPartnerIdOptions: []
+        };
+    },
+    methods: {
+        onSave() {
+            this.$refs.form.validate(valid => {
+                if (valid) {
+                    this.submit();
+                } else {
+                    return false;
+                }
+            });
+        },
+        submit() {
+            let data = { ...this.formData };
+
+            delete data.attachment1;
+            delete data.attachment2;
+            delete data.attachment3;
+            delete data.attachment4;
+
+            data.applyDate = format(new Date(), 'yyyy-MM-dd');
+            data.workflow = 'ADD_SUPPLIERS';
+
+            this.saving = true;
+            this.$http
+                .post('/internationalPatent/saveDTO', data, { body: 'json' })
+                .then(res => {
+                    this.uploadAttement(this.formData.attachment1, res.patentId);
+                    this.uploadAttement(this.formData.attachment2, res.patentId);
+                    this.uploadAttement(this.formData.attachment3, res.patentId);
+                    if (this.formData.attachment4.url) {
+                        this.uploadAttement(this.formData.attachment4, res.patentId);
+                    }
+                    this.saving = false;
+                    this.$message.success('成功');
+                    this.$router.go(-1);
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.saving = false;
+                    this.$message.error(e.error);
+                });
+        },
+        uploadAttement(info, patentId) {
+            let data = { ...info };
+            if (!data.url) {
+                return;
+            }
+            data.patentId = patentId;
+            data.userId = this.$store.state.userInfo.id;
+            data.version = 1;
+            if (data.size) {
+                data.size += 'KB';
+            }
+            this.$http.post('/attachment/save', data, { body: 'json' });
+        }
+    }
+};
+</script>
+<style lang="less" scoped></style>

+ 273 - 83
src/main/vue/src/views/InternationalPatentEdit.vue

@@ -1,82 +1,101 @@
 <template>
     <div class="edit-view">
         <page-title>
-            <el-button @click="$router.go(-1)">取消</el-button>
-            <el-button @click="del" :loading="$store.state.fetchingData" type="danger" v-if="formData.id">
-                删除
-            </el-button>
-            <el-button @click="onSave" :loading="$store.state.fetchingData" type="primary">保存</el-button>
+            <template slot="title">
+                专利详情:{{ formData.name }}
+                <el-tag :type="statusInfo.type" style="margin-left: 10px">
+                    {{ statusInfo.label }}
+                </el-tag>
+            </template>
         </page-title>
-        <div class="edit-view__content-wrapper">
-            <div class="edit-view__content-section">
-                <divider />
-                <el-form
-                    :model="formData"
-                    :rules="rules"
-                    ref="form"
-                    label-width="136px"
-                    label-position="right"
-                    size="small"
-                    style="max-width: 500px;"
-                >
-                    <el-form-item prop="workflow" label="流程">
-                        <el-select v-model="formData.workflow" clearable filterable placeholder="请选择">
-                            <el-option
-                                v-for="item in workflowOptions"
-                                :key="item.value"
-                                :label="item.label"
-                                :value="item.value"
-                            >
-                            </el-option>
-                        </el-select>
-                    </el-form-item>
-                    <el-form-item prop="pctApplyNo" label="pct申请号">
-                        <el-input v-model="formData.pctApplyNo"></el-input>
-                    </el-form-item>
-                    <el-form-item prop="pctApplyDate" label="pct申请日">
-                        <el-date-picker
-                            v-model="formData.pctApplyDate"
-                            type="date"
-                            value-format="yyyy-MM-dd"
-                            placeholder="选择日期"
-                        >
-                        </el-date-picker>
-                    </el-form-item>
-                    <el-form-item prop="actualOfficialAmount" label="官费实际金额">
-                        <el-input-number type="number" v-model="formData.actualOfficialAmount"></el-input-number>
-                    </el-form-item>
-                    <el-form-item prop="replyStatus" label="答复意见状态">
-                        <el-input v-model="formData.replyStatus"></el-input>
-                    </el-form-item>
-                    <el-form-item prop="officialCirculation" label="是否继续官文流转">
-                        <el-switch v-model="formData.officialCirculation"></el-switch>
-                    </el-form-item>
-                    <el-form-item class="form-submit">
-                        <el-button @click="onSave" :loading="saving" size="default" type="primary">保存 </el-button>
-                        <el-button @click="onDelete" :loading="saving" size="default" type="danger" v-if="formData.id"
-                            >删除
-                        </el-button>
-                        <el-button @click="$router.go(-1)" size="default">取消</el-button>
-                    </el-form-item>
-                </el-form>
+        <el-tabs class="edit-tabs" v-model="activeName" @tab-click="tabClick">
+            <div class="right-btns">
+                <!-- <el-button type="primary" size="small">新增答复</el-button> -->
+                <el-button type="primary" size="small" @click="$refs.feeAdd.init()">新增费用</el-button>
+                <el-button type="primary" size="small" @click="$refs.attachmentAdd.show = true">新增附件</el-button>
+                <!-- <el-button type="primary" size="small">分案/接续流程</el-button> -->
             </div>
-        </div>
+            <div class="tips" v-if="nowStatus && formData.applyStatus !== 'COMPLETED'">
+                <div class="tips-text">
+                    <span class="name">当前流程节点</span>
+                    <span class="val">{{ nowStatus }}</span>
+                </div>
+
+                <div class="tips-text">
+                    <span class="name">处理人</span>
+                    <span class="val">{{ user }}</span>
+                </div>
+
+                <div class="tips-text">
+                    <span class="name">处理截止日期</span>
+                    <span class="val">{{ date }}</span>
+                </div>
+
+                <el-button @click="action" type="text" size="small">立即处理</el-button>
+            </div>
+            <el-tab-pane label="基本信息" name="first">
+                <base-info ref="base" :info.sync="formData" @submit="submit"></base-info>
+            </el-tab-pane>
+            <el-tab-pane label="附件列表" name="second">
+                <attachment-list ref="attachmentList" :info="formData"></attachment-list>
+            </el-tab-pane>
+            <el-tab-pane label="费用信息" name="third">
+                <fee-list ref="feeList" :info="formData"></fee-list>
+            </el-tab-pane>
+            <!-- <el-tab-pane label="流程信息" name="fourth">
+                <workflow ref="workflow" :info="formData"></workflow>
+            </el-tab-pane> -->
+        </el-tabs>
+        <attachment-add ref="attachmentAdd" :info="formData" @refreash="init"></attachment-add>
+        <fee-add ref="feeAdd" isLogoPatent :info="formData" @refreash="init"></fee-add>
+
+        <maintain-case
+            ref="maintainCase"
+            :info="formData"
+            @submit="submit"
+            @uploadAttement="uploadAttement"
+        ></maintain-case>
+        <office-attachment
+            ref="officeAttachment"
+            :info="formData"
+            @submit="submit"
+            @uploadAttement="uploadAttement"
+        ></office-attachment>
+        <reply ref="reply" :info="formData" @submit="submit" @uploadAttement="uploadAttement"></reply>
+        <reply-submissions
+            ref="replySubmissions"
+            :info="formData"
+            @submit="submit"
+            @uploadAttement="uploadAttement"
+        ></reply-submissions>
+
+        <reply-result
+            ref="replyResult"
+            :info="formData"
+            @submit="submit"
+            @uploadAttement="uploadAttement"
+        ></reply-result>
     </div>
 </template>
 <script>
+import attachmentList from '../components/AttachmentList.vue';
+import AttachmentAdd from '../components/AttachmentAdd.vue';
+import FeeList from '../components/fee/FeeList.vue';
+import FeeAdd from '../components/fee/FeeAdd.vue';
+import internationalPatent from '@/mixins/internationalPatent';
+import BaseInfo from '../components/internationalPatent/BaseInfo.vue';
+import MaintainCase from '../components/internationalPatent/MaintainCase.vue';
+import Reply from '../components/internationalPatent/Reply.vue';
+import ReplySubmissions from '../components/internationalPatent/replySubmissions.vue';
+import ReplyResult from '../components/internationalPatent/ReplyResult.vue';
+import Workflow from '../components/Workflow.vue';
+import OfficeAttachment from '../components/internationalPatent/OfficeAttachment.vue';
 export default {
     name: 'InternationalPatentEdit',
+    mixins: [internationalPatent],
     created() {
         if (this.$route.query.id) {
-            this.$http
-                .get('internationalPatent/get/' + this.$route.query.id)
-                .then(res => {
-                    this.formData = res;
-                })
-                .catch(e => {
-                    console.log(e);
-                    this.$message.error(e.error);
-                });
+            this.getInfo();
         }
     },
     data() {
@@ -84,19 +103,93 @@ export default {
             saving: false,
             formData: {},
             rules: {},
-            workflowOptions: [
-                { label: '待添加供应商', value: 'ADD_SUPPLIERS' },
-                { label: '待提交供应商材料', value: 'SUPPLIER_MATERIALS' },
-                { label: '待维护案件', value: 'MAINTAIN_CASE' },
-                { label: '待官文流转', value: 'OFFICIAL_CIRCULATION' },
-                { label: '待补正答复', value: 'SUPPLEMENTARY_REPLY' },
-                { label: '待上传答复意见书', value: 'REPLY_SUBMISSION' },
-                { label: '待确认答复状态', value: 'CONFIRM_REPLY' },
-                { label: '已完成', value: 'COMPLETED' }
-            ]
+            clientPartnerIdOptions: [],
+            supplierPartnerIdOptions: [],
+            activeName: 'first'
         };
     },
+    computed: {
+        nowStatus() {
+            return this.workflowFormatter('', '', this.formData.workflow);
+        },
+        user() {
+            if (
+                this.formData.workflow === 'REPLY_SUBMISSION' ||
+                this.formData.workflow === 'PAYMENT_REGISTER' ||
+                this.formData.workflow === 'ANNUAL_FEE'
+            ) {
+                return '客户经理';
+            } else if (this.formData.workflow === 'REPLY_SUBMISSIONS') {
+                if (this.formData.isClientReady) {
+                    return '客户经理';
+                } else {
+                    return '项目经理';
+                }
+            } else if (this.formData.workflow) {
+                return '项目经理';
+            } else {
+                return '';
+            }
+        },
+        date() {
+            if (this.formData.workflow === 'SUPPLIER_MATERIALS') {
+                return this.formData.supplierSubmitPeriod;
+            } else if (this.formData.workflow === 'REPLY_SUBMISSION') {
+                return this.formData.submitPeriod;
+            } else {
+                return '无';
+            }
+        },
+        statusInfo() {
+            let info = [...this.statusOptions].find(item => {
+                return item.value === this.formData.applyStatus;
+            });
+
+            return (
+                info || {
+                    type: '',
+                    label: ''
+                }
+            );
+        }
+    },
     methods: {
+        applyStatusFormatter(status) {
+            let selectedOption = this.statusOptions.find(i => i.value === status);
+            if (selectedOption) {
+                return selectedOption;
+            } else {
+                return null;
+            }
+        },
+        getInfo() {
+            this.$http
+                .get('internationalPatent/getDTO/' + this.$route.query.id)
+                .then(res => {
+                    this.formData = res;
+                    this.$nextTick(() => {
+                        this.init();
+                    });
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.$message.error(e.error);
+                });
+        },
+        init() {
+            if (this.activeName === 'first') {
+                this.$refs.base.init();
+            } else if (this.activeName === 'second') {
+                this.$refs.attachmentList.init();
+            } else if (this.activeName === 'third') {
+                this.$refs.feeList.init();
+            }
+        },
+        tabClick(tab) {
+            this.$nextTick(() => {
+                this.init();
+            });
+        },
         onSave() {
             this.$refs.form.validate(valid => {
                 if (valid) {
@@ -106,16 +199,15 @@ export default {
                 }
             });
         },
-        submit() {
-            let data = { ...this.formData };
-
+        submit(info) {
+            let data = { ...info };
             this.saving = true;
             this.$http
-                .post('/internationalPatent/save', data, { body: 'json' })
+                .post('/internationalPatent/saveDTO', data, { body: 'json' })
                 .then(res => {
                     this.saving = false;
                     this.$message.success('成功');
-                    this.$router.go(-1);
+                    this.getInfo();
                 })
                 .catch(e => {
                     console.log(e);
@@ -138,8 +230,106 @@ export default {
                         this.$message.error((e || {}).error || '删除失败');
                     }
                 });
+        },
+        uploadAttement(info) {
+            let data = { ...info };
+            if (!data.url) {
+                return;
+            }
+            data.patentId = this.formData.patentId;
+            data.userId = this.$store.state.userInfo.id;
+            data.version = 1;
+            if (data.size) {
+                data.size += 'KB';
+            }
+            this.$http.post('/attachment/save', data, { body: 'json' });
+        },
+        action() {
+            if (this.formData.workflow === 'ADD_SUPPLIERS') {
+                this.$refs.addSupplierNo.show = true;
+            } else if (this.formData.workflow === 'SUPPLIER_MATERIALS') {
+                this.$refs.backSupplier.show = true;
+            } else if (this.formData.workflow === 'MAINTAIN_CASE') {
+                this.$refs.maintainCase.show = true;
+            } else if (this.formData.workflow === 'OFFICIAL_CIRCULATION') {
+                this.$refs.officeAttachment.show = true;
+            } else if (this.formData.workflow === 'SUPPLEMENTARY_REPLY') {
+                this.$refs.reply.show = true;
+            } else if (this.formData.workflow === 'REPLY_SUBMISSION') {
+                this.$refs.replySubmissions.show = true;
+            } else if (this.formData.workflow === 'CONFIRM_REPLY') {
+                this.$refs.replyResult.show = true;
+            }
         }
+    },
+    components: {
+        BaseInfo,
+        attachmentList,
+        AttachmentAdd,
+        FeeList,
+        FeeAdd,
+        MaintainCase,
+        Reply,
+        ReplySubmissions,
+        ReplyResult,
+        OfficeAttachment
     }
 };
 </script>
-<style lang="less" scoped></style>
+<style lang="less" scoped>
+.edit-tabs {
+    position: relative;
+
+    .right-btns {
+        position: absolute;
+        right: 20px;
+        top: -44px;
+        .el-button {
+            min-width: 100px;
+        }
+    }
+}
+
+.tips {
+    .flex();
+    height: 40px;
+    background: tint(@warn, 68%);
+    border: 1px solid @warn;
+    margin: 20px 20px 0;
+    padding: 0 20px;
+    position: relative;
+
+    .tips-text {
+        margin-right: 60px;
+        .name {
+            font-size: 12px;
+            color: #5e6166;
+            line-height: 22px;
+        }
+
+        .val {
+            font-size: 12px;
+            font-weight: bold;
+            color: @warn;
+            line-height: 22px;
+            margin-left: 10px;
+        }
+    }
+
+    .el-button {
+        position: absolute;
+        right: 20px;
+    }
+}
+</style>
+<style lang="less">
+.el-dialog {
+    .el-form {
+        .el-form-item {
+            &:last-child {
+                margin-top: 70px;
+            }
+        }
+    }
+}
+</style>

+ 145 - 0
src/main/vue/src/views/InternationalPatentEdit1.vue

@@ -0,0 +1,145 @@
+<template>
+    <div class="edit-view">
+        <page-title>
+            <el-button @click="$router.go(-1)">取消</el-button>
+            <el-button @click="del" :loading="$store.state.fetchingData" type="danger" v-if="formData.id">
+                删除
+            </el-button>
+            <el-button @click="onSave" :loading="$store.state.fetchingData" type="primary">保存</el-button>
+        </page-title>
+        <div class="edit-view__content-wrapper">
+            <div class="edit-view__content-section">
+                <divider />
+                <el-form
+                    :model="formData"
+                    :rules="rules"
+                    ref="form"
+                    label-width="136px"
+                    label-position="right"
+                    size="small"
+                    style="max-width: 500px;"
+                >
+                    <el-form-item prop="workflow" label="流程">
+                        <el-select v-model="formData.workflow" clearable filterable placeholder="请选择">
+                            <el-option
+                                v-for="item in workflowOptions"
+                                :key="item.value"
+                                :label="item.label"
+                                :value="item.value"
+                            >
+                            </el-option>
+                        </el-select>
+                    </el-form-item>
+                    <el-form-item prop="pctApplyNo" label="pct申请号">
+                        <el-input v-model="formData.pctApplyNo"></el-input>
+                    </el-form-item>
+                    <el-form-item prop="pctApplyDate" label="pct申请日">
+                        <el-date-picker
+                            v-model="formData.pctApplyDate"
+                            type="date"
+                            value-format="yyyy-MM-dd"
+                            placeholder="选择日期"
+                        >
+                        </el-date-picker>
+                    </el-form-item>
+                    <el-form-item prop="actualOfficialAmount" label="官费实际金额">
+                        <el-input-number type="number" v-model="formData.actualOfficialAmount"></el-input-number>
+                    </el-form-item>
+                    <el-form-item prop="replyStatus" label="答复意见状态">
+                        <el-input v-model="formData.replyStatus"></el-input>
+                    </el-form-item>
+                    <el-form-item prop="officialCirculation" label="是否继续官文流转">
+                        <el-switch v-model="formData.officialCirculation"></el-switch>
+                    </el-form-item>
+                    <el-form-item class="form-submit">
+                        <el-button @click="onSave" :loading="saving" size="default" type="primary">保存 </el-button>
+                        <el-button @click="onDelete" :loading="saving" size="default" type="danger" v-if="formData.id"
+                            >删除
+                        </el-button>
+                        <el-button @click="$router.go(-1)" size="default">取消</el-button>
+                    </el-form-item>
+                </el-form>
+            </div>
+        </div>
+    </div>
+</template>
+<script>
+export default {
+    name: 'InternationalPatentEdit',
+    created() {
+        if (this.$route.query.id) {
+            this.$http
+                .get('internationalPatent/get/' + this.$route.query.id)
+                .then(res => {
+                    this.formData = res;
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.$message.error(e.error);
+                });
+        }
+    },
+    data() {
+        return {
+            saving: false,
+            formData: {},
+            rules: {},
+            workflowOptions: [
+                { label: '待添加供应商', value: 'ADD_SUPPLIERS' },
+                { label: '待提交供应商材料', value: 'SUPPLIER_MATERIALS' },
+                { label: '待维护案件', value: 'MAINTAIN_CASE' },
+                { label: '待官文流转', value: 'OFFICIAL_CIRCULATION' },
+                { label: '待补正答复', value: 'SUPPLEMENTARY_REPLY' },
+                { label: '待上传答复意见书', value: 'REPLY_SUBMISSION' },
+                { label: '待确认答复状态', value: 'CONFIRM_REPLY' },
+                { label: '已完成', value: 'COMPLETED' }
+            ]
+        };
+    },
+    methods: {
+        onSave() {
+            this.$refs.form.validate(valid => {
+                if (valid) {
+                    this.submit();
+                } else {
+                    return false;
+                }
+            });
+        },
+        submit() {
+            let data = { ...this.formData };
+
+            this.saving = true;
+            this.$http
+                .post('/internationalPatent/save', data, { body: 'json' })
+                .then(res => {
+                    this.saving = false;
+                    this.$message.success('成功');
+                    this.$router.go(-1);
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.saving = false;
+                    this.$message.error(e.error);
+                });
+        },
+        onDelete() {
+            this.$alert('删除将无法恢复,确认要删除么?', '警告', { type: 'error' })
+                .then(() => {
+                    return this.$http.post(`/internationalPatent/del/${this.formData.id}`);
+                })
+                .then(() => {
+                    this.$message.success('删除成功');
+                    this.$router.go(-1);
+                })
+                .catch(e => {
+                    if (e !== 'cancel') {
+                        console.log(e);
+                        this.$message.error((e || {}).error || '删除失败');
+                    }
+                });
+        }
+    }
+};
+</script>
+<style lang="less" scoped></style>

+ 80 - 30
src/main/vue/src/views/InternationalPatentList.vue

@@ -18,6 +18,32 @@
             >
                 <el-button @click="getData" slot="append" icon="el-icon-search"> </el-button>
             </el-input>
+
+            <div class="filters-left">
+                <el-radio-group class="filters-item" v-model="applyStatus" size="mini" @change="refreash">
+                    <el-radio-button v-for="(item, index) in statusOptions" :key="index" :label="item.value">
+                        {{ item.label }}
+                    </el-radio-button>
+                </el-radio-group>
+
+                <el-select
+                    size="mini"
+                    class="filters-item"
+                    v-model="logoWorkflow"
+                    placeholder="筛选节点流程"
+                    clearable
+                    filterable
+                    @change="refreash"
+                >
+                    <el-option
+                        v-for="item in selectLogoWorkflowOptions"
+                        :key="item.value"
+                        :label="item.label"
+                        :value="item.value"
+                    >
+                    </el-option>
+                </el-select>
+            </div>
         </div>
         <el-table
             :data="tableData"
@@ -29,22 +55,30 @@
             cell-class-name="table-cell"
             :height="tableHeight"
         >
-            <el-table-column v-if="multipleMode" align="center" type="selection" width="50"> </el-table-column>
-            <el-table-column prop="id" label="ID" width="100"> </el-table-column>
-            <el-table-column prop="workflow" label="流程" :formatter="workflowFormatter"> </el-table-column>
-            <el-table-column prop="pctApplyNo" label="pct申请号"> </el-table-column>
-            <el-table-column prop="pctApplyDate" label="pct申请日"> </el-table-column>
-            <el-table-column prop="actualOfficialAmount" label="官费实际金额"> </el-table-column>
-            <el-table-column prop="replyStatus" label="答复意见状态"> </el-table-column>
-            <el-table-column prop="officialCirculation" label="是否继续官文流转">
+            <el-table-column align="center" type="selection" width="50"> </el-table-column>
+            <el-table-column prop="patent" label="案件状态">
                 <template slot-scope="{ row }">
-                    <el-tag :type="row.officialCirculation ? '' : 'info'">{{ row.officialCirculation }}</el-tag>
+                    <el-tag
+                        v-if="row.patent && row.patent.applyStatus"
+                        :type="applyStatusFormatter(row.patent.applyStatus).type"
+                        >{{ applyStatusFormatter(row.patent.applyStatus).label }}</el-tag
+                    >
                 </template>
             </el-table-column>
-            <el-table-column label="操作" align="center" fixed="right" min-width="150">
+            <el-table-column prop="patent.uwNo" min-width="140" label="寰球案号"> </el-table-column>
+            <el-table-column prop="patent.name" min-width="160" label="专利名称"> </el-table-column>
+            <el-table-column prop="workflow" min-width="120" label="当前流程" :formatter="workflowFormatter">
+            </el-table-column>
+            <el-table-column prop="pctApplyDate" label="pct申请日"> </el-table-column>
+            <el-table-column prop="pctApplyNo" label="pct申请号"> </el-table-column>
+            <el-table-column prop="patent.applyDate" min-width="100" label="申请日" :formatter="dateFormatter">
+            </el-table-column>
+            <el-table-column prop="patent.priorityDate" min-width="100" label="优先权日" :formatter="dateFormatter">
+            </el-table-column>
+
+            <el-table-column label="操作" align="center" fixed="right" min-width="80">
                 <template slot-scope="{ row }">
-                    <el-button @click="editRow(row)" type="primary" size="mini" plain>编辑</el-button>
-                    <el-button @click="deleteRow(row)" type="danger" size="mini" plain>删除</el-button>
+                    <el-button @click="editRow(row)" type="primary" size="mini" plain>查看详情</el-button>
                 </template>
             </el-table-column>
         </el-table>
@@ -74,34 +108,43 @@
 <script>
 import { mapState } from 'vuex';
 import pageableTable from '@/mixins/pageableTable';
-
+import internationalPatent from '@/mixins/internationalPatent';
 export default {
     name: 'InternationalPatentList',
-    mixins: [pageableTable],
+    mixins: [pageableTable, internationalPatent],
     data() {
         return {
             multipleMode: false,
             search: '',
-            url: '/internationalPatent/all',
+            url: '/internationalPatent/allDTO',
             downloading: false,
-            workflowOptions: [
-                { label: '待添加供应商', value: 'ADD_SUPPLIERS' },
-                { label: '待提交供应商材料', value: 'SUPPLIER_MATERIALS' },
-                { label: '待维护案件', value: 'MAINTAIN_CASE' },
-                { label: '待官文流转', value: 'OFFICIAL_CIRCULATION' },
-                { label: '待补正答复', value: 'SUPPLEMENTARY_REPLY' },
-                { label: '待上传答复意见书', value: 'REPLY_SUBMISSION' },
-                { label: '待确认答复状态', value: 'CONFIRM_REPLY' },
-                { label: '已完成', value: 'COMPLETED' }
-            ]
+            applyStatus: 'APPLY_STAGE',
+            logoWorkflow: ''
         };
     },
     computed: {
         selection() {
             return this.$refs.table.selection.map(i => i.id);
+        },
+        selectLogoWorkflowOptions() {
+            if (this.applyStatus) {
+                return [...this.statusOptions].find(item => {
+                    return item.value === this.applyStatus;
+                })?.workflows;
+            } else {
+                return this.workflowOptions;
+            }
         }
     },
     methods: {
+        applyStatusFormatter(status) {
+            let selectedOption = this.statusOptions.find(i => i.value === status);
+            if (selectedOption) {
+                return selectedOption;
+            } else {
+                return null;
+            }
+        },
         workflowFormatter(row, column, cellValue, index) {
             let selectedOption = this.workflowOptions.find(i => i.value === cellValue);
             if (selectedOption) {
@@ -110,7 +153,13 @@ export default {
             return '';
         },
         beforeGetData() {
-            return { search: this.search };
+            return {
+                search: this.search,
+                query: {
+                    applyStatus: this.applyStatus,
+                    workflow: this.logoWorkflow
+                }
+            };
         },
         toggleMultipleMode(multipleMode) {
             this.multipleMode = multipleMode;
@@ -120,10 +169,7 @@ export default {
         },
         addRow() {
             this.$router.push({
-                path: '/internationalPatentEdit',
-                query: {
-                    ...this.$route.query
-                }
+                path: '/internationalPatentAdd'
             });
         },
         editRow(row) {
@@ -181,6 +227,10 @@ export default {
                         this.$message.error(e.error);
                     }
                 });
+        },
+        refreash() {
+            this.page = 1;
+            this.getData();
         }
     }
 };

+ 2 - 0
src/main/vue/src/views/LogoPatentAdd.vue

@@ -154,6 +154,8 @@ export default {
             data.userId = this.$store.state.userInfo.id;
             data.applyStatus = 'APPLY_STAGE';
             delete data.attachment1;
+            let size = this.formData.attachment1.size;
+            this.formData.attachment1.size = parseFloat(size).toFixed(2) + 'KB';
             data.attachments = [{ ...this.formData.attachment1 }];
 
             this.saving = true;

+ 138 - 0
src/main/vue/src/views/OperationLogList.vue

@@ -0,0 +1,138 @@
+<template>
+    <div class="list-view">
+        <page-title name="操作日志">
+            <el-button @click="addRow" type="primary" icon="el-icon-plus" :loading="downloading" class="filter-item">
+                新增
+            </el-button>
+            <el-button @click="download" icon="el-icon-upload2" :loading="downloading" class="filter-item">
+                导出
+            </el-button>
+        </page-title>
+        <div class="filters-container">
+            <el-input
+                placeholder="搜索..."
+                v-model="search"
+                clearable
+                class="filter-item search"
+                @keyup.enter.native="getData"
+            >
+                <el-button @click="getData" slot="append" icon="el-icon-search"> </el-button>
+            </el-input>
+        </div>
+        <el-table
+            :data="tableData"
+            row-key="id"
+            ref="table"
+            header-row-class-name="table-header-row"
+            header-cell-class-name="table-header-cell"
+            row-class-name="table-row"
+            cell-class-name="table-cell"
+            :height="tableHeight"
+        >
+            <el-table-column prop="id" label="ID" width="100"> </el-table-column>
+            <el-table-column prop="name" label="操作名称" show-overflow-tooltip> </el-table-column>
+            <el-table-column prop="type" label="操作类型" show-overflow-tooltip> </el-table-column>
+            <el-table-column prop="userId" label="用户ID" show-overflow-tooltip> </el-table-column>
+            <el-table-column prop="username" label="用户名" show-overflow-tooltip> </el-table-column>
+            <el-table-column prop="desc" label="描述" show-overflow-tooltip> </el-table-column>
+            <el-table-column prop="reqMethod" label="调用方法" show-overflow-tooltip> </el-table-column>
+            <el-table-column prop="reqUrl" label="请求地址" show-overflow-tooltip> </el-table-column>
+            <el-table-column prop="reqParams" label="请求参数" show-overflow-tooltip> </el-table-column>
+            <el-table-column prop="reqIp" label="请求IP" show-overflow-tooltip> </el-table-column>
+            <el-table-column prop="resp" label="返回结果" align="center" width="80">
+                <template v-slot="{ row }">
+                    <el-button @click="viewResp(row)" type="text">查看</el-button>
+                </template>
+            </el-table-column>
+            <el-table-column prop="time" label="操作时间" width="150"> </el-table-column>
+        </el-table>
+        <div class="pagination-wrapper">
+            <!-- <div class="multiple-mode-wrapper">
+                <el-button v-if="!multipleMode" @click="toggleMultipleMode(true)">批量编辑</el-button>
+                <el-button-group v-else>
+                    <el-button @click="operation1">批量操作1</el-button>
+                    <el-button @click="operation2">批量操作2</el-button>
+                    <el-button @click="toggleMultipleMode(false)">取消</el-button>
+                </el-button-group>
+            </div> -->
+            <el-pagination
+                background
+                @size-change="onSizeChange"
+                @current-change="onCurrentChange"
+                :current-page="page"
+                :page-sizes="[10, 20, 30, 40, 50]"
+                :page-size="pageSize"
+                layout="total, sizes, prev, pager, next, jumper"
+                :total="totalElements"
+            >
+            </el-pagination>
+        </div>
+        <el-dialog :visible.sync="showResp" title="返回结果">
+            <pre
+                >{{ resp }}
+           </pre
+            >
+        </el-dialog>
+    </div>
+</template>
+<script>
+import { mapState } from 'vuex';
+import pageableTable from '@/mixins/pageableTable';
+
+export default {
+    name: 'OperationLogList',
+    mixins: [pageableTable],
+    data() {
+        return {
+            search: '',
+            url: '/operationLog/all',
+            downloading: false,
+            sortStr: 'time,desc',
+            resp: '',
+            showResp: false
+        };
+    },
+    computed: {},
+    methods: {
+        beforeGetData() {
+            if (this.search) {
+                return { search: this.search };
+            }
+        },
+        download() {
+            this.downloading = true;
+            this.$axios
+                .get('/operationLog/excel', {
+                    responseType: 'blob',
+                    params: { size: 10000 }
+                })
+                .then(res => {
+                    console.log(res);
+                    this.downloading = false;
+                    const downloadUrl = window.URL.createObjectURL(new Blob([res.data]));
+                    const link = document.createElement('a');
+                    link.href = downloadUrl;
+                    link.setAttribute('download', res.headers['content-disposition'].split('filename=')[1]);
+                    document.body.appendChild(link);
+                    link.click();
+                    link.remove();
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.downloading = false;
+                    this.$message.error(e.error);
+                });
+        },
+        viewResp(row) {
+            try {
+                this.resp = JSON.stringify(JSON.parse(row.resp), null, 4);
+            } catch (e) {
+                console.log(e);
+                this.resp = row.resp;
+            }
+            this.showResp = true;
+        }
+    }
+};
+</script>
+<style lang="less" scoped></style>

+ 44 - 0
src/test/java/com/izouma/uwip/service/CountryPatentServiceTest.java

@@ -0,0 +1,44 @@
+package com.izouma.uwip.service;
+
+import com.izouma.uwip.ApplicationTests;
+import com.izouma.uwip.domain.CountryPatent;
+import com.izouma.uwip.dto.CountryPatentDTO;
+import com.izouma.uwip.dto.PageQuery;
+import com.izouma.uwip.enums.ApplyRoute;
+import com.izouma.uwip.enums.PatentType;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.util.List;
+
+public class CountryPatentServiceTest extends ApplicationTests {
+
+    @Autowired
+    private CountryPatentService countryPatentService;
+
+    @Test
+    public void saveDTO() {
+        CountryPatentDTO dto = CountryPatentDTO.builder()
+                .name("视频监控分析法")
+                .type(PatentType.INVENTION)
+                .applyRoute(ApplyRoute.SINGLE)
+                .clientPartnerId(168L)
+                .country("韩国")
+                .applicantName("张三")
+                .applicantEnName("ZhangSan")
+                .applicantAddress("南京")
+                .applicantEnAddress("NanJing")
+                .inventorName("张三")
+                .inventorEnName("ZhangSan")
+                .build();
+        System.out.println(countryPatentService.saveDTO(dto, 1L));
+    }
+
+    @Test
+    public void allDTO() {
+        PageQuery pageQuery = new PageQuery();
+        pageQuery.getQuery().put("applyStatus","APPLY_STAGE");
+        List<CountryPatent> content = countryPatentService.allDTO(pageQuery).getContent();
+        content.forEach(System.out::println);
+    }
+}

+ 2 - 2
src/test/java/com/izouma/uwip/service/InternationalPatentServiceTest.java

@@ -54,8 +54,8 @@ public class InternationalPatentServiceTest {
     public void test() {
         PageQuery pageQuery = new PageQuery();
         Map<String, Object> query = pageQuery.getQuery();
-        query.put("applyStatus", "SUBSTANTIVE_STAGE");
+        query.put("applyStatus", "APPLY_STAGE");
         Page<InternationalPatent> all = internationalPatentService.allDTO(pageQuery);
-        System.out.println(all.getContent());
+        all.getContent().forEach(System.out::println);
     }
 }

+ 1 - 1
src/test/java/com/izouma/uwip/service/LogoPatentServiceTest.java

@@ -22,7 +22,7 @@ public class LogoPatentServiceTest extends ApplicationTests {
     @Test
     public void getUwNo() {
         LogoPatent patent = logoPatentRepo.findById(44L).orElseThrow(new BusinessException("wu"));
-        System.out.println(partnerService.getUwNo(patent.getClientPartnerId(), CaseType.LOGO, CaseStage.DOMESTIC, patent
+        System.out.println(partnerService.getUwNo(patent.getClientPartnerId(), CaseType.LOGO, CaseStage.DOMESTIC, null, patent
                 .getSort()));
     }
 }

+ 16 - 0
src/test/java/com/izouma/uwip/service/PatentServiceTest.java

@@ -0,0 +1,16 @@
+package com.izouma.uwip.service;
+
+import com.izouma.uwip.ApplicationTests;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+public class PatentServiceTest extends ApplicationTests {
+
+    @Autowired
+    private PatentService patentService;
+
+    @Test
+    public void total() {
+        System.out.println(patentService.total());
+    }
+}

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно