任一存 2 gadi atpakaļ
vecāks
revīzija
4c32dc6c96

+ 24 - 0
src/api.js

@@ -3,6 +3,19 @@ import { encodeStr } from "@/utils/pass.js"
 import { Base64 } from "js-base64"
 import store from "@/store/index.js"
 
+axios.interceptors.response.use(function (response) {
+  // 2xx 范围内的状态码都会触发该函数。
+  // 对响应数据做点什么
+  if (response.data.code === 5001) {
+    store.commit('logoutCallback')
+  }
+  return response
+}, function (error) {
+  // 超出 2xx 范围的状态码都会触发该函数。
+  // 对响应错误做点什么
+  console.log(error)
+})
+
 async function fetchBadgeAndVisitData() {
   const res = await axios({
     method: 'get',
@@ -91,4 +104,15 @@ export default {
       return
     }
   },
+  async getAnswerRecord() {
+    const lastToken = localStorage.getItem('token')
+    const res = await axios({
+      method: 'get',
+      url: `${process.env.VUE_APP_API_PREFIX}/api/cms/question/getListByUser`,
+      headers: {
+        token: lastToken,
+      }
+    })
+    return res.data.data
+  },
 }

BIN
src/assets/images/button-border-small-color.png


BIN
src/assets/images/share-bg.png


BIN
src/assets/images/stamp.png


+ 7 - 1
src/router/index.js

@@ -4,6 +4,7 @@ import Home from '../pages/Home.vue'
 import RuleDesc from "@/views/gui/RuleDesc.vue"
 import Login from "@/views/gui/Login.vue"
 import SignUp from "@/views/gui/SignUp.vue"
+import Share from "@/views/gui/Share.vue"
 
 const originalPush = VueRouter.prototype.push
 VueRouter.prototype.push = function push (location) {
@@ -32,7 +33,12 @@ const routes = [
         path: 'sign-up',
         name: 'SignUp',
         component: SignUp,
-      }
+      },
+      {
+        path: 'share',
+        name: 'Share',
+        component: Share,
+      },
     ]
   }
 ]

+ 336 - 0
src/views/gui/Share.vue

