2025-05-28 16:03:08 +08:00
|
|
|
|
<script setup>
|
2025-08-25 13:47:32 +08:00
|
|
|
|
import { ref, onMounted, onBeforeUnmount } from "vue";
|
2025-05-28 16:03:08 +08:00
|
|
|
|
import Container from "@/components/Container.vue";
|
|
|
|
|
|
import Avatar from "@/components/Avatar.vue";
|
|
|
|
|
|
import SButton from "@/components/SButton.vue";
|
2025-06-24 13:18:03 +08:00
|
|
|
|
import SModal from "@/components/SModal.vue";
|
|
|
|
|
|
import Signin from "@/components/Signin.vue";
|
2025-07-15 14:02:09 +08:00
|
|
|
|
import UserHeader from "@/components/UserHeader.vue";
|
2025-08-29 10:20:37 +08:00
|
|
|
|
import { createOrderAPI, getHomeData, getVIPDescAPI } from "@/apis";
|
2025-07-01 10:57:49 +08:00
|
|
|
|
import { formatTimestamp } from "@/util";
|
2025-05-28 16:03:08 +08:00
|
|
|
|
import useStore from "@/store";
|
|
|
|
|
|
import { storeToRefs } from "pinia";
|
|
|
|
|
|
const store = useStore();
|
2025-06-22 15:04:10 +08:00
|
|
|
|
const { user, config } = storeToRefs(store);
|
2025-07-12 17:12:24 +08:00
|
|
|
|
const { updateUser } = store;
|
2025-05-28 16:03:08 +08:00
|
|
|
|
|
2025-06-22 15:04:10 +08:00
|
|
|
|
const selectedVIP = ref(0);
|
2025-06-24 13:18:03 +08:00
|
|
|
|
const showModal = ref(false);
|
2025-07-25 10:00:18 +08:00
|
|
|
|
const lastDate = ref(user.value.expiredAt);
|
|
|
|
|
|
const refreshing = ref(false);
|
|
|
|
|
|
const timer = ref(null);
|
2025-08-29 10:20:37 +08:00
|
|
|
|
const richContent = ref("");
|
2025-05-28 16:03:08 +08:00
|
|
|
|
|
2025-07-01 00:25:17 +08:00
|
|
|
|
const onPay = async () => {
|
2025-06-19 01:55:40 +08:00
|
|
|
|
if (!user.value.id) {
|
2025-06-24 13:18:03 +08:00
|
|
|
|
showModal.value = true;
|
2025-07-01 00:25:17 +08:00
|
|
|
|
} else if (config.value.vipMenus[selectedVIP.value]) {
|
|
|
|
|
|
if (config.value.vipMenus[selectedVIP.value].id) {
|
|
|
|
|
|
const result = await createOrderAPI(
|
|
|
|
|
|
config.value.vipMenus[selectedVIP.value].id
|
|
|
|
|
|
);
|
2025-07-12 17:12:24 +08:00
|
|
|
|
if (!result.pay) return;
|
|
|
|
|
|
const params = result.pay.order.jsApi.params;
|
|
|
|
|
|
if (params) {
|
|
|
|
|
|
wx.requestPayment({
|
|
|
|
|
|
timeStamp: params.timeStamp, // 时间戳
|
|
|
|
|
|
nonceStr: params.nonceStr, // 随机字符串
|
|
|
|
|
|
package: params.package, // 统一下单接口返回的 prepay_id 参数值,格式:prepay_id=***
|
|
|
|
|
|
paySign: params.paySign, // 签名
|
|
|
|
|
|
signType: "RSA", // 签名类型,默认为RSA
|
|
|
|
|
|
async success(res) {
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: "支付成功",
|
|
|
|
|
|
icon: "none",
|
|
|
|
|
|
});
|
2025-07-25 10:00:18 +08:00
|
|
|
|
timer.value = setInterval(async () => {
|
|
|
|
|
|
refreshing.value = true;
|
|
|
|
|
|
const result = await getHomeData();
|
|
|
|
|
|
if (result.user.expiredAt > lastDate.value) {
|
|
|
|
|
|
refreshing.value = false;
|
|
|
|
|
|
if (result.user) updateUser(result.user);
|
|
|
|
|
|
clearInterval(timer.value);
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 1000);
|
2025-07-12 17:12:24 +08:00
|
|
|
|
},
|
|
|
|
|
|
fail(res) {
|
|
|
|
|
|
console.log("pay error", res);
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2025-07-01 00:25:17 +08:00
|
|
|
|
}
|
2025-06-19 01:55:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
};
|
2025-07-15 14:02:09 +08:00
|
|
|
|
|
2025-08-29 10:20:37 +08:00
|
|
|
|
onMounted(async () => {
|
|
|
|
|
|
const result = await getVIPDescAPI();
|
|
|
|
|
|
richContent.value = result.describe;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-07-15 14:02:09 +08:00
|
|
|
|
const toOrderPage = () => {
|
|
|
|
|
|
uni.navigateTo({
|
|
|
|
|
|
url: "/pages/orders",
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
2025-07-25 10:00:18 +08:00
|
|
|
|
|
2025-08-25 13:47:32 +08:00
|
|
|
|
onBeforeUnmount(() => {
|
2025-07-25 10:00:18 +08:00
|
|
|
|
if (timer.value) clearInterval(timer.value);
|
|
|
|
|
|
});
|
2025-05-28 16:03:08 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
|
<Container title="会员说明">
|
2025-07-15 15:15:47 +08:00
|
|
|
|
<view :style="{ width: '100%', height: '100%' }">
|
|
|
|
|
|
<view v-if="user.id" class="header">
|
2025-05-28 16:03:08 +08:00
|
|
|
|
<view>
|
2025-07-15 15:15:47 +08:00
|
|
|
|
<Avatar :src="user.avatar" :size="35" />
|
|
|
|
|
|
<text class="truncate">{{ user.nickName }}</text>
|
2025-07-28 15:05:19 +08:00
|
|
|
|
<image
|
|
|
|
|
|
class="user-name-image"
|
|
|
|
|
|
src="../static/vip1.png"
|
|
|
|
|
|
mode="widthFix"
|
|
|
|
|
|
/>
|
2025-05-28 16:03:08 +08:00
|
|
|
|
</view>
|
2025-07-25 10:00:18 +08:00
|
|
|
|
<block v-if="refreshing">
|
|
|
|
|
|
<image
|
|
|
|
|
|
src="../static/btn-loading.png"
|
|
|
|
|
|
mode="widthFix"
|
|
|
|
|
|
class="loading"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</block>
|
|
|
|
|
|
<block v-else>
|
|
|
|
|
|
<text v-if="user.expiredAt">
|
|
|
|
|
|
{{ formatTimestamp(user.expiredAt) }}到期
|
|
|
|
|
|
</text>
|
|
|
|
|
|
</block>
|
2025-05-28 16:03:08 +08:00
|
|
|
|
</view>
|
2025-07-15 15:15:47 +08:00
|
|
|
|
<view
|
|
|
|
|
|
class="container"
|
|
|
|
|
|
:style="{ height: !user.id ? '100%' : 'calc(100% - 62px)' }"
|
|
|
|
|
|
>
|
|
|
|
|
|
<view class="content vip-content">
|
|
|
|
|
|
<view class="title-bar">
|
|
|
|
|
|
<view />
|
|
|
|
|
|
<text>VIP 介绍</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view>
|
2025-08-29 10:20:37 +08:00
|
|
|
|
<rich-text :nodes="richContent" />
|
|
|
|
|
|
<!-- <text
|
2025-07-28 15:07:51 +08:00
|
|
|
|
>射灵星球VIP服务,为全球弓箭手提供约战、段位评级、实时排位赛、智能教练点评等专属特权。会员可在酷帅的真实射箭运动中,同步享受在线竞技的乐趣,还能找到志同道合的伙伴,并获得新鲜的功能体验和持续升级的系统。
|
|
|
|
|
|
</text>
|
2025-07-15 15:15:47 +08:00
|
|
|
|
<text
|
2025-07-28 15:07:51 +08:00
|
|
|
|
>所有新注册用户,我们都会默认赠送6个月超长会员。到期之后可续费,单月10元,年度VIP100元。我们鼓励每一位弓箭手长期坚持练习这项运动,在对战的世界中尽情驰骋,不断挑战自我,创造属于自己的辉煌战绩。
|
|
|
|
|
|
</text>
|
2025-07-15 15:15:47 +08:00
|
|
|
|
<text
|
2025-07-28 15:07:51 +08:00
|
|
|
|
>VIP会员还将获得专属客服支持。当您在游戏中遇到任何问题,无论是技术故障、规则疑问还是其他需要帮助的情况,都可联系我们的VIP专属客服团队。他们将提供全年不间断的优质服务,确保您的对战体验不受影响。
|
|
|
|
|
|
</text>
|
2025-08-29 10:20:37 +08:00
|
|
|
|
<text>期待您的加入!</text> -->
|
2025-07-15 15:15:47 +08:00
|
|
|
|
</view>
|
2025-05-28 16:03:08 +08:00
|
|
|
|
</view>
|
2025-07-15 15:15:47 +08:00
|
|
|
|
<view class="content">
|
|
|
|
|
|
<view class="title-bar">
|
|
|
|
|
|
<view />
|
2025-07-28 15:05:19 +08:00
|
|
|
|
<text>会员续费</text>
|
2025-07-15 15:15:47 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
<view class="vip-items">
|
|
|
|
|
|
<view
|
|
|
|
|
|
v-for="(item, index) in config.vipMenus || []"
|
|
|
|
|
|
:key="index"
|
|
|
|
|
|
:style="{
|
|
|
|
|
|
color: selectedVIP === index ? '#fff' : '#333333',
|
|
|
|
|
|
borderColor: selectedVIP === index ? '#FF7D57' : '#eee',
|
|
|
|
|
|
background:
|
|
|
|
|
|
selectedVIP === index
|
|
|
|
|
|
? '#FF7D57'
|
|
|
|
|
|
: 'linear-gradient(180deg, #fbfbfb 0%, #f5f5f5 100%)',
|
|
|
|
|
|
}"
|
|
|
|
|
|
@click="() => (selectedVIP = index)"
|
|
|
|
|
|
>
|
|
|
|
|
|
{{ item.name }}
|
|
|
|
|
|
</view>
|
2025-05-28 16:03:08 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
2025-07-15 15:15:47 +08:00
|
|
|
|
<SButton :onClick="onPay">支付</SButton>
|
|
|
|
|
|
<SModal :show="showModal" :onClose="() => (showModal = false)">
|
|
|
|
|
|
<Signin :onClose="() => (showModal = false)" />
|
|
|
|
|
|
</SModal>
|
|
|
|
|
|
<view class="my-orders" v-if="user.id">
|
|
|
|
|
|
<view @click="toOrderPage">
|
|
|
|
|
|
<text>我的订单</text>
|
|
|
|
|
|
<image src="../static/enter-arrow-blue.png" mode="widthFix" />
|
|
|
|
|
|
</view>
|
2025-07-15 14:02:09 +08:00
|
|
|
|
</view>
|
2025-05-28 16:03:08 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</Container>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
.header {
|
2025-06-08 12:52:49 +08:00
|
|
|
|
width: calc(100% - 30px);
|
2025-05-28 16:03:08 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
padding: 15px;
|
|
|
|
|
|
padding-top: 0;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.header > view {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
2025-07-28 15:05:19 +08:00
|
|
|
|
.header > view > text {
|
2025-05-28 16:03:08 +08:00
|
|
|
|
margin-left: 10px;
|
2025-07-28 15:05:19 +08:00
|
|
|
|
max-width: 120px;
|
2025-06-24 13:18:03 +08:00
|
|
|
|
text-align: left;
|
2025-05-28 16:03:08 +08:00
|
|
|
|
}
|
2025-07-28 15:05:19 +08:00
|
|
|
|
.header > view > image {
|
|
|
|
|
|
margin-left: 5px;
|
|
|
|
|
|
width: 20px;
|
|
|
|
|
|
}
|
2025-05-28 16:03:08 +08:00
|
|
|
|
.header > text:nth-child(2) {
|
|
|
|
|
|
color: #fed847;
|
|
|
|
|
|
}
|
|
|
|
|
|
.container {
|
|
|
|
|
|
width: 100%;
|
2025-07-14 14:25:37 +08:00
|
|
|
|
background-color: #f5f5f5;
|
2025-05-28 16:03:08 +08:00
|
|
|
|
padding-top: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.content {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
padding: 15px;
|
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.title-bar {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
.title-bar > view:first-child {
|
|
|
|
|
|
width: 5px;
|
|
|
|
|
|
height: 15px;
|
|
|
|
|
|
border-radius: 10px;
|
|
|
|
|
|
background-color: #fed847;
|
|
|
|
|
|
margin-right: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.content > view:nth-child(2) {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
}
|
|
|
|
|
|
.vip-items {
|
|
|
|
|
|
width: 100%;
|
2025-06-22 15:04:10 +08:00
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: repeat(4, 23.5%);
|
2025-05-28 16:03:08 +08:00
|
|
|
|
padding: 10px;
|
2025-06-22 15:04:10 +08:00
|
|
|
|
row-gap: 5%;
|
|
|
|
|
|
column-gap: 2%;
|
2025-05-28 16:03:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
.vip-items > view {
|
|
|
|
|
|
border: 1px solid #eee;
|
|
|
|
|
|
padding: 12px 0;
|
|
|
|
|
|
border-radius: 10px;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
2025-07-15 14:02:09 +08:00
|
|
|
|
.vip-content {
|
2025-07-28 15:07:51 +08:00
|
|
|
|
max-height: 62%;
|
2025-07-15 14:02:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
.vip-content > view:nth-child(2) {
|
|
|
|
|
|
overflow: auto;
|
|
|
|
|
|
}
|
2025-07-24 11:54:38 +08:00
|
|
|
|
.vip-content > view:nth-child(2)::-webkit-scrollbar {
|
|
|
|
|
|
width: 0;
|
|
|
|
|
|
height: 0;
|
|
|
|
|
|
color: transparent;
|
|
|
|
|
|
}
|
2025-07-15 14:02:09 +08:00
|
|
|
|
.my-orders {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
color: #39a8ff;
|
|
|
|
|
|
margin-top: 10px;
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.my-orders > view {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
.my-orders > view > image {
|
|
|
|
|
|
width: 15px;
|
|
|
|
|
|
}
|
2025-07-25 10:00:18 +08:00
|
|
|
|
.loading {
|
|
|
|
|
|
width: 20px;
|
|
|
|
|
|
height: 20px;
|
|
|
|
|
|
margin-left: 10px;
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
background-blend-mode: darken;
|
|
|
|
|
|
animation: rotate 2s linear infinite;
|
|
|
|
|
|
}
|
2025-05-28 16:03:08 +08:00
|
|
|
|
</style>
|