Files
Yi.Framework/Yi.Ai.Vue3/src/components/ProductPackage/index.vue

1770 lines
54 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import type { GoodsItem } from '@/api/pay';
import { CircleCheck, Loading } from '@element-plus/icons-vue';
import { ElMessage } from 'element-plus';
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';
import { useRouter } from 'vue-router';
import { createOrder, getOrderStatus } from '@/api';
import { getGoodsList, GoodsCategoryType } from '@/api/pay';
import SupportModelList from '@/components/userPersonalCenter/components/SupportModelList.vue';
import ProductPage from '@/pages/products/index.vue';
import { useUserStore } from '@/stores';
const emit = defineEmits(['close']);
// 商品数据类型定义
interface PackageItem {
id: number;
name: string;
desc: string;
price: number; // 用户实际支付价格(最终专属价)
originalPrice?: number; // 原价(官方价格)
perMonth?: number; // 会员月均价Token模型官方价格
tag: string;
discount: string; // 累计优惠描述,如"根据累加充值已优惠 ¥47.00"
goodsName: string; // 用于创建订单
discountAmount?: number; // 优惠金额从discount字段解析
goodsType?: any; // 商品枚举
}
// 商品数据(从接口获取)
const packagesData = ref<{
member: PackageItem[];
token: PackageItem[];
}>({
member: [],
token: [],
});
const userStore = useUserStore();
const visible = ref(true);
const activeTab = ref('member');
const selectedId = ref<number | null>(null);
const selectedPrice = ref(0);
const selectPackageObject = ref<PackageItem | null>(null);
const showDetails = ref(false);
const isMobile = ref(false);
const isLoading = ref(false);
const isLoadingGoods = ref(false); // 商品加载状态
const paymentWindow = ref<Window | null>(null);
const pollInterval = ref<NodeJS.Timeout | null>(null);
function checkMobile() {
isMobile.value = window.innerWidth < 768;
}
// 获取商品列表(逻辑不变,仅保留字段映射正确性)
async function fetchGoodsList() {
isLoadingGoods.value = true;
try {
const [vipRes, tokenRes] = await Promise.all([
getGoodsList(GoodsCategoryType.Vip),
getGoodsList(GoodsCategoryType.PremiumPackage),
]);
// 转换VIP商品数据
packagesData.value.member = (vipRes.data || []).map((item: GoodsItem, index: number) => ({
id: index + 1,
name: item.goodsName,
desc: '',
price: item.goodsPrice,
originalPrice: item.originalPrice !== item.goodsPrice ? item.originalPrice : undefined,
perMonth: item.referencePrice,
tag: item.remark || '',
discount: item.discountDescription || '',
goodsName: item.goodsName,
goodsType: item.goodsType,
}));
// 转换Token商品数据字段含义保持原定义
packagesData.value.token = (tokenRes.data || []).map((item: GoodsItem, index: number) => {
let discountAmount = 0;
if (item.discountDescription) {
const match = item.discountDescription.match(/¥([\d.]+)/);
if (match) {
discountAmount = Number.parseFloat(match[1]);
}
}
return {
id: index + 100, // 避免ID冲突
name: item.goodsName,
desc: '',
price: item.goodsPrice, // 用户专属价格(最终支付价格)
originalPrice: item.originalPrice, // 意心平台优惠价(主价格)
perMonth: item.referencePrice, // 模型官方价格
tag: item.remark || '',
discount: item.discountDescription || '',
goodsName: item.goodsName,
goodsType: item.goodsType,
discountAmount,
};
});
// 设置默认选中第一个会员套餐
if (packagesData.value.member.length > 0) {
const defaultPackage = packagesData.value.member[0];
selectedId.value = defaultPackage.id;
selectedPrice.value = defaultPackage.price;
selectPackageObject.value = defaultPackage;
}
}
catch (error) {
console.error('获取商品列表失败:', error);
ElMessage.error('获取商品列表失败,请刷新重试');
}
finally {
isLoadingGoods.value = false;
}
}
onMounted(() => {
checkMobile();
window.addEventListener('resize', checkMobile);
fetchGoodsList();
});
onBeforeUnmount(() => {
window.removeEventListener('resize', checkMobile);
cleanupPayment();
});
// 支付相关逻辑(无修改)
function cleanupPayment() {
if (pollInterval.value) {
clearInterval(pollInterval.value);
pollInterval.value = null;
}
retryCount = 0;
}
const tabs = [
{ key: 'member', label: '会员套餐' },
{ key: 'token', label: '尊享Token包' },
{ key: 'activation', label: '激活码' },
];
const benefitsData = {
member: [
{ name: '站点全模型解锁使用', value: '' },
{ name: '全站所有Ai日常“无限制”使用除尊享外', value: '' },
{ name: 'Ai专线超级加速', value: '' },
{ name: '专属Api接口提供', value: '' },
{ name: '支持文件/图片/知识库功能', value: '' },
{ name: '支持各类第三方工具集成IDE/翻译/Utools等', value: '' },
{ name: '支持Mcp/FunctionCall开发', value: '' },
{ name: '支持安卓/ios/web/客户端使用', value: '' },
{ name: '支持售后群服务一起畅玩前沿Ai', value: '' },
{ name: '如果需大量使用Agent请选择尊享Token包', value: '' },
],
token: [
{ name: '超值优惠', value: '相比官方价格,我们的价格更实惠' },
{ name: '灵活计费', value: '按调用量扣费,用多少付多少' },
{ name: '支持多模型', value: '适配多种主流AI模型' },
{ name: 'Token用途', value: '用于调用API或模型生成内容' },
{ name: '永久有效', value: 'Token永不过期随时使用' },
],
};
const benefitsData2 = {
qy: [
{ name: '需先成为意心会员后方可购买使用', value: '' },
{ name: '意心会员过期后尊享Token包会临时冻结', value: '' },
{ name: '可重复购买将自动累积Token在个人中心查看', value: '' },
{ name: 'Token长期有效无限流限制', value: '' },
{ name: '几乎是全网最低价让人人用的起Agent', value: '' },
{ name: '附带claude code独家教程手把手对接', value: '' },
{ name: '一手直连!非跑路!非套壳!非黑产!(行业普遍现象)', value: '' },
{ name: '橙子老哥担保,拒绝套路、拒绝跑路,可进售后群', value: '' },
],
yt: [
{ name: '可全站解锁claude4.5地表编程最强模型', value: '' },
{ name: '可直接接入claude code地表编程最强模Agent工具', value: '' },
{ name: '可暴力使用claude4.5,无黑名单限流机制', value: '' },
{ name: '可使用claude接口/openai接口格式接入claude4.5', value: '' },
],
};
const fullBenefitsData = {
member: [
{ category: 'YiXinAI AI Pro', free: '1项', vip: '5项', value: '价值68/月' },
{ category: '基础对话', free: '3条/天', vip: '不限条款', value: 'DeepSeek-R1 32b蒸馏版、AI-4o mini' },
{ category: '高级对话', free: '-', vip: '400条/月', value: 'DeepSeek-R1 671b满血版、4o、Cd3.5s、Code、文档对话' },
{ category: 'AI基础绘画', free: '-', vip: '500条/月', value: '' },
{ category: 'AI高级绘画', free: '-', vip: '50条/月', value: '' },
{ category: 'AI-4.0联网搜索', free: '-', vip: '支持', value: '' },
{ category: 'AI PPT', free: '1项', vip: '12项', value: '价值99/月' },
{ category: 'AI 思维导图', free: '1项', vip: '8项', value: '价值99/月' },
{ category: '文档对话', free: '0项', vip: '6项', value: '价值99/月' },
{ category: 'AI 绘图', free: '0项', vip: '5项', value: '价值99/月' },
{ category: 'AI 写作', free: '1项', vip: '6项', value: '价值99/月' },
],
};
const currentPackages = computed(() => packagesData.value[activeTab.value as 'member' | 'token']);
const currentBenefits = computed(() => benefitsData[activeTab.value]);
function selectPackage(pkg: any) {
selectedId.value = pkg.id;
selectedPrice.value = pkg.price;
selectPackageObject.value = pkg;
}
watch(activeTab, () => {
if (activeTab.value === 'activation') {
return;
}
const packages = packagesData.value[activeTab.value as 'member' | 'token'];
if (packages && packages.length > 0) {
const firstPackage = packages[0];
selectedId.value = firstPackage.id;
selectedPrice.value = firstPackage.price;
selectPackageObject.value = firstPackage;
}
});
function handleClickLogin() {
userStore.openLoginDialog();
}
async function pay() {
if (!selectedId.value || !selectPackageObject.value) {
ElMessage.warning('请选择一个套餐');
return;
}
isLoading.value = true;
try {
const returnUrl = `${window.location.origin}/pay-result`;
const params = {
GoodsType: selectPackageObject.value.goodsType,
ReturnUrl: returnUrl,
};
const response = await createOrder(params);
if (response.data.paymentPageHtml) {
handlePaymentPage(response.data.paymentPageHtml, response.data.orderId, response.data.outTradeNo);
}
else {
throw new Error('未获取到支付页面');
}
}
catch (error: any) {
console.error('支付失败:', error);
ElMessage.error(`支付失败: ${error.message || '未知错误'}`);
}
finally {
isLoading.value = false;
}
}
function handlePaymentPage(html: string, orderId: string, outTradeNo: string) {
close();
paymentWindow.value = window.open('', '_blank');
if (!paymentWindow.value) {
ElMessage.error('无法打开支付窗口,请检查浏览器弹窗设置或允许弹窗');
return;
}
paymentWindow.value.document.open();
paymentWindow.value.document.write(html);
setTimeout(() => {
startPolling(outTradeNo);
}, 3000);
}
function startPolling(outTradeNo: string) {
cleanupPayment();
checkPaymentStatus(outTradeNo);
pollInterval.value = setInterval(() => {
checkPaymentStatus(outTradeNo);
}, 3000);
}
let retryCount = 0;
async function checkPaymentStatus(outTradeNo: string) {
try {
const result = await getOrderStatus(outTradeNo);
if (result.data.tradeStatus === 'TRADE_SUCCESS') {
cleanupPayment();
ElMessage.success('支付成功!');
close();
}
else if (result.data.tradeStatus === 'TRADE_CLOSED' || result.data.tradeStatus === 'TRADE_FAILED') {
cleanupPayment();
ElMessage.warning(`支付失败: ${result.data.tradeStatusDesc || '未知原因'}`);
}
}
catch (error) {
console.error('检查订单状态失败:', error);
if (retryCount > 3) {
cleanupPayment();
ElMessage.error('检查支付状态失败,请手动刷新页面确认');
}
retryCount++;
}
}
const router = useRouter();
function toggleDetails() {
showDetails.value = !showDetails.value;
}
function close() {
visible.value = false;
emit('close');
}
function onClose() {
emit('close');
}
function goToActivation() {
close();
userStore.openUserCenter('activationCode');
}
</script>
<template>
<el-dialog
v-model="visible" :width="isMobile ? '90%' : '1000px'" :fullscreen="isMobile && showDetails"
:show-close="false" destroy-on-close class="product-package-dialog" @close="onClose"
>
<!-- 详情页无修改 -->
<div v-if="showDetails" class="details-view">
<div class="flex items-center mb-6 sticky top-0 bg-white z-10 pt-2 pb-4">
<el-button text circle size="small" class="mr-2" @click="toggleDetails">
</el-button>
<div class="text-xl font-bold">
YiXinAI会员详细权益
</div>
</div>
<ProductPage />
<div v-if="false" class="benefits-table">
<div class="table-header">
<div class="table-cell">
服务项
</div>
<div class="table-cell">
免费用户
</div>
<div class="table-cell">
AI大会员
</div>
</div>
<div v-for="(item, index) in fullBenefitsData.member" :key="index" class="table-row">
<div class="table-cell font-medium">
{{ item.category }}
</div>
<div class="table-cell">
{{ item.free }}
</div>
<div class="table-cell">
<div>{{ item.vip }}</div>
<div v-if="item.value" class="text-gray-500 text-xs">
{{ item.value }}
</div>
</div>
</div>
</div>
</div>
<!-- 主页面 -->
<div v-else>
<!-- 顶部标题和关闭按钮无修改 -->
<div class="flex justify-between items-center mb-4">
<div class="text-xl font-bold">
购买套餐
</div>
<el-button circle size="small" @click="close">
</el-button>
</div>
<!-- Tab 切换无修改 -->
<div class="flex border-b mb-6 overflow-x-auto">
<div
v-for="tab in tabs" :key="tab.key"
class="cursor-pointer px-5 py-2 -mb-px border-b-2 transition whitespace-nowrap"
:class="activeTab === tab.key ? 'border-orange-500 text-orange-500 font-semibold' : 'border-transparent text-gray-500 hover:text-orange-500'"
@click="activeTab = tab.key"
>
{{ tab.label }}
</div>
</div>
<!-- 激活码引导页 -->
<div v-if="activeTab === 'activation'" class="activation-guide-container">
<div class="activation-content">
<div class="guide-icon">
🎁
</div>
<h3 class="guide-title">
激活码兑换
</h3>
<p class="guide-desc">
如果您持有意心AI的会员激活码或Token兑换码<br>请点击下方按钮前往控制台进行兑换
</p>
<el-button
type="primary"
size="large"
class="redeem-jump-btn"
round
@click="goToActivation"
>
前往兑换中心
</el-button>
<div class="guide-tips">
<p>💡 兑换成功后权益将立即生效</p>
</div>
</div>
</div>
<!-- 移动端布局 -->
<div v-else-if="isMobile" class="mobile-layout">
<!-- 商品加载状态无修改 -->
<div v-if="isLoadingGoods" class="loading-container">
<el-icon class="is-loading" :size="40">
<Loading />
</el-icon>
<p>加载商品中...</p>
</div>
<!-- 套餐卡片列表核心修改Token套餐价格展示 -->
<div v-else-if="currentPackages.length > 0" class="package-list">
<div
v-for="pkg in currentPackages" :key="pkg.id" class="package-card"
:class="{ selected: pkg.id === selectedId }" @click="selectPackage(pkg)"
>
<!-- 标签无修改 -->
<div v-if="pkg.discount" class="discount-tag">
{{ pkg.discount }}
</div>
<div v-if="pkg.tag" class="tag">
{{ pkg.tag }}
</div>
<!-- 套餐信息无修改 -->
<div class="package-info">
<div class="package-name">
{{ pkg.name }}
</div>
<div class="package-desc">
{{ pkg.desc }}
</div>
</div>
<!-- 价格区域核心调整Token套餐突出平台优惠价 -->
<div class="package-price">
<!-- Token套餐尊享包价格展示优化 -->
<template v-if="activeTab === 'token'">
<!-- 1. 官方参考价弱化展示 -->
<div v-if="pkg.perMonth && pkg.perMonth > (pkg.originalPrice || pkg.price)" class="official-price-section">
<div class="price-label-row">
<span class="label-text"> 官方参考价</span>
</div>
<div class="official-price">
¥{{ pkg.perMonth.toFixed(2) }}
</div>
</div>
<!-- 2. 平台优惠价主价格放大字号+加重颜色 -->
<div v-if="pkg.originalPrice" class="platform-price-section">
<div class="price-label-row">
<span class="label-text main-label"> 意心平台优惠价</span>
</div>
<div class="platform-price main-price">
¥{{ pkg.originalPrice.toFixed(2) }}
</div>
</div>
<!-- 3. 个人优惠券辅助信息 -->
<div v-if="pkg.discountAmount && pkg.discountAmount > 0" class="coupon-card">
<div class="coupon-header">
<span class="coupon-icon">🎁</span>
<span class="coupon-title">您的个人尊享优惠券</span>
</div>
<div class="coupon-amount">
-¥{{ pkg.discountAmount.toFixed(2) }}
</div>
</div>
<!-- 4. 最终专属价格弱化缩小字号+浅色调非核心视觉 -->
<div v-if="false" class="final-price-section">
<div class="price-label-row">
<span class="label-text light-label">👑 您的最终专属价支付价</span>
</div>
<div class="final-price-value light-price">
<span class="price-symbol">¥</span>
<span class="price-number">{{ pkg.price.toFixed(2) }}</span>
</div>
</div>
<!-- 5. 总优惠提示无修改 -->
<div v-if="pkg.perMonth && pkg.perMonth > pkg.price" class="total-discount-bar">
<span class="bar-icon">🎉</span>
<span class="bar-text">相比官方价已为您节省 ¥{{ (pkg.perMonth - pkg.price).toFixed(2) }}</span>
</div>
</template>
<!-- 会员套餐保持原有逻辑无修改 -->
<template v-else>
<div class="current-price-section">
<span class="price-label">会员价</span>
<div class="price-row">
<span class="price">¥{{ pkg.price }}</span>
<span v-if="pkg.perMonth" class="per-month">¥{{ pkg.perMonth }}/</span>
</div>
</div>
<div v-if="pkg.discount" class="discount-info">
<el-icon class="discount-icon">
<CircleCheck />
</el-icon>
<span class="discount-text">{{ pkg.discount }}</span>
</div>
</template>
</div>
</div>
</div>
<!-- 其他辅助信息无修改 -->
<div v-if="activeTab === 'token'" class="recharge-tip-card">
<div class="tip-icon">
💝
</div>
<div class="tip-content">
<div class="tip-title">
累计充值优惠
</div>
<div class="tip-desc">
充值越多优惠越多长期使用更划算
</div>
</div>
</div>
<div style="display: flex;justify-content: space-between;margin-top: 15px;">
<div>
<p style="color: #f97316;font-weight: 800">
全站任意充值每累计充值10元永久优惠尊享包10元最高可优惠50元
</p>
<p style="margin-top: 10px;">
充值后加客服微信回复账号名可专享vip售后服务
</p>
<p style="margin-top: 10px;">
客服微信号chengzilaoge520 或扫描右侧二维码
</p>
</div>
<div><img style="height: 80px;width: 80px;" src="/src/assets/images/wx.png" alt=""></div>
</div>
<!-- 权益预览无修改 -->
<div class="benefits-preview max-h-200px overflow-y-auto">
<div class="section-title">
专属权益
</div>
<ul class="benefits-list">
<li v-for="(b, index) in currentBenefits" :key="index" class="benefit-item">
<span class="dot"><el-icon><CircleCheck /></el-icon></span>
<span>
<span class="benefit-name">{{ b.name }}</span>
<span v-if="b.value">{{ b.value }}</span>
</span>
</li>
</ul>
<SupportModelList />
</div>
<!-- 支付区域无修改 -->
<div class="payment-area">
<div v-if="false" class="agreement-text">
登录和注册都代表同意YiXinAI的会员协议
</div>
<div class="payment-info">
<div class="actual-payment">
<span>实际支付</span>
<span class="price">¥{{ selectedPrice || 0 }}</span>
</div>
<el-button text type="primary" class="view-details-btn" @click="toggleDetails">
了解更多
</el-button>
<el-button
v-if="userStore.userInfo"
type="primary" :disabled="!selectedId || isLoading" :loading="isLoading" class="pay-button"
@click="pay"
>
立即支付
</el-button>
<el-button
v-else
type="primary" class="pay-button"
@click="handleClickLogin"
>
立即登录/注册
</el-button>
</div>
<div class="note-text">
可叠加购买次数过期时间以最后订单为准<br>
最终解释权归YiXinAI所有
</div>
</div>
</div>
<!-- 桌面端布局与移动端逻辑一致仅适配样式 -->
<div v-else class="flex gap-6 desktop-layout">
<!-- 商品加载状态无修改 -->
<div v-if="isLoadingGoods" class="loading-container-desktop">
<el-icon class="is-loading" :size="50">
<Loading />
</el-icon>
<p>加载商品中...</p>
</div>
<!-- 左栏 套餐卡片 + 支付核心修改Token套餐价格展示 -->
<div v-else class="w-[60%] flex flex-col justify-between">
<div class="flex flex-wrap gap-4">
<div
v-for="pkg in currentPackages" :key="pkg.id" class="package-card"
:class="{ selected: pkg.id === selectedId }" @click="selectPackage(pkg)"
>
<!-- 标签无修改 -->
<div v-if="pkg.tag" class="tag">
{{ pkg.tag }}
</div>
<!-- 套餐信息无修改 -->
<div class="package-info">
<div class="package-name">
{{ pkg.name }}
</div>
<div class="package-desc">
{{ pkg.desc }}
</div>
</div>
<!-- 价格区域桌面端同移动端逻辑突出平台优惠价 -->
<div class="package-price">
<template v-if="activeTab === 'token'">
<!-- 1. 官方参考价弱化 -->
<div v-if="pkg.perMonth && pkg.perMonth > (pkg.originalPrice || pkg.price)" class="official-price-section">
<div class="price-label-row">
<span class="label-text"> 官方参考价</span>
<span class="label-text-number">¥{{ pkg.perMonth.toFixed(2) }} </span>
</div>
<!-- <div class="official-price"> -->
<!-- ¥{{ pkg.perMonth.toFixed(2) }} -->
<!-- </div> -->
</div>
<!-- 2. 平台优惠价主价格放大+加重 -->
<div v-if="pkg.originalPrice" class="platform-price-section">
<div class="price-label-row">
<span class="label-text main-label"> 意心平台优惠价</span>
</div>
<div class="platform-price main-price">
¥{{ pkg.originalPrice.toFixed(2) }}
</div>
</div>
<!-- 3. 个人优惠券辅助 -->
<div v-if="pkg.discountAmount && pkg.discountAmount > 0" class="coupon-card">
<div class="coupon-header">
<span class="coupon-icon">🎁</span>
<span class="coupon-title">您的个人尊享优惠券</span>
</div>
<div class="coupon-amount">
-¥{{ pkg.discountAmount.toFixed(2) }}
</div>
</div>
<!-- 4. 最终专属价弱化 -->
<div v-if="false" class="final-price-section">
<div class="price-label-row">
<span class="label-text light-label">👑 您的最终专属价支付价</span>
</div>
<div class="final-price-value light-price">
<span class="price-symbol">¥</span>
<span class="price-number">{{ pkg.price.toFixed(2) }}</span>
</div>
</div>
<!-- 5. 总优惠提示 -->
<!-- <div v-if="pkg.perMonth && pkg.perMonth > pkg.price" class="total-discount-bar"> -->
<!-- <span class="bar-icon">🎉</span> -->
<!-- <span class="bar-text">相比官方价已为您节省 ¥{{ (pkg.perMonth - pkg.price).toFixed(2) }}</span> -->
<!-- </div> -->
</template>
<!-- 会员套餐无修改 -->
<template v-else>
<div class="current-price-section">
<span class="price-label">会员价</span>
<div class="price-row">
<span class="price">¥{{ pkg.price }}</span>
<span v-if="pkg.perMonth" class="per-month">¥{{ pkg.perMonth }}/</span>
</div>
</div>
<div v-if="pkg.discount" class="discount-info">
<el-icon class="discount-icon">
<CircleCheck />
</el-icon>
<span class="discount-text">{{ pkg.discount }}</span>
</div>
</template>
</div>
</div>
</div>
<!-- 其他辅助信息无修改 -->
<div v-if="activeTab === 'token'" class="recharge-tip-card">
<div class="tip-icon">
💝
</div>
<div class="tip-content">
<div class="tip-title">
累计充值优惠
</div>
<div class="tip-desc">
{{ selectPackageObject?.discount }}
</div>
</div>
</div>
<div style="display: flex;justify-content: space-between;margin-top: 15px;">
<div>
<p style="color: #f97316;font-weight: 800">
全站任意充值每累计充值10元永久优惠尊享包10元最高可优惠50元
</p>
<p style="margin-top: 10px;">
充值后加客服微信回复账号名可专享vip售后服务
</p>
<p style="margin-top: 10px;">
客服微信号chengzilaoge520 或扫描右侧二维码
</p>
</div>
<div><img style="height: 80px;width: 80px;" src="/src/assets/images/wx.png" alt=""></div>
</div>
<!-- 支付按钮无修改 -->
<div class="payment-section">
<div v-if="false" class="agreement-text">
登录和注册都代表同意YiXinAI的会员协议
</div>
<div class="payment-action">
<div class="actual-payment">
<span>实际支付</span>
<span class="price">¥{{ selectedPrice || 0 }}</span>
</div>
<div>
<el-button class="pay-button" text type="primary" @click="toggleDetails">
了解更多
</el-button>
<el-button
v-if="userStore.userInfo"
type="primary" size="large" :disabled="!selectedId || isLoading" :loading="isLoading"
class="pay-button" @click="pay"
>
立即支付
</el-button>
<el-button
v-else
type="primary" size="large"
class="pay-button" @click="handleClickLogin"
>
立即登录/注册
</el-button>
</div>
</div>
<div class="note-text">
可叠加购买次数过期时间以最后订单为准<br>
最终解释权归YiXinAI所有
</div>
</div>
</div>
<!-- 右栏 套餐权益无修改 -->
<div class="w-[40%] flex flex-col justify-between right-panel max-h-400px overflow-y-auto">
<div>
<div v-if="activeTab === 'member'">
<div class="section-title">
会员权益
</div>
<ul class="benefits-list ">
<li v-for="(b, index) in currentBenefits" :key="index" class="benefit-item ">
<span class="dot"><el-icon><CircleCheck /></el-icon></span>
<span>
<span class="benefit-name">{{ b.name }}</span>
<span v-if="b.value">{{ b.value }}</span>
</span>
</li>
</ul>
</div>
<div v-if="activeTab === 'token'">
<div class="section-title">
尊享Token包权益
</div>
<ul class="benefits-list ">
<li v-for="(b, index) in benefitsData2.qy" :key="index" class="benefit-item ">
<span class="dot"><el-icon><CircleCheck /></el-icon></span>
<span>
<span class="benefit-name">{{ b.name }}</span>
<span v-if="b.value">{{ b.value }}</span>
</span>
</li>
</ul>
<br>
<div class="section-title">
尊享Token包用途
</div>
<ul class="benefits-list ">
<li v-for="(b, index) in benefitsData2.yt" :key="index" class="benefit-item ">
<span class="dot"><el-icon><CircleCheck /></el-icon></span>
<span>
<span class="benefit-name">{{ b.name }}</span>
<span v-if="b.value">{{ b.value }}</span>
</span>
</li>
</ul>
</div>
<div v-if="activeTab === 'member'" class="extra-description ">
<SupportModelList />
</div>
</div>
<div class="view-details" />
</div>
</div>
</div>
</el-dialog>
</template>
<style scoped lang="scss">
.product-package-dialog {
.el-dialog__header { display: none; }
/* 详情页样式(无修改) */
.details-view {
height: 600px; overflow-y: auto; padding-right: 8px;
.benefits-table {
display: table; width: 100%; border-collapse: collapse;
.table-header, .table-row { display: table-row; }
.table-cell {
display: table-cell; padding: 12px 16px;
border-bottom: 1px solid #eee; vertical-align: middle;
}
.table-header {
font-weight: bold; background-color: #f8f8f8;
.table-cell { border-bottom: 2px solid #ddd; }
}
}
}
/* 激活码引导页样式 */
.activation-guide-container {
padding: 40px 20px;
display: flex;
justify-content: center;
align-items: center;
min-height: 400px;
background: linear-gradient(to bottom, #fff, #fdfdfd);
border-radius: 8px;
.activation-content {
text-align: center;
max-width: 400px;
.guide-icon {
font-size: 64px;
margin-bottom: 24px;
animation: float-icon 3s ease-in-out infinite;
}
.guide-title {
font-size: 24px;
font-weight: 800;
color: #2c3e50;
margin-bottom: 16px;
}
.guide-desc {
color: #606266;
line-height: 1.6;
margin-bottom: 32px;
font-size: 15px;
}
.redeem-jump-btn {
width: 200px;
height: 48px;
font-size: 16px;
font-weight: bold;
letter-spacing: 1px;
background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%);
border: none;
box-shadow: 0 4px 12px rgba(255, 117, 140, 0.3);
transition: all 0.3s;
&:hover {
transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(255, 117, 140, 0.4);
}
}
.guide-tips {
margin-top: 24px;
font-size: 13px;
color: #909399;
display: flex;
justify-content: center;
gap: 8px;
}
}
}
@keyframes float-icon {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-10px); }
}
/* 移动端样式(核心新增:主价格/弱化价格样式) */
.mobile-layout {
display: flex; flex-direction: column; gap: 24px;
.package-list { display: grid; grid-template-columns: 1fr; gap: 12px; }
.package-card {
position: relative; border: 1px solid #e5e7eb; border-radius: 8px;
padding: 16px; transition: all 0.3s; cursor: pointer;
&.selected {
border: 3px solid #fde19d;
background-image: url('@/assets/images/product_background.svg');
background-repeat: no-repeat;
/* 按需设置是否重复 */
background-size: cover;
/* 按需设置背景图尺寸适配方式,比如 cover、contain 等 */
background-position: bottom;
/* 按需设置背景图位置 */
box-shadow: 0 4px 6px -1px #fff4e3;
}
.discount-tag {
position: absolute; top: -6px; left: 8px;
background-color: #ef4444; color: white; font-size: 12px;
padding: 2px 8px; border-radius: 4px;
}
.tag {
position: absolute; top: -6px; right: 8px;
background-color: #f97316; color: white; font-size: 12px;
padding: 2px 8px; border-radius: 4px;
}
.package-info {
margin-bottom: 12px;
.package-name {
font-size: 16px;
font-weight: 600;
}
.package-desc {
font-size: 12px;
color: #6b7280;
}
}
/* Token套餐价格样式优化 */
.package-price {
display: flex;
flex-direction: column;
gap: 8px;
// 官方参考价
.reference-price-section {
padding: 6px 10px;
background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%);
border-radius: 6px;
border: 1px dashed #f87171;
.reference-label {
font-size: 11px;
color: #991b1b;
margin-bottom: 2px;
}
.reference-value {
font-size: 16px;
font-weight: 700;
color: #dc2626;
text-decoration: line-through;
}
}
// 当前价格
.current-price-section {
.price-label {
font-size: 12px;
color: #6b7280;
display: block;
margin-bottom: 4px;
}
.price-row {
display: flex;
align-items: baseline;
gap: 6px;
}
.price {
font-size: 24px;
font-weight: 700;
color: #f97316;
}
.per-month {
font-size: 12px;
color: #6b7280;
}
}
// 优惠说明
.discount-info {
display: flex;
align-items: center;
gap: 6px;
padding: 6px 10px;
background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%);
border-radius: 6px;
font-size: 11px;
color: #1e40af;
line-height: 1.4;
.discount-icon {
color: #3b82f6;
flex-shrink: 0;
font-size: 14px;
}
.discount-text {
flex: 1;
}
}
// 节省金额
.save-amount {
padding: 8px 10px;
background: linear-gradient(135deg, #dcfce7 0%, #bbf7d0 100%);
border-radius: 6px;
font-size: 14px;
font-weight: 700;
color: #15803d;
text-align: center;
box-shadow: 0 2px 4px rgba(34, 197, 94, 0.2);
}
// Token套餐四层价格展示样式 - 移动端
.official-price-section {
padding: 6px 10px;
background: linear-gradient(135deg, #fef1f2 0%, #ffe4e6 100%);
border-radius: 6px;
border: 1px solid #fecdd3;
.price-label-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 3px;
.label-text {
font-size: 11px;
color: #9f1239;
font-weight: 600;
}
}
.official-price {
font-size: 16px;
font-weight: 700;
color: #be123c;
text-decoration: line-through;
text-decoration-thickness: 2px;
}
}
.platform-price-section {
padding: 8px 10px; background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
border-radius: 6px; border: 1px solid #fbbf24;
.price-label-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 3px;
.label-text {
font-size: 11px;
color: #78350f;
font-weight: 600;
}
.save-tag {
background: #dc2626;
color: white;
font-size: 9px;
padding: 2px 6px;
border-radius: 4px;
font-weight: 600;
}
}
.platform-price {
font-size: 18px;
font-weight: 700;
color: #b45309;
}
}
.coupon-card {
padding: 8px 10px; background: linear-gradient(135deg, #fef3c7 0%, #ffedd5 100%);
border-radius: 6px; border: 1px dashed #fb923c; display: flex; align-items: center; justify-content: space-between;
.coupon-header {
display: flex;
align-items: center;
gap: 4px;
.coupon-icon {
font-size: 14px;
}
.coupon-title {
font-size: 10px;
color: #78350f;
font-weight: 600;
}
}
.coupon-amount {
font-size: 16px;
font-weight: 700;
color: #ea580c;
}
}
.our-price-section {
padding: 10px 12px;
background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
border-radius: 8px;
border: 1px solid #fbbf24;
.price-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 6px;
.price-tag-small {
font-size: 12px;
color: #78350f;
font-weight: 600;
}
.save-badge {
background: #dc2626;
color: white;
font-size: 10px;
padding: 2px 6px;
border-radius: 4px;
font-weight: 600;
}
}
.our-price {
font-size: 24px;
font-weight: 700;
color: #b45309;
}
}
.final-price-section {
padding: 10px;
background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%);
border-radius: 8px;
border: 2px solid #60a5fa;
box-shadow: 0 4px 6px rgba(59, 130, 246, 0.2);
.price-label-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 6px;
.label-text.special {
font-size: 12px;
color: #1e40af;
font-weight: 700;
}
}
.final-price-value {
display: flex;
align-items: baseline;
margin-bottom: 4px;
.price-symbol {
font-size: 16px;
font-weight: 700;
color: #1e40af;
margin-right: 2px;
}
.price-number {
font-size: 26px;
font-weight: 700;
color: #1e40af;
}
}
.discount-desc {
font-size: 10px;
color: #1e3a8a;
font-weight: 500;
line-height: 1.3;
}
}
.total-discount-bar {
display: flex; align-items: center; justify-content: center; gap: 6px;
padding: 8px 10px; background: linear-gradient(135deg, #d1fae5 0%, #a7f3d0 100%);
border-radius: 8px; border: 1px solid #34d399; box-shadow: 0 2px 6px rgba(16, 185, 129, 0.25);
.bar-icon {
font-size: 14px;
}
.bar-text {
font-size: 11px;
font-weight: 700;
color: #065f46;
}
}
}
}
// 累计充值优惠提示卡片样式
.recharge-tip-card {
display: flex; align-items: center; gap: 12px; padding: 12px 16px;
background: linear-gradient(135deg, #fef3c7 0%, #ffedd5 100%);
border-radius: 8px; border: 1px solid #fbbf24; margin-top: 16px;
.tip-icon {
font-size: 24px;
}
.tip-content {
flex: 1;
.tip-title {
font-size: 14px;
font-weight: 700;
color: #78350f;
margin-bottom: 4px;
}
.tip-desc {
font-size: 12px;
color: #92400e;
line-height: 1.4;
}
}
}
.benefits-preview {
background-color: #f9fafb; border-radius: 8px; padding: 16px;
.section-title { font-weight: 600; margin-bottom: 12px; }
.benefits-list {
list-style: none;
padding: 0;
margin: 0;
.benefit-item {
display: flex;
align-items: flex-start;
margin-bottom: 8px;
font-size: 14px;
color: #4b5563;
white-space: normal;
.dot {
color: #f97316;
margin-right: 8px;
}
.benefit-name {
font-weight: 500;
}
}
}
.view-details-btn {
width: 100%;
margin-top: 16px;
justify-content: flex-end;
}
}
.payment-area {
border-top: 1px solid #e5e7eb; padding-top: 16px;
.agreement-text { font-size: 12px; color: #6b7280; margin-bottom: 12px; }
.payment-info {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
.actual-payment {
.price {
font-size: 18px;
font-weight: 700;
color: #f97316;
}
}
.pay-button {
width: 120px;
}
}
.note-text {
font-size: 12px;
color: #9ca3af;
}
}
}
/* 桌面端样式 */
.desktop-layout {
.package-card {
cursor: pointer; position: relative; width: calc(50% - 0.5rem);
border: 1px solid #e5e7eb; border-radius: 8px; padding: 16px;
transition: all 0.3s; display: flex; flex-direction: column; justify-content: space-between;
background: linear-gradient(90deg, #f1f2ebb5, white);
&.selected {
border: 3px solid #fde19d;
background-image: url('@/assets/images/product_background.svg');
background-repeat: no-repeat;
/* 按需设置是否重复 */
background-size: cover;
/* 按需设置背景图尺寸适配方式,比如 cover、contain 等 */
background-position: bottom;
/* 按需设置背景图位置 */
box-shadow: 0 4px 6px -1px #fff4e3;
}
.discount-tag {
position: absolute;
top: -6px;
left: 8px;
background-color: #ef4444;
color: white;
font-size: 12px;
padding: 2px 8px;
border-radius: 4px;
}
.tag {
position: absolute; top: -6px; right: 8px;
background-color: #f97316; color: white; font-size: 12px;
padding: 2px 8px; border-radius: 4px;
}
.package-info {
margin-bottom: 12px;
.package-name {
font-size: 16px;
font-weight: 600;
}
.package-desc {
font-size: 12px;
color: #6b7280;
}
}
/* 桌面端Token套餐价格样式优化 */
.package-price {
display: flex;
flex-direction: column;
gap: 10px;
margin-top: 12px;
// 官方参考价
.reference-price-section {
padding: 8px 12px;
background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%);
border-radius: 8px;
border: 1px dashed #f87171;
.reference-label {
font-size: 12px;
color: #991b1b;
margin-bottom: 4px;
font-weight: 600;
}
.reference-value {
font-size: 18px;
font-weight: 700;
color: #dc2626;
text-decoration: line-through;
}
}
// 当前价格
.current-price-section {
.price-label {
font-size: 13px;
color: #6b7280;
display: block;
margin-bottom: 6px;
font-weight: 500;
}
.price-row {
display: flex;
align-items: baseline;
gap: 8px;
}
.price {
font-size: 28px;
font-weight: 700;
color: #f97316;
}
.per-month {
font-size: 13px;
color: #6b7280;
}
}
// 优惠说明
.discount-info {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%);
border-radius: 8px;
font-size: 12px;
color: #1e40af;
line-height: 1.5;
.discount-icon {
color: #3b82f6;
flex-shrink: 0;
font-size: 16px;
}
.discount-text {
flex: 1;
}
}
// 节省金额
.save-amount {
padding: 10px 12px;
background: linear-gradient(135deg, #dcfce7 0%, #bbf7d0 100%);
border-radius: 8px;
font-size: 16px;
font-weight: 700;
color: #15803d;
text-align: center;
box-shadow: 0 2px 6px rgba(34, 197, 94, 0.25);
}
// Token套餐四层价格展示样式 - 桌面端
.official-price-section {
padding: 4px 6px;
background: linear-gradient(15deg, rgb(155, 155, 155) 0%, #999a9d 100%);
border-radius: 8px; border: 1px solid rgba(156, 163, 175, 0.67);
.price-label-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 4px;
.label-text {
font-size: 12px;
color: #ffffff;
font-weight: 700;
}
.label-text-number { font-size: 14px; color: #ffffff; font-weight: 700;text-decoration: line-through; }
}
.official-price {
font-size: 20px;
font-weight: 700;
color: #be123c;
text-decoration: line-through;
text-decoration-thickness: 2px;
}
}
.platform-price-section {
padding: 10px 12px; background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
border-radius: 8px; border: 1px solid #fbbf24;
.price-label-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 4px;
.label-text {
font-size: 12px;
color: #78350f;
font-weight: 700;
}
.save-tag {
background: #dc2626;
color: white;
font-size: 10px;
padding: 2px 8px;
border-radius: 4px;
font-weight: 600;
}
}
.platform-price {
font-size: 22px;
font-weight: 700;
color: #b45309;
}
}
.coupon-card {
padding: 10px 12px; background: linear-gradient(135deg, #fef3c7 0%, #ffedd5 100%);
border-radius: 8px; border: 1px dashed #fb923c; display: flex; align-items: center; justify-content: space-between;
.coupon-header { display: flex; align-items: center; gap: 6px; .coupon-icon { font-size: 16px; } .coupon-title { font-size: 11px; color: #78350f; font-weight: 700; } }
.coupon-amount {
font-size: 20px;
font-weight: 700;
color: #ea580c;
}
}
.final-price-section {
padding: 12px;
background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%);
border-radius: 10px;
border: 2px solid #60a5fa;
box-shadow: 0 4px 8px rgba(59, 130, 246, 0.25);
.price-label-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 8px;
.label-text.special {
font-size: 14px;
color: #1e40af;
font-weight: 700;
}
}
.final-price-value {
display: flex;
align-items: baseline;
margin-bottom: 6px;
.price-symbol {
font-size: 18px;
font-weight: 700;
color: #1e40af;
margin-right: 2px;
}
.price-number {
font-size: 30px;
font-weight: 700;
color: #1e40af;
}
}
.discount-desc {
font-size: 11px;
color: #1e3a8a;
font-weight: 500;
line-height: 1.4;
}
}
.total-discount-bar {
display: flex; align-items: center; justify-content: center; gap: 8px;
padding: 10px 12px; background: linear-gradient(135deg, #d1fae5 0%, #a7f3d0 100%);
border-radius: 10px; border: 1px solid #34d399; box-shadow: 0 2px 8px rgba(16, 185, 129, 0.3);
.bar-icon {
font-size: 16px;
}
.bar-text {
font-size: 13px;
font-weight: 700;
color: #065f46;
}
}
}
}
// 累计充值优惠提示卡片样式 - 桌面端
.recharge-tip-card {
display: flex; align-items: center; gap: 12px; padding: 12px 16px;
background: linear-gradient(135deg, #fef3c7 0%, #ffedd5 100%);
border-radius: 8px; border: 1px solid #fbbf24; margin-top: 16px;
.tip-icon {
font-size: 28px;
}
.tip-content {
flex: 1;
.tip-title {
font-size: 15px;
font-weight: 700;
color: #78350f;
margin-bottom: 4px;
}
.tip-desc {
font-size: 13px;
color: #92400e;
line-height: 1.5;
}
}
}
.payment-section {
border-top: 1px solid #e5e7eb; padding-top: 16px; margin-top: 16px;
.agreement-text { font-size: 12px; color: #6b7280; margin-bottom: 12px; }
.payment-action {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
.actual-payment {
.price {
font-size: 18px;
font-weight: 700;
color: #f97316;
}
}
}
.note-text {
font-size: 12px;
color: #9ca3af;
}
}
.right-panel {
.section-title { font-weight: 600; margin-bottom: 12px; }
.benefits-list {
list-style: none;
padding: 0;
margin: 0;
.benefit-item {
display: flex;
align-items: flex-start;
margin-bottom: 8px;
font-size: 14px;
color: #4b5563;
white-space: normal;
.dot {
color: #f97316;
margin-right: 8px;
}
.benefit-name {
font-weight: 500;
}
}
}
.extra-description {
margin-top: 24px;
.description-card {
background-color: #f9fafb;
border-radius: 8px;
padding: 12px;
margin-bottom: 12px;
.title {
font-weight: 600;
margin-bottom: 4px;
}
.subtext {
font-size: 12px;
color: #6b7280;
line-height: 1.4;
}
}
}
.view-details {
border-top: 1px solid #e5e7eb;
padding-top: 16px;
margin-top: 16px;
}
}
}
/* 响应式调整 */
@media (max-width: 768px) {
.el-dialog { margin-top: 20px !important; margin-bottom: 20px !important; }
.details-view {
height: auto; max-height: 80vh;
.benefits-table {
display: block;
overflow-x: auto;
white-space: nowrap;
.table-header,
.table-row {
display: table;
width: 100%;
table-layout: fixed;
}
}
}
}
::-webkit-scrollbar {
width: 6px;
}
::-webkit-scrollbar-thumb {
background-color: #ccc;
border-radius: 3px;
}
/* 加载状态样式 */
.loading-container {
display: flex; flex-direction: column; align-items: center; justify-content: center;
padding: 60px 20px; color: #909399;
p {
margin-top: 16px;
font-size: 14px;
}
}
.loading-container-desktop {
display: flex; flex-direction: column; align-items: center; justify-content: center;
width: 100%; min-height: 400px; color: #909399;
p { margin-top: 20px; font-size: 16px; }
}
}
</style>