Prechádzať zdrojové kódy

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

panhui 3 rokov pred
rodič
commit
bdada26c67
26 zmenil súbory, kde vykonal 1179 pridanie a 226 odobranie
  1. 22 6
      src/main/java/com/izouma/nineth/domain/PublicScreenChat.java
  2. 0 23
      src/main/java/com/izouma/nineth/dto/MetaWebsocketMessage.java
  3. 1 1
      src/main/java/com/izouma/nineth/enums/MetaItemEnum.java
  4. 10 2
      src/main/java/com/izouma/nineth/repo/MetaItemRepo.java
  5. 20 0
      src/main/java/com/izouma/nineth/service/MetaItemService.java
  6. 1 1
      src/main/java/com/izouma/nineth/service/MetaPlayerInfoService.java
  7. 12 0
      src/main/java/com/izouma/nineth/service/PurchaseLevelService.java
  8. 65 0
      src/main/java/com/izouma/nineth/web/MetaItemController.java
  9. 7 9
      src/main/java/com/izouma/nineth/web/MetaPlayerInfoController.java
  10. 8 1
      src/main/java/com/izouma/nineth/web/MetaSpatialInfoController.java
  11. 74 43
      src/main/java/com/izouma/nineth/websocket/PublicScreenChatWebsocket.java
  12. 1 0
      src/main/resources/genjson/MetaItem.json
  13. BIN
      src/main/vue/src/assets/png-diwen-bai.png
  14. 128 81
      src/main/vue/src/components/phone/Home.vue
  15. 175 0
      src/main/vue/src/components/phone/NewsLarge.vue
  16. 7 1
      src/main/vue/src/components/phone/module.vue
  17. 53 19
      src/main/vue/src/components/phone/productLarge.vue
  18. 1 0
      src/main/vue/src/main.js
  19. 17 1
      src/main/vue/src/router.js
  20. 145 0
      src/main/vue/src/styles/font.less
  21. 75 13
      src/main/vue/src/styles/theme.less
  22. 19 19
      src/main/vue/src/views/Admin.vue
  23. 132 0
      src/main/vue/src/views/MetaItemEdit.vue
  24. 175 0
      src/main/vue/src/views/MetaItemList.vue
  25. 16 2
      src/main/vue/src/views/PublicScreenChatList.vue
  26. 15 4
      src/main/vue/src/views/company/CompanyTheme.vue

+ 22 - 6
src/main/java/com/izouma/nineth/domain/PublicScreenChat.java

