482 lines
9.6 KiB
Vue
482 lines
9.6 KiB
Vue
<template>
|
|
<div class="points-recharge-page">
|
|
<!-- 顶部操作栏 -->
|
|
<div class="top-bar">
|
|
<!-- 返回按钮 -->
|
|
<button class="back-button" @click="goBack">
|
|
← {{ t('common.back') }}
|
|
</button>
|
|
<!-- 语言切换组件 -->
|
|
<div class="language-switcher">
|
|
<LanguageToggle />
|
|
</div>
|
|
</div>
|
|
<!-- 页面标题 -->
|
|
<div class="page-header">
|
|
<h1 class="page-title">{{ t('pointsRecharge.title') }}</h1>
|
|
<p class="page-subtitle">{{ t('pointsRecharge.subtitle') }}</p>
|
|
</div>
|
|
|
|
<!-- 套餐选择 -->
|
|
<div class="plans-container">
|
|
<!-- 动态渲染套餐卡片 -->
|
|
<div
|
|
v-for="pkg in sortedPackages"
|
|
:key="pkg.id"
|
|
class="plan-card"
|
|
:class="{
|
|
premium: pkg.is_recommended === 1
|
|
}"
|
|
@click="selectPlan(pkg.id)"
|
|
>
|
|
<div class="plan-header">
|
|
<h3 class="plan-name">{{ pkg.package_name }}</h3>
|
|
<div v-if="pkg.is_recommended === 1" class="plan-badge">{{ t('pointsRecharge.plans.premium.badge') }}</div>
|
|
</div>
|
|
|
|
<div class="plan-price">
|
|
<span class="price-amount">${{ pkg.amount }}</span>
|
|
<span class="price-period">/ {{ t('pointsRecharge.period') }}</span>
|
|
</div>
|
|
|
|
<div class="plan-points">
|
|
{{ pkg.credits }} {{ t('pointsRecharge.points') }}
|
|
</div>
|
|
|
|
<div class="plan-validity">
|
|
{{ t('pointsRecharge.validity') }}: {{ pkg.validity_days }} {{ t('pointsRecharge.period') }}
|
|
</div>
|
|
|
|
<div class="plan-features">
|
|
<ul>
|
|
<li>{{ pkg.description }}</li>
|
|
<li>{{ t('pointsRecharge.features.unlimitedAccess') }}</li>
|
|
<li>{{ t('pointsRecharge.features.prioritySupport') }}</li>
|
|
<li>{{ t('pointsRecharge.features.securePayment') }}</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<button
|
|
class="purchase-button"
|
|
:class="{ 'premium-button': pkg.is_recommended === 1 }"
|
|
@click.stop="purchasePlan(pkg)"
|
|
>
|
|
{{ t('pointsRecharge.purchase') }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 积分消耗规则 -->
|
|
<div class="points-rules">
|
|
<h2 class="rules-title">{{ t('pointsRecharge.rules.title') }}</h2>
|
|
<ul class="rules-list">
|
|
<li class="rule-item">{{ t('pointsRecharge.rules.rule1') }}</li>
|
|
<li class="rule-item">{{ t('pointsRecharge.rules.rule2') }}</li>
|
|
<li class="rule-item">{{ t('pointsRecharge.rules.rule3') }}</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed, onMounted } from 'vue'
|
|
import { useI18n } from 'vue-i18n'
|
|
import { useRouter } from 'vue-router'
|
|
import LanguageToggle from '@/components/ui/LanguageToggle.vue'
|
|
import { PointsRecharge } from './index.js'
|
|
import { WechatBus,isWeChatBrowser } from '@deotaland/utils'
|
|
const pointsRecharge = new PointsRecharge()
|
|
const { t } = useI18n()
|
|
const router = useRouter()
|
|
|
|
const selectedPlan = ref(null)
|
|
const packagesList = ref([])
|
|
|
|
const sortedPackages = computed(() => {
|
|
return [...packagesList.value].sort((a, b) => a.sort_order - b.sort_order)
|
|
})
|
|
|
|
const goBack = () => {
|
|
const history = router.options.history.state
|
|
console.log(history);
|
|
if(!history.back){
|
|
router.replace('/user-center')
|
|
}
|
|
router.back()
|
|
}
|
|
|
|
const selectPlan = (planId) => {
|
|
selectedPlan.value = planId
|
|
}
|
|
|
|
const purchasePlan = (pkg) => {
|
|
console.log(pkg,'pkgpkg');
|
|
let parmas = {
|
|
package_id: pkg.id,
|
|
}
|
|
if(isWeChatBrowser()){
|
|
const token = localStorage.getItem('token') || ''
|
|
WechatBus.BusWechartForNavigate('/pages/pay/payPoint',{
|
|
method:'pay',
|
|
payData:JSON.stringify({
|
|
package_id: pkg.id,
|
|
credits:pkg.credits,
|
|
amount:pkg.amount,
|
|
token:token})
|
|
},'1')
|
|
return
|
|
}
|
|
pointsRecharge.confirmPay(parmas)
|
|
}
|
|
|
|
const init = async () => {
|
|
let res = await pointsRecharge.getRechargePackageList()
|
|
const data = res.items || []
|
|
packagesList.value = data
|
|
}
|
|
|
|
onMounted(() => {
|
|
init()
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.points-recharge-page {
|
|
width: 100%;
|
|
margin: 0;
|
|
padding: 40px 20px;
|
|
color: #f9fafb;
|
|
background-color: #111827;
|
|
min-height: 100vh;
|
|
}
|
|
|
|
/* 顶部操作栏 */
|
|
.top-bar {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
/* margin-bottom: 40px; */
|
|
width: 100%;
|
|
}
|
|
|
|
/* 返回按钮 */
|
|
.back-button {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
padding: 12px 20px;
|
|
background: transparent;
|
|
color: #F9FAFB;
|
|
border: 2px solid #374151;
|
|
border-radius: 12px;
|
|
font-size: 1rem;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.back-button:hover {
|
|
background: #374151;
|
|
border-color: #8B5CF6;
|
|
transform: translateX(-4px);
|
|
}
|
|
|
|
/* 语言切换器 */
|
|
.language-switcher {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
/* 页面标题 */
|
|
.page-header {
|
|
text-align: center;
|
|
margin-bottom: 60px;
|
|
}
|
|
|
|
.page-title {
|
|
font-size: 3rem;
|
|
font-weight: 700;
|
|
margin: 0 0 12px 0;
|
|
background: linear-gradient(135deg, #8B5CF6 0%, #EC4899 100%);
|
|
-webkit-background-clip: text;
|
|
-webkit-text-fill-color: transparent;
|
|
background-clip: text;
|
|
}
|
|
|
|
.page-subtitle {
|
|
font-size: 1.25rem;
|
|
color: #9CA3AF;
|
|
margin: 0;
|
|
}
|
|
|
|
/* 套餐容器 */
|
|
.plans-container {
|
|
display: flex;
|
|
gap: 32px;
|
|
justify-content: center;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
/* 套餐卡片 */
|
|
.plan-card {
|
|
background: #1F2937;
|
|
border: 2px solid #374151;
|
|
border-radius: 16px;
|
|
padding: 32px;
|
|
width: 350px;
|
|
transition: all 0.3s ease;
|
|
cursor: pointer;
|
|
position: relative;
|
|
overflow: hidden;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
/* .plan-card::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: 4px;
|
|
background: linear-gradient(90deg, #8B5CF6 0%, #EC4899 100%);
|
|
opacity: 0;
|
|
transition: opacity 0.3s ease;
|
|
} */
|
|
|
|
.plan-card:hover {
|
|
transform: translateY(-8px);
|
|
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
|
|
border-color: #8B5CF6;
|
|
}
|
|
|
|
.plan-card.active {
|
|
border-color: #8B5CF6;
|
|
border-width: 3px;
|
|
box-shadow: 0 0 0 2px rgba(139, 92, 246, 0.3), 0 20px 40px rgba(139, 92, 246, 0.3);
|
|
}
|
|
|
|
.plan-card.active::before {
|
|
opacity: 1;
|
|
}
|
|
|
|
/* 高级套餐样式 */
|
|
.plan-card.premium {
|
|
background: linear-gradient(135deg, #1F2937 0%, #374151 100%);
|
|
}
|
|
|
|
/* 套餐头部 */
|
|
.plan-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 24px;
|
|
flex-wrap: nowrap;
|
|
gap: 12px;
|
|
}
|
|
|
|
.plan-name {
|
|
font-size: 1.5rem;
|
|
font-weight: 600;
|
|
margin: 0;
|
|
color: #F9FAFB;
|
|
flex: 1;
|
|
min-width: 0;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.plan-badge {
|
|
background: linear-gradient(135deg, #8B5CF6 0%, #EC4899 100%);
|
|
color: white;
|
|
font-size: 0.875rem;
|
|
font-weight: 600;
|
|
padding: 4px 12px;
|
|
border-radius: 20px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* 价格样式 */
|
|
.plan-price {
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.price-amount {
|
|
font-size: 3rem;
|
|
font-weight: 700;
|
|
color: #F9FAFB;
|
|
}
|
|
|
|
.price-period {
|
|
font-size: 1.125rem;
|
|
color: #9CA3AF;
|
|
margin-left: 4px;
|
|
}
|
|
|
|
/* 积分数量 */
|
|
.plan-points {
|
|
font-size: 1.5rem;
|
|
font-weight: 600;
|
|
color: #8B5CF6;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
/* 有效期 */
|
|
.plan-validity {
|
|
font-size: 1rem;
|
|
color: #9CA3AF;
|
|
margin-bottom: 24px;
|
|
}
|
|
|
|
/* 套餐特性 */
|
|
.plan-features {
|
|
margin-bottom: auto;
|
|
margin-top: 24px;
|
|
}
|
|
|
|
.plan-features ul {
|
|
list-style: none;
|
|
padding: 0;
|
|
margin: 0;
|
|
}
|
|
|
|
.plan-features li {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: 12px;
|
|
font-size: 0.9375rem;
|
|
color: #D1D5DB;
|
|
}
|
|
|
|
.plan-features li::before {
|
|
content: '✓';
|
|
color: #8B5CF6;
|
|
font-weight: bold;
|
|
margin-right: 10px;
|
|
font-size: 1.125rem;
|
|
}
|
|
|
|
/* 购买按钮 */
|
|
.purchase-button {
|
|
width: 100%;
|
|
padding: 16px;
|
|
margin-top: 32px;
|
|
background: linear-gradient(135deg, #8B5CF6 0%, #7C3AED 100%);
|
|
color: white;
|
|
font-size: 1.125rem;
|
|
font-weight: 600;
|
|
border: none;
|
|
border-radius: 12px;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
align-self: stretch;
|
|
}
|
|
|
|
.purchase-button:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 10px 25px rgba(139, 92, 246, 0.4);
|
|
}
|
|
|
|
.purchase-button:active {
|
|
transform: translateY(0);
|
|
}
|
|
|
|
/* 高级套餐按钮 */
|
|
.purchase-button.premium-button {
|
|
background: linear-gradient(135deg, #EC4899 0%, #DB2777 100%);
|
|
}
|
|
|
|
.purchase-button.premium-button:hover {
|
|
box-shadow: 0 10px 25px rgba(236, 72, 153, 0.4);
|
|
}
|
|
|
|
/* 积分消耗规则样式 */
|
|
.points-rules {
|
|
margin-top: 60px;
|
|
padding: 32px;
|
|
background: rgba(31, 41, 55, 0.6);
|
|
border: 2px solid rgba(139, 92, 246, 0.2);
|
|
border-radius: 16px;
|
|
max-width: 800px;
|
|
margin-left: auto;
|
|
margin-right: auto;
|
|
backdrop-filter: blur(10px);
|
|
}
|
|
|
|
.rules-title {
|
|
font-size: 1.5rem;
|
|
font-weight: 600;
|
|
color: #F9FAFB;
|
|
margin: 0 0 24px 0;
|
|
text-align: center;
|
|
}
|
|
|
|
.rules-list {
|
|
list-style: none;
|
|
padding: 0;
|
|
margin: 0;
|
|
}
|
|
|
|
.rule-item {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
margin-bottom: 16px;
|
|
font-size: 1.125rem;
|
|
color: #D1D5DB;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
.rule-item:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.rule-item::before {
|
|
content: '•';
|
|
color: #8B5CF6;
|
|
font-weight: bold;
|
|
margin-right: 12px;
|
|
font-size: 1.5rem;
|
|
line-height: 1.2;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* 响应式设计 */
|
|
@media (max-width: 768px) {
|
|
.points-recharge-page {
|
|
padding: 20px 16px;
|
|
}
|
|
|
|
.page-title {
|
|
font-size: 2rem;
|
|
}
|
|
|
|
.page-subtitle {
|
|
font-size: 1rem;
|
|
}
|
|
|
|
.plans-container {
|
|
flex-direction: column;
|
|
align-items: center;
|
|
}
|
|
|
|
.plan-card {
|
|
width: 100%;
|
|
max-width: 350px;
|
|
}
|
|
|
|
/* 响应式积分规则样式 */
|
|
.points-rules {
|
|
padding: 24px;
|
|
margin-top: 40px;
|
|
}
|
|
|
|
.rules-title {
|
|
font-size: 1.25rem;
|
|
}
|
|
|
|
.rule-item {
|
|
font-size: 1rem;
|
|
}
|
|
}
|
|
</style> |