Ver Fonte

Merge branch 'dev' of http://git.izouma.com/xiongzhu/raex_back into dev

panhui há 4 anos atrás
pai
commit
d64201e7a6
26 ficheiros alterados com 774 adições e 50 exclusões
  1. 1 1
      src/main/java/com/izouma/nineth/annotations/Searchable.java
  2. 1 0
      src/main/java/com/izouma/nineth/config/CacheConfig.java
  3. 2 0
      src/main/java/com/izouma/nineth/config/EventNames.java
  4. 31 0
      src/main/java/com/izouma/nineth/config/RocketMqConfig.java
  5. 3 0
      src/main/java/com/izouma/nineth/domain/Banner.java
  6. 33 0
      src/main/java/com/izouma/nineth/domain/Setting.java
  7. 2 1
      src/main/java/com/izouma/nineth/enums/SearchMode.java
  8. 12 0
      src/main/java/com/izouma/nineth/listener/BroadcastEventListener.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. 0 1
      src/main/java/com/izouma/nineth/security/WebSecurityConfig.java
  14. 8 1
      src/main/java/com/izouma/nineth/service/CacheService.java
  15. 48 0
      src/main/java/com/izouma/nineth/service/SettingService.java
  16. 10 5
      src/main/java/com/izouma/nineth/service/ShowroomService.java
  17. 15 4
      src/main/java/com/izouma/nineth/service/SysConfigService.java
  18. 15 1
      src/main/java/com/izouma/nineth/utils/JpaUtils.java
  19. 2 0
      src/main/java/com/izouma/nineth/web/RecommendController.java
  20. 90 0
      src/main/java/com/izouma/nineth/web/SettingController.java
  21. 1 0
      src/main/java/com/izouma/nineth/web/ShowroomController.java
  22. 19 3
      src/main/java/com/izouma/nineth/web/SysConfigController.java
  23. 1 0
      src/main/resources/genjson/Setting.json
  24. 39 28
      src/main/vue/src/router.js
  25. 26 3
      src/main/vue/src/views/BannerEdit.vue
  26. 386 0
      src/main/vue/src/views/Settings.vue

+ 1 - 1
src/main/java/com/izouma/nineth/annotations/Searchable.java

@@ -12,5 +12,5 @@ import java.lang.annotation.Target;
 public @interface Searchable {
     boolean value() default true;
 
-    SearchMode mode() default SearchMode.PREFIX;
+    SearchMode mode() default SearchMode.CONFIG;
 }

+ 1 - 0
src/main/java/com/izouma/nineth/config/CacheConfig.java

@@ -78,6 +78,7 @@ public class CacheConfig {
 //                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer()));
 //        return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
 //    }
+
     @Bean
     public RedisCacheManager userRedisCacheManager(RedisTemplate redisTemplate) {
         Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>(Object.class);

+ 2 - 0
src/main/java/com/izouma/nineth/config/EventNames.java

@@ -2,4 +2,6 @@ package com.izouma.nineth.config;
 
 public class EventNames {
     public final static String SWITCH_ACCOUNT = "switchAccount";
+
+    public final static String CONFIG_CHANGE = "configChange";
 }

+ 31 - 0
src/main/java/com/izouma/nineth/config/RocketMqConfig.java

@@ -0,0 +1,31 @@
+package com.izouma.nineth.config;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import org.apache.rocketmq.spring.support.RocketMQMessageConverter;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.messaging.converter.CompositeMessageConverter;
+import org.springframework.messaging.converter.MappingJackson2MessageConverter;
+import org.springframework.messaging.converter.MessageConverter;
+
+import java.util.List;
+
+@Configuration
+public class RocketMqConfig {
+
+    @Bean
+    public RocketMQMessageConverter createRocketMQMessageConverter() {
+        RocketMQMessageConverter converter = new RocketMQMessageConverter();
+        CompositeMessageConverter compositeMessageConverter = (CompositeMessageConverter) converter.getMessageConverter();
+        List<MessageConverter> messageConverterList = compositeMessageConverter.getConverters();
+        for (MessageConverter messageConverter : messageConverterList) {
+            if (messageConverter instanceof MappingJackson2MessageConverter) {
+                MappingJackson2MessageConverter jackson2MessageConverter = (MappingJackson2MessageConverter) messageConverter;
+                ObjectMapper objectMapper = jackson2MessageConverter.getObjectMapper();
+                objectMapper.registerModules(new JavaTimeModule());
+            }
+        }
+        return converter;
+    }
+}

+ 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/SearchMode.java

@@ -4,5 +4,6 @@ public enum SearchMode {
     PREFIX,
     SUFFIX,
     FULL,
-    EXACT
+    EXACT,
+    CONFIG
 }

+ 12 - 0
src/main/java/com/izouma/nineth/listener/BroadcastEventListener.java

@@ -3,7 +3,9 @@ package com.izouma.nineth.listener;
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.serializer.SerializerFeature;
 import com.izouma.nineth.config.EventNames;
+import com.izouma.nineth.enums.SearchMode;
 import com.izouma.nineth.service.AdapayMerchantService;
+import com.izouma.nineth.utils.JpaUtils;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.rocketmq.spring.annotation.ConsumeMode;
@@ -37,6 +39,16 @@ public class BroadcastEventListener implements RocketMQListener<JSONObject> {
                         log.error("event error", e);
                     }
                     break;
+                case EventNames.CONFIG_CHANGE:
+                    try {
+                        JSONObject data = message.getJSONObject("data");
+                        if ("default_search_mode".equals(data.getString("name"))) {
+                            SearchMode searchMode = SearchMode.valueOf(data.getString("value"));
+                            JpaUtils.setDefaultSearchMode(searchMode);
+                        }
+                    } catch (Exception e) {
+                        log.error("event error", e);
+                    }
             }
         }
     }

