Procházet zdrojové kódy

Merge branch 'dev' of xiongzhu/raex_back into master

wangqifan před 4 roky
rodič
revize
90e1851b14
25 změnil soubory, kde provedl 764 přidání a 47 odebrání
  1. 1 1
      libs/org/libjpegturbo/mozjpeg4j/maven-metadata-local.xml
  2. 1 1
      libs/org/pngquant/pngquant4j/maven-metadata-local.xml
  3. 14 1
      src/main/java/com/izouma/nineth/config/SnowflakeIdWorkerConfig.java
  4. 3 0
      src/main/java/com/izouma/nineth/domain/Banner.java
  5. 33 0
      src/main/java/com/izouma/nineth/domain/Setting.java
  6. 2 1
      src/main/java/com/izouma/nineth/enums/AuthorityName.java
  7. 2 1
      src/main/java/com/izouma/nineth/enums/CollectionSource.java
  8. 2 1
      src/main/java/com/izouma/nineth/enums/PayMethod.java
  9. 5 0
      src/main/java/com/izouma/nineth/repo/CollectionPrivilegeRepo.java
  10. 1 1
      src/main/java/com/izouma/nineth/repo/CollectionRepo.java
  11. 22 0
      src/main/java/com/izouma/nineth/repo/SettingRepo.java
  12. 1 1
      src/main/java/com/izouma/nineth/repo/ShowroomRepo.java
  13. 2 0
      src/main/java/com/izouma/nineth/security/WebSecurityConfig.java
  14. 8 1
      src/main/java/com/izouma/nineth/service/CacheService.java
  15. 59 2
      src/main/java/com/izouma/nineth/service/GiftOrderService.java
  16. 48 0
      src/main/java/com/izouma/nineth/service/SettingService.java
  17. 10 5
      src/main/java/com/izouma/nineth/service/ShowroomService.java
  18. 6 0
      src/main/java/com/izouma/nineth/web/AssetController.java
  19. 90 0
      src/main/java/com/izouma/nineth/web/SettingController.java
  20. 1 0
      src/main/java/com/izouma/nineth/web/ShowroomController.java
  21. 1 0
      src/main/resources/genjson/Setting.json
  22. 39 28
      src/main/vue/src/router.js
  23. 26 3
      src/main/vue/src/views/BannerEdit.vue
  24. 386 0
      src/main/vue/src/views/Settings.vue
  25. 1 0
      src/test/java/com/izouma/nineth/CommonTest.java

+ 1 - 1
libs/org/libjpegturbo/mozjpeg4j/maven-metadata-local.xml

@@ -7,6 +7,6 @@
     <versions>
       <version>1.1</version>
     </versions>
-    <lastUpdated>20211106131217</lastUpdated>
+    <lastUpdated>20220331162415</lastUpdated>
   </versioning>
 </metadata>

+ 1 - 1
libs/org/pngquant/pngquant4j/maven-metadata-local.xml

@@ -7,6 +7,6 @@
     <versions>
       <version>1.0.1</version>
     </versions>
-    <lastUpdated>20211106131218</lastUpdated>
+    <lastUpdated>20220331162425</lastUpdated>
   </versioning>
 </metadata>

+ 14 - 1
src/main/java/com/izouma/nineth/config/SnowflakeIdWorkerConfig.java

@@ -5,12 +5,25 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 
+import java.net.InetAddress;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
 @Configuration
 @Slf4j
 public class SnowflakeIdWorkerConfig {
     @Bean
     public SnowflakeIdWorker snowflakeIdWorker(GeneralProperties generalProperties) {
-        log.info("init snowflakeIdWorker worker={} dataCenter={}", generalProperties.getWorkerId(), generalProperties.getDataCenterId());
+        int workerId = generalProperties.getWorkerId();
+        try {
+            String hostName = InetAddress.getLocalHost().getHostName();
+            Matcher matcher = Pattern.compile("raex-server-(?<num>\\d{3})").matcher(hostName);
+            if (matcher.matches()) {
+                workerId = Integer.parseInt(matcher.group("num"));
+            }
+        } catch (Exception e) {
+        }
+        log.info("init snowflakeIdWorker worker={} dataCenter={}", workerId, generalProperties.getDataCenterId());
         return new SnowflakeIdWorker(generalProperties.getWorkerId(), generalProperties.getDataCenterId());
     }
 }