@@ -19,15 +19,31 @@ import java.time.LocalDateTime;
 @ApiModel("元宇宙用户聊天信息")
 public class PublicScreenChat extends BaseEntity {
 
-    @ApiModelProperty("发送方姓名")
-    @ExcelProperty("发送方姓名")
+    @ApiModelProperty("发送方昵称")
+    @ExcelProperty("发送方昵称")
     @Searchable
-    private String fromNickName;
+    private String nickname;
 
-    @ApiModelProperty("发送方id")
-    @ExcelProperty("发送方id")
+    @ApiModelProperty("发送方用户id")
+    @ExcelProperty("发送方用户id")
     @Searchable
-    private String fromUserId;
+    private String userId;
+
+    @ApiModelProperty("勋章等级")
+    @ExcelProperty("勋章等级")
+    private int level;
+
+    @ApiModelProperty("境界")
+    @ExcelProperty("境界")
+    private String realm;
+
+    @ApiModelProperty("头衔")
+    @ExcelProperty("头衔")
+    private String title;
+
+    @ApiModelProperty("头像")
+    @ExcelProperty("头像")
+    private String avatar;
 
     @ApiModelProperty("消息内容")
     @ExcelProperty("消息内容")

+ 0 - 23
src/main/java/com/izouma/nineth/dto/MetaWebsocketMessage.java

@@ -1,23 +0,0 @@
-package com.izouma.nineth.dto;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-@Data
-@AllArgsConstructor
-@NoArgsConstructor
-@ApiModel("元宇宙websocket通用返回消息")
-public class MetaWebsocketMessage {
-
-    @ApiModelProperty("消息类型 1 -> " +
-            "上线 2 -> 下线 " +
-            "3 -> 重复登陆")
-    private Integer type;
-
-    @ApiModelProperty("提示语")
-    private String tip;
-
-}

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

@@ -3,7 +3,7 @@ package com.izouma.nineth.enums;
 
 public enum MetaItemEnum {
 
-    BUILDING("建筑");
+    META_SHOW_ROOM("元宇宙展厅");
 
     private final String description;
 

+ 10 - 2
src/main/java/com/izouma/nineth/repo/MetaItemRepo.java

@@ -1,14 +1,22 @@
 package com.izouma.nineth.repo;
 
-
 import com.izouma.nineth.domain.MetaItem;
 import com.izouma.nineth.enums.MetaItemEnum;
 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 MetaItemRepo extends JpaRepository<MetaItem, Long>, JpaSpecificationExecutor<MetaItem> {
+    @Query("update MetaItem t set t.del = true where t.id = ?1")
+    @Modifying
+    @Transactional
+    void softDelete(Long id);
 
     List<MetaItem> findAllByType(MetaItemEnum type);
-}
+
+    MetaItem findByNameAndTypeAndDel(String name, MetaItemEnum type, boolean del);
+}

+ 20 - 0
src/main/java/com/izouma/nineth/service/MetaItemService.java

@@ -0,0 +1,20 @@
+package com.izouma.nineth.service;
+
+import com.izouma.nineth.domain.MetaItem;
+import com.izouma.nineth.dto.PageQuery;
+import com.izouma.nineth.repo.MetaItemRepo;
+import com.izouma.nineth.utils.JpaUtils;
+import lombok.AllArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.stereotype.Service;
+
+@Service
+@AllArgsConstructor
+public class MetaItemService {
+
+    private MetaItemRepo metaItemRepo;
+
+    public Page<MetaItem> all(PageQuery pageQuery) {
+        return metaItemRepo.findAll(JpaUtils.toSpecification(pageQuery, MetaItem.class), JpaUtils.toPageRequest(pageQuery));
+    }
+}

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

@@ -107,7 +107,7 @@ public class MetaPlayerInfoService {
 
     private List<BuildingDTO> buildingList(Long userId, List<SpaceObjectsInfo> spaceObjectsInfos) {
         List<BuildingDTO> buildingList = new ArrayList<>();
-        List<MetaItem> metaItems = metaItemRepo.findAllByType(MetaItemEnum.BUILDING);
+        List<MetaItem> metaItems = metaItemRepo.findAllByType(MetaItemEnum.META_SHOW_ROOM);
         // 统计该用户所有物品信息
         metaItems.forEach(metaItem -> {
             List<Asset> assets = assetRepo.findAllByUserIdAndNameLike(userId, "%" + metaItem.getName() + "%");

+ 12 - 0
src/main/java/com/izouma/nineth/service/PurchaseLevelService.java

@@ -22,4 +22,16 @@ public class PurchaseLevelService {
         return new PageWrapper<>(page.getContent(), page.getPageable().getPageNumber(),
                 page.getPageable().getPageSize(), page.getTotalElements());
     }
+
+    public PurchaseLevel findPurchaseLevelByLevel(int level) {
+        int maxStartLevel = purchaseLevelRepo.findMaxStartLevel();
+        PurchaseLevel purchaseLevel;
+        if (level >= maxStartLevel) {
+            purchaseLevel = purchaseLevelRepo.findByStartLevel(maxStartLevel);
+        } else {
+            purchaseLevel = purchaseLevelRepo.findByLevel(level);
+        }
+        return purchaseLevel;
+    }
+
 }

+ 65 - 0
src/main/java/com/izouma/nineth/web/MetaItemController.java

@@ -0,0 +1,65 @@
+package com.izouma.nineth.web;
+
+import com.izouma.nineth.domain.MetaItem;
+import com.izouma.nineth.dto.PageQuery;
+import com.izouma.nineth.exception.BusinessException;
+import com.izouma.nineth.repo.MetaItemRepo;
+import com.izouma.nineth.service.MetaItemService;
+import com.izouma.nineth.utils.ObjUtils;
+import com.izouma.nineth.utils.excel.ExcelUtils;
+import lombok.AllArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+import java.util.Objects;
+
+@RestController
+@RequestMapping("/metaItem")
+@AllArgsConstructor
+public class MetaItemController extends BaseController {
+    private MetaItemService metaItemService;
+    private MetaItemRepo metaItemRepo;
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/save")
+    public MetaItem save(@RequestBody MetaItem record) {
+        MetaItem metaItem = metaItemRepo.findByNameAndTypeAndDel(record.getName(), record.getType(), false);
+        if (Objects.nonNull(metaItem) && !Objects.equals(metaItem.getId(), record.getId())) {
+            throw new BusinessException("该类型物品名称配置已经存在!");
+        }
+        if (record.getId() != null) {
+            MetaItem orig = metaItemRepo.findById(record.getId()).orElseThrow(new BusinessException("无记录"));
+            ObjUtils.merge(orig, record);
+            return metaItemRepo.save(orig);
+        }
+        return metaItemRepo.save(record);
+    }
+
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/all")
+    public Page<MetaItem> all(@RequestBody PageQuery pageQuery) {
+        return metaItemService.all(pageQuery);
+    }
+
+    @GetMapping("/get/{id}")
+    public MetaItem get(@PathVariable Long id) {
+        return metaItemRepo.findById(id).orElseThrow(new BusinessException("无记录"));
+    }
+
+    @PostMapping("/del/{id}")
+    public void del(@PathVariable Long id) {
+        metaItemRepo.softDelete(id);
+    }
+
+    @GetMapping("/excel")
+    @ResponseBody
+    public void excel(HttpServletResponse response, PageQuery pageQuery) throws IOException {
+        List<MetaItem> data = all(pageQuery).getContent();
+        ExcelUtils.export(response, data);
+    }
+}
+

+ 7 - 9
src/main/java/com/izouma/nineth/web/MetaPlayerInfoController.java

@@ -4,8 +4,12 @@ import cn.hutool.core.collection.CollectionUtil;
 import com.izouma.nineth.domain.*;
 import com.izouma.nineth.dto.MetaRestResult;
 import com.izouma.nineth.exception.BusinessException;
-import com.izouma.nineth.repo.*;
+import com.izouma.nineth.repo.MetaPlayerOfflineInfoRepo;
+import com.izouma.nineth.repo.MetaPlayerWearRepo;
+import com.izouma.nineth.repo.MetaUserRepo;
+import com.izouma.nineth.repo.UserRepo;
 import com.izouma.nineth.service.MetaPlayerInfoService;
+import com.izouma.nineth.service.PurchaseLevelService;
 import lombok.AllArgsConstructor;
 import org.springframework.web.bind.annotation.*;
 
@@ -27,7 +31,7 @@ public class MetaPlayerInfoController {
 
     private MetaUserRepo metaUserRepo;
 
-    private PurchaseLevelRepo purchaseLevelRepo;
+    private PurchaseLevelService purchaseLevelService;
 
     @GetMapping("/{userId}/detail")
     public MetaRestResult<MetaPlayerInfo> findMetaPlayerInfo(@PathVariable Long userId) {
@@ -38,13 +42,7 @@ public class MetaPlayerInfoController {
         MetaPlayerInfo metaPlayerInfo = new MetaPlayerInfo();
         metaPlayerInfo.setAvatar(user.getAvatar());
         metaPlayerInfo.setLevel(user.getLevel());
-        int maxStartLevel = purchaseLevelRepo.findMaxStartLevel();
-        PurchaseLevel purchaseLevel;
-        if (user.getLevel() >= maxStartLevel) {
-            purchaseLevel = purchaseLevelRepo.findByStartLevel(maxStartLevel);
-        } else {
-            purchaseLevel = purchaseLevelRepo.findByLevel(user.getLevel());
-        }
+        PurchaseLevel purchaseLevel = purchaseLevelService.findPurchaseLevelByLevel(user.getLevel());
         metaPlayerInfo.setRealm(purchaseLevel.getRealm());
         metaPlayerInfo.setTitle(purchaseLevel.getTitle());
         metaPlayerInfo.setNickname(user.getNickname());

+ 8 - 1
src/main/java/com/izouma/nineth/web/MetaSpatialInfoController.java

@@ -8,6 +8,7 @@ import com.izouma.nineth.repo.MetaSpatialInfoRepo;
 import com.izouma.nineth.service.MetaSpatialInfoService;
 import com.izouma.nineth.utils.ObjUtils;
 import com.izouma.nineth.utils.excel.ExcelUtils;
+import jodd.util.StringUtil;
 import lombok.AllArgsConstructor;
 import org.springframework.data.domain.Page;
 import org.springframework.web.bind.annotation.*;
@@ -33,7 +34,7 @@ public class MetaSpatialInfoController extends BaseController {
                 throw new BusinessException("当前资产id已经存在");
             }
         }
-        if (Objects.nonNull(record.getHcTxHash())) {
+        if (StringUtil.isNotBlank(record.getHcTxHash())) {
             MetaSpatialInfo metaSpatialInfo = metaSpatialInfoRepo.findByHcTxHashAndDel(record.getHcTxHash(), false);
             if (Objects.nonNull(metaSpatialInfo) && !Objects.equals(metaSpatialInfo.getId(), record.getId())) {
                 throw new BusinessException("当前hash已经存在");
@@ -46,6 +47,12 @@ public class MetaSpatialInfoController extends BaseController {
         if (record.getId() != null) {
             MetaSpatialInfo orig = metaSpatialInfoRepo.findById(record.getId()).orElseThrow(new BusinessException("无记录"));
             ObjUtils.merge(orig, record);
+            if (Objects.isNull(record.getAssetId())) {
+                orig.setAssetId(null);
+            }
+            if (Objects.isNull(record.getUserId())) {
+                orig.setUserId(null);
+            }
             return metaSpatialInfoRepo.save(orig);
         }
         return metaSpatialInfoRepo.save(record);

+ 74 - 43
src/main/java/com/izouma/nineth/websocket/PublicScreenChatWebsocket.java

@@ -2,8 +2,12 @@ package com.izouma.nineth.websocket;
 
 import com.alibaba.fastjson.JSON;
 import com.izouma.nineth.domain.PublicScreenChat;
-import com.izouma.nineth.dto.MetaWebsocketMessage;
+import com.izouma.nineth.domain.PurchaseLevel;
+import com.izouma.nineth.domain.User;
+import com.izouma.nineth.exception.BusinessException;
 import com.izouma.nineth.repo.PublicScreenChatRepo;
+import com.izouma.nineth.repo.UserRepo;
+import com.izouma.nineth.service.PurchaseLevelService;
 import com.izouma.nineth.utils.ApplicationContextUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
@@ -32,10 +36,20 @@ public class PublicScreenChatWebsocket extends WebsocketCommon {
 
     private final String PREFIX = "meta-chat:";
 
+    private UserRepo userRepo;
+
+    private PurchaseLevelService purchaseLevelService;
+
     private void init() {
         if (Objects.isNull(publicScreenChatRepo)) {
             publicScreenChatRepo = (PublicScreenChatRepo) ApplicationContextUtil.getBean("publicScreenChatRepo");
         }
+        if (Objects.isNull(userRepo)) {
+            userRepo = (UserRepo) ApplicationContextUtil.getBean("userRepo");
+        }
+        if (Objects.isNull(purchaseLevelService)) {
+            purchaseLevelService = (PurchaseLevelService) ApplicationContextUtil.getBean("purchaseLevelService");
+        }
     }
 
     @OnOpen
@@ -43,29 +57,28 @@ public class PublicScreenChatWebsocket extends WebsocketCommon {
         init();
         // 判断当前玩家是否在其他地方登陆
         if (clients.containsKey(PREFIX.concat(userId))) {
-            String msg = String.format("玩家[%S]已在别处登陆,sessionId为[%S],正在为您关闭本连接", userId, session.getId());
-            log.info(msg);
-            // 关闭连接
-            MetaWebsocketMessage message = new MetaWebsocketMessage();
-            message.setType(3);
-            message.setTip(msg);
-            sendMessageTo(clients, JSON.toJSONString(message), PREFIX.concat(userId));
+            String msg = String.format("已在别处登陆,sessionId为[%S],正在为您关闭本连接", session.getId());
+            exceptionHandle(userId, msg);
             try {
-                log.info("关闭上次登陆的session连接");
+                log.info("关闭session连接");
                 clients.get(PREFIX.concat(userId)).close();
             } catch (Exception e) {
-                log.error("session close throw exception:", e);
+                exceptionHandle(userId, String.format("session close throw exception[%S]", e));
+                return;
             }
         }
         log.info("现在来连接的sessionId:" + session.getId() + "玩家id:" + userId + "玩家昵称" + nickName);
         clients.put(PREFIX.concat(userId), session);
-        PublicScreenChat publicScreenChat = new PublicScreenChat();
-        publicScreenChat.setFromNickName(nickName);
-        publicScreenChat.setFromUserId(userId);
-        publicScreenChat.setMessageInfo(String.format("玩家[%S][%S]进入大厅", userId, nickName));
-        publicScreenChat.setTime(LocalDateTime.now());
-        PublicScreenChat save = publicScreenChatRepo.save(publicScreenChat);
-        sendMessageToOther(clients, JSON.toJSONString(save), PREFIX.concat(userId));
+        String format = String.format("玩家[%S][%S]进入大厅", userId, nickName);
+        PublicScreenChat publicScreenChat;
+        try {
+            publicScreenChat = savePublicScreenChat(userId, format);
+        } catch (Exception e) {
+            String errMsg = String.format("玩家进入大厅,保存信息发生异常[%S]", e);
+            exceptionHandle(userId, errMsg);
+            return;
+        }
+        sendMessageToOther(clients, JSON.toJSONString(publicScreenChat), PREFIX.concat(userId));
     }
 
     @OnError
@@ -78,42 +91,36 @@ public class PublicScreenChatWebsocket extends WebsocketCommon {
     public void onClose(@PathParam("nickName") String nickName, @PathParam("userId") String userId, Session session) {
         init();
         log.info(String.format("sessionId:[%S] userId:[%S] is closed", session.getId(), userId));
-        PublicScreenChat publicScreenChat = new PublicScreenChat();
-        publicScreenChat.setFromNickName(nickName);
-        publicScreenChat.setFromUserId(userId);
-        publicScreenChat.setMessageInfo(String.format("玩家[%S][%S]离开大厅", userId, nickName));
-        publicScreenChat.setTime(LocalDateTime.now());
-        PublicScreenChat save = publicScreenChatRepo.save(publicScreenChat);
-        sendMessageToOther(clients, JSON.toJSONString(save), PREFIX.concat(userId));
+        String format = String.format("玩家[%S][%S]离开大厅", userId, nickName);
+        PublicScreenChat publicScreenChat;
+        try {
+            publicScreenChat = savePublicScreenChat(userId, format);
+        } catch (Exception e) {
+            String errMsg = String.format("玩家离开大厅,保存信息发生异常[%S]", e);
+            exceptionHandle(userId, errMsg);
+            return;
+        }
+        sendMessageToOther(clients, JSON.toJSONString(publicScreenChat), PREFIX.concat(userId));
         clients.remove(PREFIX.concat(userId));
     }
 
     @OnMessage
-    public void onMessage(@PathParam("nickName") String nickName, @PathParam("userId") String userId, String message) {
+    public void onMessage(@PathParam("userId") String userId, String message) {
         init();
         if (StringUtils.isBlank(message)) {
-            log.error("Illegal parameter : message can not be null");
+            String errMsg = "Illegal parameter : message can not be null";
+            exceptionHandle(userId, errMsg);
             return;
         }
-        PublicScreenChat publicScreenChat = JSON.parseObject(message, PublicScreenChat.class);
-        if (Objects.isNull(publicScreenChat)) {
-            log.error("metaChatResultMessage can not be null");
+        PublicScreenChat publicScreenChat;
+        try {
+            publicScreenChat = savePublicScreenChat(userId, message);
+        } catch (Exception e) {
+            String errMsg = String.format("玩家发送消息,保存信息发生异常[%S]", e);
+            exceptionHandle(userId, errMsg);
             return;
         }
-        if (StringUtils.isBlank(publicScreenChat.getMessageInfo())) {
-            log.error("Illegal parameter : messageInfo can not be null");
-            return;
-        }
-        if (StringUtils.isBlank(publicScreenChat.getFromNickName())) {
-            publicScreenChat.setFromNickName(nickName);
-        }
-        if (StringUtils.isBlank(publicScreenChat.getFromUserId())) {
-            publicScreenChat.setFromUserId(userId);
-        }
-        publicScreenChat.setTime(LocalDateTime.now());
-        // 消息入库
-        PublicScreenChat save = publicScreenChatRepo.save(publicScreenChat);
-        sendMessageToAll(clients, JSON.toJSONString(save), PREFIX.concat(userId));
+        sendMessageToAll(clients, JSON.toJSONString(publicScreenChat), PREFIX.concat(userId));
     }
 
     /**
@@ -135,5 +142,29 @@ public class PublicScreenChatWebsocket extends WebsocketCommon {
             }
         });
     }
+
+    private PublicScreenChat savePublicScreenChat(String userId, String messageInfo) {
+        User user = userRepo.findById(Long.parseLong(userId)).orElse(null);
+        if (Objects.isNull(user)) {
+            throw new BusinessException("用户信息不存在");
+        }
+        PublicScreenChat publicScreenChat = new PublicScreenChat();
+        publicScreenChat.setUserId(userId);
+        publicScreenChat.setAvatar(user.getAvatar());
+        publicScreenChat.setNickname(user.getNickname());
+        publicScreenChat.setLevel(user.getLevel());
+        PurchaseLevel purchaseLevel = purchaseLevelService.findPurchaseLevelByLevel(publicScreenChat.getLevel());
+        publicScreenChat.setRealm(purchaseLevel.getRealm());
+        publicScreenChat.setTitle(purchaseLevel.getTitle());
+        publicScreenChat.setMessageInfo(messageInfo);
+        publicScreenChat.setTime(LocalDateTime.now());
+        return publicScreenChatRepo.save(publicScreenChat);
+    }
+
+    private void exceptionHandle(String userId, String msg) {
+        log.error(msg);
+        // 推送消息给该玩家
+        sendMessageTo(clients, JSON.toJSONString(msg), PREFIX.concat(userId));
+    }
 }
 

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

@@ -0,0 +1 @@
+{"tableName":"MetaItem","className":"MetaItem","remark":"元宇宙物品","genTable":true,"genClass":true,"genList":true,"genForm":true,"genRouter":true,"javaPath":"/Users/xiaohuoban/IdeaProjects/raex_back/src/main/java/com/izouma/nineth","viewPath":"/Users/xiaohuoban/IdeaProjects/raex_back/src/main/vue/src/views","routerPath":"/Users/xiaohuoban/IdeaProjects/raex_back/src/main/vue/src","resourcesPath":"/Users/xiaohuoban/IdeaProjects/raex_back/src/main/resources","dataBaseType":"Mysql","fields":[{"name":"name","modelName":"name","remark":"物品名称","showInList":true,"showInForm":true,"formType":"singleLineText","required":true},{"name":"type","modelName":"type","remark":"物品类型","showInList":true,"showInForm":true,"formType":"select","required":true,"apiFlag":"1","optionsValue":"[{\"label\":\"元宇宙展厅\",\"value\":\"META_SHOW_ROOM\"}]"}],"readTable":false,"dataSourceCode":"dataSource","genJson":"","subtables":[],"update":false,"basePackage":"com.izouma.nineth","tablePackage":"com.izouma.nineth.domain.MetaItem"}

BIN
src/main/vue/src/assets/png-diwen-bai.png


+ 128 - 81
src/main/vue/src/components/phone/Home.vue

@@ -17,47 +17,57 @@
                 width="38"
                 height="38"
                 :radius="38"
-                :src="require('../../assets/img_default_photo.png')"
+                :src="companyInfo.logo || require('../../assets/img_default_photo.png')"
             ></van-image>
-            <div class="text1">探索者!</div>
+            <div class="text1 text3">{{ companyInfo.name }}</div>
         </div>
-        <div class="welcom" v-else>
+        <div class="welcom" v-else-if="theme === 'theme1' || theme === 'theme2'">
             <div class="left">
                 <div class="text1">WELCOME</div>
-                <div class="text2">探索者!</div>
+                <div class="text2 text3">{{ companyInfo.name }}</div>
             </div>
             <van-image
                 width="38"
                 height="38"
                 :radius="38"
-                :src="require('../../assets/img_default_photo.png')"
+                :src="companyInfo.logo || require('../../assets/img_default_photo.png')"
             ></van-image>
         </div>
-
-        <div class="mySwiper" :class="[`swiper-${theme}`]" ref="mySwiper">
-            <div class="swiper-wrapper">
-                <div class="swiper-slide" v-for="item in banners" :key="item.id">
-                    <product-small :info="item"></product-small>
+        <template v-if="theme === 'theme1' || theme === 'theme2' || theme === 'theme3'">
+            <div class="mySwiper" :class="[`swiper-${theme}`]" ref="mySwiper">
+                <div class="swiper-wrapper">
+                    <div class="swiper-slide" v-for="item in banners" :key="item.id">
+                        <product-small :info="item"></product-small>
+                    </div>
                 </div>
+                <!-- 如果需要分页器 -->
+                <div class="swiper-pagination"></div>
+            </div>
+        </template>
+        <div class="large-logo" v-else>
+            <van-image
+                width="100%"
+                height="100%"
+                radius="12"
+                fit="cover"
+                :src="companyInfo.logo || require('../../assets/img_default_photo.png')"
+            ></van-image>
+        </div>
+
+        <div class="home-title">
+            <span>新闻公告</span>
+
+            <div class="title-more">
+                <span>更多</span>
+                <van-icon name="icon-icon_inter" class-prefix="font_family" />
             </div>
-            <!-- 如果需要分页器 -->
-            <div class="swiper-pagination"></div>
         </div>
 
-        <!-- <swiper
-            pagination
-            @slideChange="changeMySwiper"
-            :space-between="theme === 'theme2' || theme === 'theme3' ? 8 : 16"
-            class="mySwiper"
-            :autoplay="{ delay: 5000, disableOnInteraction: false }"
-            v-if="banners.length > 0"
-            slidesPerView="auto"
-            centeredSlides
-        >
-            <swiper-slide v-for="item in banners" :key="item.id">
-                <product-small :info="item"></product-small>
-            </swiper-slide>
-        </swiper> -->
+        <div class="newsList">
+            <news-large v-for="(item, index) in news" :theme="theme" :key="index" :info="item.obj"></news-large>
+        </div>
+
+        <div class="home-title">数字艺术品</div>
 
         <!-- <div class="tabs" v-if="!empty">
             <div class="tab" :class="{ active: active === 0 }" @click="active = 0">数字藏品</div>
@@ -66,8 +76,9 @@
         <div class="listSwiper">
             <product-large
                 v-for="(item, index) in products"
+                :theme="theme"
                 :key="index"
-                :info="products[index].obj"
+                :info="item.obj"
                 :type="item.type"
             ></product-large>
         </div>
@@ -80,15 +91,11 @@ import Swiper from 'swiper/swiper-bundle';
 import 'swiper/swiper.min.css';
 import 'swiper/swiper-bundle.min.css';
 
-// import SwiperCore, { Pagination, Autoplay } from 'swiper';
-
-// // install Swiper modules
-// SwiperCore.use([Pagination, Autoplay]);
-
+import product from '../../mixins/product';
 import ProductLarge from './productLarge.vue';
+import NewsLarge from './NewsLarge.vue';
 import ProductSmall from './productSmall.vue';
 import { mapState } from 'vuex';
-import { Image as VanImage } from 'vant';
 
 export default {
     name: 'home',
@@ -96,12 +103,19 @@ export default {
         theme: {
             type: String,
             default: 'theme2'
+        },
+        companyInfo: {
+            type: Object,
+            default: () => {
+                return {};
+            }
         }
     },
+    mixins: [product],
     components: {
         ProductLarge,
         ProductSmall,
-        VanImage
+        NewsLarge
     },
     computed: {
         ...mapState(['userInfo']),
@@ -146,13 +160,35 @@ export default {
             riskShow: false,
             activeIndex: 0,
             isLoading: false,
-            mySwiper: null
+            mySwiper: null,
+            companyInfo: {}
         };
     },
     watch: {
         theme() {
             this.$nextTick(() => {
-                this.mySwiper.destroy();
+                if (this.mySwiper) {
+                    this.mySwiper.destroy();
+                }
+                if (this.$refs.mySwiper) {
+                    this.mySwiper = new Swiper(this.$refs.mySwiper, {
+                        pagination: {
+                            el: '.swiper-pagination'
+                        },
+                        autoplay: { delay: 5000, disableOnInteraction: false },
+                        spaceBetween: this.theme === 'theme2' || this.theme === 'theme3' ? 8 : 16,
+                        slidesPerView: 'auto',
+                        centeredSlides: true
+                    });
+                }
+            });
+        }
+    },
+    mounted() {
+        this.getInit();
+
+        this.$nextTick(() => {
+            if (this.$refs.mySwiper) {
                 this.mySwiper = new Swiper(this.$refs.mySwiper, {
                     pagination: {
                         el: '.swiper-pagination'
@@ -162,23 +198,11 @@ export default {
                     slidesPerView: 'auto',
                     centeredSlides: true
                 });
-            });
-        }
-    },
-    mounted() {
-        this.getInit();
-        console.log(new Swiper());
-        this.$nextTick(() => {
-            this.mySwiper = new Swiper(this.$refs.mySwiper, {
-                pagination: {
-                    el: '.swiper-pagination'
-                },
-                autoplay: { delay: 5000, disableOnInteraction: false },
-                spaceBetween: this.theme === 'theme2' || this.theme === 'theme3' ? 8 : 16,
-                slidesPerView: 'auto',
-                centeredSlides: true
-            });
+            }
         });
+        // this.$http.get('sysConfig/get/home_bg').then(res => {
+        //     this.bgImg = res.value || '';
+        // });
     },
     methods: {
         changeSwiper() {
@@ -199,9 +223,11 @@ export default {
                     this.products = res.filter(item => {
                         return item.type === 'collection';
                     });
-                    this.news = res.filter(item => {
-                        return item.type === 'news';
-                    });
+                    this.news = res
+                        .filter(item => {
+                            return item.type === 'news';
+                        })
+                        .slice(0, 3);
                 })
             ]).then(() => {
                 this.$toast.clear();
@@ -328,7 +354,7 @@ export default {
 
 <style lang="less" scoped>
 .darkBg {
-    background-color: #181818;
+    background-color: var(--bg);
 }
 .theme2-bg {
     width: 221px;
@@ -340,7 +366,7 @@ export default {
 }
 .theme3-bg {
     width: 100%;
-    position: absolute;
+    position: fixed;
     top: 0;
     left: 0;
     height: auto;
@@ -349,39 +375,21 @@ export default {
 .top {
     display: flex;
     padding: 9px 16px;
-    background-color: @bg;
+    background-color: var(--bg);
     display: flex;
     align-items: center;
     .logo {
         width: 74px;
         height: 26px;
     }
-
-    .search {
-        flex-grow: 1;
-        background-color: #fff;
-        display: flex;
-        align-items: center;
-        margin-left: 10px;
-        padding: 4px 20px;
-        border-radius: 21px;
-        img {
-            width: 16px;
-            height: 16px;
-            margin-right: 10px;
-        }
-        font-size: 14px;
-        color: @text3;
-        line-height: 24px;
-    }
 }
 
 .home {
     width: 100%;
-    // background-color: #fff;
+    // background-color: @bg3;
     position: relative;
     z-index: 1;
-    background-color: #272b2e;
+    background-color: var(--bg2);
     padding-top: var(--safe-top);
     overflow-y: auto;
     max-height: 720px;
@@ -396,7 +404,6 @@ export default {
     padding: 16px 0;
     // margin: 0 16px;
     box-sizing: border-box;
-    position: relative;
     // padding-bottom: 35px;
 
     .swiper-slide {
@@ -409,7 +416,7 @@ export default {
         bottom: 30px;
     }
 
-    /deep/.swiper-pagination-bullet {
+    .swiper-pagination-bullet {
         width: 5px;
         height: 5px;
         border-radius: 5px;
@@ -417,7 +424,8 @@ export default {
         margin: 0 4px;
         opacity: 1;
     }
-    /deep/.swiper-pagination-bullet-active {
+
+    .swiper-pagination-bullet-active {
         background: var(--prim);
     }
 }
@@ -441,6 +449,20 @@ export default {
         }
     }
 }
+
+.swiper-theme4,
+.swiper-theme5 {
+    padding: 20px 0 16px;
+    .swiper-slide {
+        height: 160px;
+    }
+}
+
+.large-logo {
+    padding: 20px 16px 16px;
+    height: 160px;
+    overflow: hidden;
+}
 // .swiper-slide {
 //     width: 255px;
 // }
@@ -623,4 +645,29 @@ export default {
         border-radius: 8px;
     }
 }
+
+.home-title {
+    font-size: 18px;
+    font-weight: bold;
+    color: var(--text1);
+    line-height: 24px;
+    padding: 10px 16px 8px;
+    .flex();
+
+    span {
+        flex-grow: 1;
+    }
+
+    .title-more {
+        .flex();
+        font-size: 12px;
+        color: #939599;
+        .font_family {
+            font-weight: normal;
+        }
+    }
+}
+.newsList {
+    padding-bottom: 8px;
+}
 </style>

+ 175 - 0
src/main/vue/src/components/phone/NewsLarge.vue

@@ -0,0 +1,175 @@
+<template>
+    <div class="news-small" :class="[`news-${theme}`, type === 'light' ? 'isLight' : '']">
+        <van-image :src="getImg(info.pic)" :radius="12" width="120" height="120" fit="cover" />
+
+        <div class="content">
+            <div class="name van-multi-ellipsis--l2">{{ info.title }}</div>
+            <div class="flex1"></div>
+            <van-button type="primary" round plain size="mini"> 查看</van-button>
+        </div>
+    </div>
+</template>
+
+<script>
+import product from '../../mixins/product';
+export default {
+    mixins: [product],
+    props: {
+        info: {
+            type: Object,
+            default: () => {
+                return {};
+            }
+        },
+        type: {
+            type: String,
+            default: 'dark'
+        },
+        theme: {
+            type: String,
+            default: 'theme2'
+        }
+    },
+    computed: {
+        time() {
+            if (this.info.startTime) {
+                if (this.dayjs().isSameOrBefore(this.info.startTime, 'YYYY-MM-DD HH:mm:ss')) {
+                    return this.dayjs(this.info.startTime).format('MM月DD日');
+                }
+            }
+
+            return '';
+        }
+    },
+    mounted() {
+        if (this.info.startTime) {
+            var x = this.dayjs(this.info.startTime, 'YYYY-MM-DD HH:mm:ss');
+            var y = this.dayjs();
+            let d = this.dayjs.duration(x.diff(y));
+            let day = parseInt(d.asDays());
+            if (day <= 0) {
+                this.getTime(this.info.startTime);
+            }
+        }
+    },
+    methods: {
+        likeProduct() {
+            if (!this.info.liked) {
+                this.$http.get(`/collection/${this.info.id}/like`).then(() => {
+                    this.$emit('update:info', {
+                        ...this.info,
+                        liked: true,
+                        likes: this.info.likes + 1
+                    });
+                    this.$toast.success('收藏成功');
+                });
+            } else {
+                this.$http.get(`/collection/${this.info.id}/unlike`).then(() => {
+                    this.$emit('update:info', {
+                        ...this.info,
+                        liked: false,
+                        likes: this.info.likes - 1
+                    });
+                    this.$toast.success('取消收藏');
+                });
+            }
+        }
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.news-small {
+    width: calc(354px - 32px);
+    margin: 8px 16px;
+    position: relative;
+    background-color: var(--bglight);
+    display: inline-flex;
+    border-radius: 12px;
+    overflow: hidden;
+
+    .bg {
+        position: absolute;
+        width: 92px;
+        height: 116px;
+        right: 0;
+        bottom: 0;
+        z-index: 0;
+    }
+
+    .van-image {
+        display: block;
+        position: relative;
+        z-index: 2;
+        flex-shrink: 0;
+    }
+    .content {
+        padding: 16px 15px 16px 12px;
+        .flex-col();
+        flex-grow: 1;
+        .name {
+            font-size: 16px;
+            font-weight: bold;
+            color: var(--text1);
+            line-height: 22px;
+        }
+
+        .van-button {
+            width: 68px;
+            background-color: var(--fadePrim);
+            color: var(--prim);
+            font-size: 14px;
+            border-width: 0;
+        }
+
+        .flex1 {
+            flex-grow: 1;
+        }
+
+        .sales-list {
+            margin-top: 8px;
+            .flex();
+        }
+    }
+
+    .text {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+    }
+
+    .top-bg {
+        width: 100%;
+        display: block;
+        position: absolute;
+        z-index: 2;
+        top: 0;
+        left: 0;
+    }
+
+    &.isLight {
+        background-color: @bg;
+        .content {
+            .name {
+                color: #000000;
+            }
+            .bottom {
+                .miner {
+                    color: #939599;
+                }
+            }
+        }
+    }
+
+    &.news-theme4 {
+        .content {
+            .van-button {
+                width: 68px;
+                --van-button-plain-background-color: var(--fadePrimlight);
+                --van-button-primary-background-color: var(--primlight);
+                --van-button-mini-font-size: 14px;
+            }
+        }
+    }
+}
+</style>

+ 7 - 1
src/main/vue/src/components/phone/module.vue

@@ -1,7 +1,7 @@
 <template>
     <div class="module">
         <div class="phone" :class="[theme]">
-            <phone-home :theme="theme"></phone-home>
+            <phone-home :theme="theme" :companyInfo="companyInfo"></phone-home>
         </div>
         <div class="phone-bg">
             <div class="bg" :style="{ backgroundImage: `url(${require('../../assets/phone.png')})` }"></div>
@@ -16,6 +16,12 @@ export default {
         theme: {
             type: String,
             default: 'theme2'
+        },
+        companyInfo: {
+            type: Object,
+            default: () => {
+                return {};
+            }
         }
     },
     components: { phoneHome }

+ 53 - 19
src/main/vue/src/components/phone/productLarge.vue

@@ -1,5 +1,5 @@
 <template>
-    <div class="product">
+    <div class="product" :class="[`product-${theme}`]">
         <van-image
             :radius="30"
             width="100%"
@@ -30,7 +30,7 @@
                     </div>
                     <div class="flex1"></div>
                     <div class="price" v-if="info.salable">
-                        <img src="../../assets/icon_jiage.png" alt="" />
+                        <van-icon name="icon-icon_jiage" class-prefix="font_family" />
                         <span> {{ info.price }}</span>
                     </div>
                     <div v-else class="status">仅展示</div>
@@ -38,12 +38,17 @@
             </div>
 
             <div class="sold xianliang" v-if="time && info.scheduleSale">
-                <img src="../../assets/shizhong.png" alt="" />
+                <van-icon name="icon-clock" class-prefix="font_family" />
                 <span>即将开售:{{ startTime || time }}</span>
             </div>
-
-            <div class="sold" v-if="isSolded">已售罄</div>
-            <div class="sold" v-else-if="isSold" style="color: #ff4f50">即将售罄</div>
+            <div class="sold" v-if="isSolded">
+                <van-icon name="icon-jinzhi" class-prefix="font_family" />
+                <span>已售罄</span>
+            </div>
+            <div class="sold" v-else-if="isSold">
+                <van-icon name="icon-info_icon_qianggouzhong" class-prefix="font_family" />
+                <span>即将售罄</span>
+            </div>
         </template>
 
         <div class="content" v-else>
@@ -60,8 +65,8 @@
             </div>
         </div>
 
-        <img class="bg" src="../../assets/png-diwen2.png" alt="" />
-        <!-- <img class="top-bg" v-if="time" src="@assets/collecbg.png" alt="" /> -->
+        <img class="bg" v-if="theme === 'theme4'" src="../../assets/png-diwen-bai.png" alt="" />
+        <img class="bg" v-else src="../../assets/png-diwen2.png" alt="" />
     </div>
 </template>
 
@@ -79,6 +84,10 @@ export default {
         type: {
             type: String,
             default: 'collection'
+        },
+        theme: {
+            type: String,
+            default: 'theme2'
         }
     },
     computed: {
@@ -177,7 +186,7 @@ export default {
         .name {
             font-size: 14px;
             font-weight: bold;
-            color: #fff;
+            color: var(--text1);
             line-height: 24px;
         }
 
@@ -198,7 +207,7 @@ export default {
                 display: inline-block;
                 &.sales-fir {
                     background: var(--prim);
-                    color: #000000;
+                    color: var(--text2);
                 }
                 background-color: var(--fadePrim);
                 color: var(--prim);
@@ -226,12 +235,13 @@ export default {
 
             .price {
                 font-size: 20px;
-                color: #fff;
                 line-height: 20px;
-                font-family: OSP;
-                img {
-                    width: 8px;
-                    display: inline-block;
+                color: var(--text1);
+                .flex();
+                .font_family {
+                    font-size: 8px;
+                    line-height: 16px;
+                    margin-top: 4px;
                 }
             }
         }
@@ -251,22 +261,46 @@ export default {
         top: 0;
         left: 0;
     }
+
+    &.product-theme4 {
+        .content {
+            .sales {
+                span {
+                    background: var(--fadePrimlight);
+                    &.sales-fir {
+                        background: var(--primlight);
+                    }
+                }
+            }
+        }
+        .xianliang {
+            color: var(--primlight);
+        }
+    }
 }
 
 .status {
     font-size: 14px;
-    color: #fff;
+    color: var(--text1);
 }
 .sold {
-    background-color: #ffffff;
+    background-color: var(--bglight);
     font-size: 12px;
-    color: #939599;
-    padding: 0 17px;
+    color: var(--info);
+    padding: 0 17px 0 10px;
     border-radius: 13px;
     line-height: 24px;
     position: absolute;
     top: 16px;
     left: 16px;
     z-index: 3;
+    .flex();
+    .font_family {
+        margin-right: 4px;
+    }
+
+    &.preSold {
+        color: var(--danger);
+    }
 }
 </style>

+ 1 - 0
src/main/vue/src/main.js

@@ -30,6 +30,7 @@ import 'vant/lib/index.css';
 import 'normalize.css/normalize.css';
 import './styles/element_theme/index.css';
 import './styles/theme.less';
+import './styles/font.less';
 import theme from '!less-vars-loader!./styles/common/theme.less';
 // import VueAMap from "vue-amap";
 // Vue.use(VueAMap);

+ 17 - 1
src/main/vue/src/router.js

@@ -1236,6 +1236,22 @@ const router = new Router({
                     meta: {
                        title: '公屏对话',
                     },
+               },
+                {
+                    path: '/metaItemEdit',
+                    name: 'MetaItemEdit',
+                    component: () => import(/* webpackChunkName: "metaItemEdit" */ '@/views/MetaItemEdit.vue'),
+                    meta: {
+                       title: '元宇宙物品编辑',
+                    },
+                },
+                {
+                    path: '/metaItemList',
+                    name: 'MetaItemList',
+                    component: () => import(/* webpackChunkName: "metaItemList" */ '@/views/MetaItemList.vue'),
+                    meta: {
+                       title: '元宇宙物品',
+                    },
                }
                 /**INSERT_LOCATION**/
             ]
@@ -1296,4 +1312,4 @@ router.beforeEach((to, from, next) => {
     }
 });
 
-export default router;
+export default router;

+ 145 - 0
src/main/vue/src/styles/font.less

@@ -0,0 +1,145 @@
+@font-face {
+    font-family: 'OSP';
+    src: url(https://cdn.raex.vip/font/OSP-DIN.ttf);
+}
+
+@font-face {
+    font-family: 'DIN';
+    src: url(https://cdn.raex.vip/font/OSP-DIN.ttf);
+}
+@font-face {
+    font-family: 'SourceHanSans-Medium';
+    src: url(https://cdn.raex.vip/font/SourceHanSans-Medium.otf);
+}
+@font-face {
+    font-family: 'font_family'; /* Project id 2852142 */
+    src: url('//at.alicdn.com/t/c/font_2852142_o0irw07uokf.woff2?t=1665558717758') format('woff2'),
+        url('//at.alicdn.com/t/c/font_2852142_o0irw07uokf.woff?t=1665558717758') format('woff'),
+        url('//at.alicdn.com/t/c/font_2852142_o0irw07uokf.ttf?t=1665558717758') format('truetype');
+}
+.font_family {
+    font-family: 'font_family' !important;
+    font-size: 16px;
+    font-style: normal;
+    -webkit-font-smoothing: antialiased;
+    -moz-osx-font-smoothing: grayscale;
+}
+.flex1{
+    flex-grow: 1;
+}
+.font_family-icon-icon_inter1:before {
+    content: '\e64e';
+    font-size: 24px;
+}
+.font_family-icon-icon_inter:before {
+    content: '\e631';
+    font-size: 24px;
+}
+.font_family-icon-phone:before {
+    content: '\e64b';
+    font-size: 20px;
+}
+
+.font_family-icon-weibiaoti--:before {
+    content: '\e616';
+    font-size: 20px;
+}
+.font_family-icon-jinzhi:before {
+    content: '\e610';
+    font-size: 18px;
+}
+.font_family-icon-clock:before {
+    content: '\e617';
+    font-size: 18px;
+}
+.font_family-icon-info_icon_qianggouzhong:before {
+    content: '\e64d';
+    font-size: 18px;
+}
+.font_family-icon-yanzhengma:before {
+    content: '\e624';
+    font-size: 20px;
+}
+.font_family-icon-icon_gouxuan_pre:before {
+    content: '\e64a';
+    font-size: 24px;
+}
+
+.font_family-icon-tabbar_icon_02:before {
+    content: '\e646';
+    font-size: 28px;
+}
+
+.font_family-icon-tabbar_icon_04:before {
+    content: '\e647';
+    font-size: 28px;
+}
+
+.font_family-icon-tabbar_icon_03:before {
+    content: '\e648';
+    font-size: 28px;
+}
+
+.font_family-icon-tabbar_icon_01:before {
+    content: '\e649';
+    font-size: 28px;
+}
+
+.icon-png-u-weixuanzhong:before {
+    content: '\e640';
+}
+
+.icon-png-sr-weixuanzhong:before {
+    content: '\e641';
+}
+
+.icon-png-ssr-xuanzhong:before {
+    content: '\e642';
+}
+
+.icon-png-right-bg:before {
+    content: '\e643';
+}
+
+.icon-png-middle-bg:before {
+    content: '\e644';
+}
+
+.icon-png-left-bg:before {
+    content: '\e645';
+}
+
+.icon-help::before {
+    content: '\e752';
+}
+
+.icon-sanjiao::before {
+    content: '\e63f';
+    display: block;
+}
+
+.icon-a-icon-dianzan5:before {
+    content: '\e634';
+}
+
+.icon-icon_inter:before {
+    content: '\e631';
+}
+.font_family-icon-icon_jiage {
+    display: inline-block;
+    font-size: 8px;
+    line-height: 8px;
+}
+.font_family-icon-icon_jiage:before {
+    content: '\e632';
+    font-size: 8px;
+    line-height: 8px;
+}
+.icon-icon_jiage:before {
+    content: '\e632';
+    font-size: 8px;
+    line-height: 8px;
+}
+.icon-a-icon-dianzan2:before {
+    content: '\e633';
+}

+ 75 - 13
src/main/vue/src/styles/theme.less

@@ -5,17 +5,13 @@
     --primlight: #3ab200;
     --btnText: #fff;
     --bglight:#373b3e;
-    --swiper-theme-color:var(--prim);
-    --van-primary-color: var(--prim);
-    --van-tabbar-item-active-color: var(--prim);
-    --van-tabs-default-color: var(--prim);
-    --van-tabs-bottom-bar-color: var(--prim);
-    --van-tab-active-text-color: var(--prim);
-    --van-field-error-message-color: var(--prim);
-    --van-button-primary-background-color: var(--prim);
-    --van-button-primary-border-color: var(--prim);
-    --van-number-keyboard-button-background-color: var(--prim);
-    --van-button-primary-background-color:var(--prim);
+    --danger:#FF4F50;
+    --info:#939599;
+    --bg:#181818;
+    --bg2:#272b2e;
+    --bg3:#272b2e;
+    --text1:#fff;
+    --text2:#000;
 }
 
 .theme2 {
@@ -25,7 +21,13 @@
     --primlight: #f5ab23;
     --btnText: #000;
     --bglight:#2F2519;
-    --swiper-theme-color:var(--prim);
+    --danger:#FF4F50;
+    --info:#939599;
+    --bg:#181818;
+    --bg2:#272b2e;
+    --bg3:#272b2e;
+    --text1:#fff;
+    --text2:#000;
     --van-primary-color: var(--prim);
     --van-tabbar-item-active-color: var(--prim);
     --van-tabs-default-color: var(--prim);
@@ -45,7 +47,13 @@
     --primlight: #979DFF;
     --btnText: #000;
     --bglight:#3C3766;
-    --swiper-theme-color:var(--prim);
+    --danger:#FF4F50;
+    --info:#939599;
+    --bg:#181818;
+    --bg2:#272b2e;
+    --bg3:#272b2e;
+    --text1:#fff;
+    --text2:#000;
     --van-primary-color: var(--prim);
     --van-tabbar-item-active-color: var(--prim);
     --van-tabs-default-color: var(--prim);
@@ -57,3 +65,57 @@
     --van-number-keyboard-button-background-color: var(--prim);
     --van-button-primary-background-color:var(--prim);
 }
+
+.theme4 {
+    --prim: #51B8FF;
+    --fadePrim: #51B8FF20;
+    --darkPrim: #367bd7;
+    --primlight: #4092FF;
+    --fadePrimlight: #4092FF20;
+    --btnText: #000;
+    --bglight:#fff;
+    --danger:#FF4F50;
+    --info:#939599;
+    --bg:#fff;
+    --bg2:#F5F7FA;
+    --bg3:#fff;
+    --text1:#000;
+    --text2:#fff;
+    --van-primary-color: var(--prim);
+    --van-tabbar-item-active-color: var(--prim);
+    --van-tabs-default-color: var(--prim);
+    --van-tabs-bottom-bar-color: var(--prim);
+    --van-tab-active-text-color: var(--prim);
+    --van-field-error-message-color: var(--prim);
+    --van-button-primary-background-color: var(--prim);
+    --van-button-primary-border-color: var(--prim);
+    --van-number-keyboard-button-background-color: var(--prim);
+    --van-button-primary-background-color:var(--prim);
+}
+
+.theme5 {
+    --prim: #51B8FF;
+    --fadePrim: #51B8FF20;
+    --darkPrim: #367bd7;
+    --primlight: #4092FF;
+    --fadePrimlight: #4092FF20;
+    --btnText: #000;
+    --bglight:#1C1C1C;
+    --danger:#FF4F50;
+    --info:#939599;
+    --bg:#1C1C1C;
+    --bg2:#000000;
+    --bg3:#1C1C1C;
+    --text1:#fff;
+    --text2:#000;
+    --van-primary-color: var(--prim);
+    --van-tabbar-item-active-color: var(--prim);
+    --van-tabs-default-color: var(--prim);
+    --van-tabs-bottom-bar-color: var(--prim);
+    --van-tab-active-text-color: var(--prim);
+    --van-field-error-message-color: var(--prim);
+    --van-button-primary-background-color: var(--prim);
+    --van-button-primary-border-color: var(--prim);
+    --van-number-keyboard-button-background-color: var(--prim);
+    --van-button-primary-background-color:var(--prim);
+}

+ 19 - 19
src/main/vue/src/views/Admin.vue

@@ -280,36 +280,36 @@ export default {
                         active: true,
                         category: '',
                         children: [
+                            // {
+                            //     id: '3252238',
+                            //     name: '轮播图',
+                            //     path: '/bannerList',
+                            //     icon: '',
+                            //     sort: 34,
+                            //     parent: '3252226',
+                            //     root: false,
+                            //     active: true
+                            // },
                             {
-                                id: '3252238',
-                                name: '轮播图',
-                                path: '/bannerList',
+                                id: '3252239',
+                                name: '首页推荐',
+                                path: '/recommendList',
                                 icon: '',
-                                sort: 34,
+                                sort: 35,
                                 parent: '3252226',
                                 root: false,
                                 active: true
                             },
                             {
-                                id: '3252239',
-                                name: '首页推荐',
-                                path: '/recommendList',
+                                id: '3252230',
+                                name: '新闻管理',
+                                path: '/newsList',
                                 icon: '',
-                                sort: 35,
+                                sort: 36,
                                 parent: '3252226',
                                 root: false,
                                 active: true
-                            },
-                            // {
-                            //     id: '3252230',
-                            //     name: '新闻管理',
-                            //     path: '/newsList',
-                            //     icon: '',
-                            //     sort: 36,
-                            //     parent: '3252226',
-                            //     root: false,
-                            //     active: true
-                            // }
+                            }
                         ]
                     },
                     {

+ 132 - 0
src/main/vue/src/views/MetaItemEdit.vue

@@ -0,0 +1,132 @@
+<template>
+	<div class="edit-view">
+		<page-title>
+			<el-button @click="$router.go(-1)" :disabled="saving"> 取消 </el-button>
+			<el-button @click="onDelete" :disabled="saving" type="danger" v-if="formData.id"> 删除 </el-button>
+			<el-button @click="onSave" :loading="saving" type="primary"> 保存 </el-button>
+		</page-title>
+		<div class="edit-view__content-wrapper">
+			<div class="edit-view__content-section">
+				<el-form
+					:model="formData"
+					:rules="rules"
+					ref="form"
+					label-width="80px"
+					label-position="right"
+					size="small"
+					style="max-width: 500px"
+				>
+					<el-form-item prop="name" label="物品名称">
+						<el-input v-model="formData.name"> </el-input>
+					</el-form-item>
+					<el-form-item prop="type" label="物品类型">
+						<el-select v-model="formData.type" clearable filterable placeholder="请选择">
+							<el-option
+								v-for="item in typeOptions"
+								:key="item.value"
+								:label="item.label"
+								:value="item.value"
+							>
+							</el-option>
+						</el-select>
+					</el-form-item>
+					<el-form-item class="form-submit">
+						<el-button @click="onSave" :loading="saving" type="primary"> 保存 </el-button>
+						<el-button @click="onDelete" :disabled="saving" type="danger" v-if="formData.id">
+							删除
+						</el-button>
+						<el-button @click="$router.go(-1)" :disabled="saving"> 取消 </el-button>
+					</el-form-item>
+				</el-form>
+			</div>
+		</div>
+	</div>
+</template>
+<script>
+export default {
+	name: 'MetaItemEdit',
+	created() {
+		if (this.$route.query.id) {
+			this.$http
+				.get('metaItem/get/' + this.$route.query.id)
+				.then(res => {
+					this.formData = res;
+				})
+				.catch(e => {
+					console.log(e);
+					this.$message.error(e.error);
+				});
+		}
+	},
+	data() {
+		return {
+			saving: false,
+			formData: {},
+			rules: {
+				name: [
+					{
+						required: true,
+						message: '请输入物品名称',
+						trigger: 'blur'
+					}
+				],
+				type: [
+					{
+						required: true,
+						message: '请输入物品类型',
+						trigger: 'blur'
+					}
+				]
+			},
+			typeOptions: [{ label: '元宇宙展厅', value: 'META_SHOW_ROOM' }]
+		};
+	},
+	methods: {
+		onSave() {
+			this.$refs.form.validate(valid => {
+				if (valid) {
+					this.submit();
+				} else {
+					return false;
+				}
+			});
+		},
+		submit() {
+			let data = { ...this.formData };
+
+			this.saving = true;
+			this.$http
+				.post('/metaItem/save', data, { body: 'json' })
+				.then(res => {
+					this.saving = false;
+					this.$message.success('成功');
+					this.$router.go(-1);
+				})
+				.catch(e => {
+					console.log(e);
+					this.saving = false;
+					this.$message.error(e.error);
+				});
+		},
+		onDelete() {
+			this.$confirm('删除将无法恢复,确认要删除么?', '警告', { type: 'error' })
+				.then(() => {
+					return this.$http.post(`/metaItem/del/${this.formData.id}`);
+				})
+				.then(() => {
+					this.$message.success('删除成功');
+					this.$router.go(-1);
+				})
+				.catch(e => {
+					if (e !== 'cancel') {
+						console.log(e);
+						this.$message.error((e || {}).error || '删除失败');
+					}
+				});
+		}
+	}
+};
+</script>
+<style lang="less" scoped>
+
+</style>

+ 175 - 0
src/main/vue/src/views/MetaItemList.vue

@@ -0,0 +1,175 @@
+<template>
+    <div  class="list-view">
+        <page-title>
+            <el-button @click="addRow" type="primary" icon="el-icon-plus" :disabled="fetchingData || downloading" class="filter-item">
+                新增
+            </el-button>
+            <el-button @click="download" icon="el-icon-upload2" :loading="downloading" :disabled="fetchingData" class="filter-item">
+                导出
+            </el-button>
+        </page-title>
+        <div class="filters-container">
+            <el-input
+                    placeholder="搜索..."
+                    v-model="search"
+                    clearable
+                    class="filter-item search"
+                    @keyup.enter.native="getData"
+            >
+                <el-button @click="getData" slot="append" icon="el-icon-search"> </el-button>
+            </el-input>
+        </div>
+        <el-table :data="tableData" row-key="id" ref="table"
+                  header-row-class-name="table-header-row"
+                  header-cell-class-name="table-header-cell"
+                  row-class-name="table-row" cell-class-name="table-cell"
+                  :height="tableHeight" v-loading="fetchingData">
+            <el-table-column v-if="multipleMode" align="center" type="selection"
+                             width="50">
+            </el-table-column>
+            <el-table-column prop="id" label="ID" width="100">
+            </el-table-column>
+                                <el-table-column prop="name" label="物品名称"
+>
+                    </el-table-column>
+                    <el-table-column prop="type" label="物品类型"
+                            :formatter="typeFormatter"
+                        >
+                    </el-table-column>
+            <el-table-column
+                    label="操作"
+                    align="center"
+                    fixed="right"
+                    width="150">
+                <template slot-scope="{row}">
+                    <el-button @click="editRow(row)" type="primary" size="mini" plain>编辑</el-button>
+                    <el-button @click="deleteRow(row)" type="danger" size="mini" plain>删除</el-button>
+                </template>
+            </el-table-column>
+        </el-table>
+        <div class="pagination-wrapper">
+            <!-- <div class="multiple-mode-wrapper">
+                <el-button v-if="!multipleMode" @click="toggleMultipleMode(true)">批量编辑</el-button>
+                <el-button-group v-else>
+                    <el-button @click="operation1">批量操作1</el-button>
+                    <el-button @click="operation2">批量操作2</el-button>
+                    <el-button @click="toggleMultipleMode(false)">取消</el-button>
+                </el-button-group>
+            </div> -->
+            <el-pagination background @size-change="onSizeChange"
+                           @current-change="onCurrentChange" :current-page="page"
+                           :page-sizes="[10, 20, 30, 40, 50]" :page-size="pageSize"
+                           layout="total, sizes, prev, pager, next, jumper"
+                           :total="totalElements">
+            </el-pagination>
+        </div>
+
+    </div>
+</template>
+<script>
+    import { mapState } from "vuex";
+    import pageableTable from "@/mixins/pageableTable";
+
+    export default {
+        name: 'MetaItemList',
+        mixins: [pageableTable],
+        data() {
+            return {
+                multipleMode: false,
+                search: "",
+                url: "/metaItem/all",
+                downloading: false,
+                        typeOptions:[{"label":"元宇宙展厅","value":"META_SHOW_ROOM"}],
+            }
+        },
+        computed: {
+            selection() {
+                return this.$refs.table.selection.map(i => i.id);
+            }
+        },
+        methods: {
+                    typeFormatter(row, column, cellValue, index) {
+                        let selectedOption = this.typeOptions.find(i => i.value === cellValue);
+                        if (selectedOption) {
+                            return selectedOption.label;
+                        }
+                        return '';
+                    },
+            beforeGetData() {
+                return { search: this.search, query: { del: false } };
+            },
+            toggleMultipleMode(multipleMode) {
+                this.multipleMode = multipleMode;
+                if (!multipleMode) {
+                    this.$refs.table.clearSelection();
+                }
+            },
+            addRow() {
+                this.$router.push({
+                    path: "/metaItemEdit",
+                    query: {
+                        ...this.$route.query
+                    }
+                });
+            },
+            editRow(row) {
+                this.$router.push({
+                    path: "/metaItemEdit",
+                    query: {
+                    id: row.id
+                    }
+                });
+            },
+            download() {
+                this.downloading = true;
+                this.$axios
+                    .get("/metaItem/excel", { 
+                        responseType: "blob",
+                        params: { size: 10000 }
+                    })
+                    .then(res => {
+                        console.log(res);
+                        this.downloading = false;
+                        const downloadUrl = window.URL.createObjectURL(new Blob([res.data]));
+                        const link = document.createElement("a");
+                        link.href = downloadUrl;
+                        link.setAttribute(
+                            "download",
+                            res.headers["content-disposition"].split("filename=")[1]
+                        );
+                        document.body.appendChild(link);
+                        link.click();
+                        link.remove();
+                    })
+                    .catch(e => {
+                        console.log(e);
+                        this.downloading = false;
+                        this.$message.error(e.error);
+                    });
+            },
+            operation1() {
+                this.$notify({
+                    title: '提示',
+                    message: this.selection
+                });
+            },
+            operation2() {
+                this.$message('操作2');
+            },
+            deleteRow(row) {
+                this.$alert('删除将无法恢复,确认要删除么?', '警告', {type: 'error'}).then(() => {
+                    return this.$http.post(`/metaItem/del/${row.id}`)
+                }).then(() => {
+                    this.$message.success('删除成功');
+                    this.getData();
+                }).catch(e => {
+                    if (e !== 'cancel') {
+                        this.$message.error(e.error);
+                    }
+                })
+            },
+        }
+    }
+</script>
+<style lang="less" scoped>
+</style>

+ 16 - 2
src/main/vue/src/views/PublicScreenChatList.vue

@@ -34,8 +34,22 @@
 			v-loading="fetchingData"
 		>
 			<el-table-column v-if="multipleMode" align="center" type="selection" width="50"> </el-table-column>
-			<el-table-column prop="fromNickName" label="用户昵称"> </el-table-column>
-			<el-table-column prop="fromUserId" label="用户id"> </el-table-column>
+			<el-table-column prop="nickname" label="用户昵称"> </el-table-column>
+			<el-table-column prop="userId" label="用户id"> </el-table-column>
+			<el-table-column prop="avatar" label="头像">
+				<template slot-scope="{ row }">
+					<el-image
+						style="width: 30px; height: 30px"
+						:src="row.avatar"
+						fit="cover"
+						:preview-src-list="[row.avatar]"
+					>
+					</el-image>
+				</template>
+			</el-table-column>
+			<el-table-column prop="level" label="等级"> </el-table-column>
+			<el-table-column prop="realm" label="境界"> </el-table-column>
+			<el-table-column prop="title" label="头衔"> </el-table-column>
 			<el-table-column prop="messageInfo" label="消息内容"> </el-table-column>
 			<el-table-column prop="time" label="消息发送时间"> </el-table-column>
 		</el-table>

+ 15 - 4
src/main/vue/src/views/company/CompanyTheme.vue

@@ -16,6 +16,9 @@
                     size="small"
                     style="max-width: 750px"
                 >
+                    <el-form-item prop="logo" label="LOGO">
+                        <single-upload v-model="formData.logo"></single-upload>
+                    </el-form-item>
                     <el-form-item label="选择主题">
                         <el-radio-group v-model="formData.theme">
                             <el-radio :label="item.value" v-for="(item, index) in themeOptions" :key="index">
@@ -34,7 +37,7 @@
                 </el-form>
 
                 <div class="phone">
-                    <phone-module :theme="formData.theme"></phone-module>
+                    <phone-module :theme="formData.theme" :companyInfo="formData"></phone-module>
                 </div>
             </div>
             <el-dialog title="添加藏品" :visible.sync="showCollectionDialog" width="500px">
@@ -84,6 +87,7 @@ export default {
         this.$http.get(`/company/get/${this.companyId}`).then(res => {
             if (res.theme) {
                 this.formData.theme = res.theme;
+                this.formData.logo = res.logo;
             }
         });
     },
@@ -91,13 +95,16 @@ export default {
         return {
             saving: false,
             formData: {
-                theme: 'theme1'
+                theme: 'theme1',
+                logo: ''
             },
             rules: {},
             themeOptions: [
                 { label: '主题1', value: 'theme1' },
                 { label: '主题2', value: 'theme2' },
-                { label: '主题3', value: 'theme3' }
+                { label: '主题3', value: 'theme3' },
+                { label: '主题4', value: 'theme4' },
+                { label: '主题5', value: 'theme5' }
             ],
             settings: [],
             collections: [],
@@ -114,7 +121,11 @@ export default {
     methods: {
         onSave() {
             this.$http
-                .post('/company/save', { id: this.companyId, theme: this.formData.theme }, { body: 'json' })
+                .post(
+                    '/company/save',
+                    { id: this.companyId, theme: this.formData.theme, logo: this.formData.logo },
+                    { body: 'json' }
+                )
                 .then(res => {
                     this.$message.success('保存成功');
                 });