|
|
@@ -1,20 +1,28 @@
|
|
|
<script setup lang="ts">
|
|
|
import { useUserStore } from "@/store/user";
|
|
|
-import { computed, ref } from "vue";
|
|
|
-import { upgradeGuest, purchaseMember } from "@/services/api";
|
|
|
+import { computed, ref, onMounted } from "vue";
|
|
|
+import { upgradeGuest, purchaseMember, userQueryOrder } from "@/services/api";
|
|
|
+import { vipLevelToText, VipLevel } from "@/types/vip";
|
|
|
|
|
|
const userStore = useUserStore();
|
|
|
const isLoggedIn = computed(() => !!userStore.token);
|
|
|
const isGuest = computed(() => {
|
|
|
return userStore.userInfo?.vipLevel === "guest";
|
|
|
});
|
|
|
+const isVip = computed(() => {
|
|
|
+ const level = userStore.userInfo?.vipLevel;
|
|
|
+ return level && level !== VipLevel.GUEST && level !== VipLevel.FREE;
|
|
|
+});
|
|
|
const emit = defineEmits(["show-login"]);
|
|
|
|
|
|
const showUpgradeDialog = ref(false);
|
|
|
const showMembershipDialog = ref(false);
|
|
|
const showPaymentWaitingDialog = ref(false);
|
|
|
const showErrorDialog = ref(false);
|
|
|
+const showSuccessDialog = ref(false);
|
|
|
const errorMessage = ref("");
|
|
|
+const successMessage = ref("");
|
|
|
+const currentOrderNo = ref("");
|
|
|
const upgradeForm = ref({
|
|
|
name: null,
|
|
|
password: null,
|
|
|
@@ -51,6 +59,11 @@ const showError = (message: string) => {
|
|
|
showErrorDialog.value = true;
|
|
|
};
|
|
|
|
|
|
+const showSuccess = (message: string) => {
|
|
|
+ successMessage.value = message;
|
|
|
+ showSuccessDialog.value = true;
|
|
|
+};
|
|
|
+
|
|
|
const handleMembershipPurchase = async () => {
|
|
|
if (!selectedPlan.value) {
|
|
|
alert("请选择会员套餐");
|
|
|
@@ -65,6 +78,9 @@ const handleMembershipPurchase = async () => {
|
|
|
);
|
|
|
|
|
|
if (response.code === 1) {
|
|
|
+ // 保存订单号
|
|
|
+ currentOrderNo.value = response.out_trade_no;
|
|
|
+
|
|
|
// 关闭购买弹窗
|
|
|
showMembershipDialog.value = false;
|
|
|
|
|
|
@@ -123,6 +139,65 @@ const handleUpgrade = async () => {
|
|
|
isLoading.value = false;
|
|
|
}
|
|
|
};
|
|
|
+
|
|
|
+// 检查支付成功后的用户信息同步
|
|
|
+const checkPaymentSuccess = async () => {
|
|
|
+ const urlParams = new URLSearchParams(window.location.search);
|
|
|
+ const paymentSuccess = urlParams.get("pay");
|
|
|
+ console.log("paymentSuccess", paymentSuccess);
|
|
|
+
|
|
|
+ if (paymentSuccess === "true") {
|
|
|
+ try {
|
|
|
+ const response = await userQueryOrder();
|
|
|
+ if (response.status === 1) {
|
|
|
+ // 订单状态确认正确,同步用户信息
|
|
|
+ await userStore.sync();
|
|
|
+ showSuccess(`会员购买成功`);
|
|
|
+ currentOrderNo.value = "";
|
|
|
+ } else {
|
|
|
+ // 订单状态异常,仍同步用户信息
|
|
|
+ await userStore.sync();
|
|
|
+ showError(`${response.msg}`);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 清除URL参数
|
|
|
+ const newUrl = window.location.pathname;
|
|
|
+ window.history.replaceState({}, document.title, newUrl);
|
|
|
+ } catch (error) {
|
|
|
+ console.error("同步用户信息失败:", error);
|
|
|
+ showError("会员购买失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 查询订单状态
|
|
|
+const handleQueryOrder = async () => {
|
|
|
+ if (!currentOrderNo.value) {
|
|
|
+ showError("没有找到订单信息");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ const response = await userQueryOrder(currentOrderNo.value);
|
|
|
+
|
|
|
+ if (response.status === 1) {
|
|
|
+ // 支付成功
|
|
|
+ await userStore.sync();
|
|
|
+ showPaymentWaitingDialog.value = false;
|
|
|
+ showSuccess("会员购买成功");
|
|
|
+ currentOrderNo.value = "";
|
|
|
+ } else {
|
|
|
+ showError(response.msg || "会员购买失败");
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error("查询订单状态失败:", error);
|
|
|
+ showError("会员购买失败,请重试");
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ checkPaymentSuccess();
|
|
|
+});
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
@@ -158,6 +233,13 @@ const handleUpgrade = async () => {
|
|
|
</p>
|
|
|
<h2 class="text-base font-semibold text-white/90 truncate">
|
|
|
{{ isLoggedIn ? userStore.userInfo?.name || "用户" : "点击登录账号" }}
|
|
|
+ <span
|
|
|
+ v-if="isVip"
|
|
|
+ class="ml-2 px-2 py-0.5 rounded bg-yellow-400/90 text-xs text-yellow-900 font-semibold align-middle"
|
|
|
+ style="vertical-align: middle"
|
|
|
+ >
|
|
|
+ {{ vipLevelToText(userStore.userInfo?.vipLevel) }}
|
|
|
+ </span>
|
|
|
</h2>
|
|
|
</div>
|
|
|
<div v-if="isLoggedIn" class="flex gap-2">
|
|
|
@@ -174,7 +256,7 @@ const handleUpgrade = async () => {
|
|
|
:disabled="isGuest"
|
|
|
:class="{ 'opacity-50 cursor-not-allowed': isGuest }"
|
|
|
>
|
|
|
- 开通会员
|
|
|
+ {{ isVip ? "续订会员" : "开通会员" }}
|
|
|
</button>
|
|
|
</div>
|
|
|
<button
|
|
|
@@ -432,7 +514,7 @@ const handleUpgrade = async () => {
|
|
|
取消支付
|
|
|
</button>
|
|
|
<button
|
|
|
- @click="showPaymentWaitingDialog = false"
|
|
|
+ @click="handleQueryOrder"
|
|
|
class="flex-1 px-4 py-2 bg-brand text-slate-900 rounded-lg hover:bg-brand/90 transition"
|
|
|
>
|
|
|
已完成支付
|
|
|
@@ -486,6 +568,52 @@ const handleUpgrade = async () => {
|
|
|
</button>
|
|
|
</div>
|
|
|
</div>
|
|
|
+
|
|
|
+ <!-- 成功提示弹窗 -->
|
|
|
+ <div
|
|
|
+ v-if="showSuccessDialog"
|
|
|
+ class="fixed inset-0 bg-black/50 flex items-center justify-center z-50"
|
|
|
+ @click.self="showSuccessDialog = false"
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ class="bg-surface border border-white/10 rounded-2xl p-6 w-full max-w-sm mx-4 text-center"
|
|
|
+ >
|
|
|
+ <!-- 成功图标 -->
|
|
|
+ <div class="mb-4">
|
|
|
+ <div
|
|
|
+ class="w-12 h-12 mx-auto bg-green-500/20 rounded-full flex items-center justify-center"
|
|
|
+ >
|
|
|
+ <svg
|
|
|
+ class="w-6 h-6 text-green-400"
|
|
|
+ fill="none"
|
|
|
+ stroke="currentColor"
|
|
|
+ viewBox="0 0 24 24"
|
|
|
+ >
|
|
|
+ <path
|
|
|
+ stroke-linecap="round"
|
|
|
+ stroke-linejoin="round"
|
|
|
+ stroke-width="2"
|
|
|
+ d="M5 13l4 4L19 7"
|
|
|
+ />
|
|
|
+ </svg>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 成功信息 -->
|
|
|
+ <h3 class="text-lg font-semibold text-white/90 mb-2">操作成功</h3>
|
|
|
+ <p class="text-sm text-white/70 mb-6">
|
|
|
+ {{ successMessage }}
|
|
|
+ </p>
|
|
|
+
|
|
|
+ <!-- 确认按钮 -->
|
|
|
+ <button
|
|
|
+ @click="showSuccessDialog = false"
|
|
|
+ class="w-full px-4 py-2 bg-brand text-slate-900 rounded-lg hover:bg-brand/90 transition"
|
|
|
+ >
|
|
|
+ 确定
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</section>
|
|
|
</template>
|
|
|
<style scoped>
|