Sfoglia il codice sorgente

Merge branch 'master' of http://192.168.0.115:3000/chenzimin2/ZGZQBWG

xzw 1 anno fa
parent
commit
3ce730ca8c
100 ha cambiato i file con 1690 aggiunte e 371 eliminazioni
  1. 2 1
      game/package.json
  2. BIN
      game/public/unity/antibody-battle/Build/Build.data.unityweb
  3. BIN
      game/public/unity/antibody-battle/Build/Build.framework.js.unityweb
  4. BIN
      game/public/unity/antibody-battle/Build/Build.wasm.unityweb
  5. BIN
      game/public/unity/antibody-battle/TemplateData/bg.jpg
  6. 4 4
      game/public/unity/antibody-battle/index.html
  7. BIN
      game/public/unity/disaster-relief/Build/Build.data.unityweb
  8. BIN
      game/public/unity/disaster-relief/Build/Build.framework.js.unityweb
  9. 1 1
      game/public/unity/disaster-relief/Build/Build.loader.js
  10. BIN
      game/public/unity/disaster-relief/Build/Build.wasm.unityweb
  11. BIN
      game/public/unity/disaster-relief/TemplateData/bg.jpg
  12. 1 1
      game/public/unity/disaster-relief/index.html
  13. BIN
      game/public/unity/enviroment-protection/Build/Build.data.unityweb
  14. BIN
      game/public/unity/enviroment-protection/Build/Build.framework.js.unityweb
  15. BIN
      game/public/unity/enviroment-protection/Build/Build.wasm.unityweb
  16. BIN
      game/public/unity/enviroment-protection/TemplateData/bg.jpg
  17. 4 4
      game/public/unity/enviroment-protection/index.html
  18. BIN
      game/public/unity/lost-children/Build/H5Game-ChinaSecuritiesMuseumMaze.data.unityweb
  19. BIN
      game/public/unity/lost-children/TemplateData/bg.jpg
  20. 14 1
      game/src/App.vue
  21. 30 5
      game/src/api.js
  22. BIN
      game/src/assets/images/already-redeem.png
  23. BIN
      game/src/assets/images/antibody-battle-entry.png
  24. BIN
      game/src/assets/images/cert-name-bottom-line.png
  25. BIN
      game/src/assets/images/certification.jpg
  26. BIN
      game/src/assets/images/disaster-relief-entry.png
  27. BIN
      game/src/assets/images/enviroment-protection.png
  28. BIN
      game/src/assets/images/exam-paper-entry.png
  29. BIN
      game/src/assets/images/lost-children-entry.png
  30. BIN
      game/src/assets/images/pair-up-entry.png
  31. BIN
      game/src/assets/images/plant-tree-entry.png
  32. 18 0
      game/src/router/index.js
  33. 5 1
      game/src/store/index.js
  34. 240 0
      game/src/views/CertificationView.vue
  35. 2 2
      game/src/views/ExamPaper2.vue
  36. 4 4
      game/src/views/GameByUnity.vue
  37. 20 11
      game/src/views/HomeView.vue
  38. 19 0
      game/src/views/LoginView.vue
  39. 2 2
      game/src/views/PairUp.vue
  40. 5 3
      game/src/views/PlantTree.vue
  41. 62 37
      game/src/views/RedeemForm.vue
  42. 258 0
      game/src/views/RedeemFormForCertification.vue
  43. 288 0
      game/src/views/ShopForVisitor.vue
  44. 106 32
      game/src/views/ShopView.vue
  45. 1 0
      game/src/views/SignUp.vue
  46. 34 0
      game/yarn.lock
  47. 0 0
      hot - 副本/.browserslistrc
  48. 0 0
      hot - 副本/.eslintrc.js
  49. 0 0
      hot - 副本/.gitignore
  50. 0 0
      hot - 副本/README.md
  51. 0 0
      hot - 副本/babel.config.js
  52. 0 0
      hot - 副本/package-lock.json
  53. 0 0
      hot - 副本/package.json
  54. 0 0
      hot - 副本/public/index.html
  55. 0 0
      hot - 副本/src/App.vue
  56. 0 0
      hot - 副本/src/assets/base.css
  57. 0 0
      hot - 副本/src/assets/images/IMGerror.png
  58. 0 0
      hot - 副本/src/assets/images/loading.gif
  59. 0 0
      hot - 副本/src/assets/images/pc/audio.png
  60. 0 0
      hot - 副本/src/assets/images/pc/audioAc.png
  61. 0 0
      hot - 副本/src/assets/images/pc/icon-left.png
  62. 0 0
      hot - 副本/src/assets/images/pc/icon-right.png
  63. 0 0
      hot - 副本/src/assets/images/pc/icon1.png
  64. 0 0
      hot - 副本/src/assets/images/pc/icon1Ac.png
  65. 0 0
      hot - 副本/src/assets/images/pc/icon2.png
  66. 0 0
      hot - 副本/src/assets/images/pc/icon2Ac.png
  67. 0 0
      hot - 副本/src/assets/images/pc/icon3.png
  68. 0 0
      hot - 副本/src/assets/images/pc/icon3Ac.png
  69. 0 0
      hot - 副本/src/assets/images/pc/left.png
  70. 0 0
      hot - 副本/src/assets/images/pc/right.png
  71. 0 0
      hot - 副本/src/assets/logo.png
  72. 0 0
      hot - 副本/src/components/HelloWorld.vue
  73. 0 0
      hot - 副本/src/main.js
  74. 0 0
      hot - 副本/src/router/index.js
  75. 0 0
      hot - 副本/src/utils/browser.js
  76. 0 0
      hot - 副本/src/utils/http.js
  77. 0 0
      hot - 副本/src/views/About.vue
  78. 4 5
      hot - 离线版/src/views/Home.vue
  79. 0 0
      hot - 副本/vue.config.js
  80. 1 1
      hot/src/views/Home.vue
  81. 1 1
      houtai/src/components/Z_RichText/index.tsx
  82. 6 6
      houtai/src/pages/A1Rule/RuleEdit/index.tsx
  83. 9 5
      houtai/src/pages/A1Rule/TopicSetting/index.tsx
  84. 9 4
      houtai/src/pages/A1Rule/index.module.scss
  85. 180 29
      houtai/src/pages/A1Rule/index.tsx
  86. 3 1
      houtai/src/pages/A2Integral/index.tsx
  87. 1 17
      houtai/src/pages/A3User/index.tsx
  88. 253 134
      houtai/src/pages/A4Prize/index.tsx
  89. 14 3
      houtai/src/pages/A5Exchange/index.tsx
  90. 29 3
      houtai/src/pages/A6IDUser/IntegralEdit/index.tsx
  91. 47 33
      houtai/src/pages/A6IDUser/index.tsx
  92. 8 5
      houtai/src/store/action/A6IDUser.ts
  93. 1 0
      houtai/src/types/api/A2Integral.ts
  94. 4 15
      houtai/src/types/api/A5Exchange.d.ts
  95. 0 0
      scene - 副本/.browserslistrc
  96. 0 0
      scene - 副本/.env
  97. 0 0
      scene - 副本/.env.bendi
  98. 0 0
      scene - 副本/.eslintrc.js
  99. 0 0
      scene - 副本/.gitignore
  100. 0 0
      scene - 离线版/README.md

+ 2 - 1
game/package.json

@@ -14,14 +14,15 @@
     "clipboard": "^2.0.11",
     "core-js": "^3.8.3",
     "dayjs": "^1.11.7",
+    "html2canvas": "^1.4.1",
     "js-base64": "^3.7.5",
     "lodash": "^4.17.21",
     "mitt": "^3.0.0",
     "v-viewer": "^3.0.11",
     "vant": "^4.8.2",
     "viewerjs": "^1.11.6",
-    "vue-router": "^4.0.3",
     "vue": "^3.2.13",
+    "vue-router": "^4.0.3",
     "vuex": "^4.0.0"
   },
   "devDependencies": {

BIN
game/public/unity/antibody-battle/Build/Build.data.unityweb


BIN
game/public/unity/antibody-battle/Build/Build.framework.js.unityweb


BIN
game/public/unity/antibody-battle/Build/Build.wasm.unityweb


BIN
game/public/unity/antibody-battle/TemplateData/bg.jpg


+ 4 - 4
game/public/unity/antibody-battle/index.html

@@ -3,7 +3,7 @@
   <head>
     <meta charset="utf-8">
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-    <title>抗体大作战</title>
+    <title>一起来作战</title>
     <link rel="shortcut icon" href="TemplateData/favicon.ico">
     <link rel="stylesheet" href="TemplateData/style.css">
   </head>
@@ -18,7 +18,7 @@
       <div id="unity-warning"> </div>
       <div id="unity-footer">
         <div id="unity-fullscreen-button"></div>
-        <div id="unity-build-title">抗体大作战</div>
+        <div id="unity-build-title">一起来作战</div>
       </div>
     </div>
     <script>
@@ -74,8 +74,8 @@
         codeUrl: buildUrl + "/Build.wasm.unityweb",
         streamingAssetsUrl: "StreamingAssets",
         companyName: "4dage",
-        productName: "抗体大作战",
-        productVersion: "0.1.2",
+        productName: "一起来作战",
+        productVersion: "0.1.5",
         showBanner: unityShowBanner,
       };
 

BIN
game/public/unity/disaster-relief/Build/Build.data.unityweb


BIN
game/public/unity/disaster-relief/Build/Build.framework.js.unityweb


File diff suppressed because it is too large
+ 1 - 1
game/public/unity/disaster-relief/Build/Build.loader.js


BIN
game/public/unity/disaster-relief/Build/Build.wasm.unityweb


BIN
game/public/unity/disaster-relief/TemplateData/bg.jpg


+ 1 - 1
game/public/unity/disaster-relief/index.html

@@ -3,7 +3,7 @@
   <head>
     <meta charset="utf-8">
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-    <title>应急救灾</title>
+    <title>一起来救灾</title>
     <link rel="shortcut icon" href="TemplateData/favicon.ico">
     <link rel="stylesheet" href="TemplateData/style.css">
     <link rel="manifest" href="manifest.webmanifest">

BIN
game/public/unity/enviroment-protection/Build/Build.data.unityweb


BIN
game/public/unity/enviroment-protection/Build/Build.framework.js.unityweb


BIN
game/public/unity/enviroment-protection/Build/Build.wasm.unityweb


BIN
game/public/unity/enviroment-protection/TemplateData/bg.jpg


+ 4 - 4
game/public/unity/enviroment-protection/index.html

@@ -3,7 +3,7 @@
   <head>
     <meta charset="utf-8">
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-    <title>生态保护</title>
+    <title>一起来清理</title>
     <link rel="shortcut icon" href="TemplateData/favicon.ico">
     <link rel="stylesheet" href="TemplateData/style.css">
   </head>
@@ -18,7 +18,7 @@
       <div id="unity-warning"> </div>
       <div id="unity-footer">
         <div id="unity-fullscreen-button"></div>
-        <div id="unity-build-title">生态保护</div>
+        <div id="unity-build-title">一起来清理</div>
       </div>
     </div>
     <script>
@@ -74,8 +74,8 @@
         codeUrl: buildUrl + "/Build.wasm.unityweb",
         streamingAssetsUrl: "StreamingAssets",
         companyName: "4dage",
-        productName: "生态保护",
-        productVersion: "0.1.2",
+        productName: "一起来清理",
+        productVersion: "0.1.4",
         showBanner: unityShowBanner,
       };
 

BIN
game/public/unity/lost-children/Build/H5Game-ChinaSecuritiesMuseumMaze.data.unityweb


BIN
game/public/unity/lost-children/TemplateData/bg.jpg


+ 14 - 1
game/src/App.vue

@@ -26,7 +26,20 @@ getGameRuleList().then((res) => {
   store.commit('setGameRuleList', res)
 })
 getScoreLimit().then((res) => {
-  store.commit('setScoreLimit', res)
+  store.commit('setScoreLimit', res.score)
+  const resetInfo = JSON.parse(res.description)
+  if (resetInfo.hasReset) {
+    const currentTimeMs = new Date().getTime()
+    const createTime = new Date(resetInfo.createTime)
+    const period = resetInfo.period
+    let resetTimeMs = createTime.getTime() + period * 24 * 60 * 60 * 1000
+    while (resetTimeMs <= currentTimeMs) {
+      resetTimeMs = resetTimeMs + period * 24 * 60 * 60 * 1000
+    }
+    store.commit('setScoreResetDateMs', resetTimeMs)
+  } else {
+    store.commit('setScoreResetDateMs', null)
+  }
 })
 
 </script>

+ 30 - 5
game/src/api.js

