ffi
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 1.4 MiB |
Before Width: | Height: | Size: 561 B |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 181 B |
Before Width: | Height: | Size: 169 B |
Before Width: | Height: | Size: 169 B |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 258 KiB |
Before Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 108 B |
Before Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 89 B |
Before Width: | Height: | Size: 187 B |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 1.0 KiB |
BIN
src/assets/img/badge/Badge领取(切图)-0508_slices/BRAVE.png
Normal file
After Width: | Height: | Size: 832 KiB |
BIN
src/assets/img/badge/Badge领取(切图)-0508_slices/CANDY.png
Normal file
After Width: | Height: | Size: 801 KiB |
BIN
src/assets/img/badge/Badge领取(切图)-0508_slices/EXPLTORER.png
Normal file
After Width: | Height: | Size: 858 KiB |
BIN
src/assets/img/badge/Badge领取(切图)-0508_slices/card-top-img.png
Normal file
After Width: | Height: | Size: 804 KiB |
BIN
src/assets/img/badge/Badge领取(切图)-0508_slices/next.png
Normal file
After Width: | Height: | Size: 989 B |
BIN
src/assets/img/badge/Badge领取(切图)-0508_slices/prev.png
Normal file
After Width: | Height: | Size: 1005 B |
BIN
src/assets/img/badge/Badge领取(切图)-0508_slices/右箭头交互@2x.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
src/assets/img/badge/Badge领取(切图)-0508_slices/右箭头默认@2x.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
src/assets/img/badge/Badge领取(切图)-0508_slices/左箭头默认@2x.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
src/assets/img/badge/Badge领取(切图)-0508_slices/数量交互@2x.png
Normal file
After Width: | Height: | Size: 108 B |
BIN
src/assets/img/badge/Badge领取(切图)-0508_slices/数量默认@2x.png
Normal file
After Width: | Height: | Size: 200 B |
BIN
src/assets/img/badge/Badge领取(切图)-0508_slices/默认箭头@2x(1).png
Normal file
After Width: | Height: | Size: 857 B |
BIN
src/assets/img/badge/Badge领取(切图)-0508_slices/默认箭头@2x.png
Normal file
After Width: | Height: | Size: 840 B |
Before Width: | Height: | Size: 408 KiB After Width: | Height: | Size: 804 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
@ -3,7 +3,7 @@
|
||||
wrapClassName="web"
|
||||
:visible="visible"
|
||||
:footer="null"
|
||||
width="60%"
|
||||
width="1100px"
|
||||
:closable="false"
|
||||
:centered="true"
|
||||
@cancel="onCancel"
|
||||
@ -16,7 +16,7 @@
|
||||
class="max-w-full h-auto hero-img"
|
||||
/>
|
||||
</div>
|
||||
<div class="exclusive">
|
||||
<div></div>
|
||||
<div class="cancel pr-2 pt-2 flex justify-end" @click="onCancel">
|
||||
<img
|
||||
src="../../assets/img/badge/close.png"
|
||||
@ -24,7 +24,9 @@
|
||||
class="max-w-full h-auto"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="visible" class="pt-10 w-[450px] text-gray-100 text-content">
|
||||
<div class="exclusive">
|
||||
|
||||
<div v-if="visible" class="w-[28rem] text-gray-100 text-content">
|
||||
This is an exclusive badge for CEBG Genesis NFT holders. It will
|
||||
serve as an identity credential for Genesis NFT holders to
|
||||
participate in all future activities
|
||||
@ -51,11 +53,26 @@ const onCancel = () => {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.modal-content {
|
||||
height: 302px;
|
||||
display: flex;
|
||||
// height: 302px;
|
||||
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
.cancel{
|
||||
position: absolute;
|
||||
right: 0;}
|
||||
}
|
||||
|
||||
|
||||
.hero-img {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
cursor: pointer;
|
||||
width: 35%;
|
||||
height: auto;
|
||||
opacity: 0;
|
||||
animation: slideInFromLeft 0.5s forwards;
|
||||
}
|
||||
.hero-img {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
@ -67,13 +84,14 @@ const onCancel = () => {
|
||||
animation: slideInFromLeft 0.5s forwards;
|
||||
}
|
||||
|
||||
.exclusive {
|
||||
width: 621px;
|
||||
margin-left: 529px;
|
||||
}
|
||||
// .exclusive {
|
||||
// width: 621px;
|
||||
// margin-left: 529px;
|
||||
// }
|
||||
|
||||
.text-content {
|
||||
opacity: 0;
|
||||
font-size: 18px;
|
||||
animation: slideInFromRight 0.5s forwards;
|
||||
}
|
||||
|
||||
@ -98,6 +116,32 @@ const onCancel = () => {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
// 响应式设计
|
||||
// @media screen and (max-width: 1424px) {
|
||||
// .exclusive {
|
||||
// width: 100%;
|
||||
// margin-left: 0;
|
||||
// }
|
||||
|
||||
// .text-content {
|
||||
// font-size: 14px;
|
||||
// padding: 0 10px;
|
||||
// }
|
||||
// }
|
||||
.exclusive {
|
||||
padding-top: 70px;
|
||||
padding-bottom: 70px;
|
||||
width:calc(100% - 432px) ;
|
||||
|
||||
// margin-left: 45%;
|
||||
}
|
||||
|
||||
@media (max-width: 1400px) {
|
||||
.exclusive {
|
||||
width: 50%;
|
||||
// margin-left: 35%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="scss">
|
||||
.web {
|
||||
@ -135,4 +179,5 @@ const onCancel = () => {
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.85)!important;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
@ -1,72 +0,0 @@
|
||||
<template>
|
||||
<div class="cards-container">
|
||||
<div
|
||||
class="card"
|
||||
:style="cardStyle1"
|
||||
@mousemove="startTracking1"
|
||||
@mouseleave="stopTracking1"
|
||||
>
|
||||
<div
|
||||
class="card-title text-xl font-bold mb-10 text-center text-yellow-color flex items-center justify-center cards-container"
|
||||
>
|
||||
<div class="mr-6">
|
||||
<img src="../assets/img/badge/triangle-yellow.png" alt="" />
|
||||
</div>
|
||||
<div>GENESIS</div>
|
||||
<div class="ml-6">
|
||||
<img src="../assets/img/badge/triangle-yellow.png" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="card"
|
||||
:style="cardStyle2"
|
||||
@mousemove="startTracking2"
|
||||
@mouseleave="stopTracking2"
|
||||
>
|
||||
<div
|
||||
class="text-xl font-bold card-title-right text-center mb-4 text-black-color-300 cards-container"
|
||||
>
|
||||
EXPL ORER
|
||||
</div>
|
||||
<div class="card-body cards-container flex pt-12">
|
||||
<img src="../assets/img/badge/explorer BG.png" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useMouseRotation } from "../hooks/useMouseRotation";
|
||||
|
||||
const {
|
||||
cardStyle: cardStyle1,
|
||||
startTracking: startTracking1,
|
||||
stopTracking: stopTracking1,
|
||||
} = useMouseRotation();
|
||||
|
||||
const {
|
||||
cardStyle: cardStyle2,
|
||||
startTracking: startTracking2,
|
||||
stopTracking: stopTracking2,
|
||||
} = useMouseRotation();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.cards-container {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 2rem;
|
||||
|
||||
.card {
|
||||
width: 300px;
|
||||
height: 450px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,98 +0,0 @@
|
||||
<template>
|
||||
<div class="timeline">
|
||||
<div class="timeline-container">
|
||||
<div class="timeline-item" v-for="item in timelineItems" :key="item.id">
|
||||
<div class="timeline-content">
|
||||
<div class="timeline-date">{{ item.date }}</div>
|
||||
<h3>{{ item.title }}</h3>
|
||||
<p>{{ item.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
|
||||
const timelineItems = ref([
|
||||
{
|
||||
id: 1,
|
||||
date: "2021",
|
||||
title: "Event Title 1",
|
||||
description: "Description for event 1",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
date: "2022",
|
||||
title: "Event Title 2",
|
||||
description: "Description for event 2",
|
||||
},
|
||||
// Add more items as needed
|
||||
]);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.timeline {
|
||||
padding: 2rem;
|
||||
.timeline-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
&:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
width: 4px;
|
||||
height: 100%;
|
||||
background-color: #ccc;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
.timeline-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 1rem;
|
||||
.timeline-content {
|
||||
background-color: #fff;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||
padding: 1rem;
|
||||
position: relative;
|
||||
&:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-color: #ccc;
|
||||
border-radius: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 1;
|
||||
}
|
||||
.timeline-date {
|
||||
font-size: 1.2rem;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
h3 {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
p {
|
||||
font-size: 1rem;
|
||||
line-height: 1.5;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -17,7 +17,7 @@
|
||||
class="text-lg login-btn-item italic text-my-text-color font-poppins-semiBoldItalic decoration-1"
|
||||
@click="login"
|
||||
>
|
||||
WALLET CONNECT
|
||||
Log in
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@ -28,7 +28,7 @@
|
||||
class="text-lg italic font-poppins-semiBoldItalic login-btn-item text-my-text-color decoration-1"
|
||||
@click="logout"
|
||||
>
|
||||
loginout
|
||||
logout
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -113,6 +113,7 @@ const logout = async () => {
|
||||
.login-btn-item{
|
||||
position: relative;
|
||||
padding-right: 20px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.login-btn-item::after {
|
||||
content: "";
|
||||
|
@ -22,15 +22,6 @@ function isMobileDevice(userAgent) {
|
||||
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);
|
||||
}
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
const isMobile = isMobileDevice(window.navigator.userAgent);
|
||||
|
||||
// 对于 PC 端官网项目:
|
||||
if (!isMobile) {
|
||||
next(); // 如果是 PC 设备,继续导航
|
||||
} else {
|
||||
window.location.href = 'https://mobile.cebg.games';
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
@ -16,7 +16,7 @@
|
||||
</div>
|
||||
<div class="bg"><img src="../assets/img/badge/bg.png" alt="" /></div>
|
||||
<div class="content mx-auto pb-60">
|
||||
<div class="flex pt-20">
|
||||
<div class="flex pt-20 pl-2">
|
||||
<div class="card shadow-md rounded cards-container">
|
||||
<div></div>
|
||||
<div
|
||||
@ -36,14 +36,13 @@
|
||||
<div class="card-top-img"></div>
|
||||
<div class="top-active top-boder" id="top-boder-impot"></div>
|
||||
</div>
|
||||
<div><img src="../assets/img/badge/genesis BG.png" alt="" /></div>
|
||||
<!-- <div><img src="../assets/img/badge/explorerBG.png" alt="" /></div> -->
|
||||
<!-- <div><div class="btn mx-auto mt-8">Claim</div></div> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="genesicard">
|
||||
<div class="genesis-title font-firaSans-blackItalic">
|
||||
Genesis NFT <br />
|
||||
holder Only
|
||||
{{ displayedText }}
|
||||
</div>
|
||||
<div class="title-boder">
|
||||
<img src="../assets/img/badge/title-boder.png" alt="" />
|
||||
@ -91,7 +90,7 @@
|
||||
</div>
|
||||
<div class="card shadow-md rounded cards-container">
|
||||
<div
|
||||
class="text-xl font-bold font-firaSans-blackItalic card-title-right text-black-color-300 cards-container"
|
||||
class="text-xl font-firaSans-blackItalic card-title-right cards-container"
|
||||
>
|
||||
EXPLORER
|
||||
</div>
|
||||
@ -103,7 +102,7 @@
|
||||
@mouseenter="startTracking2"
|
||||
@mouseleave="stopTracking2"
|
||||
>
|
||||
<img src="../assets/img/badge/explorer BG.png" alt="" />
|
||||
<img src="../assets/img/badge/explorerBG.png" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -114,7 +113,7 @@
|
||||
<div class="pt-2">
|
||||
<div class="flex more-btns">
|
||||
<div class="btn-more-left" @click="handlHero"></div>
|
||||
<div class="btn-more-right" >
|
||||
<div class="btn-more-right">
|
||||
<ul class="dropdown-menu">
|
||||
<li>Alpha Test</li>
|
||||
<li>Beta Test I</li>
|
||||
@ -148,10 +147,10 @@ import { useAppStore } from "@/store/app";
|
||||
import { useRouter, useRoute } from "vue-router";
|
||||
import { useMouse, useRafFn } from "@vueuse/core";
|
||||
import { beginClaim, checkClaimStatus } from "../api/badge";
|
||||
import { useMouseRotation } from "../hooks/useMouseRotation";
|
||||
import { useMouseRotation } from "@/hooks/useMouseRotation";
|
||||
import NavBar from "@/components/layout/NavBar.vue";
|
||||
import ImageTextModal from "../components/global/ImageTextModal.vue";
|
||||
import GlobalLoading from "../components/global/GlobalLoading.vue";
|
||||
import ImageTextModal from "@/components/global/ImageTextModal.vue";
|
||||
import GlobalLoading from "@/components/global/GlobalLoading.vue";
|
||||
import { useChainStore } from "@/store/chain";
|
||||
const AppModule = useAppStore();
|
||||
const scrollOffset = ref("0%");
|
||||
@ -163,10 +162,23 @@ const chain = useChainStore();
|
||||
const totalSupply = ref(0);
|
||||
const mintableCount = ref(0);
|
||||
const supplyLimit = ref(0);
|
||||
const message = ref("You’re not eligible for this stage.");
|
||||
const text = "Genesis NFT holder Only";
|
||||
const chars = text.split("");
|
||||
let shuffledChars = [...chars];
|
||||
const displayedText = ref(shuffledChars.join(""));
|
||||
const message = ref("You're not eligible for this stage.");
|
||||
|
||||
shuffledChars.sort(() => Math.random() - 0.5);
|
||||
const handlHero = () => {
|
||||
visible.value = true;
|
||||
};
|
||||
function shuffle(array) {
|
||||
for (let i = array.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[array[i], array[j]] = [array[j], array[i]];
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
const handleScroll = () => {
|
||||
const currentScrollTop =
|
||||
@ -273,7 +285,7 @@ const fetchData = async () => {
|
||||
message.value !== "claim success!" &&
|
||||
message.value !== "claim failure!"
|
||||
) {
|
||||
message.value = "You’re not eligible for this stage.";
|
||||
message.value = "You're not eligible for this stage.";
|
||||
}
|
||||
//获取当前用户的mint总数
|
||||
supplyLimit.value = await chain.chainManager.bc.supplyLimit();
|
||||
@ -288,7 +300,7 @@ const resetData = () => {
|
||||
totalSupply.value = 0;
|
||||
mintableCount.value = 0;
|
||||
supplyLimit.value = 0;
|
||||
message.value = "You’re not eligible for this stage.";
|
||||
message.value = "You're not eligible for this stage.";
|
||||
console.log("totalSupply.value:", totalSupply.value);
|
||||
console.log("mintableCount.value:", mintableCount.value);
|
||||
console.log("supplyLimit.value:", supplyLimit.value);
|
||||
@ -307,6 +319,18 @@ watch(
|
||||
);
|
||||
// 初始化时获取数据
|
||||
onMounted(async () => {
|
||||
let steps = 0;
|
||||
const maxSteps = 20;
|
||||
const interval = setInterval(() => {
|
||||
steps++;
|
||||
if (steps >= maxSteps) {
|
||||
displayedText.value = text;
|
||||
clearInterval(interval);
|
||||
} else {
|
||||
shuffle(shuffledChars);
|
||||
displayedText.value = shuffledChars.join('');
|
||||
}
|
||||
}, 10);
|
||||
if (AppModule.token && AppModule.step) {
|
||||
await fetchData();
|
||||
}
|
||||
@ -418,6 +442,7 @@ onUnmounted(() => {
|
||||
font-size: 40px;
|
||||
margin-top: 16px;
|
||||
text-align: center;
|
||||
color: #686868;
|
||||
// font-family: "Fira Sans";
|
||||
font-weight: normal;
|
||||
}
|
||||
@ -604,6 +629,8 @@ p {
|
||||
pointer-events: none;
|
||||
}
|
||||
.genesis-title {
|
||||
width: 287px;
|
||||
height: 81px;
|
||||
font-size: 40px;
|
||||
letter-spacing: 3px;
|
||||
margin-top: 75px;
|
||||
@ -616,7 +643,7 @@ p {
|
||||
position: relative; /* 添加相对定位以便伪元素定位 */
|
||||
width: 302px;
|
||||
margin-left: 39px;
|
||||
margin-right: 162px;
|
||||
margin-right: 153px;
|
||||
}
|
||||
|
||||
.genesicard::before {
|
||||
|
@ -1,86 +0,0 @@
|
||||
<template>
|
||||
<div class="my-container">
|
||||
<NavBar></NavBar>
|
||||
<div class="content-top">
|
||||
<div class="text-left">
|
||||
<img src="../assets/img/badge/left-text.png" alt="" />
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<img src="../assets/img/badge/right-text.png" alt="" />
|
||||
</div>
|
||||
<div class="bg"><img src="../assets/img/badge/bg.png" alt="" /></div>
|
||||
<CardsSection />
|
||||
<TimelineSection />
|
||||
</div>
|
||||
<ImageTextModal v-model:visible="visible" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import NavBar from '@/components/layout/NavBar.vue';
|
||||
import ImageTextModal from '../components/global/ImageTextModal.vue';
|
||||
import CardsSection from '../components/CardsSection.vue';
|
||||
import TimelineSection from '../components/TimelineSection.vue';
|
||||
|
||||
const visible = ref(false);
|
||||
const openModal = () => {
|
||||
visible.value = true;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.my-container {
|
||||
.content-top {
|
||||
position: relative;
|
||||
.bg {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: -10px;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: -1;
|
||||
img {
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.text-left {
|
||||
position: absolute;
|
||||
left: 85px;
|
||||
bottom: 30px;
|
||||
animation: slide-up 1s ease-out;
|
||||
}
|
||||
.text-right {
|
||||
position: absolute;
|
||||
right: 85px;
|
||||
top: 30px;
|
||||
animation: slide-down 1s ease-out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slide-up {
|
||||
0% {
|
||||
transform: translateY(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0%);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slide-down {
|
||||
0% {
|
||||
transform: translateY(-100%);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0%);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,57 +0,0 @@
|
||||
<!-- MedalApp.vue -->
|
||||
<template>
|
||||
<div>
|
||||
<h1>可领取的勋章数量:{{ mintableCount }}</h1>
|
||||
<button @click="mintMedals">领取勋章</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref } from 'vue';
|
||||
import { ethers } from 'ethers';
|
||||
import MEDAL_REWARDS_ABI from './MEDAL_REWARDS_ABI.json'; // 从编译后的合约中导入 ABI
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const mintableCount = ref(0);
|
||||
const medalRewardsAddress = '0x123...'; // 替换为实际的合约地址
|
||||
const provider = new ethers.providers.Web3Provider(window.ethereum); // 使用 MetaMask 提供的以太坊 provider
|
||||
const medalRewardsContract = new ethers.Contract(medalRewardsAddress, MEDAL_REWARDS_ABI, provider);
|
||||
|
||||
const loadMintableCount = async () => {
|
||||
try {
|
||||
const userAddress = await provider.getSigner().getAddress(); // 获取当前用户的地址
|
||||
const count = await medalRewardsContract.getMintableCount(userAddress);
|
||||
mintableCount.value = count.toNumber();
|
||||
} catch (error) {
|
||||
console.error('Error fetching mintable count:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const mintMedals = async () => {
|
||||
try {
|
||||
const signer = provider.getSigner(); // 获取当前用户的签名器
|
||||
const userAddress = await signer.getAddress(); // 获取当前用户的地址
|
||||
const contractWithSigner = medalRewardsContract.connect(signer);
|
||||
|
||||
const tx = await contractWithSigner.mintToUser(userAddress, mintableCount.value);
|
||||
await tx.wait(); // 等待交易被确认
|
||||
|
||||
// 重新加载可领取的勋章数量,因为用户已经领取了勋章
|
||||
await loadMintableCount();
|
||||
} catch (error) {
|
||||
console.error('Error minting medals:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 页面载入时获取可领取的勋章数量
|
||||
loadMintableCount();
|
||||
|
||||
return {
|
||||
mintableCount,
|
||||
mintMedals,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -32,7 +32,7 @@ export default defineConfig({
|
||||
// 打包文件名
|
||||
assetsDir: 'static',
|
||||
// 静态资源引用路径
|
||||
sourcemap: true,
|
||||
sourcemap: false,
|
||||
assetsPublicPath: '/',
|
||||
// 是否开启压缩
|
||||
minify: 'terser',
|
||||
|