Przeglądaj źródła

初步对接徽章相关接口

任一存 2 lat temu
rodzic
commit
b779f12a3e

+ 7 - 1
README.md

@@ -1,2 +1,8 @@
 # 测试环境部署地址
-阿里云-4dkk-culture/华南1(深圳)/wenlange/display/
+阿里云-4dkk-culture/华南1(深圳)/wenlange/display/
+
+# 测试账号
+renyicun,123456
+
+# 原则
+api负责store,store负责localStorage

+ 2 - 2
public/static/js/Hot.js

@@ -37,8 +37,8 @@ window.initHot = function (model) {
   var getCommonHotspotUrl = function (link) {
     var querySectionInLink = link.split('?')[1]
     var langParam = "en" == manage.number("lang") ? "&lang=" + manage.number("lang") : ""
-    // return `http://192.168.20.16:8082/#/${browser.isMobile() ? 'mobile' : 'web'}/?${querySectionInLink}&time=${randomTime().getTime()}&id=${window.number}${langParam}`
-    return `/XuzhouHanStoneReliefArtMuseum/hotspot/index.html#/${browser.isMobile() ? 'mobile' : 'web'}/?${querySectionInLink}&time=${randomTime().getTime()}&id=${window.number}${langParam}`
+    return `http://192.168.20.16:8084/#/${browser.isMobile() ? 'mobile' : 'web'}/?${querySectionInLink}&time=${randomTime().getTime()}&id=${window.number}${langParam}`
+    // return `/XuzhouHanStoneReliefArtMuseum/hotspot/index.html#/${browser.isMobile() ? 'mobile' : 'web'}/?${querySectionInLink}&time=${randomTime().getTime()}&id=${window.number}${langParam}`
   }
   var removeSrcPostMark = function (url) {//去除texture.load时自动加上的'?'
     var index = url.indexOf('?')

+ 10 - 0
src/App.vue

@@ -24,6 +24,16 @@ export default {
     if (this.isMobile) {
       document.body.classList.add('mobile')
     }
+
+    globalApi.checkLoginStatusAndProcess().then((isLogin) => {
+      if (isLogin) {
+        globalApi.fetchBadgeAndVisitData()
+      } else {
+
+      }
+    })
+  },
+  methods: {
   }
 }
 </script>

+ 50 - 0
src/api.js

@@ -22,6 +22,43 @@ export default {
       store.commit('setUserInfo', res.data.data.user)
     }
   },