@@ -176,7 +176,7 @@ export async function getScoreLimit() {
   if (res.data.code !== 0) {
     throw (`获取积分上限失败:${res.data.msg}`)
   } else {
-    return res.data.data[0].score
+    return res.data.data[0]
   }
 }
 export async function getScore() {
@@ -243,14 +243,11 @@ updateTime: "2024-01-09 09:35:10"
 export async function getPrizeList(pageNum, pageSize) {
   const res = await axios({
     method: 'post',
-    url: `${process.env.VUE_APP_DEPLOY_ORIGIN}/api/cms/game/prize/pageList`,
+    url: `${process.env.VUE_APP_DEPLOY_ORIGIN}/api/show/prize/pageList`,
     data: {
       pageNum,
       pageSize,
     },
-    headers: {
-      token: store.state.token,
-    }
   })
   if (res.data.code !== 0) {
     throw (`获取奖品列表失败:${res.data.msg}`)
@@ -294,6 +291,34 @@ export async function redeem(description, name, phone, prizeId, score, prizeName
     return res.data.data
   }
 }
+export async function checkCertificationStatus() {
+  const res = await axios({
+    method: 'get',
+    url: `${process.env.VUE_APP_DEPLOY_ORIGIN}/api/cms/game/redeem/check`,
+    headers: {
+      token: store.state.token,
+    },
+  })
+  if (res.data.code !== 0) {
+    throw (`检查证书状态失败:${res.data.msg}`)
+  } else {
+    return res.data.data
+  }
+}
+export async function getMyCertificationInfo() {
+  const res = await axios({
+    method: 'get',
+    url: `${process.env.VUE_APP_DEPLOY_ORIGIN}/api/cms/game/redeem/info`,
+    headers: {
+      token: store.state.token,
+    },
+  })
+  if (res.data.code !== 0) {
+    throw (`获取证书信息失败:${res.data.msg}`)
+  } else {
+    return res.data.data
+  }
+}
 
 export function notifyQuit() {
   console.log('小游戏:调用父窗口的goBackSceneFu方法……')

BIN
game/src/assets/images/already-redeem.png


BIN
game/src/assets/images/antibody-battle-entry.png


BIN
game/src/assets/images/cert-name-bottom-line.png


BIN
game/src/assets/images/certification.jpg


BIN
game/src/assets/images/disaster-relief-entry.png


BIN
game/src/assets/images/enviroment-protection.png


BIN
game/src/assets/images/exam-paper-entry.png


BIN
game/src/assets/images/lost-children-entry.png


BIN
game/src/assets/images/pair-up-entry.png


BIN
game/src/assets/images/plant-tree-entry.png


+ 18 - 0
game/src/router/index.js

@@ -11,7 +11,10 @@ import ExamPaper3 from '../views/ExamPaper3.vue'
 import PairUp from '../views/PairUp.vue'
 import GameByUnity from '../views/GameByUnity.vue'
 import ShopView from '../views/ShopView.vue'
+import ShopForVisitor from '../views/ShopForVisitor.vue'
 import RedeemForm from '../views/RedeemForm.vue'
+import RedeemFormForCertification from '../views/RedeemFormForCertification.vue'
+import CertificationView from '../views/CertificationView.vue'
 // import store from '@/store/index.js'
 
 const routes = [
@@ -76,10 +79,25 @@ const routes = [
     component: ShopView,
   },
   {
+    path: '/shop-for-visitor',
+    name: 'ShopForVisitor',
+    component: ShopForVisitor,
+  },
+  {
     path: '/redeem-form',
     name: 'RedeemForm',
     component: RedeemForm,
   },
+  {
+    path: '/redeem-form-for-certification',
+    name: 'RedeemFormForCertification',
+    component: RedeemFormForCertification,
+  },
+  {
+    path: '/certification-view',
+    name: 'CertificationView',
+    component: CertificationView,
+  },
 ]
 
 const router = createRouter({

+ 5 - 1
game/src/store/index.js

@@ -26,7 +26,7 @@ export default createStore({
       // creatorName: "",
       // description: "完成任一环节(浇水,施肥,除虫,修剪)可得分",
       // id: 3,
-      // name: "乡村林场",
+      // name: "一起来植树",
       // rtf: "<p>123</p><p>321</p>",
       // score: 101,
       // second: null,
@@ -37,6 +37,7 @@ export default createStore({
     ],
     isDirectPlayGame: false,
     score: undefined,
+    scoreResetDateMs: undefined,
     ifScoreLimitReached: undefined,
     scoreLimit: undefined,
   },
@@ -76,6 +77,9 @@ export default createStore({
     setScore(state, value) {
       state.score = value
     },
+    setScoreResetDateMs(state, value) {
+      state.scoreResetDateMs = value
+    },
     setIfScoreLimitReached(state, value) {
       state.ifScoreLimitReached = value
     },

+ 240 - 0
game/src/views/CertificationView.vue

@@ -0,0 +1,240 @@
+<template>
+  <div class="certification-view">
+    <div
+      ref="certifWrap"
+      class="certif-wrap"
+    >
+      <img
+        class="certif"
+        src="@/assets/images/certification.jpg"
+        alt=""
+        draggable="false"
+      >
+      <div class="certif-code">
+        {{ certificationCode }}
+      </div>
+      <div class="name">
+        {{ name }}
+      </div>
+      <img
+        class="cert-name-bottom-line"
+        src="@/assets/images/cert-name-bottom-line.png"
+        alt=""
+        draggable="false"
+      >
+      <div class="main-text">
+        业已完成“担当——证券期货基金行业公益力量展”观展任务,实现见证证券期货基金行业公益力量的目标,中国证券博物馆特授予公益合伙人证书。
+      </div>
+      <div class="organization-name">
+        中国证券博物馆
+      </div>
+      <div class="date">
+        {{ date }}
+      </div>
+    </div>
+    <div class="btn-group">
+      <button
+        class="download"
+        @click="onClickDownload"
+      >
+        保存证书
+      </button>
+      <button
+        class="return"
+        @click="router.go(-1)"
+      >
+        返回
+      </button>
+    </div>
+
+
+    <van-loading
+      v-show="isShowLoading"
+      class="loading"
+      type="spinner"
+    />
+
+    <a
+      v-show="false"
+      ref="forDownload"
+      :href="aDownloadHref"
+      download="share.jpg"
+    />
+  </div>
+</template>
+
+<script setup>
+import { ref, computed, watch, onMounted, nextTick } from "vue"
+import { useRoute, useRouter } from "vue-router"
+import { useStore } from "vuex"
+import { getMyCertificationInfo } from '@/api.js'
+import dayjs from 'dayjs'
+import html2canvas from 'html2canvas'
+
+const route = useRoute()
+const router = useRouter()
+const store = useStore()
+
+const {
+  windowSizeInCssForRef,
+  windowSizeWhenDesignForRef,
+} = useSizeAdapt(390, 752)
+
+const certificationCode = ref('')
+const name = ref('')
+const date = ref('')
+
+const isShowLoading = ref(true)
+getMyCertificationInfo().then((res) => {
+  isShowLoading.value = false
+  certificationCode.value = res.description
+  name.value = res.certName
+  date.value = dayjs(res.createTime).format('YYYY年MM月DD日')
+})
+
+const certifWrap = ref(null)
+const aDownloadHref = ref(null)
+const forDownload = ref('')
+
+const onClickDownload = utils.throttle(function() {
+  isShowLoading.value = true
+  nextTick(() => {
+    // #capture 就是我们要获取截图对应的 DOM 元素选择器
+    html2canvas(certifWrap.value, {
+      useCORS: true, // 【重要】开启跨域配置
+      scale: 1920 / certifWrap.value.clientWidth,
+      allowTaint: true, // 允许跨域图片
+      preserveDrawingBuffer: true,
+    }).then((canvas) => {
+      aDownloadHref.value = canvas.toDataURL('image/jpeg', 1.0)
+      nextTick(() => {
+        forDownload.value.click()
+        isShowLoading.value = false
+      })
+    })
+  })
+})
+
+</script>
+
+<style lang="less" scoped>
+.certification-view{
+  position: absolute;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 100%;
+  background-color: rgba(207, 187, 156, 1);
+  >.certif-wrap{
+    position: absolute;
+    top: 43%;
+    left: 0;
+    width: calc(390 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    transform: translateY(-50%);
+    >img.certif{
+      width: 100%;
+    }
+    >.certif-code{
+      position: absolute;
+      right: calc(43 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      top: calc(29 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      font-size: calc(6 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      font-family: Source Han Serif CN, Source Han Serif CN;
+      font-weight: bold;
+      color: #31271D;
+      line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    }
+    >.name{
+      position: absolute;
+      left: calc(66 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      width: calc(37 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      top: calc(130 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      font-size: calc(8 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      font-family: Source Han Serif CN, Source Han Serif CN;
+      font-weight: bold;
+      color: #31271D;
+      line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      text-align: center;
+      white-space: pre;
+    }
+    .cert-name-bottom-line{
+      position: absolute;
+      left: calc(66 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      top: calc(145 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      width: calc(37 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    }
+    >.main-text{
+      position: absolute;
+      left: calc(66 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      top: calc(149 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      width: calc(261 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      text-indent: 2em;
+      font-size: calc(8 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      font-family: Source Han Serif CN, Source Han Serif CN;
+      font-weight: bold;
+      color: #31271D;
+      line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    }
+    >.organization-name{
+      position: absolute;
+      right: calc(66 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      top: calc(206 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      font-size: calc(7 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      font-family: Source Han Serif CN, Source Han Serif CN;
+      font-weight: bold;
+      color: #31271D;
+      line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    }
+    >.date{
+      position: absolute;
+      right: calc(66 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      top: calc(217 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      font-size: calc(7 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      font-family: Source Han Serif CN, Source Han Serif CN;
+      font-weight: bold;
+      color: #31271D;
+      line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    }
+  }
+  >.btn-group{
+    position: absolute;
+    bottom: calc(50 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    left: 50%;
+    transform: translate(-50%, 0);
+    >button.download{
+      width: calc(348 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      height: calc(50 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      background-color: #FFE6A5;
+      border-radius: calc(3 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      font-family: Source Han Sans SC, Source Han Sans SC;
+      font-weight: bold;
+      color: #A97C46;
+      line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    }
+    >button.return{
+      margin-top: calc(10 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      border: 1px solid #fff;
+      width: calc(348 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      height: calc(50 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      border-radius: calc(3 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      font-family: Source Han Sans SC, Source Han Sans SC;
+      font-weight: bold;
+      color: #fff;
+      line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    }
+  }
+  >.loading{
+    position: absolute;
+    left: 0;
+    top: 0;
+    width: 100%;
+    height: 100%;
+    background-color: rgba(0, 0, 0, 0.3);
+    display: flex;
+    justify-content: center;
+    align-items: center;
+  }
+}
+</style>

+ 2 - 2
game/src/views/ExamPaper2.vue

@@ -127,7 +127,7 @@
 
     <GameRule
       v-show="isShowRule"
-      game-title="助农课堂"
+      game-title="一起来助农"
       :rich-text="store.state.gameRuleList[1].rtf"
       @close="isShowRule=false"
     />
@@ -274,7 +274,7 @@ function onClickNext() {
     selectedIdx.value = null
   } else {
     if (store.state.loginStatus && !store.state.ifScoreLimitReached && bonusPoint.value !== 0) {
-      addScore(bonusPoint.value, '助农课堂').then(() => {
+      addScore(bonusPoint.value, '一起来助农').then(() => {
         getScore().then((res) => {
           store.commit('setScore', res.total)
           store.commit('setIfScoreLimitReached', res.hasOver)

+ 4 - 4
game/src/views/GameByUnity.vue

@@ -92,19 +92,19 @@ function onClickReturnHome() {
 
 const gameRuleConfigMap = {
   AntibodyBattle: {
-    title: '抗体大作战',
+    title: '一起来作战',
     idxInGameRule: 3,
   },
   DisasterRelief: {
-    title: '应急救灾',
+    title: '一起来救灾',
     idxInGameRule: 4,
   },
   EnviromentProtection: {
-    title: '生态保护',
+    title: '一起来清理',
     idxInGameRule: 5,
   },
   LostChildren: {
-    title: '找回走失儿童',
+    title: '一起找儿童',
     idxInGameRule: 6,
   },
 }

+ 20 - 11
game/src/views/HomeView.vue

@@ -83,7 +83,7 @@
       </button>
     </div>
     <div class="entry-list">
-      <!-- 乡村林场 -->
+      <!-- 一起来植树 -->
       <button
         class="game-entry plant-tree-entry"
         @click="onClickGameEntry(0)"
@@ -95,7 +95,7 @@
           draggable="false"
         >
       </button>
-      <!-- 助农课堂 -->
+      <!-- 一起来助农 -->
       <button
         class="game-entry exam-paper-entry"
         @click="onClickGameEntry(1)"
@@ -107,7 +107,7 @@
           draggable="false"
         >
       </button>
-      <!-- 企业翻翻看 -->
+      <!-- 一起来记录 -->
       <button
         class="game-entry pair-up-entry"
         @click="onClickGameEntry(2)"
@@ -119,7 +119,7 @@
           draggable="false"
         >
       </button>
-      <!-- 抗体大作战 -->
+      <!-- 一起来作战 -->
       <button
         class="game-entry antibody-battle-entry"
         @click="onClickGameEntry(3)"
@@ -131,7 +131,7 @@
           draggable="false"
         >
       </button>
-      <!-- 应急救灾 -->
+      <!-- 一起来救灾 -->
       <button
         class="game-entry disaster-relief-entry"
         @click="onClickGameEntry(4)"
@@ -143,7 +143,7 @@
           draggable="false"
         >
       </button>
-      <!-- 生态保护 -->
+      <!-- 一起来清理 -->
       <button
         class="game-entry enviroment-protection"
         @click="onClickGameEntry(5)"
@@ -155,7 +155,7 @@
           draggable="false"
         >
       </button>
-      <!-- 找回走失儿童 -->
+      <!-- 一起找儿童 -->
       <button
         class="game-entry lost-children-entry"
         @click="onClickGameEntry(6)"
@@ -172,11 +172,8 @@
     <!-- 悬浮按钮 -->
     <div class="floating-btn-group">
       <button
-        v-if="store.state.loginStatus"
         class="redeem"
-        @click="router.push({
-          name: 'ShopView'
-        })"
+        @click="onClickRedeem"
       >
         <img
           class=""
@@ -299,6 +296,18 @@ function onClickLogout() {
   logout()
 }
 
+function onClickRedeem() {
+  if (loginStatus.value) {
+    router.push({
+      name: 'ShopView'
+    })
+  } else {
+    router.push({
+      name: 'ShopForVisitor'
+    })
+  }
+}
+
 const shareText = location.href
 const clipboard = new ClipboardJS('button.share')
 clipboard.on('success', function(e) {

+ 19 - 0
game/src/views/LoginView.vue

@@ -74,6 +74,12 @@
     >
       暂无账号,去注册
     </button>
+    <button
+      class="return"
+      @click="$router.go(-1)"
+    >
+      返回
+    </button>
   </div>
 </template>
 
@@ -234,6 +240,19 @@ function submit() {
     line-height: calc(23 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
   }
   >button.sign-up{
+    margin-top: calc(15 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    width: calc(332 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    height: calc(56 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    background: rgba(197, 161, 108, 0.8);
+    border-radius: calc(10 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    font-size: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    font-family: Source Han Sans SC, Source Han Sans SC;
+    font-weight: 400;
+    color: #FFFFFF;
+    line-height: calc(23 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+  }
+  >button.return{
+    margin-top: calc(5 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
     font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
     font-family: Source Han Sans SC, Source Han Sans SC;
     font-weight: 400;

+ 2 - 2
game/src/views/PairUp.vue

@@ -102,7 +102,7 @@
 
     <GameRule
       v-show="isShowRule"
-      game-title="企业翻翻看"
+      game-title="一起来记录"
       :rich-text="store.state.gameRuleList[2].rtf"
       @close="isShowRule=false"
     />
@@ -200,7 +200,7 @@ function replay() {
 watch(isOver, (vNew) => {
   if (vNew) {
     if (store.state.loginStatus && !store.state.ifScoreLimitReached && bonusPoint.value !== 0) {
-      addScore(bonusPoint.value, '企业翻翻看').then(() => {
+      addScore(bonusPoint.value, '一起来记录').then(() => {
         getScore().then((res) => {
           store.commit('setScore', res.total)
           store.commit('setIfScoreLimitReached', res.hasOver)

+ 5 - 3
game/src/views/PlantTree.vue

@@ -143,7 +143,7 @@
 
     <GameRule
       v-show="isShowRule"
-      game-title="乡村林场"
+      game-title="一起来植树"
       :rich-text="store.state.gameRuleList[0].rtf"
       @close="isShowRule=false"
     />
@@ -255,7 +255,8 @@ if (lastPlayTimeStr) {
 
   if (lastPlayYear === currentYear && lastPlayMonth === currentMonth && lastPlayDay === currentDay) {
     currentStepIdx.value = stepList.length - 1
-    bonusPoint.value = 4 * store.state.gameRuleList[0].score
+    const lastPlayScoreStr = localStorage.getItem(`plant-tree-last-score-${store.state.token}`)
+    bonusPoint.value = Number(lastPlayScoreStr)
   }
 }
 // }
@@ -265,8 +266,9 @@ const isOver = computed(() => {
 watch(isOver, (vNew) => {
   if (vNew) {
     localStorage.setItem(`plant-tree-last-time-${store.state.token}`, (new Date()).getTime())
+    localStorage.setItem(`plant-tree-last-score-${store.state.token}`, bonusPoint.value)
     if (store.state.loginStatus && !store.state.ifScoreLimitReached && bonusPoint.value !== 0) {
-      addScore(bonusPoint.value, '乡村林场').then(() => {
+      addScore(bonusPoint.value, '一起来植树').then(() => {
         getScore().then((res) => {
           store.commit('setScore', res.total)
           store.commit('setIfScoreLimitReached', res.hasOver)

+ 62 - 37
game/src/views/RedeemForm.vue

@@ -54,17 +54,25 @@
       </div>
     </div>
 
-    <button
-      class="submit"
-      :class="{
-        needInfo: !name || !contact || !detail,
-        notEnough: result < 0,
-        over: haveSubmitted,
-      }"
-      @click="submit"
-    >
-      发起兑换
-    </button>
+    <div class="btn-group">
+      <button
+        class="submit"
+        :class="{
+          needInfo: !name || !contact || !detail,
+          notEnough: result < 0,
+          over: haveSubmitted,
+        }"
+        @click="submit"
+      >
+        {{ result >= 0 ? '发起兑换' : '积分不足,无法兑换' }}
+      </button>
+      <button
+        class="return"
+        @click="$router.go(-1)"
+      >
+        返回
+      </button>
+    </div>
 
     <transition name="fade-in-out">
       <NotifyComp
@@ -256,33 +264,50 @@ function submit() {
       }
     }
   }
-  >button.submit{
+  >.btn-group{
     position: absolute;
-    width: calc(348 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
-    height: calc(60 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
-    top: calc(630 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
-    left: 50%;
-    transform: translate(-50%, 0);
-    background-color: #FFE6A5;
-    border-radius: calc(3 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
-    font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
-    font-family: Source Han Sans SC, Source Han Sans SC;
-    font-weight: bold;
-    color: #A97C46;
-    line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
-  }
-  >button.submit.needInfo{
-    opacity: 0.5;
-    pointer-events: none;
-  }
-  >button.submit.notEnough{
-    opacity: 1;
-    color: #7B7B7B;
-    background: #CECECE;
-    pointer-events: none;
-  }
-  >button.over{
-    pointer-events: none;
+    top: calc(620 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    width: 100%;
+    left: 0;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    >button.submit{
+      width: calc(348 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      height: calc(50 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      background-color: #FFE6A5;
+      border-radius: calc(3 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      font-family: Source Han Sans SC, Source Han Sans SC;
+      font-weight: bold;
+      color: #A97C46;
+      line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    }
+    >button.submit.needInfo{
+      opacity: 0.5;
+      pointer-events: none;
+    }
+    >button.submit.notEnough{
+      opacity: 1;
+      color: #7B7B7B;
+      background: #CECECE;
+      pointer-events: none;
+    }
+    >button.submit.over{
+      pointer-events: none;
+    }
+    >button.return{
+      margin-top: calc(10 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      border: 1px solid #fff;
+      width: calc(348 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      height: calc(50 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      border-radius: calc(3 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      font-family: Source Han Sans SC, Source Han Sans SC;
+      font-weight: bold;
+      color: #fff;
+      line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    }
   }
 }
 </style>

+ 258 - 0
game/src/views/RedeemFormForCertification.vue

@@ -0,0 +1,258 @@
+<template>
+  <div class="redeem-form">
+    <div class="paper">
+      <div class="form-item">
+        <h3>您的称呼</h3>
+        <input
+          v-model="name"
+          type="text"
+          autofocus
+          placeholder="请输入内容,5字以内"
+        >
+      </div>
+
+      <hr>
+
+      <div class="number-info-item">
+        <div class="key">
+          您的积分
+        </div>
+        <div class="value">
+          {{ store.state.score }}
+        </div>
+      </div>
+      <div class="number-info-item">
+        <div class="key">
+          礼品消费
+        </div>
+        <div class="value red">
+          -{{ prizeInfo.score }}
+        </div>
+      </div>
+      <div class="number-info-item">
+        <div class="key bold">
+          剩余
+        </div>
+        <div class="value">
+          {{ result }}
+        </div>
+      </div>
+    </div>
+
+    <div class="btn-group">
+      <button
+        class="submit"
+        :class="{
+          needInfo: !name,
+          notEnough: result < 0,
+          over: haveSubmitted,
+        }"
+        @click="submit"
+      >
+        {{ result >= 0 ? '发起兑换' : '积分不足,无法兑换' }}
+      </button>
+      <button
+        class="return"
+        @click="$router.go(-1)"
+      >
+        返回
+      </button>
+    </div>
+
+    <transition name="fade-in-out">
+      <NotifyComp
+        v-show="ifShowNotify"
+        text="提交成功,工作人员会与您及时联系"
+      />
+    </transition>
+  </div>
+</template>
+
+<script setup>
+import { ref, computed, watch, onMounted } from "vue"
+import { useRoute, useRouter } from "vue-router"
+import { useStore } from "vuex"
+import { redeem, getScore } from '@/api.js'
+import NotifyComp from '@/components/NotifyComp.vue'
+
+const route = useRoute()
+const router = useRouter()
+const store = useStore()
+
+const {
+  windowSizeInCssForRef,
+  windowSizeWhenDesignForRef,
+} = useSizeAdapt(390, 752)
+
+const prizeInfo = JSON.parse(route.query.prizeInfo)
+
+const result = ref(store.state.score - prizeInfo.score)
+
+const name = ref('')
+watch(name, (vNew) => {
+  if (vNew.length > 5) {
+    vNew = vNew.slice(0, 5)
+    name.value = vNew
+  }
+})
+const ifShowNotify = ref(false)
+const haveSubmitted = ref(false)
+
+function submit() {
+  redeem('', name.value, '', prizeInfo.id, prizeInfo.score, prizeInfo.name).then((res) => {
+    haveSubmitted.value = true
+    getScore().then((res) => {
+      store.commit('setScore', res.total)
+      store.commit('setIfScoreLimitReached', res.hasOver)
+    })
+    router.replace({
+      name: 'CertificationView'
+    })
+  })
+}
+</script>
+
+<style lang="less" scoped>
+.redeem-form{
+  position: absolute;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 100%;
+  background-color: rgba(207, 187, 156, 1);
+  >.paper{
+    position: absolute;
+    width: calc(348 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    height: calc(582 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    top: calc(24 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    left: 50%;
+    transform: translate(-50%, 0);
+    background-image: url(@/assets/images/redeem-paper.png);
+    background-size: contain;
+    background-repeat: no-repeat;
+    background-position: center center;
+    padding-top: calc(25 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    padding-left: calc(25 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    padding-right: calc(25 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    >.form-item{
+      margin-bottom: calc(410 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      >h3{
+        font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        font-family: Source Han Sans SC, Source Han Sans SC;
+        font-weight: bold;
+        color: #A97C46;
+        line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        margin-bottom: calc(10 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      }
+      >input{
+        font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        font-family: Source Han Sans SC, Source Han Sans SC;
+        font-weight: 400;
+        color: rgba(169, 124, 70, 1);
+        line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        width: 100%;
+        border-bottom: 1px dashed #CFBB9C;
+        padding-bottom: calc(9 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        &::placeholder {
+          font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+          font-family: Source Han Sans SC, Source Han Sans SC;
+          font-weight: 400;
+          color: #B8B8B8;
+          line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        }
+      }
+    }
+    >.form-item.last{
+      margin-bottom: calc(60 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    }
+    >hr{
+      position: absolute;
+      top: calc(468 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      left: 50%;
+      transform: translate(-50%, 0);
+      width: calc(306 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      height: 0;
+      border-top: 1px dashed #CFBB9C;
+    }
+    >.number-info-item{
+      margin-bottom: calc(10 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      >.key{
+        font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        font-family: Source Han Sans SC, Source Han Sans SC;
+        font-weight: 400;
+        color: #A97C46;
+        line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      }
+      >.key.bold{
+        font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        font-family: Source Han Sans SC, Source Han Sans SC;
+        font-weight: bold;
+        color: #A97C46;
+        line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      }
+      >.value{
+        font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        font-family: Source Han Sans SC, Source Han Sans SC;
+        font-weight: bold;
+        color: #A97C46;
+        line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      }
+      >.value.red{
+        font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        font-family: Source Han Sans SC, Source Han Sans SC;
+        font-weight: bold;
+        color: #FF4040;
+        line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      }
+    }
+  }
+  >.btn-group{
+    position: absolute;
+    top: calc(620 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    width: 100%;
+    left: 0;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    >button.submit{
+      width: calc(348 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      height: calc(50 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      background-color: #FFE6A5;
+      border-radius: calc(3 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      font-family: Source Han Sans SC, Source Han Sans SC;
+      font-weight: bold;
+      color: #A97C46;
+      line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    }
+    >button.submit.needInfo{
+      opacity: 0.5;
+      pointer-events: none;
+    }
+    >button.submit.notEnough{
+      opacity: 1;
+      color: #7B7B7B;
+      background: #CECECE;
+      pointer-events: none;
+    }
+    >button.submit.over{
+      pointer-events: none;
+    }
+    >button.return{
+      margin-top: calc(10 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      border: 1px solid #fff;
+      width: calc(348 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      height: calc(50 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      border-radius: calc(3 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      font-family: Source Han Sans SC, Source Han Sans SC;
+      font-weight: bold;
+      color: #fff;
+      line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    }
+  }
+}
+</style>

+ 288 - 0
game/src/views/ShopForVisitor.vue

@@ -0,0 +1,288 @@
+<template>
+  <div class="shop-view">
+    <img
+      class="banner"
+      src="@/assets/images/redeem-banner.png"
+      alt=""
+      draggable="false"
+    >
+    <button
+      class="return"
+      @click="router.go(-1)"
+    />
+    <div class="main-wrap">
+      <div
+        v-if="prizeList && prizeList.length"
+        ref="prizeListRef"
+        class="prize-list"
+        @scroll="onPrizeListScroll"
+      >
+        <article
+          v-for="prizeItem in prizeList"
+          :key="prizeItem.id"
+          class="prize-item"
+          :class="{
+            disabled: prizeItem.stock === 0
+          }"
+          @click="onClickPrizeItem(prizeItem)"
+        >
+          <img
+            class="thumb"
+            :src="prizeItem.thumb"
+            alt=""
+            draggable="false"
+          >
+          <div class="title">
+            {{ prizeItem.name }}
+          </div>
+          <div
+            class="remaining"
+            :style="{
+              color: prizeItem.name === '公益合伙人证书' ? 'transparent' : '',
+            }"
+          >
+            剩余:{{ prizeItem.stock }}
+          </div>
+          <div class="price">
+            <span class="number">{{ prizeItem.score }}</span>
+            <span class="not-number">积分</span>
+          </div>
+          <img
+            v-show="prizeItem.isEnabled && prizeItem.stock > 0"
+            class="icon-enabled"
+            src="@/assets/images/icon-gift.png"
+            alt=""
+            draggable="false"
+          >
+          <img
+            v-show="prizeItem.isEnabled && prizeItem.stock === 0"
+            class="icon-no-stock"
+            src="@/assets/images/no-stock.png"
+            alt=""
+            draggable="false"
+          >
+        </article>
+      </div>
+      <div
+        v-if="prizeList?.length === 0"
+        class="prize-list"
+      >
+        <img
+          class="no-data"
+          src="@/assets/images/no-prize.png"
+          alt=""
+          draggable="false"
+        >
+        <p class="no-data">
+          礼物准备中
+        </p>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref, computed, watch, onMounted } from "vue"
+import { useRoute, useRouter } from "vue-router"
+import { useStore } from "vuex"
+import { getScore, getPrizeList, getBonusPointRecord } from '@/api.js'
+
+const route = useRoute()
+const router = useRouter()
+const store = useStore()
+
+const {
+  windowSizeInCssForRef,
+  windowSizeWhenDesignForRef,
+} = useSizeAdapt(390, 752)
+
+if (store.state.loginStatus) {
+  router.replace({
+    name: 'ShopView'
+  })
+}
+
+/**
+ * 奖品列表
+ */
+const prizeListRef = ref(null)
+const prizeList = ref(null)
+const isFetchingMorePrize = ref(false)
+const haveGotAllPrize = ref(false)
+
+function fetchMorePrizeData() {
+  if (haveGotAllPrize.value) {
+    return
+  }
+  if (isFetchingMorePrize.value) {
+    return
+  }
+  isFetchingMorePrize.value = true
+  getPrizeList(prizeList.value?.length / 10 + 1 || 0, 10).then((res) => {
+    if (prizeList.value) {
+      prizeList.value = prizeList.value.concat(res.records)
+    } else {
+      prizeList.value = res.records
+    }
+    console.log(prizeList.value.length, res.total)
+    if (prizeList.value.length >= res.total) {
+      haveGotAllPrize.value = true
+    }
+  }).finally(() => {
+    isFetchingMorePrize.value = false
+  })
+}
+
+fetchMorePrizeData()
+
+function onPrizeListScroll(e) {
+  console.log(prizeListRef.value.scrollHeight)
+  console.log(prizeListRef.value.scrollTop + prizeListRef.value.clientHeight)
+  if (Math.abs(prizeListRef.value.scrollTop + prizeListRef.value.clientHeight - prizeListRef.value.scrollHeight) < 10) {
+    fetchMorePrizeData()
+  }
+}
+
+function onClickPrizeItem(prizeItem) {
+  router.push({
+    name: 'LoginView',
+  })
+}
+
+</script>
+
+<style lang="less" scoped>
+.shop-view{
+  position: absolute;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 100%;
+  >img.banner{
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+  }
+  >button.return {
+    position: absolute;
+    top: calc(12 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    left: calc(24 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    width: calc(24 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    height: calc(24 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    background-image: url(@/assets/images/icon-return.png);
+    background-size: cover;
+    background-repeat: no-repeat;
+    background-position: center center;
+  }
+  >.main-wrap{
+    position: absolute;
+    left: 0;
+    bottom: 0;
+    width: 100%;
+    height: calc(700 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    background: #F6F6F6;
+    border-radius: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef')) calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef')) 0 0;
+    padding-top: calc(25 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    >div.prize-list{
+      height: calc(674 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      overflow: auto;
+      padding-left: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      position: relative;
+      >article.prize-item{
+        display: inline-block;
+        width: calc(168 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        height: calc(200 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        background: #FFFFFF;
+        border-radius: calc(11 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        padding: calc(15 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef')) calc(12 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        position: relative;
+        margin-right: calc(14 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        margin-bottom: calc(15 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        cursor: pointer;
+        >img.thumb{
+          width: 100%;
+          height: calc(92 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+          object-fit: cover;
+        }
+        >.title{
+          margin-top: calc(3 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+          font-size: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+          font-family: Source Han Sans SC, Source Han Sans SC;
+          font-weight: 400;
+          color: #414141;
+          line-height: calc(23 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+          overflow: hidden;
+          white-space: pre;
+          text-overflow: ellipsis;
+        }
+        >.remaining{
+          margin-top: calc(5 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+          font-size: calc(12 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+          font-family: Source Han Sans SC, Source Han Sans SC;
+          font-weight: 400;
+          color: #414141;
+          opacity: 0.5;
+          line-height: calc(14 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+          overflow: hidden;
+          white-space: pre;
+          text-overflow: ellipsis;
+        }
+        >.price{
+          margin-top: calc(3 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+          >.number{
+            font-size: calc(24 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+            font-family: heiti;
+            font-weight: 800;
+            color: #C5A16C;
+            line-height: calc(28 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+          }
+          >.not-number{
+            font-size: calc(12 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+            font-family: Source Han Sans SC, Source Han Sans SC;
+            font-weight: 400;
+            color: #C5A16C;
+            line-height: calc(14 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+            margin-left: 0.3em;
+          }
+        }
+        >img.icon-enabled{
+          position: absolute;
+          right: calc(12 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+          bottom: calc(15 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+          width: calc(30 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+          height: calc(30 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        }
+        >img.icon-no-stock{
+          position: absolute;
+          right: calc(12 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+          bottom: calc(7 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+          width: calc(64 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+          height: calc(64 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        }
+      }
+      >article.prize-item.disabled{
+        pointer-events: none;
+      }
+      >img.no-data{
+        position: absolute;
+        left: 50%;
+        top: 50%;
+        top: calc(120 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        transform: translate(-50%, 0);
+      }
+      >p.no-data{
+        position: absolute;
+        left: 50%;
+        top: calc(265 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        transform: translate(-50%, 0);
+        font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        font-family: Source Han Sans SC, Source Han Sans SC;
+        font-weight: 400;
+        color: #AF9D85;
+        line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      }
+    }
+  }
+}
+</style>

+ 106 - 32
game/src/views/ShopView.vue

@@ -13,8 +13,16 @@
     <div class="my-bonus-point-title">
       我的积分
     </div>
-    <div class="my-bonus-point-value">
-      {{ store.state.score }}
+    <div class="bonus-point-data">
+      <div class="my-bonus-point-value">
+        {{ store.state.score }}
+      </div>
+      <div
+        v-if="scoreResetDate"
+        class="bonus-point-clear-date"
+      >
+        积分将在 {{ scoreResetDate }} 清零
+      </div>
     </div>
     <div class="main-wrap">
       <div class="tabbar">
@@ -60,7 +68,7 @@
           :key="prizeItem.id"
           class="prize-item"
           :class="{
-            disabled: prizeItem.stock === 0
+            disabled: prizeItem.stock === 0,
           }"
           @click="onClickPrizeItem(prizeItem)"
         >
@@ -73,27 +81,50 @@
           <div class="title">
             {{ prizeItem.name }}
           </div>
-          <div class="remaining">
+          <div
+            class="remaining"
+            :style="{
+              color: prizeItem.name === '公益合伙人证书' ? 'transparent' : '',
+            }"
+          >
             剩余:{{ prizeItem.stock }}
           </div>
           <div class="price">
             <span class="number">{{ prizeItem.score }}</span>
             <span class="not-number">积分</span>
           </div>
-          <img
-            v-show="prizeItem.isEnabled && prizeItem.stock > 0"
-            class="icon-enabled"
-            src="@/assets/images/icon-gift.png"
-            alt=""
-            draggable="false"
-          >
-          <img
-            v-show="prizeItem.isEnabled && prizeItem.stock === 0"
-            class="icon-no-stock"
-            src="@/assets/images/no-stock.png"
-            alt=""
-            draggable="false"
-          >
+          <template v-if="prizeItem.name !== '公益合伙人证书'">
+            <img
+              v-show="prizeItem.isEnabled && prizeItem.stock > 0"
+              class="icon-enabled"
+              src="@/assets/images/icon-gift.png"
+              alt=""
+              draggable="false"
+            >
+            <img
+              v-show="prizeItem.isEnabled && prizeItem.stock === 0"
+              class="icon-no-stock"
+              src="@/assets/images/no-stock.png"
+              alt=""
+              draggable="false"
+            >
+          </template>
+          <template v-else>
+            <img
+              v-show="prizeItem.isEnabled && haveGotCertification === false"
+              class="icon-enabled"
+              src="@/assets/images/icon-gift.png"
+              alt=""
+              draggable="false"
+            >
+            <img
+              v-show="prizeItem.isEnabled && haveGotCertification"
+              class="icon-no-stock"
+              src="@/assets/images/already-redeem.png"
+              alt=""
+              draggable="false"
+            >
+          </template>
         </article>
       </div>
       <div
@@ -135,7 +166,7 @@
               negative: recordItem.type === '奖品兑换',
             }"
           >
-            {{ recordItem.type === '奖品兑换' ? '' : '+' }}{{ recordItem.score }}
+            {{ recordItem.score > 0 ? '+' : '' }}{{ recordItem.score }}
           </div>
         </div>
       </div>
@@ -161,7 +192,8 @@
 import { ref, computed, watch, onMounted } from "vue"
 import { useRoute, useRouter } from "vue-router"
 import { useStore } from "vuex"
-import { getScore, getPrizeList, getBonusPointRecord } from '@/api.js'
+import { getScore, getPrizeList, getBonusPointRecord, checkCertificationStatus } from '@/api.js'
+import dayjs from 'dayjs'
 
 const route = useRoute()
 const router = useRouter()
@@ -177,6 +209,16 @@ getScore().then((res) => {
   store.commit('setIfScoreLimitReached', res.hasOver)
 })
 
+const scoreResetDate = computed(() => {
+  if (store.state.scoreResetDateMs) {
+    console.log(store.state.scoreResetDateMs)
+    return dayjs(store.state.scoreResetDateMs).format('YY年M月D日')
+  } else {
+    return ''
+  }
+})
+
+
 const currentTabIdx = ref(0)
 
 /**
@@ -220,13 +262,33 @@ function onPrizeListScroll(e) {
   }
 }
 
+const haveGotCertification = ref(undefined)
+checkCertificationStatus().then((res) => {
+  haveGotCertification.value = res
+})
+
 function onClickPrizeItem(prizeItem) {
-  router.push({
-    name: 'RedeemForm',
-    query: {
-      prizeInfo: JSON.stringify(prizeItem),
-    }
-  })
+  if (prizeItem.name !== '公益合伙人证书') {
+    router.push({
+      name: 'RedeemForm',
+      query: {
+        prizeInfo: JSON.stringify(prizeItem),
+      }
+    })
+  } else if (prizeItem.name === '公益合伙人证书' && haveGotCertification.value === undefined) {
+    return
+  } else if (prizeItem.name === '公益合伙人证书' && haveGotCertification.value === false) {
+    router.push({
+      name: 'RedeemFormForCertification',
+      query: {
+        prizeInfo: JSON.stringify(prizeItem),
+      }
+    })
+  } else if (prizeItem.name === '公益合伙人证书' && haveGotCertification.value === true) {
+    router.push({
+      name: 'CertificationView',
+    })
+  }
 }
 
 const recordList = ref(null)
@@ -272,15 +334,27 @@ getBonusPointRecord().then((res) => {
     color: #FFFFFF;
     line-height: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
   }
-  >.my-bonus-point-value{
+  >.bonus-point-data{
     position: absolute;
     top: calc(80 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
     left: calc(24 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
-    font-size: calc(40 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
-    font-family: Source Han Sans SC, Source Han Sans SC;
-    font-weight: 800;
-    color: #FFFFFF;
-    line-height: calc(47 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    display: flex;
+    align-items: flex-end;
+    >.my-bonus-point-value{
+      font-size: calc(40 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      font-family: Source Han Sans SC, Source Han Sans SC;
+      font-weight: 800;
+      color: #FFFFFF;
+      line-height: calc(47 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    }
+    >.bonus-point-clear-date{
+      margin-left: calc(10 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      font-size: calc(12 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      font-family: Source Han Sans SC, Source Han Sans SC;
+      font-weight: 400;
+      color: #FFFFFF;
+      line-height: calc(30 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    }
   }
   >.main-wrap{
     position: absolute;

+ 1 - 0
game/src/views/SignUp.vue

@@ -287,6 +287,7 @@ function submit() {
   >button.submit{
     width: calc(332 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
     height: calc(56 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+    min-height: 2.5em;
     background: rgba(197, 161, 108, 0.8);
     border-radius: calc(10 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
     font-size: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));

+ 34 - 0
game/yarn.lock

@@ -2144,6 +2144,11 @@ balanced-match@^1.0.0:
   resolved "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
   integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
 
+base64-arraybuffer@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.npmmirror.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz#1c37589a7c4b0746e34bd1feb951da2df01c1bdc"
+  integrity sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==
+
 base64-js@^1.3.1:
   version "1.5.1"
   resolved "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
@@ -2646,6 +2651,13 @@ css-declaration-sorter@^6.3.1:
   resolved "https://registry.npmmirror.com/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz#28beac7c20bad7f1775be3a7129d7eae409a3a71"
   integrity sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==
 
+css-line-break@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.npmmirror.com/css-line-break/-/css-line-break-2.1.0.tgz#bfef660dfa6f5397ea54116bb3cb4873edbc4fa0"
+  integrity sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==
+  dependencies:
+    utrie "^1.0.2"
+
 css-loader@^6.5.0:
   version "6.8.1"
   resolved "https://registry.npmmirror.com/css-loader/-/css-loader-6.8.1.tgz#0f8f52699f60f5e679eab4ec0fcd68b8e8a50a88"
@@ -3744,6 +3756,14 @@ html-webpack-plugin@^5.1.0:
     pretty-error "^4.0.0"
     tapable "^2.0.0"
 
+html2canvas@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.npmmirror.com/html2canvas/-/html2canvas-1.4.1.tgz#7cef1888311b5011d507794a066041b14669a543"
+  integrity sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==
+  dependencies:
+    css-line-break "^2.1.0"
+    text-segmentation "^1.0.3"
+
 htmlparser2@^6.1.0:
   version "6.1.0"
   resolved "https://registry.npmmirror.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7"
@@ -5933,6 +5953,13 @@ terser@^5.10.0, terser@^5.26.0:
     commander "^2.20.0"
     source-map-support "~0.5.20"
 
+text-segmentation@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.npmmirror.com/text-segmentation/-/text-segmentation-1.0.3.tgz#52a388159efffe746b24a63ba311b6ac9f2d7943"
+  integrity sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==
+  dependencies:
+    utrie "^1.0.2"
+
 text-table@^0.2.0:
   version "0.2.0"
   resolved "https://registry.npmmirror.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
@@ -6103,6 +6130,13 @@ utils-merge@1.0.1:
   resolved "https://registry.npmmirror.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
   integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
 
+utrie@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.npmmirror.com/utrie/-/utrie-1.0.2.tgz#d42fe44de9bc0119c25de7f564a6ed1b2c87a645"
+  integrity sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==
+  dependencies:
+    base64-arraybuffer "^1.0.2"
+
 uuid@^8.3.2:
   version "8.3.2"
   resolved "https://registry.npmmirror.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"

scene - 离线版/.browserslistrc → hot - 副本/.browserslistrc


scene - 离线版/.eslintrc.js → hot - 副本/.eslintrc.js


hot - 离线版/.gitignore → hot - 副本/.gitignore


hot - 离线版/README.md → hot - 副本/README.md


scene - 离线版/babel.config.js → hot - 副本/babel.config.js


hot - 离线版/package-lock.json → hot - 副本/package-lock.json


hot - 离线版/package.json → hot - 副本/package.json


hot - 离线版/public/index.html → hot - 副本/public/index.html


hot - 离线版/src/App.vue → hot - 副本/src/App.vue


hot - 离线版/src/assets/base.css → hot - 副本/src/assets/base.css


hot - 离线版/src/assets/images/IMGerror.png → hot - 副本/src/assets/images/IMGerror.png


hot - 离线版/src/assets/images/loading.gif → hot - 副本/src/assets/images/loading.gif


hot - 离线版/src/assets/images/pc/audio.png → hot - 副本/src/assets/images/pc/audio.png


hot - 离线版/src/assets/images/pc/audioAc.png → hot - 副本/src/assets/images/pc/audioAc.png


hot - 离线版/src/assets/images/pc/icon-left.png → hot - 副本/src/assets/images/pc/icon-left.png


hot - 离线版/src/assets/images/pc/icon-right.png → hot - 副本/src/assets/images/pc/icon-right.png


hot - 离线版/src/assets/images/pc/icon1.png → hot - 副本/src/assets/images/pc/icon1.png


hot - 离线版/src/assets/images/pc/icon1Ac.png → hot - 副本/src/assets/images/pc/icon1Ac.png


hot - 离线版/src/assets/images/pc/icon2.png → hot - 副本/src/assets/images/pc/icon2.png


hot - 离线版/src/assets/images/pc/icon2Ac.png → hot - 副本/src/assets/images/pc/icon2Ac.png


hot - 离线版/src/assets/images/pc/icon3.png → hot - 副本/src/assets/images/pc/icon3.png


hot - 离线版/src/assets/images/pc/icon3Ac.png → hot - 副本/src/assets/images/pc/icon3Ac.png


hot - 离线版/src/assets/images/pc/left.png → hot - 副本/src/assets/images/pc/left.png


hot - 离线版/src/assets/images/pc/right.png → hot - 副本/src/assets/images/pc/right.png


hot - 离线版/src/assets/logo.png → hot - 副本/src/assets/logo.png


hot - 离线版/src/components/HelloWorld.vue → hot - 副本/src/components/HelloWorld.vue


hot - 离线版/src/main.js → hot - 副本/src/main.js


hot - 离线版/src/router/index.js → hot - 副本/src/router/index.js


hot - 离线版/src/utils/browser.js → hot - 副本/src/utils/browser.js


hot - 离线版/src/utils/http.js → hot - 副本/src/utils/http.js


hot - 离线版/src/views/About.vue → hot - 副本/src/views/About.vue


+ 4 - 5
hot - 离线版/src/views/Home.vue

@@ -43,7 +43,7 @@
             </div>
             <!-- 视频页面 -->
             <div class="videoBox" v-else-if="myType === 'video'">
-              <video id="videoID" controls :src="urlToFitFu(item.url)" v-if="index === myInd"></video>
+              <video id="videoID" controls :src="urlToFitFu(item.url)" v-if="index === myInd" autoplay></video>
             </div>
             <!-- 图片页面 -->
             <div class="imgBox" v-else-if="myType === 'img'">
@@ -157,6 +157,7 @@ export default {
         return url.replace("http://super.4dage.com", "");
       } else return resUrl;
     },
+
     // 点击左右箭头
     cutMyInd(num, flag) {
       if (flag) return;
@@ -170,9 +171,7 @@ export default {
     },
     async getData() {
       // https://www.4dmodel.com/
-      // let url = `https://super.4dage.com/data/${
-      let url = `/data/${
-        this.id
+      let url = `/data/${this.id
         }/hot/js/data.js?time=${Math.random()}`;
       let result = (await this.$http.get(url)).data;
       const resData = result[this.m];
@@ -230,7 +229,7 @@ export default {
       const videoIDDom = document.getElementById('videoID')
       videoIDDom.addEventListener('ended', () => {
         console.log('视频观看完成', window, window.parent, window.parent.window, window.parent.window.parent.window)
-        if(window.parent && window.parent.window.parent.window && window.parent.window.parent.window.addScoreFu){
+        if (window.parent && window.parent.window.parent.window && window.parent.window.parent.window.addScoreFu) {
           window.parent.window.parent.window.addScoreFu('观看视频')
         }
       })

hot - 离线版/vue.config.js → hot - 副本/vue.config.js


+ 1 - 1
hot/src/views/Home.vue

@@ -43,7 +43,7 @@
             </div>
             <!-- 视频页面 -->
             <div class="videoBox" v-else-if="myType === 'video'">
-              <video id="videoID" controls :src="item.url" v-if="index === myInd"></video>
+              <video id="videoID" controls :src="item.url" v-if="index === myInd" autoplay></video>
             </div>
             <!-- 图片页面 -->
             <div class="imgBox" v-else-if="myType === 'img'">

+ 1 - 1
houtai/src/components/Z_RichText/index.tsx

@@ -196,7 +196,7 @@ function RichText({ check, dirCode, isLook, myUrl }: Props, ref: any) {
           check && isTxtFlag ? "noUpThumbAc" : ""
         )}
       >
-        请输入正文!
+        {/* 请输入正文! */}
       </div>
     </div>
   );

+ 6 - 6
houtai/src/pages/A1Rule/RuleEdit/index.tsx

@@ -61,10 +61,10 @@ function RuleEdit({ id, closePage, upTableList, editMode }: Props) {
       // 富文本 为空
       const { val, flag } = richTxtRef.current.fatherBtnOkFu();
       // console.log("富文本", val, flag);
-      if (flag) {
-        MessageFu.error("游戏规则不能为空");
-        return;
-      }
+      // if (flag) {
+      //   MessageFu.error("游戏规则不能为空");
+      //   return;
+      // }
 
       if(values.second > 300) {
         MessageFu.error("时限不能大于300s");
@@ -186,8 +186,8 @@ function RuleEdit({ id, closePage, upTableList, editMode }: Props) {
 
               <Form.Item name="gameRule">
                 <div style={{ marginLeft: "0%", display: "flex" }}>
-                  <span style={{ marginRight: "2px", color: "red" }}>*</span>
-                  <div>游戏规则:</div>
+                  {/* <span style={{ marginRight: "2px", color: "red" }}>*</span> */}
+                  <div style={{ marginLeft: "10px" }}>游戏规则:</div>
                 </div>
                 <div style={{ marginLeft: "8%" }}>
                   <RichText

+ 9 - 5
houtai/src/pages/A1Rule/TopicSetting/index.tsx

@@ -61,6 +61,7 @@ function TopicSetting({ closeFu }: Props) {
   const paginationChange = (pageNum: number, pageSize: number) => {
     pageNumRef.current = pageNum;
     pagePageRef.current = pageSize;
+    console.log("减少会触发吗?");
     setTableSelect({ ...tableSelect, pageNum, pageSize });
   };
 
@@ -245,15 +246,21 @@ function TopicSetting({ closeFu }: Props) {
           return item.id !== id;
         });
         setEditShowData([...newList]);
+        if (newList.length % pagePageRef.current === 0) {
+          paginationChange(pageNumRef.current - 1, pagePageRef.current);
+        }
       } else {
         setDelTopicIdList([...delTopicIdList, id]);
         let newList = editShowData.filter((item: any) => {
           return item.id !== id;
         });
         setEditShowData([...newList]);
+        if (newList.length % pagePageRef.current === 0) {
+          paginationChange(pageNumRef.current - 1, pagePageRef.current);
+        }
       }
     },
-    [delTopicIdList, editShowData]
+    [delTopicIdList, editShowData, paginationChange]
   );
 
   const FormBoxRef = useRef<FormInstance>(null);
@@ -265,7 +272,6 @@ function TopicSetting({ closeFu }: Props) {
         title: "序号",
         render: (text: any, record: any, index: any) =>
           index + 1 + (pageNumRef.current - 1) * pagePageRef.current,
-        // index,
       },
       {
         title: "题目描述",
@@ -634,9 +640,7 @@ function TopicSetting({ closeFu }: Props) {
               initialValue={curEdit ? curEdit.value : ""}
               style={{ marginTop: "40px" }}
               hide-required-asterisk={true}
-              getValueFromEvent={(e) =>
-                e.target.value.replace(" ", "")
-              }
+              getValueFromEvent={(e) => e.target.value.replace(" ", "")}
             >
               <Input
                 placeholder="请输入"

+ 9 - 4
houtai/src/pages/A1Rule/index.module.scss

@@ -3,14 +3,15 @@
   height: 100%;
   display: flex;
   flex-direction: column;
-  background-color: rgb(239, 239, 239);
+  background-color: rgb(255, 255, 255);
+  overflow: auto;
 
   :global {
     .ruleTop {
       border-radius: 4px;
       padding: 15px 20px 10px 20px;
       background-color: #fff;
-      box-shadow: 3px 0px 10px 0px #d5d5d9;
+      // box-shadow: 3px 0px 10px 0px #d5d5d9;
       position: relative;
 
       .pageTitle {
@@ -18,6 +19,10 @@
           width: 100px;
           height: 40px;
         }
+        span{
+          font-size: 12px;
+          color: #a1a1a5;
+        }
       }
 
       .scoreLimitBtn {
@@ -53,7 +58,7 @@
 
 
         .ant-table-body {
-          height: 200px;
+          height: 40vh;
           overflow-y: auto !important;
           overflow-y: overlay !important;
 
@@ -80,7 +85,7 @@
         // box-shadow: 3px 0px 10px 0px #d5d5d9;
 
         .ant-table-body {
-          height: 200px;
+          height: 15vh;
           overflow-y: auto !important;
           overflow-y: overlay !important;
 

+ 180 - 29
houtai/src/pages/A1Rule/index.tsx

@@ -6,7 +6,17 @@ import React, {
   useState,
 } from "react";
 import styles from "./index.module.scss";
-import { Button, Form, Input, Modal, Popconfirm, Table } from "antd";
+import {
+  Button,
+  Form,
+  Input,
+  Modal,
+  Popconfirm,
+  Radio,
+  RadioChangeEvent,
+  Select,
+  Table,
+} from "antd";
 import { useDispatch, useSelector } from "react-redux";
 import { RootState } from "@/store";
 import { RulesTableType } from "@/types";
@@ -36,6 +46,31 @@ function A1Rule() {
 
   const [surScoreLimit, setSurScoreLimit] = useState({} as any);
 
+  const addMonths = useCallback((date: any, months: string) => {
+    // 复制传入的日期对象以避免修改原始对象
+    var result = new Date(date.getTime());
+    console.log(timestampToDate(result));
+
+    // 增加月份,同时处理由于增加月份可能导致的日期溢出问题
+    result.setDate(result.getDate() + parseInt(months));
+
+    // // 如果日期溢出(比如2月29日加上1个月),则手动调整到正确的最后一天
+    // if (result.getDate() < date.getDate()) {
+    //   result.setDate(0);
+    // }
+
+    return result;
+  }, []);
+
+  const changeClearMonth = useCallback(
+    (e: any) => {
+      // @ts-ignore
+      setNewDate(timestampToDate(addMonths(new Date(), e.target.value)));
+      setClearMonth(e.target.value);
+    },
+    [addMonths]
+  );
+
   const getList = useCallback(async () => {
     dispatch(getRuleAPI("game"));
     const onlineRes = await getOnlineRuleAPI("online");
@@ -45,9 +80,13 @@ function A1Rule() {
     const res = await getScoreLimitAPI(1);
     if (res.code === 0) {
       setSurScoreLimit(res.data);
-      // alert(res.data)
+      let resetScoreData = JSON.parse(res.data.description);
+      console.log(resetScoreData);
+      setIsClear(resetScoreData.hasReset ? 1 : 2);
+      setClearMonth(resetScoreData.period);
+      changeClearMonth({ target: { value: resetScoreData.period } });
     }
-  }, [dispatch]);
+  }, [changeClearMonth, dispatch]);
 
   // 积分上限窗口开关
   const [limitScoreShow, setLimitScoreShow] = useState(false);
@@ -56,26 +95,70 @@ function A1Rule() {
   const editId = useRef(0);
   // 编辑模式 1是游戏规则 2是线上展厅
   const editMode = useRef(1);
-  const openEditPageFu = useCallback(
-    (type: number, id: number) => {
-      // alert('编辑2')
-      editMode.current = type;
-      editId.current = id;
-      setEditPageShow(true);
-      // console.log(editPageShow, editMode.current);
-    },
-    [editPageShow]
-  );
+  const openEditPageFu = useCallback((type: number, id: number) => {
+    // alert('编辑2')
+    editMode.current = type;
+    editId.current = id;
+    setEditPageShow(true);
+    // console.log(editPageShow, editMode.current);
+  }, []);
+
+  // 积分是否清除相关
+  const [isClear, setIsClear] = useState(2);
+  const onChange = (e: RadioChangeEvent) => {
+    // 从转换成是
+    if (e.target.value === 1 && clearMonth === "null") {
+      setClearMonth(undefined);
+    }
+    setIsClear(e.target.value);
+  };
+
+  const [clearMonth, setClearMonth] = useState(undefined);
+  const [newDate, setNewDate] = useState();
+
+  const timestampToDate = (timestamp: any) => {
+    var date = new Date(timestamp);
+    var year = date.getFullYear();
+    var month = ("0" + (date.getMonth() + 1)).slice(-2);
+    var day = ("0" + date.getDate()).slice(-2);
+
+    return year + "年" + month + "月" + day + "日";
+  };
+
+  function getFirstDayOfMonth() {
+    var now = new Date(); // 获取当前时间
+    var year = now.getFullYear(); // 获取当前年份
+    var month = now.getMonth(); // 获取当前月份(注意:月份从0开始,0表示一月)
+
+    return `${year}-${month + 1}-1 00:00:01`; // 返回时间戳
+  }
 
   const [form] = Form.useForm();
-  const [form2] = Form.useForm();
 
   const onFinish = useCallback(
     async (values: any) => {
+      if (isClear === 1) {
+        if (!clearMonth) {
+          MessageFu.error("积分清零的日数不能为空!");
+          return;
+        }
+        if (clearMonth <= 0 || clearMonth > 301) {
+          MessageFu.error("积分清零的日数范围为1-300!");
+          return;
+        }
+      }
       if (values.numberVal) {
+        let desc = {
+          hasReset: isClear === 1 ? true : false,
+          createTime: isClear === 1 ? getFirstDayOfMonth() : "null",
+          period:
+            isClear === 1 ? parseInt(clearMonth ? clearMonth : "null") : "null",
+        };
+        console.log(desc);
         const data = {
           ...surScoreLimit,
           score: values.numberVal,
+          description: JSON.stringify(desc),
         };
         const res: any = await scoreLimitSaveAPI(data);
         if (res.code === 0) {
@@ -85,7 +168,7 @@ function A1Rule() {
         }
       }
     },
-    [getList, surScoreLimit]
+    [clearMonth, getList, isClear, surScoreLimit]
   );
 
   const columns = useMemo(() => {
@@ -185,7 +268,9 @@ function A1Rule() {
     <>
       <div className={styles.A1Rule}>
         <div className="ruleTop">
-          <div className="pageTitle">游戏规则</div>
+          <div className="pageTitle">
+            游戏规则 <span>游戏规则需用户刷新浏览器后生效</span>
+          </div>
           <button
             className="scoreLimitBtn"
             onClick={() => {
@@ -193,7 +278,8 @@ function A1Rule() {
               setLimitScoreShow(true);
             }}
           >
-            单日可获得积分上限:<span>{surScoreLimit.score}</span>
+            {/* 单日可获得积分上限:<span>{surScoreLimit.score}</span> */}
+            其他规则设置
           </button>
           {/* 表格主体 */}
           <div className="tableBox1">
@@ -203,12 +289,7 @@ function A1Rule() {
               dataSource={tableInfo.list}
               columns={columns}
               rowKey="id"
-              pagination={{
-                showQuickJumper: true,
-                position: ["bottomCenter"],
-                showSizeChanger: true,
-                total: tableInfo.total,
-              }}
+              pagination={false}
             />
           </div>
         </div>
@@ -222,12 +303,7 @@ function A1Rule() {
               dataSource={onlineTableInfo}
               columns={columns2}
               rowKey="id"
-              pagination={{
-                showQuickJumper: true,
-                position: ["bottomCenter"],
-                showSizeChanger: true,
-                total: tableInfo.total,
-              }}
+              pagination={false}
             />
           </div>
         </div>
@@ -275,6 +351,80 @@ function A1Rule() {
                 placeholder="请输入正整数,不超过999999999"
               />
             </Form.Item>
+
+            <Form.Item
+              label="积分清零"
+              name="isClear"
+              style={{ marginTop: "40px" }}
+              initialValue={isClear}
+              rules={[{ required: true, message: "不能为空!" }]}
+              hide-required-asterisk={true}
+            >
+              <Radio.Group onChange={onChange} value={isClear}>
+                <Radio value={1}>是</Radio>
+                <Radio value={2}>否</Radio>
+              </Radio.Group>
+            </Form.Item>
+            {isClear === 1 ? (
+              <Form.Item
+                label=""
+                name="clearMonth"
+                style={{ marginTop: "-15px", marginLeft: "30%" }}
+                hide-required-asterisk={true}
+                getValueFromEvent={(e) =>
+                  e.target.value.replace(/^(0+)|[^\d]+/g, "")
+                }
+              >
+                <span style={{ color: "red", marginRight: "10px" }}>*</span>每
+                {/* <Select
+                  value={clearMonth}
+                  onChange={changeClearMonth}
+                  placeholder="请选择"
+                  options={[
+                    { value: "1", label: "1" },
+                    { value: "2", label: "2" },
+                    { value: "3", label: "3" },
+                    { value: "4", label: "4" },
+                    { value: "5", label: "5" },
+                    { value: "6", label: "6" },
+                    { value: "7", label: "7" },
+                    { value: "8", label: "8" },
+                    { value: "9", label: "9" },
+                    { value: "10", label: "10" },
+                    { value: "11", label: "11" },
+                    { value: "12", label: "12" },
+                  ]}
+                  style={{
+                    width: "130px",
+                    height: "30px",
+                    margin: "0 5px",
+                  }}
+                /> */}
+                <Input
+                  style={{
+                    width: "150px",
+                    height: "30px",
+                    margin: "0 5px",
+                  }}
+                  defaultValue={clearMonth}
+                  maxLength={3}
+                  onChange={changeClearMonth}
+                  placeholder="请选择数字,1-300"
+                />
+                个自然日清空一次
+                {clearMonth ? (
+                  <div
+                    style={{
+                      color: "gray",
+                      marginTop: "10px",
+                      marginLeft: "5%",
+                    }}
+                  >
+                    将在{newDate}清空积分
+                  </div>
+                ) : null}
+              </Form.Item>
+            ) : null}
             {/* 确定和取消按钮 */}
             <br />
             <Form.Item wrapperCol={{ offset: 9, span: 16 }}>
@@ -288,6 +438,7 @@ function A1Rule() {
                 cancelText="取消"
                 onConfirm={() => {
                   setLimitScoreShow(false);
+                  getList();
                 }}
                 okButtonProps={{ loading: false }}
               >

+ 3 - 1
houtai/src/pages/A2Integral/index.tsx

@@ -118,7 +118,9 @@ function A2Integral() {
       {
         title: "说明",
         render: (item: IntegralTableAPIType) => {
-          return <>{item.description}</>;
+          return (
+            <>{item.type === "奖品兑换" ? item.prizeName : item.description}</>
+          );
         },
       },
     ];

+ 1 - 17
houtai/src/pages/A3User/index.tsx

@@ -71,22 +71,6 @@ function A3User() {
     }, 100);
   }, [getList, tableSelect]);
 
-  // 用户昵称的输入
-  const nameTime = useRef(-1);
-  const nameChange = useCallback(
-    (e: React.ChangeEvent<HTMLInputElement>) => {
-      clearTimeout(nameTime.current);
-      nameTime.current = window.setTimeout(() => {
-        setTableSelect({
-          ...tableSelect,
-          nickName: e.target.value.trim(),
-          pageNum: 1,
-        });
-      }, 500);
-    },
-    [tableSelect]
-  );
-
   // 真实姓名的输入
   const realNameTime = useRef(-1);
   const realNameChange = useCallback(
@@ -233,7 +217,7 @@ function A3User() {
           ) : (
             <>
               <Popconfirm
-                title="密码重置后为123456,是否重置?"
+                title="是否将密码重置为123456?"
                 okText="重置"
                 cancelText="取消"
                 onConfirm={() => resetPassFu(item.id!)}

+ 253 - 134
houtai/src/pages/A4Prize/index.tsx

@@ -30,7 +30,6 @@ import {
 } from "@/store/action/A4Prise";
 import { MessageFu } from "@/utils/message";
 import { RangePickerProps } from "antd/es/date-picker";
-import { RcFile } from "antd/es/upload";
 import RichText from "@/components/Z_RichText";
 import moment from "moment";
 import UpFileOne from "@/components/Z_upFileOne";
@@ -82,7 +81,9 @@ function A4Prize() {
           setCover(res.data.thumb);
           setDirCode(res.data.id);
           // 调用富文本子组件的函数,回显数据
-          richTxtRef.current.ritxtShowFu(res.data.rtf);
+          if (res.data.name !== "公益合伙人证书") {
+            richTxtRef.current.ritxtShowFu(res.data.rtf);
+          }
         }
       } else {
         setModalType("add");
@@ -149,6 +150,31 @@ function A4Prize() {
     [cover, curEditItem, form, getList, modalType]
   );
 
+  const onFinishForZhengShu = useCallback(
+    async (values: any) => {
+      if (values) {
+        setCheck(true);
+
+        const obj = {
+          ...values,
+          id: curEditItem && modalType !== "add" ? curEditItem.id : null,
+          thumb: curEditItem?.thumb,
+          rtf: curEditItem?.rtf,
+        };
+
+        const res: any = await editPrizeByIdAPI(obj);
+        if (res.code === 0) {
+          MessageFu.success("提交成功!");
+          getList();
+          setEditPageVisible(false);
+        }
+      }
+      form.resetFields();
+      setCover("");
+    },
+    [curEditItem, form, getList, modalType]
+  );
+
   const handleChange = (value: string) => {
     // console.log(`selected ${value}`);
   };
@@ -176,11 +202,17 @@ function A4Prize() {
       },
       {
         title: "库存",
-        dataIndex: "stock",
+        // dataIndex: "stock",
+        render: (item: PrizeTableType) => (
+          <div>{item.name === "公益合伙人证书" ? "-" : item.stock}</div>
+        ),
       },
       {
         title: "登记日期",
-        dataIndex: "updateTime",
+        // dataIndex: "updateTime",
+        render: (item: PrizeTableType) => (
+          <div>{item.name === "公益合伙人证书" ? "-" : item.updateTime}</div>
+        ),
       },
       {
         title: "状态",
@@ -191,7 +223,7 @@ function A4Prize() {
       {
         title: "操作",
         render: (item: PrizeTableType) => {
-          return (
+          return item.name !== "公益合伙人证书" ? (
             <>
               <Button
                 size="small"
@@ -215,6 +247,14 @@ function A4Prize() {
                 </Button>
               </Popconfirm>
             </>
+          ) : (
+            <Button
+              size="small"
+              type="text"
+              onClick={() => openEditPageFu(item.id)}
+            >
+              编辑
+            </Button>
           );
         },
       },
@@ -280,141 +320,220 @@ function A4Prize() {
           />
         </div>
       </div>
-      {/* 编辑/新增弹窗 */}
-      <Modal
-        destroyOnClose
-        closable={false}
-        maskClosable={false}
-        open={editPageVisible}
-        title={modalType === "add" ? "新增奖品" : "编辑奖品"}
-        width={1000}
-        onCancel={() => setEditPageVisible(false)}
-        footer={
-          [] // 设置footer为空,去掉 取消 确定默认按钮
-        }
-      >
-        <Form
-          form={form}
-          ref={FormBoxRef}
-          name="basic"
-          labelCol={{ span: 3 }}
-          onFinish={onFinish}
-          onFinishFailed={onFinishFailed}
-          autoComplete="off"
+      {curEditItem?.name === "公益合伙人证书" && modalType === "edit" ? (
+        <Modal
+          destroyOnClose
+          closable={false}
+          maskClosable={false}
+          open={editPageVisible}
+          title={"编辑奖品"}
+          width={1000}
+          onCancel={() => setEditPageVisible(false)}
+          footer={
+            [] // 设置footer为空,去掉 取消 确定默认按钮
+          }
         >
-          <Form.Item
-            label="奖品名称"
-            name="name"
-            rules={[{ required: true, message: "不能为空!" }]}
-          >
-            <Input maxLength={20} placeholder="请输入内容,不超过20个字" />
-          </Form.Item>
-          <Form.Item
-            label="所需的积分"
-            name="score"
-            rules={[{ required: true, message: "不能为空!" }]}
-            getValueFromEvent={(e) =>
-              e.target.value.replace(/^(0+)|[^\d]+/g, "")
-            }
-          >
-            <Input maxLength={5} placeholder="请输入正整数,1-99999" />
-          </Form.Item>
-          <Form.Item
-            label="库存"
-            name="stock"
-            rules={[{ required: true, message: "不能为空!" }]}
-            getValueFromEvent={(e) =>
-              e.target.value.replace(/^(0+)|[^\d]+/g, "")
-            }
-          >
-            <Input maxLength={5} placeholder="请输入正整数,1-99999" />
-          </Form.Item>
-          <Form.Item
-            label="登记日期"
-            name="date"
-            initialValue={moment() as any}
-            rules={[{ required: true, message: "不能为空!" }]}
+          <Form
+            form={form}
+            ref={FormBoxRef}
+            name="basic"
+            labelCol={{ span: 3 }}
+            onFinish={onFinishForZhengShu}
+            onFinishFailed={onFinishFailed}
+            autoComplete="off"
           >
-            <DatePicker showTime onChange={onChange} onOk={onOk} />
-          </Form.Item>
-          <Form.Item
-            label="状态"
-            name="isEnabled"
-            initialValue={curEditItem ? (curEditItem.stock > 0 ? 1 : 0) : 1}
-            rules={[{ required: true, message: "不能为空!" }]}
-          >
-            <Select
-              defaultValue={"上架"}
-              style={{ width: 120 }}
-              onChange={handleChange}
-              options={[
-                { value: 1, label: "上架" },
-                { value: 0, label: "下架" },
-              ]}
-            />
-          </Form.Item>
-          <Form.Item name="themb" initialValue={cover ? cover : ""}>
-            <div style={{ marginLeft: "7%", display: "flex" }}>
-              <span style={{ marginRight: "2px", color: "red" }}>*</span>
-              <div>封面:</div>
-            </div>
-            <div style={{ marginLeft: "14%" }}>
-              <UpFileOne
-                myUrl="cms/prize/upload"
-                cover={cover}
-                setCover={(val) => {
-                  setCover(val);
+            <Form.Item
+              label="奖品名称"
+              name="name"
+              rules={[{ required: true, message: "不能为空!" }]}
+            >
+              {curEditItem.name}
+            </Form.Item>
+            <Form.Item
+              label="所需的积分"
+              name="score"
+              rules={[{ required: true, message: "不能为空!" }]}
+              getValueFromEvent={(e) =>
+                e.target.value.replace(/^(0+)|[^\d]+/g, "")
+              }
+            >
+              <Input maxLength={5} placeholder="请输入正整数,1-99999" />
+            </Form.Item>
+            <Form.Item
+              label="状态"
+              name="isEnabled"
+              initialValue={curEditItem ? (curEditItem.stock > 0 ? 1 : 0) : 1}
+              rules={[{ required: true, message: "不能为空!" }]}
+            >
+              <Select
+                defaultValue={"上架"}
+                style={{ width: 120 }}
+                onChange={handleChange}
+                options={[
+                  { value: 1, label: "上架" },
+                  { value: 0, label: "下架" },
+                ]}
+              />
+            </Form.Item>
+            {/* 确定和取消按钮 */}
+            <br />
+            <Form.Item wrapperCol={{ offset: 9, span: 16 }}>
+              <Button type="primary" htmlType="submit">
+                提交
+              </Button>
+              &emsp;
+              <Popconfirm
+                title="放弃编辑后,信息将不会保存!"
+                okText="放弃"
+                cancelText="取消"
+                onConfirm={() => {
+                  setEditPageVisible(false);
+                  form.resetFields();
+                  setCover("");
                 }}
-                isLook={false}
-                coverCheck={check}
-                size={5}
-                dirCode={dirCode}
-                checkTxt="请上传图片!"
+                okButtonProps={{ loading: false }}
+              >
+                <Button>取消</Button>
+              </Popconfirm>
+            </Form.Item>
+          </Form>
+        </Modal>
+      ) : (
+        <Modal
+          destroyOnClose
+          closable={false}
+          maskClosable={false}
+          open={editPageVisible}
+          title={modalType === "add" ? "新增奖品" : "编辑奖品"}
+          width={1000}
+          onCancel={() => setEditPageVisible(false)}
+          footer={
+            [] // 设置footer为空,去掉 取消 确定默认按钮
+          }
+        >
+          <Form
+            form={form}
+            ref={FormBoxRef}
+            name="basic"
+            labelCol={{ span: 3 }}
+            onFinish={onFinish}
+            onFinishFailed={onFinishFailed}
+            autoComplete="off"
+          >
+            <Form.Item
+              label="奖品名称"
+              name="name"
+              rules={[{ required: true, message: "不能为空!" }]}
+            >
+              <Input maxLength={20} placeholder="请输入内容,不超过20个字" />
+            </Form.Item>
+            <Form.Item
+              label="所需的积分"
+              name="score"
+              rules={[{ required: true, message: "不能为空!" }]}
+              getValueFromEvent={(e) =>
+                e.target.value.replace(/^(0+)|[^\d]+/g, "")
+              }
+            >
+              <Input maxLength={5} placeholder="请输入正整数,1-99999" />
+            </Form.Item>
+            <Form.Item
+              label="库存"
+              name="stock"
+              rules={[{ required: true, message: "不能为空!" }]}
+              getValueFromEvent={(e) =>
+                e.target.value.replace(/^(0+)|[^\d]+/g, "")
+              }
+            >
+              <Input maxLength={5} placeholder="请输入正整数,1-99999" />
+            </Form.Item>
+            <Form.Item
+              label="登记日期"
+              name="date"
+              initialValue={moment() as any}
+              rules={[{ required: true, message: "不能为空!" }]}
+            >
+              <DatePicker showTime onChange={onChange} onOk={onOk} />
+            </Form.Item>
+            <Form.Item
+              label="状态"
+              name="isEnabled"
+              initialValue={curEditItem ? (curEditItem.stock > 0 ? 1 : 0) : 1}
+              rules={[{ required: true, message: "不能为空!" }]}
+            >
+              <Select
+                defaultValue={"上架"}
+                style={{ width: 120 }}
+                onChange={handleChange}
+                options={[
+                  { value: 1, label: "上架" },
+                  { value: 0, label: "下架" },
+                ]}
               />
-            </div>
+            </Form.Item>
+            <Form.Item name="themb" initialValue={cover ? cover : ""}>
+              <div style={{ marginLeft: "7%", display: "flex" }}>
+                <span style={{ marginRight: "2px", color: "red" }}>*</span>
+                <div>封面:</div>
+              </div>
+              <div style={{ marginLeft: "14%" }}>
+                <UpFileOne
+                  myUrl="cms/prize/upload"
+                  cover={cover}
+                  setCover={(val) => {
+                    setCover(val);
+                  }}
+                  isLook={false}
+                  coverCheck={check}
+                  size={2}
+                  dirCode={dirCode}
+                  checkTxt="请上传图片!"
+                />
+              </div>
 
-            <span style={{ marginLeft: "14%" }}>
+              {/* <span style={{ marginLeft: "14%" }}>
               格式要求:支持png、jpg和jpeg的图片格式;最大支持2M;最多1张
-            </span>
-          </Form.Item>
-          <Form.Item name="introduction">
-            <div style={{ marginLeft: "4%", display: "flex" }}>
-              <span style={{ marginRight: "2px", color: "red" }}>*</span>
-              <div>产品简介:</div>
-            </div>
-            <div style={{ marginLeft: "12%" }}>
-              <RichText
-                myUrl="cms/prize/upload"
-                ref={richTxtRef}
-                check={check}
-                dirCode={dirCode}
-                isLook={false}
-              />
-            </div>
-          </Form.Item>
-          {/* 确定和取消按钮 */}
-          <br />
-          <Form.Item wrapperCol={{ offset: 9, span: 16 }}>
-            <Button type="primary" htmlType="submit">
-              提交
-            </Button>
-            &emsp;
-            <Popconfirm
-              title="放弃编辑后,信息将不会保存!"
-              okText="放弃"
-              cancelText="取消"
-              onConfirm={() => {
-                setEditPageVisible(false);
-                form.resetFields();
-                setCover("");
-              }}
-              okButtonProps={{ loading: false }}
-            >
-              <Button>取消</Button>
-            </Popconfirm>
-          </Form.Item>
-        </Form>
-      </Modal>
+            </span> */}
+            </Form.Item>
+            <Form.Item name="introduction">
+              <div style={{ marginLeft: "4%", display: "flex" }}>
+                <span style={{ marginRight: "2px", color: "red" }}>*</span>
+                <div>产品简介:</div>
+              </div>
+              <div style={{ marginLeft: "12%" }}>
+                <RichText
+                  myUrl="cms/prize/upload"
+                  ref={richTxtRef}
+                  check={check}
+                  dirCode={dirCode}
+                  isLook={false}
+                />
+              </div>
+            </Form.Item>
+            {/* 确定和取消按钮 */}
+            <br />
+            <Form.Item wrapperCol={{ offset: 9, span: 16 }}>
+              <Button type="primary" htmlType="submit">
+                提交
+              </Button>
+              &emsp;
+              <Popconfirm
+                title="放弃编辑后,信息将不会保存!"
+                okText="放弃"
+                cancelText="取消"
+                onConfirm={() => {
+                  setEditPageVisible(false);
+                  form.resetFields();
+                  setCover("");
+                }}
+                okButtonProps={{ loading: false }}
+              >
+                <Button>取消</Button>
+              </Popconfirm>
+            </Form.Item>
+          </Form>
+        </Modal>
+      )}
     </div>
   );
 }

+ 14 - 3
houtai/src/pages/A5Exchange/index.tsx

@@ -5,6 +5,7 @@ import { useDispatch, useSelector } from "react-redux";
 
 import styles from "./index.module.scss";
 import { getExchangeListAPI } from "@/store/action/A5Exchange";
+import { ExchangeTableType } from "@/types";
 
 const { RangePicker } = DatePicker;
 
@@ -97,15 +98,25 @@ function A5Exchange() {
       },
       {
         title: "称呼",
-        dataIndex: "name",
+        render: (item: ExchangeTableType) => (
+          <div>{item.prizeName === "公益合伙人证书" || item.name === "" ? "-" : item.name}</div>
+        ),
       },
       {
         title: "联系方式",
-        dataIndex: "phone",
+        render: (item: ExchangeTableType) => (
+          <div>{item.prizeName === "公益合伙人证书" || item.phone === "" ? "-" : item.phone}</div>
+        ),
       },
       {
         title: "地址和留言",
-        dataIndex: "description",
+        render: (item: ExchangeTableType) => (
+          <div>
+            {item.prizeName === "公益合伙人证书" || item.description === ""
+              ? "-"
+              : item.description}
+          </div>
+        ),
       },
     ];
   }, []);

+ 29 - 3
houtai/src/pages/A6IDUser/IntegralEdit/index.tsx

@@ -13,6 +13,7 @@ import {
   IDUserScoreSaveAPI,
   getIDUserInfoByIdAPI,
   getIDUserListAPI,
+  getIDUserListAPI2,
 } from "@/store/action/A6IDUser";
 import { IDUserTableType, IDUserType, SaveIDUserScoreType } from "@/types";
 import { MessageFu } from "@/utils/message";
@@ -44,6 +45,21 @@ function IntegralEdit({ currentItem, closeFu }: Props) {
     if (res.code === 0) {
       setResults(res.data);
     }
+
+    const ress = await getIDUserListAPI2({
+      pageNum: 0,
+      pageSize: 9999999,
+      searchKey: "",
+    });
+    if (ress.code === 0) {
+      const curItem = ress.data.records.find((item: any) => {
+        return item.id === currentItem.id;
+      });
+      console.log('当前',ress.data.record)
+      if (curItem) {
+        setCurrentItemShow(curItem);
+      }
+    }
   }, [currentItem.id]);
 
   const [currentItemShow, setCurrentItemShow] = useState<IDUserTableType>();
@@ -96,21 +112,31 @@ function IntegralEdit({ currentItem, closeFu }: Props) {
         const res: any = await IDUserScoreSaveAPI({
           description: values.description,
           userId: currentItem.id,
-          score:  encodeStr(Base64.encode(values.score)),
+          score: encodeStr(Base64.encode(values.score)),
           type: "编辑",
         });
         if (res.code === 0) {
           MessageFu.success("提交成功!");
           pageNumRef.current = tableSelect.pageNum;
           pagePageRef.current = tableSelect.pageSize;
+          console.log(
+            "积分计算",
+            Number(currentItem.score) + Number(values.score),
+            Number(currentItem.score),
+            Number(values.score),
+            resultss
+          );
           getInfoById();
           dispatch(getIDUserListAPI(tableSelect));
-          setCurrentItemShow({...currentItem,score: Number(currentItem.score) + Number(values.score)});
+          // setCurrentItemShow({
+          //   ...currentItem,
+          //   score: Number(currentItem.score) + Number(values.score),
+          // });
           setEditIntegralVisible(false);
         }
       }
     },
-    [currentItem, dispatch, getInfoById, tableSelect]
+    [currentItem, dispatch, getInfoById, tableSelect, resultss]
   );
 
   return (

+ 47 - 33
houtai/src/pages/A6IDUser/index.tsx

@@ -1,5 +1,5 @@
 import { RootState } from "@/store";
-import { Input, DatePicker, Table, Button, Popconfirm, Switch } from "antd";
+import { Input, Table, Button, Popconfirm, Select } from "antd";
 import React, {
   useCallback,
   useEffect,
@@ -19,8 +19,6 @@ import {
 } from "@/store/action/A6IDUser";
 import { MessageFu } from "@/utils/message";
 
-const { RangePicker } = DatePicker;
-
 function A6IDUser() {
   const dispatch = useDispatch();
 
@@ -31,8 +29,7 @@ function A6IDUser() {
     searchKey: "",
     pageSize: 10,
     pageNum: 1,
-    startTime: "",
-    endTime: "",
+    isEnabled: "",
   });
 
   // 账号的输入
@@ -43,27 +40,18 @@ function A6IDUser() {
       setTableSelect({ ...tableSelect, searchKey: e.target.value, pageNum: 1 });
     }, 500);
   };
-  // 时间选择器改变
-  const timeChange = (date: any, dateString: any) => {
-    let startTime = "";
-    let endTime = "";
-    if (dateString[0] && dateString[1]) {
-      startTime = dateString[0] + " 00:00:00";
-      endTime = dateString[1] + " 23:59:59";
-    }
-    setTableSelect({ ...tableSelect, startTime, endTime, pageNum: 1 });
-  };
 
   const [inputKey, setInputKey] = useState(1);
-  // 重置
+
+  // // 重置
   const resetFu = () => {
     setInputKey(Date.now());
+    setSelectKey(null)
     setTableSelect({
       searchKey: "",
       pageSize: 10,
       pageNum: 1,
-      startTime: "",
-      endTime: "",
+      isEnabled: "",
     });
   };
 
@@ -72,6 +60,17 @@ function A6IDUser() {
   //   history.push(path);
   // }, []);
 
+  const [selectKey, setSelectKey] = useState(null);
+
+  // 类型选择发生改变
+  const typeChange = useCallback(
+    (value: any) => {
+      setSelectKey(value);
+      setTableSelect({ ...tableSelect, isEnabled: value, pageNum: 1 });
+    },
+    [tableSelect]
+  );
+
   useEffect(() => {
     pageNumRef.current = tableSelect.pageNum;
     pagePageRef.current = tableSelect.pageSize;
@@ -98,7 +97,8 @@ function A6IDUser() {
   // 点击重置密码
   const resetPassFu = useCallback(async (id: number) => {
     const res: any = await IDUserPassResetAPI(id);
-    if (res.code === 0) MessageFu.success("重置成功!");
+    if (res.code === 0)
+      MessageFu.success("用户密码已重置并以邮件形式发送至用户邮箱!");
   }, []);
 
   // 切换表格中的启用停用状态
@@ -118,15 +118,18 @@ function A6IDUser() {
   );
 
   // 删除用户
-  const deleteIDUser = useCallback(async(id:number) => {
-    const res: any = await DelIDUserAPI(id);
-    if (res.code === 0) {
-      MessageFu.success("删除成功!")
-      pageNumRef.current = tableSelect.pageNum;
-      pagePageRef.current = tableSelect.pageSize;
-      dispatch(getIDUserListAPI(tableSelect));
-    };
-  }, [dispatch, tableSelect]);
+  const deleteIDUser = useCallback(
+    async (id: number) => {
+      const res: any = await DelIDUserAPI(id);
+      if (res.code === 0) {
+        MessageFu.success("删除成功!");
+        pageNumRef.current = tableSelect.pageNum;
+        pagePageRef.current = tableSelect.pageSize;
+        dispatch(getIDUserListAPI(tableSelect));
+      }
+    },
+    [dispatch, tableSelect]
+  );
 
   const columns = useMemo(() => {
     return [
@@ -169,7 +172,7 @@ function A6IDUser() {
                 积分管理
               </Button>
               <Popconfirm
-                title="是否将密码重置为123456?"
+                title="用户重置的密码将以邮件形式发送至用户邮箱"
                 okText="确认"
                 cancelText="取消"
                 onConfirm={() => resetPassFu(item.id!)}
@@ -198,11 +201,13 @@ function A6IDUser() {
                 cancelText="取消"
                 onConfirm={() => {
                   // IDUserStateChange(item.id, item.isEnabled === 0 ? 1 : 0);
-                  deleteIDUser(item.id)
+                  deleteIDUser(item.id);
                 }}
                 okButtonProps={{ loading: false }}
               >
-                <Button type="text" style={{color: "red"}}>{"删除"}</Button>
+                <Button type="text" style={{ color: "red" }}>
+                  {"删除"}
+                </Button>
               </Popconfirm>
             </>
           );
@@ -228,8 +233,17 @@ function A6IDUser() {
             />
           </div>
           <div className="row">
-            <span>日期:</span>
-            <RangePicker key={inputKey} onChange={timeChange} />
+            <span>类型:</span>
+            <Select
+              style={{ width: 120 }}
+              value={selectKey}
+              onChange={typeChange}
+              placeholder="请选择"
+              options={[
+                { value: 0, label: "禁用" },
+                { value: 1, label: "启用" },
+              ]}
+            />
           </div>
           <Button
             className="reSetBtn"

+ 8 - 5
houtai/src/store/action/A6IDUser.ts

@@ -18,9 +18,16 @@ export const getIDUserListAPI = (data: any) => {
 };
 
 /**
+ * 获取用户列表
+ */
+export const getIDUserListAPI2 = (data: any) => {
+  return http.post("cms/user/pageList", data);
+};
+
+/**
  * 切换用户账号状态
  */
-export const IDUserStateChangeAPI = (id:number,num:number) => {
+export const IDUserStateChangeAPI = (id: number, num: number) => {
   return http.get(`cms/user/isEnabled/${id}/${num}`);
 };
 
@@ -31,7 +38,6 @@ export const getIDUserInfoByIdAPI = (id: number) => {
   return http.get(`cms/user/point/getList/${id}`);
 };
 
-
 /**
  * 保存用户积分修改
  */
@@ -39,7 +45,6 @@ export const IDUserScoreSaveAPI = (data: SaveIDUserScoreType) => {
   return http.post("cms/user/point/add", data);
 };
 
-
 /**
  * 重置密码
  */
@@ -47,11 +52,9 @@ export const IDUserPassResetAPI = (id: number) => {
   return http.get(`cms/user/reset/pass/${id}`);
 };
 
-
 /**
  * 删除用户
  */
 export const DelIDUserAPI = (id: number) => {
   return http.get(`cms/user/del/${id}`);
 };
-

+ 1 - 0
houtai/src/types/api/A2Integral.ts

@@ -7,4 +7,5 @@ export type IntegralTableAPIType = {
   score: number;
   type: string;
   updateTime: string;
+  prizeName: string;
 };

+ 4 - 15
houtai/src/types/api/A5Exchange.d.ts

@@ -3,22 +3,11 @@ export type ExchangeTableType = {
   creatorId: number;
   creatorName: string;
   description: string;
-  dictAge: string;
-  dictLevel: string;
-  dictSource: string;
-  dictTexture: string;
-  dirCode: string;
-  display: number;
-  fileIds: string;
   id: number;
-  isBarrage: number;
   name: string;
-  num: string;
-  thumb: string;
-  topic: string;
-  type: string;
+  phone: string;
+  prizeId: number;
+  prizeName: string;
+  score: number;
   updateTime: string;
-  tagType?: string;
-  tagCountry?: string;
 };
-

hot - 离线版/.browserslistrc → scene - 副本/.browserslistrc


scene - 离线版/.env → scene - 副本/.env


scene - 离线版/.env.bendi → scene - 副本/.env.bendi


hot - 离线版/.eslintrc.js → scene - 副本/.eslintrc.js


scene - 离线版/.gitignore → scene - 副本/.gitignore


+ 0 - 0
scene - 离线版/README.md


Some files were not shown because too many files changed in this diff