|
|
@@ -1,7 +1,7 @@
|
|
|
<script setup lang="ts">
|
|
|
import { useUserStore } from "@/store/user";
|
|
|
import { computed, ref } from "vue";
|
|
|
-import { upgradeGuest } from "@/services/api";
|
|
|
+import { upgradeGuest, purchaseMember } from "@/services/api";
|
|
|
|
|
|
const userStore = useUserStore();
|
|
|
const isLoggedIn = computed(() => !!userStore.token);
|
|
|
@@ -12,6 +12,9 @@ const emit = defineEmits(["show-login"]);
|
|
|
|
|
|
const showUpgradeDialog = ref(false);
|
|
|
const showMembershipDialog = ref(false);
|
|
|
+const showPaymentWaitingDialog = ref(false);
|
|
|
+const showErrorDialog = ref(false);
|
|
|
+const errorMessage = ref("");
|
|
|
const upgradeForm = ref({
|
|
|
name: null,
|
|
|
password: null,
|
|
|
@@ -19,6 +22,7 @@ const upgradeForm = ref({
|
|
|
phone: undefined,
|
|
|
});
|
|
|
const isLoading = ref(false);
|
|
|
+const isPaymentLoading = ref(false);
|
|
|
|
|
|
// 会员购买选项
|
|
|
const membershipPlans = [
|
|
|
@@ -42,22 +46,45 @@ const showLoginDialog = () => {
|
|
|
emit("show-login");
|
|
|
};
|
|
|
|
|
|
-const handleMembershipPurchase = () => {
|
|
|
+const showError = (message: string) => {
|
|
|
+ errorMessage.value = message;
|
|
|
+ showErrorDialog.value = true;
|
|
|
+};
|
|
|
+
|
|
|
+const handleMembershipPurchase = async () => {
|
|
|
if (!selectedPlan.value) {
|
|
|
alert("请选择会员套餐");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- const plan = membershipPlans.find((p) => p.key === selectedPlan.value);
|
|
|
- console.log("购买会员:", plan, "支付方式:", selectedPayment.value);
|
|
|
+ isPaymentLoading.value = true;
|
|
|
+ try {
|
|
|
+ const response = await purchaseMember(
|
|
|
+ userStore.userInfo.id,
|
|
|
+ selectedPlan.value
|
|
|
+ );
|
|
|
+
|
|
|
+ if (response.code === 1) {
|
|
|
+ // 关闭购买弹窗
|
|
|
+ showMembershipDialog.value = false;
|
|
|
+
|
|
|
+ // 打开支付页面
|
|
|
+ window.open(response.code_url, "_blank");
|
|
|
|
|
|
- // TODO: 调用支付API
|
|
|
- alert(
|
|
|
- `即将跳转到支付页面\n套餐: ${plan?.label}\n价格: ${plan?.price}\n支付方式: 支付宝`
|
|
|
- );
|
|
|
+ // 显示支付等待弹窗
|
|
|
+ showPaymentWaitingDialog.value = true;
|
|
|
|
|
|
- showMembershipDialog.value = false;
|
|
|
- selectedPlan.value = "";
|
|
|
+ // 重置选择
|
|
|
+ selectedPlan.value = "";
|
|
|
+ } else {
|
|
|
+ showError(`支付失败: ${response.msg || "未知错误"}`);
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error("购买会员失败", error);
|
|
|
+ showError("购买失败,请重试");
|
|
|
+ } finally {
|
|
|
+ isPaymentLoading.value = false;
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
const handleUpgrade = async () => {
|
|
|
@@ -365,14 +392,100 @@ const handleUpgrade = async () => {
|
|
|
</button>
|
|
|
<button
|
|
|
@click="handleMembershipPurchase"
|
|
|
- :disabled="!selectedPlan"
|
|
|
+ :disabled="!selectedPlan || isPaymentLoading"
|
|
|
class="flex-1 px-4 py-2 bg-brand text-slate-900 rounded-lg hover:bg-brand/90 transition disabled:opacity-50 disabled:cursor-not-allowed"
|
|
|
>
|
|
|
- 立即购买
|
|
|
+ {{ isPaymentLoading ? "处理中..." : "立即购买" }}
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 支付等待弹窗 -->
|
|
|
+ <div
|
|
|
+ v-if="showPaymentWaitingDialog"
|
|
|
+ class="fixed inset-0 bg-black/50 flex items-center justify-center z-50"
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ class="bg-surface border border-white/10 rounded-2xl p-8 w-full max-w-sm mx-4 text-center"
|
|
|
+ >
|
|
|
+ <!-- 加载动画 -->
|
|
|
+ <div class="mb-6">
|
|
|
+ <div
|
|
|
+ class="w-16 h-16 mx-auto border-4 border-white/20 border-t-brand rounded-full animate-spin"
|
|
|
+ ></div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 等待文字 -->
|
|
|
+ <h3 class="text-lg font-semibold text-white/90 mb-2">等待支付...</h3>
|
|
|
+ <p class="text-sm text-white/60 mb-6">
|
|
|
+ 请在支付页面完成支付<br />
|
|
|
+ 支付完成后会自动跳转
|
|
|
+ </p>
|
|
|
+
|
|
|
+ <!-- 操作按钮 -->
|
|
|
+ <div class="flex gap-3">
|
|
|
+ <button
|
|
|
+ @click="showPaymentWaitingDialog = false"
|
|
|
+ class="flex-1 px-4 py-2 border border-white/20 text-white/70 rounded-lg hover:bg-white/5 transition"
|
|
|
+ >
|
|
|
+ 取消支付
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ @click="showPaymentWaitingDialog = false"
|
|
|
+ class="flex-1 px-4 py-2 bg-brand text-slate-900 rounded-lg hover:bg-brand/90 transition"
|
|
|
+ >
|
|
|
+ 已完成支付
|
|
|
</button>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
+
|
|
|
+ <!-- 错误提示弹窗 -->
|
|
|
+ <div
|
|
|
+ v-if="showErrorDialog"
|
|
|
+ class="fixed inset-0 bg-black/50 flex items-center justify-center z-50"
|
|
|
+ @click.self="showErrorDialog = 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-red-500/20 rounded-full flex items-center justify-center"
|
|
|
+ >
|
|
|
+ <svg
|
|
|
+ class="w-6 h-6 text-red-400"
|
|
|
+ fill="none"
|
|
|
+ stroke="currentColor"
|
|
|
+ viewBox="0 0 24 24"
|
|
|
+ >
|
|
|
+ <path
|
|
|
+ stroke-linecap="round"
|
|
|
+ stroke-linejoin="round"
|
|
|
+ stroke-width="2"
|
|
|
+ d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"
|
|
|
+ />
|
|
|
+ </svg>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 错误信息 -->
|
|
|
+ <h3 class="text-lg font-semibold text-white/90 mb-2">操作失败</h3>
|
|
|
+ <p class="text-sm text-white/70 mb-6">
|
|
|
+ {{ errorMessage }}
|
|
|
+ </p>
|
|
|
+
|
|
|
+ <!-- 确认按钮 -->
|
|
|
+ <button
|
|
|
+ @click="showErrorDialog = 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>
|