Files
yaoayanui/src/views/CardActivateView.vue
fengchuanhn@gmail.com 8293ebf489 1
2026-05-24 00:43:38 +08:00

180 lines
5.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup>
import { computed, ref, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
import { useAuthStore } from "../stores/auth.js";
import { activateCardKeyApi } from "../api/cardKeys.js";
import AuthLayout from "../components/AuthLayout.vue";
const route = useRoute();
const router = useRouter();
const auth = useAuthStore();
const username = ref("");
const serialNumber = ref("");
const loading = ref(false);
const feedback = ref({ severity: "", message: "" });
const resultSnapshot = ref(null);
const vipEndLabel = computed(() => {
const raw = resultSnapshot.value?.vip_end_time ?? auth.currentUser?.vip_end_time;
if (!raw) return "未开通";
const d = new Date(raw);
if (Number.isNaN(d.getTime())) return "—";
return d.toLocaleString("zh-CN", { hour12: false });
});
const pointsLabel = computed(() => {
const p = resultSnapshot.value?.points ?? auth.currentUser?.points;
if (p == null || Number.isNaN(Number(p))) return "0";
return String(p);
});
const showStatus = computed(() => auth.isAuthenticated || resultSnapshot.value != null);
watch(
() => route.query.username,
(value) => {
if (typeof value === "string" && value.trim()) {
username.value = value.trim();
} else if (auth.currentUser?.username) {
username.value = auth.currentUser.username;
}
},
{ immediate: true },
);
function showMessage(severity, message) {
feedback.value = { severity, message };
}
function formatActivateDetail(data) {
if (!data) return "";
if (data.card_type === "时长" && data.added_days != null) {
return `会员已延长 ${data.added_days}`;
}
if (data.card_type === "点数" && data.added_points != null) {
return `已获得 ${data.added_points} 点数`;
}
return "";
}
async function onSubmit() {
const name = username.value.trim();
const serial = serialNumber.value.trim().toUpperCase();
if (!name) {
showMessage("warn", "请输入用户名");
return;
}
if (!serial) {
showMessage("warn", "请输入卡密");
return;
}
loading.value = true;
feedback.value = { severity: "", message: "" };
const res = await activateCardKeyApi({ username: name, serialNumber: serial });
loading.value = false;
if (!res.ok) {
showMessage("error", res.message || "激活失败");
return;
}
serialNumber.value = "";
resultSnapshot.value = res.data ?? null;
if (auth.isAuthenticated && auth.currentUser?.username === name) {
await auth.refreshProfile();
}
const detail = formatActivateDetail(res.data);
showMessage("success", detail ? `${res.message}${detail}` : res.message || "激活成功");
// if (auth.isAuthenticated && auth.currentUser?.username === name && !auth.isVipExpired) {
// router.replace({ name: "home" });
// }
}
function goLogin() {
router.push({ name: "login" });
}
</script>
<template>
<AuthLayout title="卡密激活" subtitle="输入用户名与卡密序列号,兑换会员时长或点数">
<Message
v-if="feedback.message"
:severity="feedback.severity"
:closable="true"
class="mb-4 w-full"
@close="feedback.message = ''"
>
{{ feedback.message }}
</Message>
<div v-if="showStatus" class="card-activate-page__status mb-4">
<div class="card-activate-page__status-item">
<span class="text-xs uppercase text-slate-500">会员到期</span>
<span class="text-sm text-slate-200">{{ vipEndLabel }}</span>
</div>
<div class="card-activate-page__status-item">
<span class="text-xs uppercase text-slate-500">当前点数</span>
<span class="text-sm text-slate-200">{{ pointsLabel }}</span>
</div>
</div>
<form class="flex flex-col gap-4" @submit.prevent="onSubmit">
<div class="flex flex-col gap-2">
<label for="card-username" class="font-mono text-xs text-text-muted uppercase">用户名</label>
<InputText
id="card-username"
v-model="username"
placeholder="请输入要激活的用户名"
autocomplete="username"
class="w-full"
:disabled="loading"
/>
</div>
<div class="flex flex-col gap-2">
<label for="card-serial" class="font-mono text-xs text-text-muted uppercase">卡密序列号</label>
<InputText
id="card-serial"
v-model="serialNumber"
placeholder="请输入卡密"
class="w-full font-mono uppercase tracking-wider"
autocomplete="off"
:disabled="loading"
/>
</div>
<Button type="submit" label="立即激活" :loading="loading" class="w-full" />
<Button
v-if="!auth.isAuthenticated"
type="button"
label="已有账号,去登录"
severity="secondary"
text
class="w-full"
@click="goLogin"
/>
</form>
</AuthLayout>
</template>
<style scoped>
.card-activate-page__status {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.75rem;
}
.card-activate-page__status-item {
display: flex;
flex-direction: column;
gap: 0.25rem;
padding: 0.75rem;
border-radius: 0.5rem;
background: rgb(0 0 0 / 0.2);
}
</style>