Parcourir la source

供给侧数据库设计

licailing il y a 4 ans
Parent
commit
8afbb57acf
24 fichiers modifiés avec 1239 ajouts et 5 suppressions
  1. 7 0
      pom.xml
  2. 13 0
      src/main/java/com/izouma/zhirongip/domain/Setting.java
  3. 80 0
      src/main/java/com/izouma/zhirongip/domain/supply/Copyright.java
  4. 88 0
      src/main/java/com/izouma/zhirongip/domain/supply/DeclassificationPatent.java
  5. 109 0
      src/main/java/com/izouma/zhirongip/domain/supply/GeneralPatent.java
  6. 90 0
      src/main/java/com/izouma/zhirongip/domain/supply/Logo.java
  7. 77 0
      src/main/java/com/izouma/zhirongip/domain/supply/SoftwareCopyright.java
  8. 78 0
      src/main/java/com/izouma/zhirongip/domain/supply/Technology.java
  9. 21 0
      src/main/java/com/izouma/zhirongip/enums/CommissionType.java
  10. 27 0
      src/main/java/com/izouma/zhirongip/enums/LawStatus.java
  11. 26 0
      src/main/java/com/izouma/zhirongip/enums/LawStatusGeneral.java
  12. 22 0
      src/main/java/com/izouma/zhirongip/enums/LogoType.java
  13. 22 0
      src/main/java/com/izouma/zhirongip/enums/OwnerType.java
  14. 17 0
      src/main/java/com/izouma/zhirongip/enums/PatentType.java
  15. 18 0
      src/main/java/com/izouma/zhirongip/enums/TradingMethod.java
  16. 23 0
      src/main/java/com/izouma/zhirongip/repo/SettingRepo.java
  17. 50 0
      src/main/java/com/izouma/zhirongip/service/SettingService.java
  18. 77 0
      src/main/java/com/izouma/zhirongip/web/SettingController.java
  19. 1 0
      src/main/resources/genjson/Setting.json
  20. 2 2
      src/main/resources/templates/ControllerTemplate.ftl
  21. 1 1
      src/main/resources/templates/ServiceTemplate.ftl
  22. 8 0
      src/main/vue/src/router.js
  23. 377 0
      src/main/vue/src/views/Settings.vue
  24. 5 2
      src/test/java/com/izouma/zhirongip/repo/UserRepoTest.java

+ 7 - 0
pom.xml

@@ -286,6 +286,13 @@
             <artifactId>pngquant4j</artifactId>
             <version>1.0</version>
         </dependency>
+
+        <!-- hutool -->
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.3.8</version>
+        </dependency>
     </dependencies>
 
 </project>

+ 13 - 0
src/main/java/com/izouma/zhirongip/domain/Setting.java

@@ -1,14 +1,24 @@
 package com.izouma.zhirongip.domain;
 
+import io.swagger.annotations.ApiModel;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
+import org.hibernate.annotations.Where;
+
+import javax.persistence.Entity;
+import javax.persistence.Transient;
+import java.util.ArrayList;
+import java.util.List;
 
 @Data
 @AllArgsConstructor
 @NoArgsConstructor
 @Builder
