feat: 增加支付宝在线支付、套餐订购弹窗、会员权益、支持模型展示等

This commit is contained in:
Gsh
2025-08-14 00:26:39 +08:00
parent 48d8c528f6
commit ee6b4827fa
11 changed files with 1564 additions and 38 deletions

View File

@@ -0,0 +1,201 @@
<script setup lang="ts">
import { ElButton, ElDivider } from 'element-plus';
import { onMounted, ref } from 'vue';
import { useRouter } from 'vue-router';
import { getUserInfo } from '@/api';
import {
SSO_CLIENT_LOGIN_AGAIN,
SSO_SEVER_URL,
} from '@/config/sso.ts';
import { useUserStore } from '@/stores';
import { useSessionStore } from '@/stores/modules/session.ts';
const userStore = useUserStore();
const router = useRouter();
const sessionStore = useSessionStore();
interface PayResult {
out_trade_no: string;
trade_no: string;
total_amount: string;
[key: string]: string;
}
const payResult = ref<PayResult>({
out_trade_no: '',
trade_no: '',
total_amount: '',
});
function parseUrlParams() {
const params = new URLSearchParams(window.location.search);
const result: PayResult = {
out_trade_no: params.get('out_trade_no') || '',
trade_no: params.get('trade_no') || '',
total_amount: params.get('total_amount') || '',
};
params.forEach((value, key) => {
if (!(key in result))
result[key] = value;
});
payResult.value = result;
}
onMounted(() => {
parseUrlParams();
});
function handleThirdPartyLogin(type: any) {
const redirectUri = encodeURIComponent(`${window.location.origin}/chat`);
console.log('cccc', type);
const popup = window.open(
`${SSO_SEVER_URL}/login?client_id=${type}&redirect_uri=${redirectUri}`,
'SSOLogin',
'width=1000,height=800',
);
// 使用标志位防止重复执行
let isHandled = false;
const messageHandler = async (event: any) => {
if (event.origin === new URL(SSO_SEVER_URL).origin
&& event.data.type === 'SSO_LOGIN_SUCCESS'
&& !isHandled) {
isHandled = true;
try {
// 清理监听
window.removeEventListener('message', messageHandler);
const { token, refreshToken } = event.data;
userStore.setToken(token, refreshToken);
const resUserInfo = await getUserInfo();
userStore.setUserInfo(resUserInfo.data);
// 关闭弹窗
if (popup && !popup.closed) {
popup.close();
}
// 后续逻辑
ElMessage.success('登录成功');
userStore.closeLoginDialog();
await sessionStore.requestSessionList(1, true);
await router.replace('/');
}
catch (error) {
console.error('登录处理失败:', error);
ElMessage.error('登录失败');
}
}
};
// 先移除旧监听,再添加新监听
window.removeEventListener('message', messageHandler);
window.addEventListener('message', messageHandler);
// 超时自动清理
// setTimeout(() => {
// if (!isHandled) {
// window.removeEventListener('message', messageHandler);
// if (popup && !popup.closed)
// popup.close();
// ElMessage.warning('登录超时');
// }
// }, 60 * 1000); // 60分钟超时关闭
}
function toHome() {
router.replace('/');
}
</script>
<template>
<div class="pay-result-container flex flex-col items-center justify-center p-6 min-h-screen bg-gray-50">
<div class="card bg-white rounded-xl shadow-lg p-8 max-w-md w-full text-center">
<!-- 成功提示 -->
<h1 class="text-4xl font-extrabold mb-4 text-orange-500">
🎉 恭喜
</h1>
<p class="text-xl font-semibold mb-6">
您已成为尊贵的 <span class="text-orange-500">YixinAI VIP</span>
</p>
<!-- 订单信息卡片 -->
<div class="order-info bg-gray-100 p-4 rounded-lg mb-4 text-left">
<p class="mb-2">
<strong>商户订单号</strong>{{ payResult.out_trade_no }}
</p>
<p class="mb-2">
<strong>支付交易号</strong>{{ payResult.trade_no }}
</p>
<p class="mb-0">
<strong>支付金额</strong><span class="text-red-500 font-bold">¥{{ payResult.total_amount }}</span>
</p>
</div>
<!-- 更多信息提示 -->
<div class="mb-6 text-gray-600 text-sm">
更多订单信息和会员详情<br>请前往 <strong>用户中心 充值记录</strong> 查看<br>
用户中心在首页右上角个人头像点击下拉菜单
</div>
<!-- 重新登录提示 -->
<div class="mb-4 text-gray-600">
开通 VIP 需要重新登录意社区生效
</div>
<ElDivider content-position="center">
<span class="text-gray-400 text-sm">操作</span>
</ElDivider>
<!-- 按钮区域 -->
<div class="flex flex-col gap-3 mt-4">
<ElButton
class="w-full py-3 text-lg font-medium"
type="primary"
size="large"
@click="handleThirdPartyLogin(SSO_CLIENT_LOGIN_AGAIN)"
>
意社区重新登录
</ElButton>
<ElButton
class="w-full py-3 text-lg font-medium"
type="default"
size="large"
@click="toHome()"
>
返回首页
</ElButton>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.pay-result-container {
.card {
transition: transform 0.2s;
&:hover {
transform: translateY(-5px);
}
}
.order-info p {
font-size: 1rem;
}
.el-button {
border-radius: 8px;
}
@media (max-width: 768px) {
.card {
padding: 6vw;
}
.order-info p {
font-size: 0.95rem;
}
.el-button {
font-size: 1rem;
}
}
}
</style>