@@ -0,0 +1,336 @@
+<template>
+  <div
+    class="share"
+  >
+    <div
+      id="capture"
+      class="wrapper-1"
+    >
+      <button
+        v-show="!isSaving"
+        class="close"
+        @click="$router.go(-1)"
+      />
+      <div class="introduction-title-wrapper">
+        <h1
+          class="introduction-title"
+        >
+          分享成绩
+        </h1>
+      </div>
+
+      <p
+        v-if="answerNumber !== undefined"
+        class="main"
+      >
+        <span class="name">{{ userInfo.userName }}</span>在浙江省博物馆文澜阁学习系统中参与答题{{ answerNumber }}道
+      </p>
+      <p
+        v-if="(badgeArchCurrent >= badgeArchGoal) || (badgeHistoryCurrent >= badgeHistoryGoal) || (badgeProtectorCurrent >= badgeProtectorGoal)"
+        class="badge-num"
+      >
+        获得徽章:
+      </p>
+      <ul
+        v-if="(badgeArchCurrent >= badgeArchGoal) || (badgeHistoryCurrent >= badgeHistoryGoal) || (badgeProtectorCurrent >= badgeProtectorGoal)"
+        class="sample-wrap"
+      >
+        <li v-if="badgeArchCurrent >= badgeArchGoal">
+          <img
+            class=""
+            src="@/assets/images/badge-architecture.png"
+            alt=""
+            draggable="false"
+          >
+          <span>营造专家</span>
+        </li>
+        <li v-if="badgeHistoryCurrent >= badgeHistoryGoal">
+          <img
+            class=""
+            src="@/assets/images/badge-hitstory.png"
+            alt=""
+            draggable="false"
+          >
+          <span>历史达人</span>
+        </li>
+        <li v-if="badgeProtectorCurrent >= badgeProtectorGoal">
+          <img
+            class=""
+            src="@/assets/images/badge-protector.png"
+            alt=""
+            draggable="false"
+          >
+          <span>护书使者</span>
+        </li>
+      </ul>
+      <div
+        v-else
+        class="no-badge"
+      >
+        暂未获得勋章
+      </div>
+      <div class="splitter" />
+      <div class="QRCode">
+        <img
+          class=""
+          src="@/assets/images/floor-3.png"
+          alt=""
+          draggable="false"
+        >
+        <p>长按识别二维码</p>
+        <p>云游西湖文澜阁</p>
+      </div>
+      <img
+        v-if="(badgeArchCurrent >= badgeArchGoal) || (badgeHistoryCurrent >= badgeHistoryGoal) || (badgeProtectorCurrent >= badgeProtectorGoal)"
+        src="@/assets/images/stamp.png"
+        alt=""
+        class="stamp"
+      >
+      <button
+        v-show="!isSaving"
+        class="save"
+        @click="onClickSave"
+      >
+        <div class="text-wrapper">
+          保存图片
+        </div>
+      </button>
+    </div>
+    <a
+      v-show="false"
+      ref="for-download"
+      :href="aDownloadHref"
+      download="share.jpg"
+    />
+  </div>
+</template>
+
+<script>
+import html2canvas from "html2canvas"
+
+export default {
+  data() {
+    return {
+      visitNum: 1939,
+      yingZaoZhuanJiaNum: 56,
+      liShiDaRen: 424,
+      huShuShiZhe: 32,
+
+      answerNumber: undefined,
+
+      isSaving: false,
+      aDownloadHref: ''
+    }
+  },
+  computed: {
+    ...globalMapState([
+      'userInfo',
+      'loginStatus',
+      'badgeArchCurrent',
+      'badgeHistoryCurrent',
+      'badgeProtectorCurrent',
+      'badgeArchGoal',
+      'badgeHistoryGoal',
+      'badgeProtectorGoal',
+    ])
+  },
+  mounted() {
+    globalApi.getAnswerRecord().then((res) => {
+      this.answerNumber = res.length
+    })
+  },
+  methods: {
+    onClickSave: globalUtils.throttle(function() {
+      this.isSaving = true
+      setTimeout(() => {
+        // #capture 就是我们要获取截图对应的 DOM 元素选择器
+        html2canvas(document.querySelector('#capture'), {
+          useCORS: true, // 【重要】开启跨域配置
+          scale: 1,
+          allowTaint: true, // 允许跨域图片
+          preserveDrawingBuffer: true,
+        }).then((canvas) => {
+          this.aDownloadHref = canvas.toDataURL('image/jpeg', 1.0)
+          setTimeout(() => {
+            this.$refs['for-download'].click()
+            this.isSaving = false
+          }, 300)
+        })
+      }, 300) // 这里加上 300ms 的延迟是为了让 DOM 元素完全渲染完成后再进行图片的生成
+    }, 400)
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.share {
+  position: fixed;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 100%;
+  background: rgba(46,32,19,0.55);
+  backdrop-filter: blur(5px);
+  z-index: 10000;
+  font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  > .wrapper-1 {
+    width: 804px;
+    height: 793px;
+    position: relative;
+    background-image: url(@/assets/images/share-bg.png);
+    background-size: contain;
+    background-repeat: no-repeat;
+    background-position: center center;
+    text-align: left;
+    padding: 40px 100px 80px 100px;
+    overflow: auto;
+    font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+    > button.close {
+      position: absolute;
+      top: 42px;
+      right: 36px;
+      width: 35px;
+      height: 35px;
+      background-image: url(@/assets/images/close.png);
+      background-size: contain;
+      background-repeat: no-repeat;
+      background-position: center center;
+      font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+    }
+    > .introduction-title-wrapper {
+      text-align: center;
+      > h1.introduction-title {
+        display: inline-block;
+        background-image: url(@/assets/images/title-decorator-long.png);
+        background-size: contain;
+        background-repeat: no-repeat;
+        background-position: center center;
+        padding: 0 45px 15px 45px;
+        font-size: 36px;
+        font-family: LiSu-Regular, LiSu;
+        font-weight: 400;
+        color: #9A2D0A;
+      }
+    }
+    > p.main {
+      margin-top: 40px;
+      font-size: 16px;
+      font-family: Source Han Sans CN-Bold, Source Han Sans CN;
+      color: #8F4831;
+      line-height: 20px;
+      letter-spacing: 3px;
+      > .name {
+        font-size: 36px;
+        font-family: Source Han Sans CN-Bold, Source Han Sans CN;
+        font-weight: bold;
+        color: #8F4831;
+        line-height: 40px;
+        letter-spacing: 3px;
+        text-decoration: underline;
+      }
+    }
+    > p.badge-num {
+      margin-top: 20px;
+      text-align: left;
+      font-size: 16px;
+      font-family: Source Han Sans CN-Bold, Source Han Sans CN;
+      color: #8F4831;
+      line-height: 20px;
+      letter-spacing: 3px;
+    }
+    > ul.sample-wrap {
+      margin-top: 40px;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+      > li {
+        text-align: center;
+        margin-right: 87px;
+        font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+        &:last-of-type {
+          margin-right: initial;
+        }
+        > img {
+          display: block;
+          width: 120px;
+          height: 120px;
+          margin-bottom: 7px;
+        }
+        > span {
+          font-size: 16px;
+          font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+          font-weight: 400;
+          color: #693D2F;
+        }
+      }
+    }
+    > .no-badge {
+      width: 100%;
+      height: 238px;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      font-size: 32px;
+      font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+      font-weight: 400;
+      color: #8F4831;
+      letter-spacing: 3px;
+      opacity: 0.5;
+    }
+    > .splitter {
+      margin-top: 32px;
+      width: 100%;
+      height: 2px;
+      background: #8F4831;
+      opacity: 0.5;
+      font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+    }
+    > .QRCode {
+      margin-top: 22px;
+      width: 124px;
+      font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+      > img {
+        width: 124px;
+        height: 124px;
+      }
+      > p {
+        margin-top: 6px;
+        width: 100%;
+        text-align: center;
+        font-size: 14px;
+        font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+        font-weight: 400;
+        color: #583329;
+      }
+    }
+    > img.stamp {
+      position: absolute;
+      width: 300px;
+      height: 300px;
+      right: 25px;
+      bottom: 60px;
+    }
+    > button.save {
+      position: absolute;
+      left: 50%;
+      bottom: 75px;
+      transform: translateX(-50%);
+      background-image: url(@/assets/images/button-border-small-color.png);
+      background-size: contain;
+      background-repeat: no-repeat;
+      background-position: center center;
+      width: 149px;
+      height: 40px;
+      padding: 3px;
+      font-size: 20px;
+      font-family: LiSu-Regular, LiSu;
+      font-weight: 400;
+      color: #FFFFFF;
+    }
+  }
+}
+</style>

+ 7 - 1
src/views/gui/UserInfo.vue

@@ -109,7 +109,10 @@
         </div>
       </button>
       <button>
-        <div class="text-wrapper">
+        <div
+          class="text-wrapper"
+          @click="onClickShare"
+        >
           分享成绩
         </div>
       </button>
@@ -197,6 +200,9 @@ export default {
     },
     onClickRuleDesc() {
       this.$router.push({ name: 'RuleDesc' })
+    },
+    onClickShare() {
+      this.$router.push({ name: 'Share' })
     }
   }
 }