+@Entity
+@ApiModel(value = "参数设置")
+@Where(clause = "del = 0")
 public class Setting extends BaseEntity {
 
     private String name;
@@ -17,4 +27,7 @@ public class Setting extends BaseEntity {
 
     private int flag;
 
+    @Transient
+    private List<Setting> children = new ArrayList<>();
+
 }

+ 80 - 0
src/main/java/com/izouma/zhirongip/domain/supply/Copyright.java

@@ -0,0 +1,80 @@
+package com.izouma.zhirongip.domain.supply;
+
+import com.izouma.zhirongip.domain.BaseEntity;
+import com.izouma.zhirongip.enums.CommissionType;
+import com.izouma.zhirongip.enums.TradingMethod;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.NoArgsConstructor;
+import org.hibernate.annotations.Where;
+
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import java.time.LocalDate;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+//@Entity
+@ApiModel(value = "版权")
+@Where(clause = "del = 0")
+public class Copyright extends BaseEntity {
+    @ApiModelProperty(value = "作品名称")
+    private String name;
+
+    @ApiModelProperty(value = "登记号")
+    private String code;
+
+    @ApiModelProperty(value = "登记日期")
+    private LocalDate registrationTime;
+
+    /*
+    setting
+     */
+    @ApiModelProperty(value = "作品类型")
+    private Long workType;
+
+    @ApiModelProperty(value = "作者")
+    private String author;
+
+    @ApiModelProperty(value = "著作权人")
+    private String copyrightHolder;
+
+    @Enumerated(EnumType.STRING)
+    @ApiModelProperty(value = "交易方式")
+    private TradingMethod tradingMethod;
+
+    /*
+    (万元)
+     */
+    @ApiModelProperty(value = "期望价(万元)")
+    private String expectedPrice;
+
+    @ApiModelProperty(value = "面议")
+    private Boolean negotiateDirectly;
+
+    @ApiModelProperty(value = "底价(万元)")
+    private String basePrice;
+
+    @Enumerated(EnumType.STRING)
+    @ApiModelProperty(value = "佣金类型")
+    private CommissionType commissionType;
+
+    @ApiModelProperty(value = "佣金(万元)")
+    private String commission;
+
+    @ApiModelProperty(value = "联系人")
+    private String contact;
+
+    @ApiModelProperty(value = "电话")
+    private String phone;
+
+    @ApiModelProperty(value = "邮箱")
+    private String email;
+
+    @ApiModelProperty(value = "所在地区")
+    private String address;
+
+}

+ 88 - 0
src/main/java/com/izouma/zhirongip/domain/supply/DeclassificationPatent.java

@@ -0,0 +1,88 @@
+package com.izouma.zhirongip.domain.supply;
+
+import com.izouma.zhirongip.domain.BaseEntity;
+import com.izouma.zhirongip.enums.LawStatus;
+import com.izouma.zhirongip.enums.TradingMethod;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.NoArgsConstructor;
+import org.hibernate.annotations.Where;
+
+import javax.persistence.Column;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import java.time.LocalDate;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+//@Entity
+@ApiModel(value = "脱密专利")
+@Where(clause = "del = 0")
+public class DeclassificationPatent extends BaseEntity {
+
+    @ApiModelProperty(value = "专利名称")
+    private String name;
+
+    @ApiModelProperty(value = "申请号")
+    private String code;
+
+    @ApiModelProperty(value = "申请日期")
+    private LocalDate applyTime;
+
+    /*
+    setting
+     */
+    @ApiModelProperty(value = "行业分类")
+    private Long industryClass;
+
+    @ApiModelProperty(value = "IPC分类号")
+    private String ipc;
+
+    @Enumerated(EnumType.STRING)
+    @ApiModelProperty(value = "法律状态")
+    private LawStatus lawStatus;
+
+    @ApiModelProperty(value = "专利权人")
+    private String owner;
+
+    @ApiModelProperty(value = "摘要")
+    private String digest;
+
+    @Column(columnDefinition = "TEXT")
+    @ApiModelProperty(value = "说明书")
+    private String manual;
+
+    @ApiModelProperty(value = "专利附图")
+    private String img;
+
+    @Enumerated(EnumType.STRING)
+    @ApiModelProperty(value = "交易方式")
+    private TradingMethod tradingMethod;
+
+    /*
+    (万元)
+     */
+    @ApiModelProperty(value = "期望价(万元)")
+    private String expectedPrice;
+
+    @ApiModelProperty(value = "面议")
+    private Boolean negotiateDirectly;
+
+    @ApiModelProperty(value = "底价(万元)")
+    private String basePrice;
+
+    @ApiModelProperty(value = "联系人")
+    private String contact;
+
+    @ApiModelProperty(value = "电话")
+    private String phone;
+
+    @ApiModelProperty(value = "邮箱")
+    private String email;
+
+    @ApiModelProperty(value = "所在地区")
+    private String address;
+}

+ 109 - 0
src/main/java/com/izouma/zhirongip/domain/supply/GeneralPatent.java

@@ -0,0 +1,109 @@
+package com.izouma.zhirongip.domain.supply;
+
+import com.izouma.zhirongip.converter.StringArrayConverter;
+import com.izouma.zhirongip.domain.BaseEntity;
+import com.izouma.zhirongip.enums.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.NoArgsConstructor;
+import org.hibernate.annotations.Where;
+
+import javax.persistence.Column;
+import javax.persistence.Convert;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import java.time.LocalDate;
+import java.util.List;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+//@Entity
+@ApiModel(value = "普通专利")
+@Where(clause = "del = 0")
+public class GeneralPatent extends BaseEntity {
+    @ApiModelProperty(value = "专利名称")
+    private String name;
+
+    @ApiModelProperty(value = "申请号")
+    private String code;
+
+    @Enumerated(EnumType.STRING)
+    @ApiModelProperty(value = "专利类型")
+    private PatentType patentType;
+
+    @ApiModelProperty(value = "申请日期")
+    private LocalDate applyTime;
+
+    /*
+    setting
+     */
+    @ApiModelProperty(value = "行业分类")
+    private Long industryClass;
+
+    @ApiModelProperty(value = "IPC分类号")
+    private String ipc;
+
+    @Enumerated(EnumType.STRING)
+    @ApiModelProperty(value = "法律状态")
+    private LawStatusGeneral lawStatus;
+
+    @ApiModelProperty(value = "专利权人")
+    private String owner;
+
+    @Enumerated(EnumType.STRING)
+    @ApiModelProperty(value = "专利权人类型")
+    private OwnerType ownerType;
+
+    @ApiModelProperty(value = "发明人")
+    @Convert(converter = StringArrayConverter.class)
+    private List<String> inventor;
+
+    @ApiModelProperty(value = "摘要")
+    private String digest;
+
+    @Column(columnDefinition = "TEXT")
+    @ApiModelProperty(value = "说明书")
+    private String manual;
+
+    @ApiModelProperty(value = "专利附图")
+    private String img;
+
+    @Enumerated(EnumType.STRING)
+    @ApiModelProperty(value = "交易方式")
+    private TradingMethod tradingMethod;
+
+    /*
+    (万元)
+     */
+    @ApiModelProperty(value = "期望价(万元)")
+    private String expectedPrice;
+
+    @ApiModelProperty(value = "面议")
+    private Boolean negotiateDirectly;
+
+    @ApiModelProperty(value = "底价(万元)")
+    private String basePrice;
+
+    @Enumerated(EnumType.STRING)
+    @ApiModelProperty(value = "佣金类型")
+    private CommissionType commissionType;
+
+    @ApiModelProperty(value = "佣金(万元)")
+    private String commission;
+
+    @ApiModelProperty(value = "联系人")
+    private String contact;
+
+    @ApiModelProperty(value = "电话")
+    private String phone;
+
+    @ApiModelProperty(value = "邮箱")
+    private String email;
+
+    @ApiModelProperty(value = "所在地区")
+    private String address;
+
+}

+ 90 - 0
src/main/java/com/izouma/zhirongip/domain/supply/Logo.java

@@ -0,0 +1,90 @@
+package com.izouma.zhirongip.domain.supply;
+
+import com.izouma.zhirongip.converter.StringArrayConverter;
+import com.izouma.zhirongip.domain.BaseEntity;
+import com.izouma.zhirongip.enums.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.NoArgsConstructor;
+import org.hibernate.annotations.Where;
+
+import javax.persistence.Convert;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import java.time.LocalDate;
+import java.util.List;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+//@Entity
+@ApiModel(value = "商标")
+@Where(clause = "del = 0")
+public class Logo extends BaseEntity {
+    @ApiModelProperty(value = "商标名称")
+    private String name;
+
+    @ApiModelProperty(value = "申请号")
+    private String code;
+
+    @ApiModelProperty(value = "申请日期")
+    private LocalDate applyTime;
+
+    @Enumerated(EnumType.STRING)
+    @ApiModelProperty(value = "商标类型")
+    private LogoType logoType;
+
+    /*
+    setting
+     */
+    @ApiModelProperty(value = "所属分类")
+    private Long category;
+
+    @ApiModelProperty(value = "核定使用商品/服务项目")
+    @Convert(converter = StringArrayConverter.class)
+    private List<String>  servicesItem;
+
+    @ApiModelProperty(value = "商标注册人")
+    private String owner;
+
+    @ApiModelProperty(value = "商标图样")
+    private String img;
+
+    @Enumerated(EnumType.STRING)
+    @ApiModelProperty(value = "交易方式")
+    private TradingMethod tradingMethod;
+
+    /*
+    (万元)
+     */
+    @ApiModelProperty(value = "期望价(万元)")
+    private String expectedPrice;
+
+    @ApiModelProperty(value = "面议")
+    private Boolean negotiateDirectly;
+
+    @ApiModelProperty(value = "底价(万元)")
+    private String basePrice;
+
+    @Enumerated(EnumType.STRING)
+    @ApiModelProperty(value = "佣金类型")
+    private CommissionType commissionType;
+
+    @ApiModelProperty(value = "佣金(万元)")
+    private String commission;
+
+    @ApiModelProperty(value = "联系人")
+    private String contact;
+
+    @ApiModelProperty(value = "电话")
+    private String phone;
+
+    @ApiModelProperty(value = "邮箱")
+    private String email;
+
+    @ApiModelProperty(value = "所在地区")
+    private String address;
+
+}

+ 77 - 0
src/main/java/com/izouma/zhirongip/domain/supply/SoftwareCopyright.java

@@ -0,0 +1,77 @@
+package com.izouma.zhirongip.domain.supply;
+
+import com.izouma.zhirongip.domain.BaseEntity;
+import com.izouma.zhirongip.enums.CommissionType;
+import com.izouma.zhirongip.enums.TradingMethod;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.NoArgsConstructor;
+import org.hibernate.annotations.Where;
+
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import java.time.LocalDate;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+//@Entity
+@ApiModel(value = "软著")
+@Where(clause = "del = 0")
+public class SoftwareCopyright extends BaseEntity {
+    @ApiModelProperty(value = "软件名称")
+    private String name;
+
+    @ApiModelProperty(value = "登记号")
+    private String code;
+
+    @ApiModelProperty(value = "登记日期")
+    private LocalDate registrationTime;
+
+    /*
+    setting
+     */
+    @ApiModelProperty(value = "软著类型")
+    private Long softType;
+
+    @ApiModelProperty(value = "著作权人")
+    private String copyrightHolder;
+
+    @Enumerated(EnumType.STRING)
+    @ApiModelProperty(value = "交易方式")
+    private TradingMethod tradingMethod;
+
+    /*
+    (万元)
+     */
+    @ApiModelProperty(value = "期望价(万元)")
+    private String expectedPrice;
+
+    @ApiModelProperty(value = "面议")
+    private Boolean negotiateDirectly;
+
+    @ApiModelProperty(value = "底价(万元)")
+    private String basePrice;
+
+    @Enumerated(EnumType.STRING)
+    @ApiModelProperty(value = "佣金类型")
+    private CommissionType commissionType;
+
+    @ApiModelProperty(value = "佣金(万元)")
+    private String commission;
+
+    @ApiModelProperty(value = "联系人")
+    private String contact;
+
+    @ApiModelProperty(value = "电话")
+    private String phone;
+
+    @ApiModelProperty(value = "邮箱")
+    private String email;
+
+    @ApiModelProperty(value = "所在地区")
+    private String address;
+
+}

+ 78 - 0
src/main/java/com/izouma/zhirongip/domain/supply/Technology.java

@@ -0,0 +1,78 @@
+package com.izouma.zhirongip.domain.supply;
+
+import com.izouma.zhirongip.domain.BaseEntity;
+import com.izouma.zhirongip.enums.LawStatus;
+import com.izouma.zhirongip.enums.TradingMethod;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.NoArgsConstructor;
+import org.hibernate.annotations.Where;
+
+import javax.persistence.Column;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import java.time.LocalDate;
+
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+//@Entity
+@ApiModel(value = "技术")
+@Where(clause = "del = 0")
+public class Technology extends BaseEntity {
+
+    @ApiModelProperty(value = "成果名称")
+    private String name;
+
+    /*
+    setting
+     */
+    @ApiModelProperty(value = "所属领域")
+    private Long field;
+
+    @ApiModelProperty(value = "成果所属人")
+    private String owner;
+
+    @ApiModelProperty(value = "技术成熟度")
+    private String maturity;
+
+    @ApiModelProperty(value = "摘要")
+    private String digest;
+
+    @Column(columnDefinition = "TEXT")
+    @ApiModelProperty(value = "成果描述")
+    private String manual;
+
+    @ApiModelProperty(value = "专利附图")
+    private String img;
+
+    @Enumerated(EnumType.STRING)
+    @ApiModelProperty(value = "交易方式")
+    private TradingMethod tradingMethod;
+
+    /*
+    (万元)
+     */
+    @ApiModelProperty(value = "期望价(万元)")
+    private String expectedPrice;
+
+    @ApiModelProperty(value = "面议")
+    private Boolean negotiateDirectly;
+
+    @ApiModelProperty(value = "底价(万元)")
+    private String basePrice;
+
+    @ApiModelProperty(value = "联系人")
+    private String contact;
+
+    @ApiModelProperty(value = "电话")
+    private String phone;
+
+    @ApiModelProperty(value = "邮箱")
+    private String email;
+
+    @ApiModelProperty(value = "所在地区")
+    private String address;
+}

+ 21 - 0
src/main/java/com/izouma/zhirongip/enums/CommissionType.java

@@ -0,0 +1,21 @@
+package com.izouma.zhirongip.enums;
+
+/*
+佣金类型
+ */
+public enum CommissionType {
+
+    COMMISSION("佣金"),
+    PERCENTAGE("百分比"),
+    ;
+
+    private final String desc;
+
+    CommissionType(String desc) {
+        this.desc = desc;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+}

+ 27 - 0
src/main/java/com/izouma/zhirongip/enums/LawStatus.java

@@ -0,0 +1,27 @@
+package com.izouma.zhirongip.enums;
+
+public enum LawStatus {
+
+    /*
+    有权—授权
+     */
+    EMPOWERED_DELEGATED("有权—授权"),
+    /*
+    无权—未缴年费
+     */
+    UNPAID_ANNUAL_FEE("无权—未缴年费"),
+    /*
+    无权—期限届满
+     */
+    EXPIRY_OF_TERM("无权—期限届满");
+
+    private final String desc;
+
+    LawStatus(String desc) {
+        this.desc = desc;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+}

+ 26 - 0
src/main/java/com/izouma/zhirongip/enums/LawStatusGeneral.java

@@ -0,0 +1,26 @@
+package com.izouma.zhirongip.enums;
+
+/*
+普通专利法律状态
+ */
+public enum LawStatusGeneral {
+
+    EMPOWERED_DELEGATED("有权—授权"),
+    UNPAID_ANNUAL_FEE("无权—未缴年费"),
+    EXPIRY_OF_TERM("无权—期限届满"),
+    REJECTED("无权—驳回"),
+    DEEMED_WITHDRAWN("无权—视为撤回"),
+    DISCLOSURE_OF_INVENTIONS("审中—发明公开"),
+    SUBSTANTIVE_REVIEW("审中—实质审查"),
+    ;
+
+    private final String desc;
+
+    LawStatusGeneral(String desc) {
+        this.desc = desc;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+}

+ 22 - 0
src/main/java/com/izouma/zhirongip/enums/LogoType.java

@@ -0,0 +1,22 @@
+package com.izouma.zhirongip.enums;
+
+/*
+商标类型
+ */
+public enum LogoType {
+
+    GENERAL("普通商标"),
+    COLLECTIVE("集体商标"),
+    PROOF("证明商标"),
+    ;
+
+    private final String desc;
+
+    LogoType(String desc) {
+        this.desc = desc;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+}

+ 22 - 0
src/main/java/com/izouma/zhirongip/enums/OwnerType.java

@@ -0,0 +1,22 @@
+package com.izouma.zhirongip.enums;
+
+/*
+专利权人类型
+ */
+public enum OwnerType {
+
+    ENTERPRISES_AND_INSTITUTIONS("企事业单位"),
+    UNIVERSITIES_AND_INSTITUTES("高校院所"),
+    Personal("个人"),
+    ;
+
+    private final String desc;
+
+    OwnerType(String desc) {
+        this.desc = desc;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+}

+ 17 - 0
src/main/java/com/izouma/zhirongip/enums/PatentType.java

@@ -0,0 +1,17 @@
+package com.izouma.zhirongip.enums;
+
+public enum PatentType {
+    INVENTION("发明专利"),
+    UTILITY_MODEL("实用新型专利"),
+    APPEARANCE_DESIGN("外观设计专利");
+
+    private final String description;
+
+    public String getDescription() {
+        return description;
+    }
+
+    PatentType(String description) {
+        this.description = description;
+    }
+}

+ 18 - 0
src/main/java/com/izouma/zhirongip/enums/TradingMethod.java

@@ -0,0 +1,18 @@
+package com.izouma.zhirongip.enums;
+
+public enum TradingMethod {
+    TRANSFER("转让"),
+    GENERAL_PERMIT("普通许可"),
+    EXCLUSIVE_PERMIT("独占许可"),
+    EXCLUSIVITY_PERMIT("排他许可"),
+    INVEST("入股");
+    private final String desc;
+
+    TradingMethod(String desc) {
+        this.desc = desc;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+}

+ 23 - 0
src/main/java/com/izouma/zhirongip/repo/SettingRepo.java

@@ -0,0 +1,23 @@
+package com.izouma.zhirongip.repo;
+
+import com.izouma.zhirongip.domain.Setting;
+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 javax.validation.constraints.Size;
+import java.util.List;
+
+public interface SettingRepo extends JpaRepository<Setting, Long>, JpaSpecificationExecutor<Setting> {
+    @Query("update Setting t set t.del = true where t.id = ?1")
+    @Modifying
+    @Transactional
+    void softDelete(Long id);
+
+    List<Setting> findAllByFlag(int flag);
+
+    @Query(nativeQuery = true, value = "SELECT ifnull(max(flag + 1),1) FROM setting")
+    int nextSort();
+}

+ 50 - 0
src/main/java/com/izouma/zhirongip/service/SettingService.java

@@ -0,0 +1,50 @@
+package com.izouma.zhirongip.service;
+
+import com.alibaba.fastjson.JSON;
+import com.izouma.zhirongip.domain.Setting;
+import com.izouma.zhirongip.dto.PageQuery;
+import com.izouma.zhirongip.repo.SettingRepo;
+import com.izouma.zhirongip.utils.JpaUtils;
+import lombok.AllArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Service
+@AllArgsConstructor
+public class SettingService {
+
+    private final SettingRepo settingRepo;
+
+    public Page<Setting> all(PageQuery pageQuery) {
+        return settingRepo.findAll(JpaUtils.toSpecification(pageQuery, Setting.class), JpaUtils.toPageRequest(pageQuery));
+    }
+
+    public List<Setting> getTree(List<Setting> list) {
+//        String s = JSON.toJSONString(list1);
+//        List<Setting> list = JSON.parseArray(s, Setting.class);
+        Map<Long, Setting> dtoMap = new HashMap<>();
+        for (Setting node : list) {
+            dtoMap.put(node.getId(), node);
+        }
+
+        List<Setting> resultList = new ArrayList<>();
+        for (Map.Entry<Long, Setting> entry : dtoMap.entrySet()) {
+            Setting node = entry.getValue();
+            if (node.getParent() == null) {
+                // 如果是顶层节点,直接添加到结果集合中
+                resultList.add(node);
+            } else {
+                // 如果不是顶层节点,找其父节点,并且添加到父节点的子节点集合中
+                if (dtoMap.get(node.getParent()) != null) {
+                    dtoMap.get(node.getParent()).getChildren().add(node);
+                }
+            }
+        }
+        return resultList;
+    }
+}

+ 77 - 0
src/main/java/com/izouma/zhirongip/web/SettingController.java

@@ -0,0 +1,77 @@
+package com.izouma.zhirongip.web;
+import com.izouma.zhirongip.domain.Setting;
+import com.izouma.zhirongip.service.SettingService;
+import com.izouma.zhirongip.dto.PageQuery;
+import com.izouma.zhirongip.exception.BusinessException;
+import com.izouma.zhirongip.repo.SettingRepo;
+import com.izouma.zhirongip.utils.ObjUtils;
+import com.izouma.zhirongip.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;
+import java.io.IOException;
+import java.util.List;
+
+@RestController
+@RequestMapping("/setting")
+@AllArgsConstructor
+public class SettingController extends BaseController {
+    private final SettingService settingService;
+    private final SettingRepo    settingRepo;
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/save")
+    public Setting save(@RequestBody Setting record) {
+        if (record.getId() != null) {
+            Setting orig = settingRepo.findById(record.getId()).orElseThrow(new BusinessException("无记录"));
+            ObjUtils.merge(orig, record);
+            return settingRepo.save(orig);
+        }
+        if (record.getParent() == null) {
+            record.setFlag(settingRepo.nextSort());
+        }
+        return settingRepo.save(record);
+    }
+
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/all")
+    public Page<Setting> all(@RequestBody PageQuery pageQuery) {
+        return settingService.all(pageQuery);
+    }
+
+    @GetMapping("/get/{id}")
+    public Setting get(@PathVariable Long id) {
+        return settingRepo.findById(id).orElseThrow(new BusinessException("无记录"));
+    }
+
+    @PostMapping("/del/{id}")
+    public void del(@PathVariable Long id) {
+        settingRepo.softDelete(id);
+    }
+
+    @GetMapping("/excel")
+    @ResponseBody
+    public void excel(HttpServletResponse response, PageQuery pageQuery) throws IOException {
+        List<Setting> data = all(pageQuery).getContent();
+        ExcelUtils.export(response, data);
+    }
+
+    @PostMapping("/allList")
+    public List<Setting> allList() {
+        return settingService.getTree(settingRepo.findAll());
+    }
+
+    @PostMapping("/byFlag")
+    public List<Setting> byFlag(int flag) {
+        List<Setting> tree = settingService.getTree(settingRepo.findAllByFlag(flag));
+//        if (CollUtil.isEmpty(tree)){
+//            return null;
+//        }
+        return tree.get(0).getChildren();
+    }
+}
+

+ 1 - 0
src/main/resources/genjson/Setting.json

@@ -0,0 +1 @@
+{"tableName":"Setting","className":"Setting","remark":"分类设置","genTable":true,"genClass":true,"genList":false,"genForm":false,"genRouter":false,"javaPath":"/Users/qiufangchao/Desktop/project/zhirongip/src/main/java/com/izouma/zhirongip","viewPath":"/Users/qiufangchao/Desktop/project/zhirongip/src/main/vue/src/views","routerPath":"/Users/qiufangchao/Desktop/project/zhirongip/src/main/vue/src","resourcesPath":"/Users/qiufangchao/Desktop/project/zhirongip/src/main/resources","dataBaseType":"Mysql","fields":[{"name":"name","modelName":"name","remark":"name","showInList":true,"showInForm":true,"formType":"singleLineText"},{"name":"parent","modelName":"parent","remark":"parent","showInList":true,"showInForm":true,"formType":"number"},{"name":"flag","modelName":"flag","remark":"flag","showInList":true,"showInForm":true,"formType":"singleLineText"}],"readTable":false,"dataSourceCode":"dataSource","genJson":"","subtables":[],"update":false,"basePackage":"com.izouma.zhirongip","tablePackage":"com.izouma.zhirongip.domain.Setting"}

+ 2 - 2
src/main/resources/templates/ControllerTemplate.ftl

@@ -28,8 +28,8 @@ import java.util.List;
 @RequestMapping("/${model.className?uncap_first}")
 @AllArgsConstructor
 public class ${model.className}Controller extends BaseController {
-    private ${model.className}Service ${model.className?uncap_first}Service;
-    private ${model.className}Repo ${model.className?uncap_first}Repo;
+    private final ${model.className}Service ${model.className?uncap_first}Service;
+    private final ${model.className}Repo ${model.className?uncap_first}Repo;
 
     //@PreAuthorize("hasRole('ADMIN')")
     @PostMapping("/save")

+ 1 - 1
src/main/resources/templates/ServiceTemplate.ftl

@@ -12,7 +12,7 @@ import org.springframework.stereotype.Service;
 @AllArgsConstructor
 public class ${model.className}Service {
 
-    private ${model.className}Repo ${model.className?uncap_first}Repo;
+    private final ${model.className}Repo ${model.className?uncap_first}Repo;
 
     public Page<${model.className}> all(PageQuery pageQuery) {
         return ${model.className?uncap_first}Repo.findAll(JpaUtils.toSpecification(pageQuery, ${model.className}.class), JpaUtils.toPageRequest(pageQuery));

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

@@ -71,6 +71,14 @@ const router = new Router({
                         title: '菜单权限'
                     }
                 },
+                {
+                    path: '/settings',
+                    name: 'Settings',
+                    component: () => import(/* webpackChunkName: "settingList" */ '@/views/Settings.vue'),
+                    meta: {
+                        title: '分类设置'
+                    }
+                },
                 {
                     path: '/userEdit',
                     name: 'userEdit',

+ 377 - 0
src/main/vue/src/views/Settings.vue

@@ -0,0 +1,377 @@
+<template>
+    <div>
+        <el-row :gutter="20">
+            <el-col :span="12">
+                <div class="menu-tree">
+                    <el-tree
+                        :data="menus"
+                        :render-content="renderContent"
+                        :highlight-current="true"
+                        :expand-on-click-node="true"
+                        node-key="id"
+                        v-loading="loading"
+                        accordion
+                        @node-click="nodeClick"
+                        :default-expanded-keys="expandKeys"
+                        :default-checked-keys="expandKeys"
+                    >
+                    </el-tree>
+                    <el-button type="text" @click="addRootMenu" style="margin-left: 24px;">添加 </el-button>
+                </div>
+            </el-col>
+            <transition name="el-fade-in">
+                <el-col :span="12" v-if="dialogVisible">
+                    <div class="menu-tree">
+                        <div style="font-weight:bold;padding:10px 0">{{ menu.id ? '编辑' : '新增' }}</div>
+                        <el-form :model="menu" ref="form" label-position="top">
+                            <el-form-item
+                                label="名称"
+                                prop="name"
+                                :rules="[{ required: true, message: '请填写名称', trigger: 'blur' }]"
+                            >
+                                <el-input v-model="menu.name"></el-input>
+                            </el-form-item>
+                            <!-- <el-form-item label="代码" prop="code">
+                                <el-input v-model="menu.code"></el-input>
+                            </el-form-item> -->
+                        </el-form>
+                        <div slot="footer">
+                            <el-button @click="dialogVisible = false">取消 </el-button>
+                            <el-button type="primary" @click="addMenu" :loading="loading">保存 </el-button>
+                        </div>
+                    </div>
+                </el-col>
+            </transition>
+        </el-row>
+    </div>
+</template>
+<script>
+export default {
+    created() {
+        this.getData();
+    },
+    data() {
+        return {
+            dialogVisible: false,
+            curr: null,
+            loading: false,
+            menus: [],
+            menu: {
+                name: ''
+            },
+            parent: null,
+            currentRef: null,
+            edit: false,
+            expandKeys: [],
+            authorities: []
+        };
+    },
+    methods: {
+        addRootMenu() {
+            this.menu = {
+                name: ''
+                // authorities: [{ name: 'ROLE_ADMIN' }]
+            };
+            this.parent = null;
+            this.icon = 'bars';
+            this.dialogVisible = true;
+            setTimeout(() => {
+                this.showIcon('bars');
+            }, 100);
+        },
+        showAddDialog(node, data) {
+            this.edit = false;
+            this.parent = node.data;
+            this.menu = {
+                parent: node.data.id,
+                flag: node.data.flag,
+                name: ''
+                // authorities: [{ name: 'ROLE_ADMIN' }]
+            };
+            this.dialogVisible = true;
+        },
+        showEditDialog(node, data) {
+            this.edit = true;
+            this.currentRef = node.data;
+            this.menu = {
+                ...data
+            };
+            this.dialogVisible = true;
+        },
+        addMenu() {
+            this.$refs.form.validate(valid => {
+                if (valid) {
+                    this.loading = true;
+                    let menu = { ...this.menu };
+                    delete menu.children;
+                    this.$http
+                        .post('/setting/save', menu, { body: 'json' })
+                        .then(res => {
+                            this.loading = false;
+                            this.$message.success('添加成功');
+                            this.dialogVisible = false;
+                            this.getData();
+                        })
+                        .catch(e => {
+                            console.log(e);
+                            this.loading = false;
+                            this.$message.error(e.error);
+                        });
+                }
+            });
+        },
+        remove(node, data) {
+            console.log(node);
+            this.$confirm('确定删除菜单?', '提示', {
+                confirmButtonText: '确定',
+                cancelButtonText: '取消',
+                type: 'error'
+            })
+                .then(() => {
+                    return this.$http.post(
+                        '/setting/save',
+                        {
+                            ...data,
+                            active: false,
+                            children: null
+                        },
+                        { body: 'json' }
+                    );
+                })
+                .then(res => {
+                    this.$message.success('删除成功');
+                    this.getData();
+                })
+                .catch(e => {
+                    this.loading = false;
+                    if (e !== 'cancel') {
+                        console.log(e);
+                        this.$message.error(e.error);
+                    }
+                });
+        },
+        moveUp(node, data) {
+            if (node.previousSibling) {
+                this.loading = true;
+                let sort0 = node.previousSibling.data.sort,
+                    sort1 = node.data.sort;
+                Promise.all([
+                    this.$http.post(
+                        '/setting/save',
+                        {
+                            ...node.data,
+                            children: null,
+                            sort: sort0
+                        },
+                        { body: 'json' }
+                    ),
+                    this.$http.post(
+                        '/setting/save',
+                        {
+                            ...node.previousSibling.data,
+                            children: null,
+                            sort: sort1
+                        },
+                        { body: 'json' }
+                    )
+                ])
+                    .then(_ => {
+                        this.loading = false;
+                        this.getData();
+                    })
+                    .catch(e => {
+                        console.log(e);
+                        this.loading = false;
+                        this.$message.error(e.error);
+                    });
+            }
+        },
+        moveDown(node, data) {
+            if (node.nextSibling) {
+                this.loading = true;
+                let sort0 = node.data.sort,
+                    sort1 = node.nextSibling.data.sort;
+                Promise.all([
+                    this.$http.post(
+                        '/setting/save',
+                        {
+                            ...node.data,
+                            children: null,
+                            sort: sort1
+                        },
+                        { body: 'json' }
+                    ),
+                    this.$http.post(
+                        '/setting/save',
+                        {
+                            ...node.nextSibling.data,
+                            children: null,
+                            sort: sort0
+                        },
+                        { body: 'json' }
+                    )
+                ])
+                    .then(_ => {
+                        this.loading = false;
+                        this.getData();
+                    })
+                    .catch(e => {
+                        console.log(e);
+                        this.loading = false;
+                        this.$message.error(e.error);
+                    });
+            }
+        },
+        getData() {
+            this.$http
+                .post('/setting/allList')
+                .then(res => {
+                    this.menus = res;
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.$message.error(e.error);
+                });
+        },
+        renderContent(h, { node, data, store }) {
+            return (
+                <span
+                    class={
+                        this.menu.id == data.id || (this.menu.parent == data.id && !this.menu.id)
+                            ? 'custom-tree-node selected'
+                            : 'custom-tree-node'
+                    }
+                >
+                    <span>{data.name}</span>
+                    <span class="opt">
+                        <el-button
+                            type="text"
+                            on-click={e => {
+                                this.showEditDialog(node, data), e.stopPropagation();
+                            }}
+                            icon="el-icon-edit"
+                        >
+                            编辑
+                        </el-button>
+                        <el-button
+                            type="text"
+                            on-click={e => {
+                                this.showAddDialog(node, data), e.stopPropagation();
+                            }}
+                            icon="el-icon-plus"
+                        >
+                            添加
+                        </el-button>
+                        <el-button
+                            type="text"
+                            on-click={e => {
+                                this.remove(node, data), e.stopPropagation();
+                            }}
+                            icon="el-icon-delete"
+                        >
+                            删除
+                        </el-button>
+                    </span>
+                </span>
+            );
+        },
+        showIcon(val) {
+            if (!this.$refs.iconContainer) return;
+            if (FontAwesome.icon({ prefix: 'fas', iconName: val })) {
+                this.$refs.iconContainer.innerHTML = '';
+                let i = document.createElement('i');
+                i.className = 'fas fa-' + val;
+                this.$refs.iconContainer.append(i);
+                FontAwesome.dom.i2svg();
+                this.menu.icon = 'fas fa-' + val;
+            } else if (FontAwesome.icon({ prefix: 'fab', iconName: val })) {
+                this.$refs.iconContainer.innerHTML = '';
+                let i = document.createElement('i');
+                i.className = 'fab fa-' + val;
+                this.$refs.iconContainer.append(i);
+                FontAwesome.dom.i2svg();
+                this.menu.icon = 'fab fa-' + val;
+            } else {
+                this.$refs.iconContainer.innerHTML = '';
+                let i = document.createElement('i');
+                i.className = 'fab fa-' + val;
+                this.$refs.iconContainer.append(i);
+                FontAwesome.dom.i2svg();
+                this.menu.icon = '';
+            }
+        },
+        nodeClick(data, node, el) {
+            if (this.expandKeys[0] != data.id) {
+                this.expandKeys = [data.id];
+            }
+        }
+    },
+    watch: {
+        icon(val) {
+            this.showIcon(val);
+        },
+        category() {
+            this.getData();
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+.menu-tree {
+    border-radius: 4px;
+    background: white;
+    margin-top: 20px;
+    padding: 10px;
+}
+</style>
+<style lang="less">
+.menu-tree {
+    .el-tree-node__content {
+        height: 40px;
+        line-height: 40px;
+    }
+}
+.custom-tree-node {
+    flex: 1;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    font-size: 14px;
+    padding-right: 8px;
+    line-height: 40px;
+    height: 40px;
+    .url {
+        flex-grow: 1;
+        text-align: right;
+        margin-right: 20px;
+        color: #999;
+    }
+    .opt {
+        opacity: 0;
+    }
+    &.selected {
+        border: 2px solid #409eff;
+        border-radius: 4px;
+        padding: 0 10px;
+        box-sizing: border-box;
+        .opt {
+            opacity: 1;
+        }
+    }
+}
+
+.custom-tree-node:hover {
+    .opt {
+        opacity: 1;
+    }
+}
+
+.available-icons {
+    color: #409eff;
+    text-decoration: none;
+    &:hover {
+        color: #409eff;
+        text-decoration: none;
+    }
+}
+</style>

+ 5 - 2
src/test/java/com/izouma/zhirongip/repo/UserRepoTest.java

@@ -1,6 +1,7 @@
 package com.izouma.zhirongip.repo;
 
 import com.izouma.zhirongip.domain.User;
+import com.izouma.zhirongip.enums.AuthorityName;
 import com.izouma.zhirongip.security.Authority;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -9,6 +10,7 @@ import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 import org.springframework.test.context.junit4.SpringRunner;
 
+import java.util.Collections;
 import java.util.List;
 
 @RunWith(SpringRunner.class)
@@ -20,9 +22,10 @@ public class UserRepoTest {
     @Test
     public void testUser() {
         User user = User.builder()
-                .username("testuser")
-                .password("123")
+                .username("root")
+                .password(new BCryptPasswordEncoder().encode("123456"))
                 .avatar("")
+                .authorities(Collections.singleton(Authority.get(AuthorityName.ROLE_ADMIN)))
                 .build();
         userRepo.save(user);
     }