Files
Yi.Admin/Yi.Ai.Vue3/src/components/ProductPackage/index.vue
2026-02-01 00:52:10 +08:00

1823 lines
47 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 { 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 ProductPage from '@/pages/products/index.vue';
import { useUserStore } from '@/stores';
import ActivationGuide from './ActivationGuide.vue';
import NewbieGuide from './NewbieGuide.vue';
import PackageTab from './PackageTab.vue';
const emit = defineEmits(['close']);
const router = useRouter();
// 商品数据类型定义
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: 'newbie', label: '新人特惠' },
{ 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 = 实际消耗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++;
}
}
function toggleDetails() {
showDetails.value = !showDetails.value;
}
function close() {
visible.value = false;
emit('close');
}
function onClose() {
emit('close');
}
function goToActivation() {
close();
// 使用 router 进行跳转,避免完整页面刷新
setTimeout(() => {
router.push('/console/activation');
}, 300); // 等待对话框关闭动画完成
}
</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="tabs-container">
<div
v-for="tab in tabs" :key="tab.key"
class="tab-item"
:class="{ 'tab-active': activeTab === tab.key }"
@click="activeTab = tab.key"
>
{{ tab.label }}
</div>
</div>
<!-- 新人特惠页面 -->
<NewbieGuide v-if="activeTab === 'newbie'" />
<!-- 激活码引导页 -->
<ActivationGuide v-else-if="activeTab === 'activation'" @close="close" />
<!-- 会员套餐和Token包 -->
<PackageTab
v-else
:package-type="activeTab as 'member' | 'token'"
:packages="currentPackages"
:selected-id="selectedId"
:selected-price="selectedPrice"
:is-loading="isLoading"
:is-loading-goods="isLoadingGoods"
:benefits="activeTab === 'token' ? benefitsData2.qy : currentBenefits"
:benefits-extra="activeTab === 'token' ? benefitsData2.yt : undefined"
:is-mobile="isMobile"
@select-package="selectPackage"
@pay="pay"
@view-details="toggleDetails"
@login="handleClickLogin"
/>
</div>
</el-dialog>
</template>
<style scoped lang="scss">
.product-package-dialog {
.el-dialog__header { display: none; }
/* Tab 切换样式 */
.tabs-container {
display: flex;
border-bottom: 2px solid #e5e7eb;
margin-bottom: 24px;
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
scrollbar-width: none; /* Firefox */
&::-webkit-scrollbar {
display: none; /* Chrome, Safari */
}
.tab-item {
flex-shrink: 0;
padding: 12px 20px;
cursor: pointer;
font-size: 15px;
font-weight: 500;
color: #6b7280;
border-bottom: 3px solid transparent;
margin-bottom: -2px;
transition: all 0.3s;
white-space: nowrap;
user-select: none;
&:hover {
color: #f97316;
}
&.tab-active {
color: #f97316;
font-weight: 600;
border-bottom-color: #f97316;
}
}
}
/* 详情页样式(无修改) */
.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; }
}
}
}
/* 新人特惠页面样式 - 紧凑版(匹配激活码页面风格) */
.newbie-guide-container {
padding: 20px 16px;
display: flex;
justify-content: center;
align-items: center;
min-height: 300px;
background: linear-gradient(to bottom, #fff, #fdfdfd);
border-radius: 8px;
.newbie-content {
text-align: center;
max-width: 450px;
width: 100%;
.newbie-header {
margin-bottom: 20px;
padding: 16px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 10px;
color: white;
.header-icon {
font-size: 32px;
margin-bottom: 6px;
}
.header-title {
font-size: 20px;
font-weight: 700;
margin: 0 0 6px 0;
}
.header-subtitle {
font-size: 13px;
margin: 0;
opacity: 0.95;
}
}
.newbie-body {
display: flex;
flex-direction: column;
gap: 14px;
// 购买方式卡片
.purchase-card {
background: #f7f8fa;
border-radius: 10px;
padding: 16px;
border: 2px solid #e8ecf0;
.card-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
.card-col {
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
.method-label {
font-size: 13px;
font-weight: 600;
color: #606266;
}
.el-button {
width: 100%;
}
}
}
}
// 淘口令展示
.taobao-code-box {
background: linear-gradient(135deg, #f0f4ff 0%, #e8f0fe 100%);
border-radius: 8px;
padding: 14px;
border: 2px dashed #bae6fd;
.code-label {
font-size: 12px;
color: #0369a1;
font-weight: 600;
margin-bottom: 8px;
}
.code-text {
font-size: 11px;
color: #667eea;
font-family: 'Courier New', monospace;
line-height: 1.5;
word-break: break-all;
background: white;
padding: 8px;
border-radius: 6px;
text-align: left;
}
}
// 温馨提示
.tips-box {
background: #f0f9ff;
border: 1px solid #bae6fd;
border-radius: 8px;
padding: 14px;
text-align: left;
.tips-title {
margin: 0 0 10px 0;
font-size: 13px;
font-weight: 600;
color: #0369a1;
display: flex;
align-items: center;
gap: 6px;
.el-icon {
font-size: 16px;
}
}
.tips-text {
margin: 4px 0;
font-size: 12px;
color: #0c4a6e;
line-height: 1.5;
}
}
}
}
}
/* 响应式:移动端优化 */
@media (max-width: 768px) {
/* Tab 移动端优化 */
.tabs-container {
margin-bottom: 16px;
padding-bottom: 2px;
gap: 4px;
justify-content: flex-start;
.tab-item {
padding: 10px 12px;
font-size: 13px;
min-width: fit-content;
}
}
/* 新人特惠移动端优化 */
.newbie-guide-container {
padding: 16px 12px;
min-height: auto;
.newbie-content {
max-width: 100%;
.newbie-header {
padding: 16px;
margin-bottom: 16px;
border-radius: 8px;
.header-icon {
font-size: 28px;
margin-bottom: 6px;
}
.header-title {
font-size: 18px;
margin-bottom: 6px;
}
.header-subtitle {
font-size: 13px;
}
}
.newbie-body {
gap: 12px;
.purchase-card {
padding: 14px;
border-radius: 8px;
.card-row {
grid-template-columns: 1fr;
gap: 10px;
.card-col {
.method-label {
font-size: 12px;
}
.el-button {
font-size: 13px;
}
}
}
}
.taobao-code-box {
padding: 12px;
.code-label {
font-size: 11px;
}
.code-text {
font-size: 10px;
padding: 6px;
line-height: 1.4;
}
}
.tips-box {
padding: 12px;
.tips-title {
font-size: 12px;
margin-bottom: 8px;
.el-icon {
font-size: 14px;
}
}
.tips-text {
font-size: 11px;
}
}
}
}
}
}
/* 小屏手机进一步优化 */
@media (max-width: 480px) {
.tabs-container {
gap: 2px;
.tab-item {
padding: 8px 10px;
font-size: 12px;
min-width: fit-content;
}
}
.newbie-guide-container {
padding: 12px 8px;
.newbie-content {
.newbie-header {
padding: 12px;
.header-icon {
font-size: 24px;
}
.header-title {
font-size: 16px;
}
.header-subtitle {
font-size: 12px;
}
}
.newbie-body {
.purchase-card {
padding: 12px;
}
.taobao-code-box {
padding: 10px;
.code-text {
font-size: 9px;
}
}
.tips-box {
padding: 10px;
}
}
}
}
}
/* 激活码引导页样式 */
.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;
}
}
}
/* 模型库卡片样式 - 桌面端 */
.model-library-section {
margin-top: 16px;
.model-library-card {
display: flex;
align-items: center;
gap: 16px;
padding: 16px;
background: linear-gradient(135deg, #f0f4ff 0%, #e8f0fe 100%);
border-radius: 12px;
border: 2px solid #bae6fd;
transition: all 0.3s;
&:hover {
border-color: #667eea;
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.15);
transform: translateY(-2px);
}
.card-icon {
display: flex;
align-items: center;
justify-content: center;
width: 56px;
height: 56px;
background: white;
border-radius: 12px;
color: #667eea;
flex-shrink: 0;
}
.card-content {
flex: 1;
.card-title {
margin: 0 0 4px 0;
font-size: 16px;
font-weight: 700;
color: #1a1a1a;
}
.card-desc {
margin: 0;
font-size: 13px;
color: #606266;
line-height: 1.5;
}
}
.goto-btn {
flex-shrink: 0;
font-weight: 600;
.ml-1 {
margin-left: 4px;
}
}
}
}
.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-cards-container {
max-height: 500px;
overflow-y: auto;
overflow-x: hidden;
padding-right: 8px;
/* 滚动条样式 */
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-track {
background: #f5f5f5;
border-radius: 3px;
}
&::-webkit-scrollbar-thumb {
background: #d0d7de;
border-radius: 3px;
&:hover {
background: #a8b3c1;
}
}
}
.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;
}
}
}
}
/* 模型库卡片样式 - 移动端 */
.model-library-section-mobile {
margin-top: 16px;
.model-library-card-mobile {
padding: 16px;
background: linear-gradient(135deg, #f0f4ff 0%, #e8f0fe 100%);
border-radius: 12px;
border: 2px solid #bae6fd;
transition: all 0.3s;
.card-header-mobile {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 12px;
.el-icon {
color: #667eea;
background: white;
padding: 8px;
border-radius: 8px;
}
.card-title-mobile {
margin: 0;
font-size: 16px;
font-weight: 700;
color: #1a1a1a;
}
}
.card-desc-mobile {
margin: 0 0 12px 0;
font-size: 13px;
color: #606266;
line-height: 1.5;
}
.goto-btn-mobile {
font-weight: 600;
.ml-1 {
margin-left: 4px;
}
}
}
}
// 累计充值优惠提示卡片样式 - 桌面端
.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>