deotalandAi/apps/frontend/src/views/PointsRecharge/PointsRecharge.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>