+  async logout() {
+    const res = await axios({
+      method: 'get',
+      url: `${process.env.VUE_APP_API_PREFIX}/api/admin/logout`,
+      headers: {
+        token: store.state.token,
+      }
+    })
+    if (res?.data?.code === 0) {
+      store.commit('logoutCallback')
+    }
+  },
+  async checkLoginStatusAndProcess() {
+    const lastToken = localStorage.getItem('token')
+    const lastUserInfoStr = localStorage.getItem('userInfo')
+    if (lastToken && lastUserInfoStr) {
+      const res = await axios({
+        method: 'get',
+        url: `${process.env.VUE_APP_API_PREFIX}/api/admin/checkLogin`,
+        headers: {
+          token: lastToken,
+        }
+      })
+      if (res.data.code === 0 && res.data.data) {
+        store.commit('setLoginStatus', true)
+        store.commit('setToken', lastToken)
+        store.commit('setUserInfo', JSON.parse(lastUserInfoStr))
+        return true
+      } else {
+        store.commit('logoutCallback')
+        return false
+      }
+    } else {
+      store.commit('logoutCallback')
+      return false
+    }
+  },
   async signUp(userName, password) {
     const res = await axios({
       method: 'post',
@@ -38,4 +75,17 @@ export default {
       return
     }
   },
+  async fetchBadgeAndVisitData() {
+    const res = await axios({
+      method: 'get',
+      url: `${process.env.VUE_APP_API_PREFIX}/api/cms/question/getVisit`,
+      headers: {
+        token: store.state.token,
+      }
+    })
+    store.commit('setBadgeArchCurrent', res.data.data['1'])
+    store.commit('setBadgeHistoryCurrent', res.data.data['2'])
+    store.commit('setBadgeProtectorCurrent', res.data.data['3'])
+    store.commit('setVisitCount', res.data.visit)
+  },
 }

BIN
src/assets/images/pull-down.png


src/assets/images/quiz-menu-bg-visitor-pc.png → src/assets/images/quiz-menu-bg-pc.png


BIN
src/assets/images/user-info-bg-pc.png


+ 13 - 2
src/pages/Home.vue

@@ -15,7 +15,14 @@
     <MiniMapDecorator
       class="mini-map-decorator"
     />
-    <QuizMenu class="quiz-menu" />
+    <QuizMenu
+      v-if="!loginStatus"
+      class="quiz-menu"
+    />
+    <UserInfo
+      v-if="loginStatus"
+      class="user-info"
+    />
 
     <!-- 底部菜单 -->
     <div
@@ -105,6 +112,7 @@ import vrCon from "@/views/gui/vrcon"
 import vOther from "@/views/gui/other"
 import MiniMapDecorator from "@/views/gui/MiniMapDecorator.vue"
 import QuizMenu from "@/views/gui/QuizMenu.vue"
+import UserInfo from "@/views/gui/UserInfo.vue"
 
 export default {
   name: "Home",
@@ -122,6 +130,7 @@ export default {
     vOther,
     MiniMapDecorator,
     QuizMenu,
+    UserInfo,
   },
 
   data() {
@@ -131,7 +140,9 @@ export default {
       isMusicInitiallyPlayed: false,
     }
   },
-
+  computed: {
+    ...globalMapState(['loginStatus'])
+  },
   mounted() {
   },
   created() {

+ 37 - 0
src/store/index.js

@@ -8,8 +8,24 @@ export default new Vuex.Store({
     loginStatus: false,
     token: '',
     userInfo: {},
+    badgeArchCurrent: 0,
+    badgeHistoryCurrent: 0,
+    badgeProtectorCurrent: 0,
+    badgeArchGoal: 5,
+    badgeHistoryGoal: 5,
+    badgeProtectorGoal: 5,
+    visitCount: 0,
   },
   getters: {
+    badgeArchForShow(state) {
+      return Math.min(state.badgeArchCurrent, state.badgeArchGoal)
+    },
+    badgeHistoryForShow(state) {
+      return Math.min(state.badgeHistoryCurrent, state.badgeHistoryGoal)
+    },
+    badgeProtectorForShow(state) {
+      return Math.min(state.badgeProtectorCurrent, state.badgeProtectorGoal)
+    },
   },
   mutations: {
     setLoginStatus(state, value) {
@@ -17,9 +33,30 @@ export default new Vuex.Store({
     },
     setToken(state, value) {
       state.token = value
+      localStorage.setItem('token', value)
     },
     setUserInfo(state, value) {
       state.userInfo = value
+      localStorage.setItem('userInfo', JSON.stringify(value))
+    },
+    logoutCallback(state) {
+      state.loginStatus = false
+      state.token = ''
+      localStorage.removeItem('token')
+      state.userInfo = {}
+      localStorage.removeItem('userInfo')
+    },
+    setBadgeArchCurrent(state, value) {
+      state.badgeArchCurrent = value
+    },
+    setBadgeHistoryCurrent(state, value) {
+      state.badgeHistoryCurrent = value
+    },
+    setBadgeProtectorCurrent(state, value) {
+      state.badgeProtectorCurrent = value
+    },
+    setVisitCount(state, value) {
+      state.visitCount = value
     }
   },
   actions: {

+ 1 - 1
src/views/gui/QuizMenu.vue

@@ -57,7 +57,7 @@ export default {
     right: 45px;
     width: 166px;
     height: 162px;
-    background-image: url(@/assets/images/quiz-menu-bg-visitor-pc.png);
+    background-image: url(@/assets/images/quiz-menu-bg-pc.png);
     background-size: cover;
     background-repeat: no-repeat;
     background-position: center center;

+ 357 - 0
src/views/gui/UserInfo.vue

@@ -0,0 +1,357 @@
+<template>
+  <div class="user-info">
+    <div
+      v-if="!isMobile"
+      class="pc-wrapper"
+    >
+      <div
+        class="top-wrapper"
+        @click.stop="onClickPullDown"
+      >
+        <img
+          class="avatar"
+          src="@/assets/images/username-icon.png"
+          alt=""
+          draggable="false"
+        >
+        <span class="user-name">{{ userInfo.userName }}</span>
+        <button
+          class="pull-down"
+        >
+          <img
+            :style="{
+              transform: isPulledDown ? 'rotate(180deg)' : '',
+            }"
+            src="@/assets/images/pull-down.png"
+            alt=""
+            draggable="false"
+          >
+        </button>
+        <menu
+          v-click-outside.click="onClickOutsideOfPullDownMenu"
+          :style="{
+            opacity: isPulledDown ? '1' : '0',
+            top: isPulledDown ? '100%' : '0',
+            pointerEvents: isPulledDown ? 'initial' : 'none',
+          }"
+        >
+          <button @click="onClickLogout">
+            退出登录
+          </button>
+        </menu>
+      </div>
+      <div class="badge-info-wrapper">
+        <div class="img-wrapper">
+          <img
+            class=""
+            src="@/assets/images/badge-architecture.png"
+            alt=""
+            draggable="false"
+          >
+          <div
+            class="mask"
+            :style="{
+              background: badgeArchBgStyle,
+            }"
+          />
+          <span>{{ badgeArchForShow }}/{{ badgeArchGoal }}</span>
+        </div>
+        <div class="badge-name">
+          营造专家
+        </div>
+      </div>
+      <div class="badge-info-wrapper">
+        <div class="img-wrapper">
+          <img
+            class=""
+            src="@/assets/images/badge-hitstory.png"
+            alt=""
+            draggable="false"
+          >
+          <div
+            class="mask"
+            :style="{
+              background: badgeHistoryBgStyle,
+            }"
+          />
+          <span>{{ badgeHistoryForShow }}/{{ badgeHistoryGoal }}</span>
+        </div>
+        <div class="badge-name">
+          历史达人
+        </div>
+      </div>
+      <div class="badge-info-wrapper">
+        <div class="img-wrapper">
+          <img
+            class=""
+            src="@/assets/images/badge-protector.png"
+            alt=""
+            draggable="false"
+          >
+          <div
+            class="mask"
+            :style="{
+              background: badgeProtectorBgStyle,
+            }"
+          />
+          <span>{{ badgeProtectorForShow }}/{{ badgeProtectorGoal }}</span>
+        </div>
+        <div class="badge-name">
+          护书使者
+        </div>
+      </div>
+      <button>
+        <div class="text-wrapper">
+          规则说明
+        </div>
+      </button>
+      <button>
+        <div class="text-wrapper">
+          分享成绩
+        </div>
+      </button>
+    </div>
+    <div
+      v-if="isMobile"
+      class="mobile-wrapper"
+    >
+      <button>
+        <img
+          class=""
+          src="@/assets/images/login.png"
+          alt=""
+          draggable="false"
+        >
+      </button>
+      <button>
+        <img
+          class=""
+          src="@/assets/images/rule-desc.png"
+          alt=""
+          draggable="false"
+        >
+      </button>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      isPulledDown: false,
+    }
+  },
+  computed: {
+    ...globalMapState([
+      'userInfo',
+      'badgeArchGoal',
+      'badgeHistoryGoal',
+      'badgeProtectorGoal',
+    ]),
+    ...globalMapGetters([
+      'badgeArchForShow',
+      'badgeHistoryForShow',
+      'badgeProtectorForShow',
+    ]),
+    badgeArchBgStyle() {
+      if (this.badgeArchForShow === this.badgeArchGoal) {
+        return 'transparent'
+      } else if (this.badgeArchForShow === 0) {
+        return 'rgba(0, 0, 0, 0.8)'
+      } else {
+        return `linear-gradient(180deg,rgba(0,0,0,0.8) ${(1 - this.badgeArchForShow / this.badgeArchGoal) * 100 - 10}%, rgba(0,0,0,0) ${(1 - this.badgeArchForShow / this.badgeArchGoal) * 100 + 10}%)`
+      }
+    },
+    badgeHistoryBgStyle() {
+      if (this.badgeHistoryForShow === this.badgeHistoryGoal) {
+        return 'transparent'
+      } else if (this.badgeHistoryForShow === 0) {
+        return 'rgba(0, 0, 0, 0.8)'
+      } else {
+        return `linear-gradient(180deg,rgba(0,0,0,0.8) ${(1 - this.badgeHistoryForShow / this.badgeHistoryGoal) * 100 - 10}%, rgba(0,0,0,0) ${(1 - this.badgeHistoryForShow / this.badgeHistoryGoal) * 100 + 10}%)`
+      }
+    },
+    badgeProtectorBgStyle() {
+      if (this.badgeProtectorForShow === this.badgeProtectorGoal) {
+        return 'transparent'
+      } else if (this.badgeProtectorForShow === 0) {
+        return 'rgba(0, 0, 0, 0.8)'
+      } else {
+        return `linear-gradient(180deg,rgba(0,0,0,0.8) ${(1 - this.badgeProtectorForShow / this.badgeProtectorGoal) * 100 - 10}%, rgba(0,0,0,0) ${(1 - this.badgeProtectorForShow / this.badgeProtectorGoal) * 100 + 10}%)`
+      }
+    }
+  },
+  methods: {
+    onClickPullDown() {
+      this.isPulledDown = !this.isPulledDown
+    },
+    onClickOutsideOfPullDownMenu() {
+      this.isPulledDown = false
+    },
+    onClickLogout() {
+      globalApi.logout()
+    },
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.user-info {
+  background: linear-gradient(180deg,rgba(0,0,0,1) 40%, rgba(0,0,0,0) 60%);
+  > .pc-wrapper {
+    position: fixed;
+    top: 200px;
+    right: 45px;
+    width: 158px;
+    height: 514px;
+    background-image: url(@/assets/images/user-info-bg-pc.png);
+    background-size: cover;
+    background-repeat: no-repeat;
+    background-position: center center;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    padding-top: 40px;
+    > .top-wrapper {
+      position: relative;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      margin-bottom: 20px;
+      > img.avatar {
+        width: 30px;
+        height: 30px;
+        border-radius: 15px;
+        margin-right: 10px;
+      }
+      > span {
+        font-size: 16px;
+        font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+        font-weight: 400;
+        color: #000000;
+        margin-right: 5px;
+      }
+      > button {
+        padding: 5px;
+        > img {
+          width: 16px;
+          height: 8px;
+          transition: all 0.3s;
+        }
+      }
+      > menu {
+        position: absolute;
+        border-radius: 5px;
+        width: 100%;
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        padding-top: 10px;
+        background: #ffeeea;
+        transition: all 0.3s;
+        z-index: 3;
+        > button {
+          width: 100%;
+          height: 25px;
+          font-size: 16px;
+          font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+          font-weight: 400;
+          color: #000000;
+          margin-bottom: 10px;
+        }
+      }
+    }
+    > .badge-info-wrapper {
+      margin-bottom: 9px;
+      > .img-wrapper {
+        width: 80px;
+        height: 80px;
+        position: relative;
+        > img {
+          width: 100%;
+          height: 100%;
+        }
+        > .mask {
+          position: absolute;
+          top: 0;
+          left: 0;
+          width: 100%;
+          height: 100%;
+          border-radius: 50%;
+          z-index: 1;
+        }
+        > span {
+          position: absolute;
+          left: 50%;
+          top: 50%;
+          transform: translate(-50%, -50%);
+          font-size: 16px;
+          font-family: Source Han Sans CN-Bold, Source Han Sans CN;
+          font-weight: bold;
+          color: #FFFFFF;
+          z-index: 2;
+        }
+      }
+      .badge-name {
+        text-align: center;
+        font-size: 14px;
+        font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+        font-weight: 400;
+        color: #4D332B;
+      }
+    }
+    > button {
+      background-image: url(@/assets/images/button-border-small.png);
+      background-size: contain;
+      background-repeat: no-repeat;
+      background-position: center center;
+      width: 119px;
+      height: 33px;
+      padding: 3px;
+      &:first-of-type {
+        margin-bottom: 10px;
+        > .text-wrapper {
+          height: 100%;
+          width: 100%;
+          display: flex;
+          justify-content: center;
+          align-items: center;
+          font-size: 16px;
+          font-family: LiSu-Regular, LiSu;
+          color: #A26751;
+        }
+      }
+      &:last-of-type {
+        > .text-wrapper {
+          height: 100%;
+          width: 100%;
+          background: rgba(143, 72, 49, 0.8);
+          display: flex;
+          justify-content: center;
+          align-items: center;
+          font-size: 16px;
+          font-family: LiSu-Regular, LiSu;
+          color: #FFFFFF;
+        }
+      }
+    }
+  }
+  > .mobile-wrapper {
+    position: fixed;
+    top: 126px;
+    right: 15px;
+    display: flex;
+    flex-direction: column;
+    > button {
+      margin-bottom: 11px;
+      width: 40px;
+      height: 40px;
+      > img {
+        width: 100%;
+        height: 100%;
+      }
+    }
+  }
+}
+</style>