+ 3 - 0
src/main/java/com/izouma/nineth/domain/Banner.java

@@ -45,4 +45,7 @@ public class Banner extends BaseEntity {
 
     @ApiModelProperty("跳转内容")
     private String linkContent;
+
+    @ApiModelProperty("配置id")
+    private Long settingId;
 }

+ 33 - 0
src/main/java/com/izouma/nineth/domain/Setting.java

@@ -0,0 +1,33 @@
+package com.izouma.nineth.domain;
+
+import io.swagger.annotations.ApiModel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Entity;
+import javax.persistence.Transient;
+import java.util.ArrayList;
+import java.util.List;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@Entity
+@ApiModel("配置")
+public class Setting extends BaseEntity {
+    private int flag;
+
+    private String name;
+
+    private String pic;
+
+    private String description;
+
+    private Long parent;
+
+    @Transient
+    private List<Setting> children = new ArrayList<>();
+}

+ 2 - 1
src/main/java/com/izouma/nineth/enums/AuthorityName.java

@@ -6,7 +6,8 @@ public enum AuthorityName {
     ROLE_DEV("开发者"),
     ROLE_ADMIN("高级管理员"),
     ROLE_OPERATOR("普通管理员"),
-    ROLE_NEWS("新闻管理员")
+    ROLE_NEWS("新闻管理员"),
+    ROLE_COMPANY("企业用户")
     ;
     private final String description;
 

+ 2 - 1
src/main/java/com/izouma/nineth/enums/CollectionSource.java

@@ -3,7 +3,8 @@ package com.izouma.nineth.enums;
 public enum CollectionSource {
     OFFICIAL("官方铸造"),
     USER("用户铸造"),
-    TRANSFER("转让");
+    TRANSFER("转让"),
+    COMPANY("企业铸造");
 
     private final String description;
 

+ 2 - 1
src/main/java/com/izouma/nineth/enums/PayMethod.java

@@ -2,7 +2,8 @@ package com.izouma.nineth.enums;
 
 public enum PayMethod {
     WEIXIN("微信"),
-    ALIPAY("支付宝");
+    ALIPAY("支付宝"),
+    FREE("无GAS费");
 
     private final String description;
 

+ 5 - 0
src/main/java/com/izouma/nineth/repo/CollectionPrivilegeRepo.java

@@ -24,4 +24,9 @@ public interface CollectionPrivilegeRepo extends JpaRepository<CollectionPrivile
             "c.showroom_bg = ?5, c.vip = ?6 where c.id = ?1", nativeQuery = true)
     @CacheEvict(value = {"collectionInfo"}, allEntries = true)
     void update(@Nonnull Long id, Long collectionId, String headBg, Integer maxCollection, String showroomBg, Boolean vip);
+
+    @Transactional
+    @Modifying
+    @CacheEvict(value = {"collectionInfo"}, allEntries = true)
+    CollectionPrivilege save(CollectionPrivilege record);
 }

+ 1 - 1
src/main/java/com/izouma/nineth/repo/CollectionRepo.java

@@ -33,7 +33,7 @@ public interface CollectionRepo extends JpaRepository<Collection, Long>, JpaSpec
             "c.properties = ?9, c.model3d = ?10, c.max_count = ?11, c.count_id = ?12, c.scan_code = ?13, " +
             "c.no_sold_out = ?14, c.assignment = ?15, c.coupon_payment = ?16, c.share_bg = ?17," +
             "c.register_bg = ?18, c.vip_quota = ?19, c.time_delay = ?20, c.sale_time = ?21, c.hold_days = ?22, " +
-            "c.open_quota = ?23, c.total_quota = ?24 " +
+            "c.open_quota = ?23, c.total_quota = ?24, c.minimum_charge = ?25 " +
             "where c.id = ?1", nativeQuery = true)
     @CacheEvict(value = {"collection", "recommend"}, allEntries = true)
     void update(@Nonnull Long id, boolean onShelf, boolean salable, LocalDateTime startTime,

+ 22 - 0
src/main/java/com/izouma/nineth/repo/SettingRepo.java

@@ -0,0 +1,22 @@
+package com.izouma.nineth.repo;
+
+import com.izouma.nineth.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 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);
+
+    @Query(nativeQuery = true, value = "SELECT ifnull(max(flag + 1),1) FROM setting")
+    int nextSort();
+
+    List<Setting> findAllByFlag(int flag);
+}

