971 lines
27 KiB
Vue
971 lines
27 KiB
Vue
<script setup lang="ts">
|
||
import { CircleCheck } from '@element-plus/icons-vue';
|
||
import { ElMessage } from 'element-plus';
|
||
import { computed, onBeforeUnmount, onMounted, ref } from 'vue';
|
||
import { useRouter } from 'vue-router';
|
||
import { createOrder, getOrderStatus } from '@/api';
|
||
import SupportModelList from '@/components/userPersonalCenter/components/SupportModelList.vue';
|
||
import ProductPage from '@/pages/products/index.vue';
|
||
|
||
const emit = defineEmits(['close']);
|
||
|
||
const packagesData = {
|
||
member: [
|
||
{ id: 1, name: '10个月', desc: '', price: 199.9, perMonth: 19.9, tag: '超高性价比', discount: '长期省心', key: 10 },
|
||
{ id: 2, name: '6个月', desc: '', price: 143.9, perMonth: 23.9, tag: '年度热销', key: 6 },
|
||
{ id: 3, name: '3个月', desc: '', price: 80.7, perMonth: 26.9, tag: '短期体验', discount: '', key: 3 },
|
||
{ id: 4, name: '1个月', desc: '', price: 29.9, originalPrice: 49.9, tag: '灵活选择', discount: '', key: 1 },
|
||
{ id: 5, name: '测试', desc: '', price: 0.01, originalPrice: 9.9, tag: '测试使用', discount: '', key: 0 },
|
||
],
|
||
token: [
|
||
{ id: 6, name: '10M 输入Token', desc: '', price: 49.9, tag: '轻量用户', discount: '' },
|
||
{ id: 7, name: '20M 输入Token', desc: '', price: 79.9, tag: '中等使用', discount: '' },
|
||
{ id: 8, name: '30M 输入Token', desc: '', price: 99.9, tag: '量大管饱', discount: '' },
|
||
{ id: 9, name: '联系站长', desc: '', price: 0, tag: '企业级需求', discount: '' },
|
||
],
|
||
};
|
||
|
||
const visible = ref(true);
|
||
const activeTab = ref('member');
|
||
const selectedId = ref<number | null>(packagesData.member[3].id);
|
||
const selectedPrice = ref(packagesData.member[3].price);
|
||
const selectPackageObject = ref<any>(packagesData.member[3]);
|
||
const showDetails = ref(false);
|
||
const isMobile = ref(false);
|
||
const isLoading = ref(false);
|
||
const paymentWindow = ref<Window | null>(null);
|
||
const pollInterval = ref<NodeJS.Timeout | null>(null);
|
||
|
||
function checkMobile() {
|
||
isMobile.value = window.innerWidth < 768;
|
||
}
|
||
|
||
onMounted(() => {
|
||
checkMobile();
|
||
window.addEventListener('resize', checkMobile);
|
||
});
|
||
|
||
onBeforeUnmount(() => {
|
||
window.removeEventListener('resize', checkMobile);
|
||
cleanupPayment();
|
||
});
|
||
|
||
function cleanupPayment() {
|
||
if (pollInterval.value) {
|
||
clearInterval(pollInterval.value);
|
||
pollInterval.value = null;
|
||
}
|
||
// if (paymentWindow.value && !paymentWindow.value.closed) {
|
||
// paymentWindow.value.close();
|
||
// }
|
||
// 清除轮询定时器
|
||
if (pollInterval.value) {
|
||
clearInterval(pollInterval.value);
|
||
pollInterval.value = null;
|
||
}
|
||
|
||
// 关闭支付窗口(如果还在)
|
||
// if (paymentWindow.value && !paymentWindow.value.closed) {
|
||
// paymentWindow.value.close();
|
||
// paymentWindow.value = null;
|
||
// }
|
||
|
||
retryCount = 0; // 重置重试计数器
|
||
}
|
||
|
||
const tabs = [
|
||
{ key: 'member', label: '会员套餐' },
|
||
// { key: 'token', label: 'Token 套餐' },
|
||
];
|
||
|
||
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: '' },
|
||
],
|
||
|
||
token: [
|
||
{ name: 'Token 用途', value: '用于调用 API 或模型生成内容' },
|
||
{ name: '灵活计费', value: '按调用量扣费,更加自由' },
|
||
{ name: '支持多模型', 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[activeTab.value]);
|
||
const currentBenefits = computed(() => benefitsData[activeTab.value]);
|
||
|
||
function selectPackage(pkg: any) {
|
||
selectedId.value = pkg.id;
|
||
selectedPrice.value = pkg.price;
|
||
selectPackageObject.value = pkg;
|
||
}
|
||
|
||
async function pay() {
|
||
if (!selectedId.value) {
|
||
ElMessage.warning('请选择一个套餐');
|
||
return;
|
||
}
|
||
|
||
isLoading.value = true;
|
||
try {
|
||
const params = {
|
||
goodsType: selectPackageObject.value?.key,
|
||
};
|
||
|
||
const response = await createOrder(params);
|
||
console.log('订单创建成功:', response);
|
||
|
||
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;
|
||
}
|
||
|
||
// 写入支付页面HTML并自动提交
|
||
paymentWindow.value.document.open();
|
||
paymentWindow.value.document.write(html);
|
||
// paymentWindow.value.document.close();
|
||
|
||
// 3秒后开始轮询支付状态(给支付页面加载时间)
|
||
setTimeout(() => {
|
||
startPolling(outTradeNo);
|
||
}, 3000);
|
||
}
|
||
|
||
function startPolling(outTradeNo: string) {
|
||
// 先清理之前的轮询任务
|
||
cleanupPayment();
|
||
|
||
// 立即检查一次状态(避免等待第一个间隔)
|
||
checkPaymentStatus(outTradeNo);
|
||
|
||
// 设置轮询任务(每3秒检查一次)
|
||
pollInterval.value = setInterval(() => {
|
||
checkPaymentStatus(outTradeNo);
|
||
}, 3000);
|
||
}
|
||
|
||
let retryCount = 0; // 错误重试计数器
|
||
async function checkPaymentStatus(outTradeNo: string) {
|
||
try {
|
||
const result = await getOrderStatus(outTradeNo);
|
||
console.log('订单状态检查结果:', result);
|
||
|
||
if (result.data.tradeStatus === 'TRADE_SUCCESS') {
|
||
// 支付成功处理
|
||
cleanupPayment();
|
||
ElMessage.success('支付成功!');
|
||
close(); // 关闭弹窗
|
||
|
||
// 可以在这里添加跳转到成功页面的逻辑
|
||
// window.location.href = '/pay/success?order=' + outTradeNo;
|
||
}
|
||
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');
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<el-dialog
|
||
v-model="visible"
|
||
:width="isMobile ? '90%' : '980px'"
|
||
: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="isMobile" class="mobile-layout">
|
||
<!-- 套餐卡片列表 -->
|
||
<div 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>
|
||
|
||
<!-- 价格 -->
|
||
<div class="package-price">
|
||
<span class="price">¥{{ pkg.price }}</span>
|
||
<span v-if="pkg.perMonth" class="per-month">
|
||
仅¥{{ pkg.perMonth }}/月
|
||
</span>
|
||
<div v-if="pkg.originalPrice" class="original-price">
|
||
原价¥{{ pkg.originalPrice }}
|
||
</div>
|
||
</div>
|
||
</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
|
||
type="primary"
|
||
:disabled="!selectedId || isLoading"
|
||
:loading="isLoading"
|
||
class="pay-button"
|
||
@click="pay"
|
||
>
|
||
立即支付
|
||
</el-button>
|
||
</div>
|
||
<div class="note-text">
|
||
可叠加购买次数,过期时间以最后订单为准。<br>
|
||
最终解释权归YiXinAI所有。
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 桌面端布局 -->
|
||
<div v-else class="flex gap-6 desktop-layout">
|
||
<!-- 左栏 套餐卡片 + 支付 -->
|
||
<div 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.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>
|
||
|
||
<!-- 价格 -->
|
||
<div class="package-price">
|
||
<span class="price">¥{{ pkg.price }}</span>
|
||
<span v-if="pkg.perMonth" class="per-month">
|
||
仅¥{{ pkg.perMonth }}/月
|
||
</span>
|
||
<div v-if="pkg.originalPrice" class="original-price">
|
||
原价¥{{ pkg.originalPrice }}
|
||
</div>
|
||
</div>
|
||
</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
|
||
type="primary"
|
||
size="large"
|
||
:disabled="!selectedId || isLoading"
|
||
:loading="isLoading"
|
||
class="pay-button"
|
||
@click="pay"
|
||
>
|
||
立即支付
|
||
</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 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 v-if="activeTab === 'member'" class="extra-description ">
|
||
<SupportModelList />
|
||
|
||
<!-- <div class="description-card"> -->
|
||
<!-- <div class="title"> -->
|
||
<!-- 前沿模型AI对话 -->
|
||
<!-- </div> -->
|
||
<!-- <div class="subtext"> -->
|
||
<!-- DP-RI深度思考、精准解答 -->
|
||
<!-- </div> -->
|
||
<!-- <div class="subtext"> -->
|
||
<!-- AI写作、文档对话、AI思维导图等赋能职场 -->
|
||
<!-- </div> -->
|
||
<!-- </div> -->
|
||
|
||
<!-- <div class="description-card"> -->
|
||
<!-- <div class="title"> -->
|
||
<!-- AI绘图与设计能力 -->
|
||
<!-- </div> -->
|
||
<!-- <div class="subtext"> -->
|
||
<!-- 视觉吸睛赋能 -->
|
||
<!-- </div> -->
|
||
<!-- <div class="subtext"> -->
|
||
<!-- "AI+办公!"解锁300+工具箱会员权益 -->
|
||
<!-- </div> -->
|
||
<!-- </div> -->
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 查看详情 -->
|
||
<div class="view-details">
|
||
<!-- <el-button text type="primary" @click="toggleDetails"> -->
|
||
<!-- 查看详情 -->
|
||
<!-- </el-button> -->
|
||
</div>
|
||
</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;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 移动端样式 */
|
||
.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;
|
||
|
||
&.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;
|
||
}
|
||
}
|
||
|
||
.package-price {
|
||
.price {
|
||
font-size: 20px;
|
||
font-weight: 700;
|
||
color: #f97316;
|
||
}
|
||
|
||
.per-month {
|
||
font-size: 12px;
|
||
color: #6b7280;
|
||
margin-left: 4px;
|
||
}
|
||
|
||
.original-price {
|
||
font-size: 12px;
|
||
color: #9ca3af;
|
||
text-decoration: line-through;
|
||
}
|
||
}
|
||
}
|
||
|
||
.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;
|
||
|
||
.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 {
|
||
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-color: rgba(255, 245, 238, 0.38);
|
||
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;
|
||
}
|
||
}
|
||
|
||
.package-price {
|
||
.price {
|
||
font-size: 20px;
|
||
font-weight: 700;
|
||
color: #f97316;
|
||
}
|
||
|
||
.per-month {
|
||
font-size: 12px;
|
||
color: #6b7280;
|
||
margin-left: 4px;
|
||
}
|
||
|
||
.original-price {
|
||
font-size: 12px;
|
||
color: #9ca3af;
|
||
text-decoration: line-through;
|
||
}
|
||
}
|
||
}
|
||
|
||
.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;
|
||
|
||
.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;
|
||
}
|
||
}
|
||
</style>
|