ShopView.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. <template>
  2. <div
  3. class="shop-view"
  4. >
  5. <menu class="tab-bar">
  6. <button
  7. :class="{
  8. active: tabIdx === 0
  9. }"
  10. @click="tabIdx = 0"
  11. >
  12. 爱心兑换
  13. </button>
  14. <button
  15. :class="{
  16. active: tabIdx === 2
  17. }"
  18. @click="tabIdx = 2"
  19. >
  20. 排行榜
  21. </button>
  22. <button
  23. :class="{
  24. active: tabIdx === 1
  25. }"
  26. @click="tabIdx = 1"
  27. >
  28. 爱心记录
  29. </button>
  30. </menu>
  31. <template v-if="tabIdx === 0">
  32. <button
  33. class="prev-page"
  34. :class="{
  35. hide: pageNumber === 0
  36. }"
  37. @click="onClickPrevPage"
  38. />
  39. <ul
  40. v-loading.fullscreen.lock="pageLoading"
  41. class="prize-list"
  42. >
  43. <li
  44. v-for="prizeItem in prizeList"
  45. :key="prizeItem.id"
  46. class="prize"
  47. :class="{
  48. disabled: prizeItem.stock === 0,
  49. }"
  50. @click="onClickPrizeItem(prizeItem)"
  51. >
  52. <img
  53. class="thumb"
  54. :src="`${$env.VUE_APP_DEPLOY_ORIGIN}${prizeItem.thumb}`"
  55. alt=""
  56. draggable="false"
  57. >
  58. <div class="prize-inner">
  59. <div class="title">
  60. {{ prizeItem.name }}
  61. </div>
  62. <div
  63. class="remaining"
  64. >
  65. <span v-if="prizeItem.id !== 1">剩余:{{ prizeItem.stock }}</span>
  66. </div>
  67. <div class="price">
  68. <span class="number">{{ prizeItem.score }}</span>
  69. <span class="unit">爱心</span>
  70. </div>
  71. <img
  72. v-show="prizeItem.stock > 0 || (prizeItem.id === 1 && !isRedeemed)"
  73. class="icon-enabled"
  74. src="@/assets/images/icon-gift.png"
  75. alt=""
  76. draggable="false"
  77. >
  78. <img
  79. v-if="prizeItem.id === 1 && isRedeemed"
  80. class="icon-enabled redeemed"
  81. src="@/assets/images/icon_complete@2x-min.png"
  82. alt=""
  83. draggable="false"
  84. >
  85. <!-- <img
  86. v-show="prizeItem.isEnabled && prizeItem.stock === 0"
  87. class="icon-no-stock"
  88. src="@/assets/images/no-stock.png"
  89. alt=""
  90. draggable="false"
  91. > -->
  92. </div>
  93. </li>
  94. <p
  95. class="product-tip"
  96. >
  97. 更多礼品敬请期待
  98. </p>
  99. </ul>
  100. <button
  101. class="next-page"
  102. :class="{
  103. hide: !haveNextPage
  104. }"
  105. @click="onClickNextPage"
  106. />
  107. </template>
  108. <div
  109. v-show="tabIdx === 1"
  110. class="redeem-record-content"
  111. >
  112. <p
  113. v-show="redeemRecordContact"
  114. class="tip"
  115. >
  116. 如有疑问,请咨询 {{ redeemRecordContact }}
  117. </p>
  118. <div class="table">
  119. <div class="row-header">
  120. <div>时间</div>
  121. <div>类型</div>
  122. <div>爱心</div>
  123. <div>说明</div>
  124. </div>
  125. <div class="splitter" />
  126. <div class="table-content">
  127. <div
  128. v-for="item in redeemRecord"
  129. :key="item.id"
  130. class="row-data"
  131. >
  132. <div>
  133. {{ item.createTime }}
  134. </div>
  135. <div>
  136. {{ item.type }}
  137. </div>
  138. <div>
  139. {{ item.score > 0 ? '+' : item.score < 0 ? '' : '' }}{{ item.score }}
  140. </div>
  141. <div>
  142. {{ item.description || `(空)` }}
  143. </div>
  144. </div>
  145. </div>
  146. </div>
  147. </div>
  148. <div
  149. v-show="tabIdx === 2"
  150. class="ranking-content"
  151. >
  152. <div
  153. v-loading="rankingLoading"
  154. class="table"
  155. >
  156. <div class="row-header">
  157. <div>排名</div>
  158. <div>用户名</div>
  159. <div>爱心</div>
  160. </div>
  161. <div class="splitter" />
  162. <div class="table-content">
  163. <div
  164. v-for="(item, idx) in rankingList"
  165. :key="item.id"
  166. :class="['row-data', {
  167. 'is-me': store.state.userInfo.userId === item.id
  168. }]"
  169. >
  170. <div :class="['ranking-sort', idx === 0 && 'is-first']">
  171. <span>{{ idx + 1 }}</span>
  172. </div>
  173. <div class="ranking-name">
  174. <img
  175. class="ranking-name__avatar"
  176. fit="cover"
  177. src="@/assets/images/default-avatar-min.png"
  178. >
  179. <span>{{ item.nickName.slice(0, 1) }}***</span>
  180. </div>
  181. <div>
  182. {{ item.pcs }}
  183. </div>
  184. </div>
  185. </div>
  186. </div>
  187. </div>
  188. <div class="coin-number">
  189. <img
  190. class="icon"
  191. src="@/assets/images/icon_money.png"
  192. alt=""
  193. draggable="false"
  194. >
  195. <span class="value">{{ myScore }}</span>
  196. </div>
  197. <PrizeRedeem
  198. v-if="isShowRedeem"
  199. :prize-data="redeemPrizeData"
  200. :score="myScore"
  201. @open-cert="openCertImg"
  202. @close="redeemPrizeData = {}, isShowRedeem = false"
  203. @success="handlePrizeSuccess"
  204. />
  205. </div>
  206. <div
  207. ref="certCanvas"
  208. class="cert-canvas"
  209. >
  210. <p>{{ certInfo.certName }}</p>
  211. <p>{{ certInfo.createTime }}</p>
  212. </div>
  213. </template>
  214. <script setup>
  215. import { ref, computed, watch, onMounted, inject, nextTick } from "vue"
  216. import { useStore } from "vuex"
  217. import PrizeRedeem from '@/components/PrizeRedeem.vue'
  218. import {
  219. getMyScore,
  220. getShopContact,
  221. getPrizeList,
  222. getRedeemRecord,
  223. getRankingListApi,
  224. checkRedeemApi,
  225. getRedeemApi
  226. } from '@/api.js'
  227. import html2canvas from 'html2canvas'
  228. import { formatDate } from '@dage/utils'
  229. import { ElMessage } from 'element-plus'
  230. import { useRouter } from 'vue-router'
  231. const store = useStore()
  232. const router = useRouter()
  233. const pageLoading = ref(false)
  234. const $env = inject('$env')
  235. const {
  236. windowSizeInCssForRef,
  237. windowSizeWhenDesignForRef,
  238. } = useSizeAdapt(1920, 972)
  239. const myScore = ref(undefined)
  240. getMyScore().then((res) => {
  241. myScore.value = res
  242. })
  243. const tabIdx = ref(0)
  244. const redeemRecordContact = ref('')
  245. getShopContact().then((res) => {
  246. if (res.display === 0) {
  247. ElMessage({
  248. message: '商城暂未开启,敬请期待',
  249. type: 'warning',
  250. })
  251. router.replace({
  252. name: 'HomeView'
  253. })
  254. return
  255. }
  256. redeemRecordContact.value = res.rtf
  257. })
  258. const handlePrizeSuccess = async() => {
  259. try {
  260. pageLoading.value = true
  261. await checkRedeem()
  262. const scoreRes = await getMyScore()
  263. myScore.value = scoreRes
  264. const res = await getPrizeList(pageNumber.value, 8)
  265. total.value = res.total
  266. prizeList.value = res.records
  267. } finally {
  268. pageLoading.value = false
  269. }
  270. isShowRedeem.value = false
  271. }
  272. /**
  273. * 一页页的商品
  274. */
  275. const prizeList = ref([])
  276. const pageNumber = ref(0)
  277. const total = ref(0)
  278. function onClickPrevPage() {
  279. if (pageNumber.value > 0) {
  280. pageNumber.value--
  281. }
  282. }
  283. function onClickNextPage() {
  284. if (haveNextPage.value) {
  285. pageNumber.value++
  286. }
  287. }
  288. const haveNextPage = computed(() => {
  289. return total.value > ((pageNumber.value + 1) * 8)
  290. })
  291. watch(pageNumber, (v) => {
  292. getPrizeList(v + 1, 8).then((res) => {
  293. total.value = res.total
  294. prizeList.value = res.records
  295. })
  296. }, {
  297. immediate: true,
  298. })
  299. const isShowRedeem = ref(false)
  300. const redeemPrizeData = ref({})
  301. function onClickPrizeItem(prizeItem) {
  302. if (prizeItem.id === 1 && isRedeemed.value) {
  303. openCertImg()
  304. return
  305. }
  306. if (prizeItem.score > myScore.value) {
  307. ElMessage.warning('积分不足,无法兑换')
  308. return
  309. }
  310. redeemPrizeData.value = prizeItem
  311. isShowRedeem.value = true
  312. }
  313. const redeemRecord = ref([])
  314. getRedeemRecord().then((res) => {
  315. redeemRecord.value = res
  316. })
  317. const rankingList = ref([])
  318. const rankingLoading = ref(false)
  319. const getRankingList = async() => {
  320. try {
  321. rankingLoading.value = true
  322. const data = await getRankingListApi()
  323. rankingList.value = data
  324. } finally {
  325. rankingLoading.value = false
  326. }
  327. }
  328. watch(tabIdx, val => {
  329. if (val === 2) {
  330. getRankingList()
  331. }
  332. })
  333. onMounted(() => {
  334. checkRedeem()
  335. })
  336. const isRedeemed = ref(false)
  337. const checkRedeem = async() => {
  338. const data = await checkRedeemApi()
  339. isRedeemed.value = data
  340. }
  341. const certCanvas = ref()
  342. const $isSafari = inject('$isSafari')
  343. const openCertImg = async(certName) => {
  344. try {
  345. pageLoading.value = true
  346. let winRef
  347. if ($isSafari) {
  348. winRef = window.open('', '_blank')
  349. }
  350. if (isRedeemed.value) {
  351. await getRedeem()
  352. } else {
  353. certInfo.value = {
  354. certName,
  355. createTime: formatDate(new Date(), "YYYY年MM月DD日")
  356. }
  357. }
  358. await nextTick(async() => {
  359. const canvas = await html2canvas(certCanvas.value, {
  360. width: certCanvas.value.offsetWidth,
  361. scale: 2
  362. })
  363. canvas.toBlob((blob) => {
  364. if (blob) {
  365. if ($isSafari && winRef) {
  366. winRef.location.href = URL.createObjectURL(blob)
  367. } else {
  368. window.open(URL.createObjectURL(blob))
  369. }
  370. }
  371. })
  372. })
  373. } finally {
  374. pageLoading.value = false
  375. }
  376. }
  377. const certInfo = ref({
  378. certName: '',
  379. createTime: ''
  380. })
  381. const getRedeem = async() => {
  382. const data = await getRedeemApi()
  383. data.createTime = formatDate(data.createTime, "YYYY年MM月DD日")
  384. certInfo.value = data
  385. }
  386. </script>
  387. <style lang="less" scoped>
  388. .shop-view{
  389. position: absolute;
  390. left: 0;
  391. top: 0;
  392. width: 100%;
  393. height: 100%;
  394. display: flex;
  395. align-items: center;
  396. >menu{
  397. flex: 0 0 auto;
  398. display: flex;
  399. flex-direction: column;
  400. justify-content: center;
  401. align-items: center;
  402. width: calc(300 / 1920 * 100%);
  403. >button{
  404. margin: 28px 0;
  405. font-family: Source Han Sans CN, Source Han Sans CN;
  406. font-weight: 400;
  407. font-size: 28px;
  408. color: #424A4A;
  409. line-height: 33px;
  410. position: relative;
  411. &.active{
  412. font-weight: bold;
  413. color: #589498;
  414. &::after{
  415. content: '';
  416. position: absolute;
  417. left: 50%;
  418. top: 100%;
  419. transform: translate(-50%);
  420. width: 90px;
  421. height: 9px;
  422. background: #FFE794;
  423. box-shadow: 0px 1px 4px 0px rgba(193,165,64,0.5);
  424. border-radius: 4px;
  425. }
  426. }
  427. }
  428. }
  429. >button.prev-page{
  430. width: 58px;
  431. height: 58px;
  432. background-image: url(@/assets/images/icon_arrow-left-round.png);
  433. background-size: cover;
  434. background-repeat: no-repeat;
  435. background-position: center center;
  436. margin-right: calc(25 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  437. &.hide {
  438. pointer-events: none;
  439. opacity: 0;
  440. }
  441. }
  442. ul.prize-list{
  443. position: relative;
  444. flex: 0 0 auto;
  445. width: calc(1400 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  446. height: calc((393 * 2 + 25) / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  447. .product-tip {
  448. position: absolute;
  449. left: 50%;
  450. bottom: -20px;
  451. transform: translateX(-50%);
  452. color: #666;
  453. }
  454. li.prize{
  455. display: inline-block;
  456. width: calc(322 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  457. height: calc(393 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  458. background: linear-gradient( 180deg, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.8) 100%);
  459. border-radius: calc(7 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  460. padding: calc(7 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef')) calc(12 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  461. box-shadow: 0px 1px 11px 0px rgba(0,0,0,0.1);
  462. position: relative;
  463. margin-right: calc(25 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  464. margin-bottom: calc(25 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  465. cursor: pointer;
  466. >img.thumb{
  467. width: calc(307 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  468. height: calc(246 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  469. object-fit: cover;
  470. border-radius: calc(4 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  471. }
  472. .prize-inner {
  473. padding: 0 calc(22 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  474. }
  475. .title{
  476. margin-top: calc(13 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  477. font-size: calc(28 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  478. font-family: Source Han Sans SC, Source Han Sans SC;
  479. color: #424A4A;
  480. line-height: calc(33 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  481. font-weight: bold;
  482. overflow: hidden;
  483. white-space: pre;
  484. text-overflow: ellipsis;
  485. }
  486. .remaining{
  487. min-height: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  488. margin-top: calc(5 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  489. font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  490. font-family: Source Han Sans SC, Source Han Sans SC;
  491. font-weight: 400;
  492. color: rgba(0, 0, 0, 0.5);
  493. line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  494. overflow: hidden;
  495. white-space: pre;
  496. text-overflow: ellipsis;
  497. }
  498. .price{
  499. margin-top: calc(10 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  500. >.number{
  501. font-family: Source Han Sans CN, Source Han Sans CN;
  502. font-weight: bold;
  503. font-size: calc(28 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  504. color: #589498;
  505. line-height: calc(33 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  506. }
  507. >.unit{
  508. font-family: Source Han Sans CN, Source Han Sans CN;
  509. font-weight: 400;
  510. font-size: calc(16 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  511. color: #424A4A;
  512. line-height: calc(19 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  513. margin-left: 0.5em;
  514. }
  515. }
  516. img.icon-enabled{
  517. position: absolute;
  518. right: calc(29 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  519. bottom: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  520. width: calc(57 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  521. height: calc(57 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  522. &.redeemed {
  523. width: calc(80 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  524. height: calc(80 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
  525. }
  526. }
  527. }
  528. >article.prize-item.disabled{
  529. pointer-events: none;
  530. }
  531. }
  532. >button.next-page{
  533. width: 58px;
  534. height: 58px;
  535. background-image: url(@/assets/images/icon_arrow-right-round.png);
  536. background-size: cover;
  537. background-repeat: no-repeat;
  538. background-position: center center;
  539. &.hide {
  540. pointer-events: none;
  541. opacity: 0;
  542. }
  543. }
  544. .ranking-sort {
  545. position: relative;
  546. font-family: 'Alibaba PuHuiTi-Bold' !important;
  547. &.is-first {
  548. color: #70581A !important;
  549. &::after {
  550. content: '';
  551. position: absolute;
  552. top: 50%;
  553. left: 50%;
  554. width: 36px;
  555. height: 36px;
  556. background: url('@/assets/images/icon_winner@2x-min.png') no-repeat center / contain;
  557. transform: translate(-50%, -50%);
  558. }
  559. }
  560. span {
  561. position: relative;
  562. z-index: 1;
  563. }
  564. }
  565. .ranking-name {
  566. display: flex !important;
  567. align-items: center;
  568. justify-content: center;
  569. gap: 17px;
  570. &__avatar {
  571. width: 36px;
  572. height: 36px;
  573. border: 2px solid white;
  574. border-radius: 50%;
  575. }
  576. }
  577. .ranking-content{
  578. flex: 1 0 1px;
  579. height: 100%;
  580. margin: 25px;
  581. display: flex;
  582. flex-direction: column;
  583. align-items: center;
  584. .table{
  585. margin-top: 14px;
  586. flex: 1 0 1px;
  587. width: 100%;
  588. margin-bottom: 43px;
  589. background: linear-gradient( 180deg, rgba(255,255,255,0.6) 0%, rgba(255,255,255,0) 100%);
  590. box-shadow: 15px 15px 38px 0px rgba(255,255,255,0.5);
  591. border-radius: 8px 8px 8px 8px;
  592. display: flex;
  593. flex-direction: column;
  594. >.row-header{
  595. flex: 0 0 auto;
  596. height: 72px;
  597. display: flex;
  598. align-items: center;
  599. margin-right: 16px;
  600. >div{
  601. display: inline-block;
  602. width: 33.3333%;
  603. text-align: center;
  604. font-family: Source Han Sans CN, Source Han Sans CN;
  605. font-weight: bold;
  606. font-size: 20px;
  607. color: #424A4A;
  608. line-height: 23px;
  609. }
  610. }
  611. .table-content{
  612. flex: 1 0 1px;
  613. overflow: auto;
  614. margin-right: 10px;
  615. >.row-data{
  616. height: 68px;
  617. display: flex;
  618. align-items: center;
  619. &.is-me {
  620. background: linear-gradient( 90deg, rgba(88,148,152,0.1) 0%, #589498 50%, rgba(88,148,152,0.1) 100%);
  621. }
  622. >div{
  623. display: inline-block;
  624. width: 33.3333%;
  625. text-align: center;
  626. font-family: Source Han Sans CN, Source Han Sans CN;
  627. font-weight: 400;
  628. font-size: 20px;
  629. color: #424A4A;
  630. line-height: 23px;
  631. opacity: 0.8;
  632. }
  633. }
  634. }
  635. }
  636. }
  637. >.redeem-record-content{
  638. flex: 1 0 1px;
  639. height: 100%;
  640. margin: 25px;
  641. display: flex;
  642. flex-direction: column;
  643. align-items: center;
  644. >p.tip{
  645. margin-top: 23px;
  646. font-family: Source Han Sans CN, Source Han Sans CN;
  647. font-weight: 400;
  648. font-size: 16px;
  649. color: #589498;
  650. line-height: 19px;
  651. }
  652. >.table{
  653. margin-top: 14px;
  654. flex: 1 0 1px;
  655. width: 100%;
  656. margin-bottom: 43px;
  657. background: linear-gradient( 180deg, rgba(255,255,255,0.6) 0%, rgba(255,255,255,0) 100%);
  658. box-shadow: 15px 15px 38px 0px rgba(255,255,255,0.5);
  659. border-radius: 8px 8px 8px 8px;
  660. display: flex;
  661. flex-direction: column;
  662. >.row-header{
  663. flex: 0 0 auto;
  664. height: 72px;
  665. display: flex;
  666. align-items: center;
  667. margin-right: 16px;
  668. >div{
  669. display: inline-block;
  670. width: 25%;
  671. text-align: center;
  672. font-family: Source Han Sans CN, Source Han Sans CN;
  673. font-weight: bold;
  674. font-size: 20px;
  675. color: #424A4A;
  676. line-height: 23px;
  677. }
  678. }
  679. >.splitter{
  680. width: calc(100% - 30px * 2);
  681. height: 1px;
  682. background-color: #B5C2B9;
  683. margin-left: auto;
  684. margin-right: auto;
  685. }
  686. >.table-content{
  687. flex: 1 0 1px;
  688. overflow: auto;
  689. margin-right: 10px;
  690. >.row-data{
  691. height: 68px;
  692. display: flex;
  693. align-items: center;
  694. >div{
  695. display: inline-block;
  696. width: 25%;
  697. text-align: center;
  698. font-family: Source Han Sans CN, Source Han Sans CN;
  699. font-weight: 400;
  700. font-size: 20px;
  701. color: #424A4A;
  702. line-height: 23px;
  703. opacity: 0.8;
  704. }
  705. }
  706. }
  707. }
  708. }
  709. >.coin-number{
  710. position: absolute;
  711. left: 0;
  712. bottom: 43px;
  713. width: 266px;
  714. height: 56px;
  715. background: linear-gradient( 90deg, #589498 0%, rgba(88,148,152,0) 100%);
  716. display: flex;
  717. justify-content: center;
  718. align-items: center;
  719. >img.icon{
  720. position: relative;
  721. top: -15px;
  722. width: 59px;
  723. height: 59px;
  724. margin-right: 20px;
  725. }
  726. >.value{
  727. font-family: Source Han Sans CN, Source Han Sans CN;
  728. font-weight: bold;
  729. font-size: 28px;
  730. line-height: 33px;
  731. color: #fff;
  732. margin-bottom: 10px;
  733. text-shadow: 0px 1px 1px rgba(0,0,0,0.25);
  734. }
  735. }
  736. }
  737. .cert-canvas {
  738. position: absolute;
  739. top: calc(-200% - 1920px);
  740. left: calc(-200% - 2880px);
  741. width: 2880px;
  742. height: 1920px;
  743. background: url('@/assets/images/cert-min.png') no-repeat center / contain;
  744. p:first-child {
  745. position: absolute;
  746. top: calc(50% - 16px);
  747. left: 50%;
  748. color: #CFC49E;
  749. font-size: 140px;
  750. letter-spacing: 10px;
  751. font-family: 'Source Han Sans CN-Bold';
  752. transform: translate(-50%, -50%);
  753. }
  754. p:last-child {
  755. position: absolute;
  756. left: 765px;
  757. bottom: 310px;
  758. font-size: 40px;
  759. }
  760. }
  761. </style>