+ 1 - 1
src/main/java/com/izouma/nineth/repo/ShowroomRepo.java

@@ -31,6 +31,6 @@ public interface ShowroomRepo extends JpaRepository<Showroom, Long>, JpaSpecific
     @Transactional
     void addShare(Long id, int num);
 
-    @Cacheable("showroom")
+    @Cacheable(value = "showroom", key = "#id")
     Optional<Showroom> findById(@Nonnull Long id);
 }

+ 2 - 0
src/main/java/com/izouma/nineth/security/WebSecurityConfig.java

@@ -84,6 +84,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
                 .antMatchers("/payOrder/**").permitAll()
                 .antMatchers("/notify/**").permitAll()
                 .antMatchers("/banner/all").permitAll()
+                .antMatchers("/setting/all").permitAll()
+                .antMatchers("/setting/byFlag").permitAll()
                 .antMatchers("/collection/all").permitAll()
                 .antMatchers("/collection/get/**").permitAll()
                 .antMatchers("/asset/get/**").permitAll()

+ 8 - 1
src/main/java/com/izouma/nineth/service/CacheService.java

@@ -75,7 +75,6 @@ public class CacheService {
     public void clearOrderPriceTrend() {
     }
 
-    //    @Scheduled(fixedRate = 120000)
     @CacheEvict(value = "top", key = "#month")
     public void clearTop(int month) {
     }
@@ -83,4 +82,12 @@ public class CacheService {
     @CacheEvict(value = "checkUpdate", allEntries = true)
     public void clearCheckUpdate() {
     }
+
+    @CacheEvict(value = "settingList", allEntries = true)
+    public void clearSettingList() {
+    }
+
+    @CacheEvict(value = {"showroom"}, allEntries = true)
+    public void clearShowroom() {
+    }
 }

+ 59 - 2
src/main/java/com/izouma/nineth/service/GiftOrderService.java

@@ -70,8 +70,63 @@ public class GiftOrderService {
     private SnowflakeIdWorker snowflakeIdWorker;
     private ErrorOrderRepo    errorOrderRepo;
 
+    @Transactional
+    public GiftOrder giftWithoutGasFee(Long userId, Long assetId, Long toUserId) {
+        Asset asset = assetRepo.findById(assetId).orElseThrow(new BusinessException("资产不存在"));
+        if (!asset.getUserId().equals(userId)) {
+            throw new BusinessException("无权限");
+        }
+
+        int holdDays;
+        if (ObjectUtils.isEmpty(asset.getHoldDays())) {
+            holdDays = sysConfigService.getInt("hold_days");
+        } else {
+            holdDays = asset.getHoldDays();
+        }
+
+        if (ChronoUnit.DAYS.between(asset.getCreatedAt(), LocalDateTime.now()) < holdDays) {
+            throw new BusinessException("需持有满" + holdDays + "天才能转赠");
+        }
+        if (toUserId.equals(userId)) {
+            throw new BusinessException("不能送给自己");
+        }
+        if (!(asset.getStatus() == AssetStatus.NORMAL)) {
+            throw new BusinessException("当前状态不可转赠");
+        }
+        if (asset.isConsignment()) {
+            throw new BusinessException("请先取消寄售");
+        }
+        if (asset.isPublicShow()) {
+            assetService.cancelPublic(asset);
+        }
+
+        asset.setStatus(AssetStatus.GIFTING);
+        assetRepo.save(asset);
+
+        GiftOrder giftOrder = GiftOrder.builder()
+                .userId(userId)
+                .assetId(assetId)
+                .toUserId(toUserId)
+                .gasPrice(sysConfigService.getBigDecimal("gas_fee"))
+                .status(OrderStatus.NOT_PAID)
+                .build();
+        giftOrder.setPayMethod(PayMethod.FREE);
+        giftOrder.setStatus(OrderStatus.FINISH);
+        giftOrder.setTransactionId(null);
+        giftOrder.setPayTime(LocalDateTime.now());
+        giftOrder.setPayMethod(PayMethod.FREE);
+
+        User newOwner = userRepo.findById(giftOrder.getToUserId()).orElseThrow(new BusinessException("用户不存在"));
+        assetService.transfer(asset, asset.getPrice(), newOwner, "转赠", null);
+
+        return giftOrderRepo.save(giftOrder);
+    }
+
     @Transactional
     public GiftOrder gift(Long userId, Long assetId, Long toUserId) {
+        if (BigDecimal.ZERO.compareTo(sysConfigService.getBigDecimal("gift_gas_fee")) == 0) {
+            return giftWithoutGasFee(userId, assetId, toUserId);
+        }
         Asset asset = assetRepo.findById(assetId).orElseThrow(new BusinessException("资产不存在"));
         if (!asset.getUserId().equals(userId)) {
             throw new BusinessException("无权限");
@@ -131,7 +186,8 @@ public class GiftOrderService {
 
             assetService.transfer(asset, asset.getPrice(), newOwner, "转赠", null);
         } else {
-            log.error("转赠回调出错 状态错误 orderid={} transactionid={} status={}", orderId, transactionId, giftOrder.getStatus());
+            log.error("转赠回调出错 状态错误 orderid={} transactionid={} status={}", orderId, transactionId, giftOrder
+                    .getStatus());
             errorOrderRepo.save(ErrorOrder.builder()
                     .orderId(orderId)
                     .transactionId(transactionId)
@@ -268,7 +324,8 @@ public class GiftOrderService {
             case "alipay_qr":
                 return MapUtils.getString(MapUtils.getMap(response, "expend"), "qrcode_url");
             case "wx_pub":
-                JSONObject payParams = JSON.parseObject(MapUtils.getString(MapUtils.getMap(response, "expend"), "pay_info"));
+                JSONObject payParams = JSON
+                        .parseObject(MapUtils.getString(MapUtils.getMap(response, "expend"), "pay_info"));
                 payParams.put("timestamp", payParams.get("timeStamp"));
                 payParams.remove("timeStamp");
                 return payParams;

+ 48 - 0
src/main/java/com/izouma/nineth/service/SettingService.java

@@ -0,0 +1,48 @@
+package com.izouma.nineth.service;
+
+import com.alibaba.fastjson.JSON;
+import com.izouma.nineth.domain.Setting;
+import com.izouma.nineth.dto.PageQuery;
+import com.izouma.nineth.repo.SettingRepo;
+import com.izouma.nineth.utils.JpaUtils;
+import lombok.AllArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+
+@Service
+@AllArgsConstructor
+public class SettingService {
+
+    private 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> list1) {
+        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);
+                }
+            }
+        }
+        resultList.sort(Comparator.comparing(Setting::getId));
+        return resultList;
+    }
+}

+ 10 - 5
src/main/java/com/izouma/nineth/service/ShowroomService.java

@@ -30,6 +30,7 @@ public class ShowroomService {
     private CollectionRepo          collectionRepo;
     private ShowCollectionRepo      showCollectionRepo;
     private CollectionPrivilegeRepo collectionPrivilegeRepo;
+    private CacheService            cacheService;
 
     public Page<Showroom> all(PageQuery pageQuery) {
         return showroomRepo.findAll(JpaUtils.toSpecification(pageQuery, Showroom.class), JpaUtils.toPageRequest(pageQuery));
@@ -38,7 +39,6 @@ public class ShowroomService {
     /*
     不做盲盒
      */
-    @CacheEvict(value = {"showroom"}, allEntries = true)
     public Showroom save(Long userId, Showroom showroom) {
         Asset asset = assetRepo.findById(showroom.getAssetId()).orElseThrow(new BusinessException("资产不存在"));
         if (!userId.equals(asset.getUserId())) {
@@ -99,6 +99,8 @@ public class ShowroomService {
                 showCollectionRepo.save(showCollection);
             }
         });
+
+        cacheService.clearShowroom();
         return show;
     }
 
@@ -123,12 +125,12 @@ public class ShowroomService {
                 .assetId(asset.getId())
                 .nickname(asset.getOwner())
                 .build();
+        showroom = showroomRepo.save(showroom);
 
-
-        return showroomRepo.save(showroom);
+        cacheService.clearShowroom();
+        return showroom;
     }
 
-    @CacheEvict(value = {"showroom"}, allEntries = true)
     public Showroom update(Long userId, Showroom showroom) {
         Showroom recordRoom = showroomRepo.findById(showroom.getId()).orElseThrow(new BusinessException("无展厅"));
         showroom.setMaxCollection(recordRoom.getMaxCollection());
@@ -204,7 +206,10 @@ public class ShowroomService {
 
         ObjUtils.merge(recordRoom, showroom);
         recordRoom.setPublish(true);
-        return showroomRepo.save(recordRoom);
+
+        showroom = showroomRepo.save(recordRoom);
+        cacheService.clearShowroom();
+        return showroom;
     }
 
 }

+ 6 - 0
src/main/java/com/izouma/nineth/web/AssetController.java

@@ -108,6 +108,12 @@ public class AssetController extends BaseController {
         return giftOrderService.gift(SecurityUtils.getAuthenticatedUser().getId(), assetId, toUserId);
     }
 
+    @PostMapping("/giftWithoutGasFee")
+    @ApiOperation("转赠(无gas费)")
+    public GiftOrder giftWithoutGasFee(@RequestParam Long assetId, @RequestParam Long toUserId) {
+        return giftOrderService.giftWithoutGasFee(SecurityUtils.getAuthenticatedUser().getId(), assetId, toUserId);
+    }
+
     @GetMapping("/tokenHistory")
     @ApiOperation("交易历史")
     public List<TokenHistory> tokenHistory(@RequestParam(required = false) String tokenId, @RequestParam(required = false) Long assetId) {

+ 90 - 0
src/main/java/com/izouma/nineth/web/SettingController.java

@@ -0,0 +1,90 @@
+package com.izouma.nineth.web;
+
+import cn.hutool.core.collection.CollUtil;
+import com.izouma.nineth.domain.Setting;
+import com.izouma.nineth.service.CacheService;
+import com.izouma.nineth.service.SettingService;
+import com.izouma.nineth.dto.PageQuery;
+import com.izouma.nineth.exception.BusinessException;
+import com.izouma.nineth.repo.SettingRepo;
+import com.izouma.nineth.utils.ObjUtils;
+import com.izouma.nineth.utils.excel.ExcelUtils;
+import lombok.AllArgsConstructor;
+import org.springframework.cache.annotation.CachePut;
+import org.springframework.cache.annotation.Cacheable;
+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 SettingService settingService;
+    private SettingRepo    settingRepo;
+    private CacheService   cacheService;
+
+    //@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);
+            orig = settingRepo.save(orig);
+            cacheService.clearSettingList();
+            return orig;
+        }
+
+        if (record.getParent() == null) {
+            record.setFlag(settingRepo.nextSort());
+        }
+        record = settingRepo.save(record);
+        cacheService.clearSettingList();
+        return 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());
+    }
+
+    @Cacheable(value = "settingList", key = "#flag")
+    @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/java/com/izouma/nineth/web/ShowroomController.java

@@ -15,6 +15,7 @@ import com.izouma.nineth.utils.SecurityUtils;
 import com.izouma.nineth.utils.excel.ExcelUtils;
 import lombok.AllArgsConstructor;
 import org.apache.commons.lang3.ObjectUtils;
+import org.springframework.cache.annotation.Cacheable;
 import org.springframework.data.domain.Page;
 import org.springframework.web.bind.annotation.*;
 

+ 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/raex_back/src/main/java/com/izouma/nineth","viewPath":"/Users/qiufangchao/Desktop/project/raex_back/src/main/vue/src/views","routerPath":"/Users/qiufangchao/Desktop/project/raex_back/src/main/vue/src","resourcesPath":"/Users/qiufangchao/Desktop/project/raex_back/src/main/resources","dataBaseType":"Mysql","fields":[{"name":"name","modelName":"name","remark":"名称","showInList":true,"showInForm":true,"formType":"singleLineText"},{"name":"pic","modelName":"pic","remark":"图片","showInList":true,"showInForm":true,"formType":"singleLineText"},{"name":"description","modelName":"description","remark":"描述","showInList":true,"showInForm":true,"formType":"singleLineText"}],"readTable":false,"dataSourceCode":"dataSource","genJson":"","subtables":[],"update":false,"basePackage":"com.izouma.nineth","tablePackage":"com.izouma.nineth.domain.Setting"}

+ 39 - 28
src/main/vue/src/router.js

@@ -444,72 +444,75 @@ const router = new Router({
                     name: 'MintActivityEdit',
                     component: () => import(/* webpackChunkName: "mintActivityEdit" */ '@/views/MintActivityEdit.vue'),
                     meta: {
-                       title: '铸造活动编辑',
-                    },
+                        title: '铸造活动编辑'
+                    }
                 },
                 {
                     path: '/mintActivityList',
                     name: 'MintActivityList',
                     component: () => import(/* webpackChunkName: "mintActivityList" */ '@/views/MintActivityList.vue'),
                     meta: {
-                       title: '铸造活动',
-                    },
-               },
+                        title: '铸造活动'
+                    }
+                },
                 {
                     path: '/mintOrderEdit',
                     name: 'MintOrderEdit',
                     component: () => import(/* webpackChunkName: "mintOrderEdit" */ '@/views/MintOrderEdit.vue'),
                     meta: {
-                       title: '铸造订单编辑',
-                    },
+                        title: '铸造订单编辑'
+                    }
                 },
                 {
                     path: '/mintOrderList',
                     name: 'MintOrderList',
                     component: () => import(/* webpackChunkName: "mintOrderList" */ '@/views/MintOrderList.vue'),
                     meta: {
-                       title: '铸造订单',
-                    },
-               },
+                        title: '铸造订单'
+                    }
+                },
                 {
                     path: '/purchaseLevelEdit',
                     name: 'PurchaseLevelEdit',
-                    component: () => import(/* webpackChunkName: "purchaseLevelEdit" */ '@/views/PurchaseLevelEdit.vue'),
+                    component: () =>
+                        import(/* webpackChunkName: "purchaseLevelEdit" */ '@/views/PurchaseLevelEdit.vue'),
                     meta: {
-                       title: '会员等级编辑',
-                    },
+                        title: '会员等级编辑'
+                    }
                 },
                 {
                     path: '/purchaseLevelList',
                     name: 'PurchaseLevelList',
-                    component: () => import(/* webpackChunkName: "purchaseLevelList" */ '@/views/PurchaseLevelList.vue'),
+                    component: () =>
+                        import(/* webpackChunkName: "purchaseLevelList" */ '@/views/PurchaseLevelList.vue'),
                     meta: {
-                       title: '会员等级',
-                    },
-               },
+                        title: '会员等级'
+                    }
+                },
                 {
                     path: '/newsEdit',
                     name: 'NewsEdit',
                     component: () => import(/* webpackChunkName: "newsEdit" */ '@/views/NewsEdit.vue'),
                     meta: {
-                       title: '新闻管理编辑',
-                    },
+                        title: '新闻管理编辑'
+                    }
                 },
                 {
                     path: '/newsList',
                     name: 'NewsList',
                     component: () => import(/* webpackChunkName: "newsList" */ '@/views/NewsList.vue'),
                     meta: {
-                       title: '新闻管理',
-                    },
-               },
+                        title: '新闻管理'
+                    }
+                },
                 {
                     path: '/adapayMerchantEdit',
                     name: 'AdapayMerchantEdit',
-                    component: () => import(/* webpackChunkName: "adapayMerchantEdit" */ '@/views/AdapayMerchantEdit.vue'),
+                    component: () =>
+                        import(/* webpackChunkName: "adapayMerchantEdit" */ '@/views/AdapayMerchantEdit.vue'),
                     meta: {
-                        title: 'ada编辑',
-                    },
+                        title: 'ada编辑'
+                    }
                 },
                 {
                     path: '/adapayMerchantList',
@@ -534,15 +537,23 @@ const router = new Router({
                     component: () => import(/* webpackChunkName: "showroomList" */ '@/views/ShowroomList.vue'),
                     meta: {
                         title: '展厅'
-                    },
+                    }
                 },
                 {
                     path: '/querySettle',
                     name: 'QuerySettle',
                     component: () => import(/* webpackChunkName: "querySettle" */ '@/views/QuerySettle.vue'),
                     meta: {
-                        title: '结算查询',
-                    },
+                        title: '结算查询'
+                    }
+                },
+                {
+                    path: '/settings',
+                    name: 'Settings',
+                    component: () => import(/* webpackChunkName: "settings" */ '@/views/Settings.vue'),
+                    meta: {
+                        title: '结算查询'
+                    }
                 }
                 /**INSERT_LOCATION**/
             ]