+ 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);
 }

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

@@ -100,7 +100,6 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
                 .antMatchers("/blindBoxItem/all").permitAll()
                 .antMatchers("/collection/recommend").permitAll()
                 .antMatchers("/order/**/status").permitAll()
-                .antMatchers("/order/checkLimit").permitAll()
                 .antMatchers("/mintOrder/**/status").permitAll()
                 .antMatchers("/activity/all").permitAll()
                 .antMatchers("/activity/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() {
+    }
 }

+ 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;
     }
 
 }

+ 15 - 4
src/main/java/com/izouma/nineth/service/SysConfigService.java

@@ -2,6 +2,7 @@ package com.izouma.nineth.service;
 
 import com.izouma.nineth.domain.SysConfig;
 import com.izouma.nineth.dto.PageQuery;
+import com.izouma.nineth.enums.SearchMode;
 import com.izouma.nineth.exception.BusinessException;
 import com.izouma.nineth.repo.SysConfigRepo;
 import com.izouma.nineth.utils.JpaUtils;
@@ -49,7 +50,7 @@ public class SysConfigService {
 
     @PostConstruct
     public void init() {
-        if (!sysConfigRepo.findByName("gift_gas_fee").isPresent()) {
+        if (sysConfigRepo.findByName("gift_gas_fee").isEmpty()) {
             sysConfigRepo.save(SysConfig.builder()
                     .name("gift_gas_fee")
                     .desc("转赠gas费")
@@ -57,7 +58,7 @@ public class SysConfigService {
                     .value("1")
                     .build());
         }
-        if (!sysConfigRepo.findByName("enable_wx_pub").isPresent()) {
+        if (sysConfigRepo.findByName("enable_wx_pub").isEmpty()) {
             sysConfigRepo.save(SysConfig.builder()
                     .name("enable_wx_pub")
                     .desc("使用公众号支付")
@@ -65,7 +66,7 @@ public class SysConfigService {
                     .value("FALSE")
                     .build());
         }
-        if (!sysConfigRepo.findByName("enable_wx_lite").isPresent()) {
+        if (sysConfigRepo.findByName("enable_wx_lite").isEmpty()) {
             sysConfigRepo.save(SysConfig.builder()
                     .name("enable_wx_lite")
                     .desc("使用小程序支付")
@@ -73,7 +74,7 @@ public class SysConfigService {
                     .value("FALSE")
                     .build());
         }
-        if (!sysConfigRepo.findByName("hold_days").isPresent()) {
+        if (sysConfigRepo.findByName("hold_days").isEmpty()) {
             sysConfigRepo.save(SysConfig.builder()
                     .name("hold_days")
                     .desc("持有满几天可销售")
@@ -81,5 +82,15 @@ public class SysConfigService {
                     .value("5")
                     .build());
         }
+        if (sysConfigRepo.findByName("default_search_mode").isEmpty()) {
+            sysConfigRepo.save(SysConfig.builder()
+                    .name("default_search_mode")
+                    .desc("默认搜索方式")
+                    .type(SysConfig.ValueType.STRING)
+                    .value("FULL")
+                    .build());
+        }
+        SearchMode searchMode = SearchMode.valueOf(sysConfigRepo.findByName("default_search_mode").get().getValue());
+        JpaUtils.setDefaultSearchMode(searchMode);
     }
 }

+ 15 - 1
src/main/java/com/izouma/nineth/utils/JpaUtils.java

@@ -3,11 +3,13 @@ package com.izouma.nineth.utils;
 import com.izouma.nineth.annotations.Searchable;
 import com.izouma.nineth.annotations.SearchableOne;
 import com.izouma.nineth.dto.PageQuery;
+import com.izouma.nineth.enums.SearchMode;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.data.domain.PageRequest;
 import org.springframework.data.domain.Sort;
 import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Component;
 
 import javax.persistence.criteria.CriteriaBuilder;
 import javax.persistence.criteria.CriteriaQuery;
@@ -23,7 +25,15 @@ import java.util.regex.Pattern;
 
 @Slf4j
 @SuppressWarnings("ALL")
+@Component
 public class JpaUtils {
+
+    private static SearchMode defaultSearchMode = SearchMode.PREFIX;
+
+    public static void setDefaultSearchMode(SearchMode defaultSearchMode) {
+        JpaUtils.defaultSearchMode = defaultSearchMode;
+    }
+
     public static PageRequest toPageRequest(PageQuery pageQuery) {
         PageRequest pageRequest;
         if (StringUtils.isNotEmpty(pageQuery.getSort())) {
@@ -171,8 +181,12 @@ public class JpaUtils {
                     continue;
                 }
 
+                SearchMode searchMode = annotation.mode();
+                if (searchMode == SearchMode.CONFIG) {
+                    searchMode = defaultSearchMode;
+                }
                 if (field.getType() == String.class) {
-                    switch (annotation.mode()) {
+                    switch (searchMode) {
                         case PREFIX:
                             or.add(criteriaBuilder.like(root.get(field.getName()), pageQuery.getSearch() + "%"));
                             break;

+ 2 - 0
src/main/java/com/izouma/nineth/web/RecommendController.java

@@ -9,6 +9,7 @@ import com.izouma.nineth.service.RecommendService;
 import com.izouma.nineth.utils.ObjUtils;
 import com.izouma.nineth.utils.excel.ExcelUtils;
 import lombok.AllArgsConstructor;
+import org.springframework.cache.annotation.CacheEvict;
 import org.springframework.data.domain.Page;
 import org.springframework.web.bind.annotation.*;
 
@@ -51,6 +52,7 @@ public class RecommendController extends BaseController {
         return recommendRepo.findById(id).orElseThrow(new BusinessException("无记录"));
     }
 
+    @CacheEvict(value = "recommend", key = "#id")
     @PostMapping("/del/{id}")
     public void del(@PathVariable Long id) {
         recommendRepo.deleteById(id);

+ 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.*;
 

+ 19 - 3
src/main/java/com/izouma/nineth/web/SysConfigController.java

@@ -1,5 +1,8 @@
 package com.izouma.nineth.web;
 
+import com.alibaba.fastjson.JSONObject;
+import com.izouma.nineth.config.EventNames;
+import com.izouma.nineth.config.GeneralProperties;
 import com.izouma.nineth.domain.SysConfig;
 import com.izouma.nineth.dto.PageQuery;
 import com.izouma.nineth.exception.BusinessException;
@@ -7,6 +10,7 @@ import com.izouma.nineth.repo.SysConfigRepo;
 import com.izouma.nineth.service.SysConfigService;
 import com.izouma.nineth.utils.excel.ExcelUtils;
 import lombok.AllArgsConstructor;
+import org.apache.rocketmq.spring.core.RocketMQTemplate;
 import org.springframework.cache.annotation.CacheEvict;
 import org.springframework.data.domain.Page;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -21,14 +25,26 @@ import java.util.List;
 @RequestMapping("/sysConfig")
 @AllArgsConstructor
 public class SysConfigController extends BaseController {
-    private SysConfigService sysConfigService;
-    private SysConfigRepo    sysConfigRepo;
+    private SysConfigService  sysConfigService;
+    private SysConfigRepo     sysConfigRepo;
+    private RocketMQTemplate  rocketMQTemplate;
+    private GeneralProperties generalProperties;
 
     @PreAuthorize("hasRole('ADMIN')")
     @PostMapping("/save")
     @CacheEvict(value = {"SysConfigServiceGetBigDecimal", "SysConfigServiceGetTime", "SysConfigServiceGetBoolean", "SysConfigServiceGetInt"}, allEntries = true)
     public SysConfig save(@RequestBody SysConfig record) {
-        return sysConfigRepo.save(record);
+        record = sysConfigRepo.save(record);
+
+        JSONObject jsonObject = new JSONObject();
+        jsonObject.put("name", EventNames.CONFIG_CHANGE);
+        JSONObject data = new JSONObject();
+        data.put("name", record.getName());
+        data.put("value", record.getValue());
+        jsonObject.put("data", data);
+        rocketMQTemplate.convertAndSend(generalProperties.getBroadcastEventTopic(), jsonObject);
+
+        return record;
     }
 
 

+ 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>