View File

@@ -1,5 +1,4 @@
<script lang="ts" setup>
import { CircleCheck } from '@element-plus/icons-vue';
import { ElMessageBox } from 'element-plus';
import SupportModelProducts from '@/components/SupportModelProducts/indexl.vue';
@@ -193,46 +192,124 @@ function openContact() {
</p>
<div class="grid md:grid-cols-3 gap-6 flex justify-center">
<el-card
style="width: 400px;"
v-for="(plan, index) in pricing"
:key="index"
class="rounded-2xl shadow hover:shadow-lg transition-all" :class="[plan.isPopular ? 'border-2 border-blue-500' : '']"
>
<div class="flex flex-col items-center text-center">
<h2 class="text-2xl font-semibold mb-2">
{{ plan.name }}
</h2>
<p class="text-3xl font-bold text-blue-600 mb-2" style="color: #E8CB96">
<span>优惠后</span>{{ plan.newPrice }} <del style="color: #889F9F;font-size: 16px">{{ plan.price }}</del>
</p>
<p class="text-sm text-gray-500 mb-4">
{{ plan.period }}
</p>
<el-divider />
<ul class="text-left space-y-2 w-full min-h-200px">
<li v-for="(feature, i) in plan.features" :key="i" class="flex items-start gap-2">
<el-icon><CircleCheck /></el-icon>
<span>{{ feature }}</span>
</li>
</ul>
<el-button
class="mt-6 w-full"
type="primary"
size="large"
style="background: #D7BD8D;color: white;border: #191919"
@click="openContact"
<div class="text-center relative">
<h3 class="text-lg font-bold mb-3">
请扫码加入微信交流群<br>
获取专属客服支持
</h3>
<div class="mb-4 flex items-center justify-center space-x-2">
<!-- <span class="font-semibold">站长微信账号</span> -->
<!-- <span id="wechat-id" class="text-blue-600 font-mono select-text">chengzilaoge520</span> -->
<span
v-if="false"
class="cursor-pointer" onclick="navigator.clipboard.writeText('chengzilaoge520').then(() => { window.parent.ElMessage({
message: '微信号已复制到剪贴板',
type: 'success',
duration: 2000,
});})"
title="点击复制"
>
立即订阅
</el-button>
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 opacity-70 hover:opacity-100" viewBox="0 0 24 24" fill="currentColor">
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v16h14c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 18H8V7h11v16z" />
</svg>
</span>
</div>
</el-card>
</div>
<el-divider class="my-16">
<div class="flex justify-center mb-4">
<div v-if="false">
<h4>
站长微信
</h4>
<img
:src="wxSrc"
class="w-50 h-70 border border-gray-200 rounded-lg shadow-md cursor-pointer hover:shadow-lg transition-transform hover:scale-105"
onclick="document.getElementById('wechat-qrcode-fullscreen').style.display = 'flex'"
alt="微信二维码"
>
</div><div>
<h4>
微信交流群
</h4>
<img
:src="wxGroupQD"
class="w-50 h-70 border border-gray-200 rounded-lg shadow-md cursor-pointer hover:shadow-lg transition-transform hover:scale-105"
onclick="document.getElementById('wx-group-qrcode-fullscreen').style.display = 'flex'"
alt="微信二维码"
>
</div>
</div>
<div v-if="false" class="text-sm text-gray-600">
<p class="mb-1">
请备注 <span class="inline-block bg-yellow-100 text-yellow-800 px-2 py-0.5 rounded text-xs">ai</span> 快速通过验证
</p>
</div>
<!-- 全屏放大二维码 -->
<div
id="wechat-qrcode-fullscreen"
style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.8); z-index:9999; justify-content:center; align-items:center;"
onclick="this.style.display='none'"
>
<img
:src="wxSrc"
style="max-width:90%; max-height:90%; border:8px solid white; border-radius:16px; box-shadow:0 0 40px rgba(255,255,255,0.2);"
>
</div>
<div
id="wx-group-qrcode-fullscreen"
style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.8); z-index:9999; justify-content:center; align-items:center;"
onclick="this.style.display='none'"
>
<img
:src="wxGroupQD"
style="max-width:90%; max-height:90%; border:8px solid white; border-radius:16px; box-shadow:0 0 40px rgba(255,255,255,0.2);"
>
</div>
</div>
<!-- <el-card -->
<!-- style="width: 400px;" -->
<!-- v-for="(plan, index) in pricing" -->
<!-- :key="index" -->
<!-- class="rounded-2xl shadow hover:shadow-lg transition-all" :class="[plan.isPopular ? 'border-2 border-blue-500' : '']" -->
<!-- > -->
<!-- <div class="flex flex-col items-center text-center"> -->
<!-- <h2 class="text-2xl font-semibold mb-2"> -->
<!-- {{ plan.name }} -->
<!-- </h2> -->
<!-- <p class="text-3xl font-bold text-blue-600 mb-2" style="color: #E8CB96"> -->
<!-- <span>优惠后</span>{{ plan.newPrice }} <del style="color: #889F9F;font-size: 16px">{{ plan.price }}</del> -->
<!-- </p> -->
<!-- <p class="text-sm text-gray-500 mb-4"> -->
<!-- {{ plan.period }} -->
<!-- </p> -->
<!-- <el-divider /> -->
<!-- <ul class="text-left space-y-2 w-full min-h-200px"> -->
<!-- <li v-for="(feature, i) in plan.features" :key="i" class="flex items-start gap-2"> -->
<!-- <el-icon><CircleCheck /></el-icon> -->
<!-- <span>{{ feature }}</span> -->
<!-- </li> -->
<!-- </ul> -->
<!-- <el-button -->
<!-- class="mt-6 w-full" -->
<!-- type="primary" -->
<!-- size="large" -->
<!-- style="background: #D7BD8D;color: white;border: #191919" -->
<!-- @click="openContact" -->
<!-- > -->
<!-- 立即订阅 -->
<!-- </el-button> -->
<!-- </div> -->
<!-- </el-card> -->
</div>
<!-- <SupportModelList /> -->
<el-divider v-if="false" class="my-16">
充值流程说明
</el-divider>
<el-card class="max-w-2xl mx-auto shadow-md rounded-2xl">
<el-card v-if="false" class="max-w-2xl mx-auto shadow-md rounded-2xl">
<h3 class="text-xl font-semibold mb-4">
如何充值 VIP
</h3>
@@ -270,7 +347,7 @@ function openContact() {
<el-divider class="my-16">
加入群聊
</el-divider>
<el-collapse class="max-w-3xl mx-auto flex justify-center" accordion >
<el-collapse class="max-w-3xl mx-auto flex justify-center" accordion>
<el-image
style="width: 500px; height: auto;"
:src="wxGroupQD"