+ 26 - 3
src/main/vue/src/views/BannerEdit.vue

@@ -39,6 +39,11 @@
                             </el-option>
                         </el-select>
                     </el-form-item>
+                    <el-form-item prop="settingId" label="分类" v-if="formData.type == 'MARKET'">
+                        <el-select v-model="formData.settingId">
+                            <el-option v-for="item in settings" :key="item.id" :label="item.name" :value="item.id"></el-option>
+                        </el-select>
+                    </el-form-item>
                     <el-form-item prop="link" label="跳转">
                         <el-switch v-model="formData.link"></el-switch>
                     </el-form-item>
@@ -53,8 +58,16 @@
                         </el-select>
                     </el-form-item>
                     <el-form-item prop="linkContent" label="跳转内容" v-if="formData.link">
-                        <el-input v-if="formData.linkType === 'collections'" v-model="formData.linkContent" placeholder="输入藏品名称"></el-input>
-                        <el-input v-else-if="formData.linkType === 'hyperlink'" v-model="formData.linkContent" placeholder="输入链接"></el-input>
+                        <el-input
+                            v-if="formData.linkType === 'collections'"
+                            v-model="formData.linkContent"
+                            placeholder="输入藏品名称"
+                        ></el-input>
+                        <el-input
+                            v-else-if="formData.linkType === 'hyperlink'"
+                            v-model="formData.linkContent"
+                            placeholder="输入链接"
+                        ></el-input>
                         <el-input v-else v-model="formData.linkContent" placeholder="输入ID"></el-input>
                     </el-form-item>
                     <el-form-item class="form-submit">
