feat: 增加尊享产品

This commit is contained in:
Gsh
2025-10-12 22:59:14 +08:00
parent 3ace29e692
commit 49e6cb26fc
7 changed files with 561 additions and 92 deletions

View File

@@ -1,40 +1,49 @@
<script setup lang="ts">
import { CircleCheck } from '@element-plus/icons-vue';
import { CircleCheck, Loading } 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 { GoodsCategoryType, getGoodsList, type GoodsItem } 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']);
const packagesData = {
member: [
{ id: 1, name: '8个月推荐', desc: '', price: 183.2, perMonth: 22.9, tag: '超高性价比', discount: '限时活动', key: 8 },
{ id: 2, name: '6个月', desc: '', price: 155.4, perMonth: 25.9, tag: '年度热销', key: 6 },
{ id: 3, name: '3个月', desc: '', price: 83.7, perMonth: 27.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: '' },
],
};
// 商品数据类型定义
interface PackageItem {
id: number;
name: string;
desc: string;
price: number;
originalPrice?: number;
perMonth?: number;
tag: string;
discount: string;
goodsName: string; // 用于创建订单
}
// 商品数据(从接口获取)
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>(packagesData.member[3].id);
const selectedPrice = ref(packagesData.member[3].price);
const selectPackageObject = ref<any>(packagesData.member[3]);
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);
@@ -42,9 +51,63 @@ function checkMobile() {
isMobile.value = window.innerWidth < 768;
}
// 获取商品列表
async function fetchGoodsList() {
isLoadingGoods.value = true;
try {
// 并行获取会员和Token商品列表
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, // 保存原始商品名称用于创建订单
}));
// 转换Token商品数据
packagesData.value.token = (tokenRes.data || []).map((item: GoodsItem, index: number) => ({
id: index + 100, // 避免ID冲突
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,
}));
// 设置默认选中第一个会员套餐
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(() => {
@@ -116,7 +179,7 @@ const fullBenefitsData = {
],
};
const currentPackages = computed(() => packagesData[activeTab.value]);
const currentPackages = computed(() => packagesData.value[activeTab.value as 'member' | 'token']);
const currentBenefits = computed(() => benefitsData[activeTab.value]);
function selectPackage(pkg: any) {
@@ -130,18 +193,17 @@ function handleClickLogin() {
}
async function pay() {
if (!selectedId.value) {
if (!selectedId.value || !selectPackageObject.value) {
ElMessage.warning('请选择一个套餐');
return;
}
isLoading.value = true;
try {
// const returnUrl = `https://ai.ccnetcore.com/pay-result`;
const returnUrl = `${window.location.origin}/pay-result`;
const params = {
goodsType: selectPackageObject.value?.key,
goodsName: selectPackageObject.value.goodsName, // 使用商品名称
ReturnUrl: returnUrl,
};
@@ -322,8 +384,16 @@ function onClose() {
<!-- 移动端布局 -->
<div v-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>
<!-- 套餐卡片列表 -->
<div class="package-list">
<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)"
@@ -348,12 +418,32 @@ function onClose() {
<!-- 价格 -->
<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 }}
<!-- 官方参考价仅Token套餐显示 -->
<div v-if="activeTab === 'token' && pkg.perMonth" class="reference-price-section">
<div class="reference-label">官方参考价</div>
<div class="reference-value">¥{{ pkg.perMonth }}</div>
</div>
<!-- 当前价格 -->
<div class="current-price-section">
<span class="price-label">{{ activeTab === 'member' ? '会员价' : '我们的价格' }}</span>
<div class="price-row">
<span class="price">¥{{ pkg.price }}</span>
<span v-if="activeTab === 'member' && 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>
<!-- 节省金额如果有官方参考价 -->
<div v-if="activeTab === 'token' && pkg.perMonth && pkg.perMonth > pkg.price" class="save-amount">
立省 ¥{{ (pkg.perMonth - pkg.price).toFixed(2) }}
</div>
</div>
</div>
@@ -429,8 +519,16 @@ function onClose() {
<!-- 桌面端布局 -->
<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>
<!-- 左栏 套餐卡片 + 支付 -->
<div class="w-[60%] flex flex-col justify-between">
<div v-else class="w-[60%] flex flex-col justify-between">
<!-- 套餐卡片列表 -->
<div class="flex flex-wrap gap-4">
<div
@@ -457,12 +555,32 @@ function onClose() {
<!-- 价格 -->
<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 }}
<!-- 官方参考价仅Token套餐显示 -->
<div v-if="activeTab === 'token' && pkg.perMonth" class="reference-price-section">
<div class="reference-label">官方参考价</div>
<div class="reference-value">¥{{ pkg.perMonth }}</div>
</div>
<!-- 当前价格 -->
<div class="current-price-section">
<span class="price-label">{{ activeTab === 'member' ? '会员价' : '我们的价格' }}</span>
<div class="price-row">
<span class="price">¥{{ pkg.price }}</span>
<span v-if="activeTab === 'member' && 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>
<!-- 节省金额如果有官方参考价 -->
<div v-if="activeTab === 'token' && pkg.perMonth && pkg.perMonth > pkg.price" class="save-amount">
立省 ¥{{ (pkg.perMonth - pkg.price).toFixed(2) }}
</div>
</div>
</div>
@@ -686,22 +804,91 @@ function onClose() {
}
.package-price {
.price {
font-size: 20px;
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: #f97316;
}
.per-month {
font-size: 12px;
color: #6b7280;
margin-left: 4px;
}
.original-price {
font-size: 12px;
color: #9ca3af;
text-decoration: line-through;
color: #15803d;
text-align: center;
box-shadow: 0 2px 4px rgba(34, 197, 94, 0.2);
}
}
}
@@ -848,22 +1035,94 @@ function onClose() {
}
.package-price {
.price {
font-size: 20px;
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: #f97316;
}
.per-month {
font-size: 12px;
color: #6b7280;
margin-left: 4px;
}
.original-price {
font-size: 12px;
color: #9ca3af;
text-decoration: line-through;
color: #15803d;
text-align: center;
box-shadow: 0 2px 6px rgba(34, 197, 94, 0.25);
}
}
}
@@ -993,5 +1252,35 @@ function onClose() {
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>