@@ -84,6 +97,15 @@ export default {
                     this.$message.error(e.error);
                 });
         }
+        this.$http
+            .post('/setting/byFlag', { flag: 1 })
+            .then(res => {
+                this.settings = res;
+            })
+            .catch(e => {
+                console.log(e);
+                this.$message.error(e.error);
+            });
     },
     data() {
         return {
@@ -144,7 +166,8 @@ export default {
                 { label: '活动', value: 'activity' },
                 { label: '多个藏品', value: 'collections' },
                 { label: '指定链接', value: 'hyperlink' }
-            ]
+            ],
+            settings: []
         };
     },
     methods: {

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

@@ -0,0 +1,386 @@
+<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="pic" v-if="menu.parent">
+                                <single-upload v-model="menu.pic"></single-upload>
+                            </el-form-item>
+                            <el-form-item label="备注" prop="description">
+                                <el-input v-model="menu.description"></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>
+import SingleUpload from '../components/SingleUpload.vue';
+export default {
+    created() {
+        this.getData()
+    },
+    data() {
+        return {
+            dialogVisible: false,
+            curr: null,
+            loading: false,
+            menus: [],
+            menu: {
+                name: '',
+                pic: '',
+                description: ''
+            },
+            parent: null,
+            currentRef: null,
+            edit: false,
+            expandKeys: [],
+            authorities: []
+        };
+    },
+    methods: {
+        addRootMenu() {
+            this.menu = {
+                name: '',
+                pic: '',
+                description: ''
+            };
+            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: '',
+                pic: '',
+                description: ''
+            };
+            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,
+                            del: true,
+                            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="url">{data.description}</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>

+ 1 - 0
src/test/java/com/izouma/nineth/CommonTest.java

@@ -71,6 +71,7 @@ import java.util.*;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ForkJoinPool;
+import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.IntStream;