2024-08-14 21:24:12 +08:00
|
|
|
|
<template>
|
2025-08-10 02:07:48 +08:00
|
|
|
|
<div v-if="!settingStore.isComm || userStore.isAdmin" class="layout-vip isPlus" :class="{ isForever: settingStore.isForever }" @click="openUpgrade">
|
2025-06-29 14:09:09 +08:00
|
|
|
|
<contextHolder />
|
|
|
|
|
|
<fs-icon icon="mingcute:vip-1-line" :title="text.title" />
|
|
|
|
|
|
|
|
|
|
|
|
<div v-if="mode !== 'icon'" class="text hidden md:block ml-0.5">
|
|
|
|
|
|
<a-tooltip>
|
|
|
|
|
|
<template #title> {{ text.title }}</template>
|
|
|
|
|
|
<span class="">{{ text.name }}</span>
|
|
|
|
|
|
</a-tooltip>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2024-08-14 21:24:12 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
<script lang="tsx" setup>
|
2025-11-09 00:12:31 +08:00
|
|
|
|
import { computed, onMounted, reactive, ref } from "vue";
|
2024-08-14 21:24:12 +08:00
|
|
|
|
import dayjs from "dayjs";
|
|
|
|
|
|
import { message, Modal } from "ant-design-vue";
|
|
|
|
|
|
import * as api from "./api";
|
2025-04-12 23:59:03 +08:00
|
|
|
|
import { useSettingStore } from "/@/store/settings";
|
2024-09-24 02:42:08 +08:00
|
|
|
|
import { useRouter } from "vue-router";
|
2025-04-12 23:59:03 +08:00
|
|
|
|
import { useUserStore } from "/@/store/user";
|
2024-11-30 01:57:09 +08:00
|
|
|
|
import { mitter } from "/@/utils/util.mitt";
|
2025-06-25 20:09:29 +02:00
|
|
|
|
import { useI18n } from "vue-i18n";
|
2025-08-09 23:41:59 +08:00
|
|
|
|
import { env } from "/@/utils/util.env";
|
2025-06-25 20:09:29 +02:00
|
|
|
|
const { t } = useI18n();
|
2024-11-17 01:06:27 +08:00
|
|
|
|
|
2024-10-05 01:46:25 +08:00
|
|
|
|
const settingStore = useSettingStore();
|
2024-09-01 04:49:26 +08:00
|
|
|
|
const props = withDefaults(
|
|
|
|
|
|
defineProps<{
|
2024-11-30 01:57:09 +08:00
|
|
|
|
mode?: "comm" | "button" | "nav" | "icon";
|
2024-09-01 04:49:26 +08:00
|
|
|
|
}>(),
|
|
|
|
|
|
{
|
2025-04-27 22:51:47 +08:00
|
|
|
|
mode: "button",
|
2024-09-01 04:49:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
);
|
|
|
|
|
|
type Text = {
|
|
|
|
|
|
name: string;
|
|
|
|
|
|
title?: string;
|
2024-08-24 23:48:26 +08:00
|
|
|
|
};
|
2024-09-01 04:49:26 +08:00
|
|
|
|
const text = computed<Text>(() => {
|
2024-10-05 01:46:25 +08:00
|
|
|
|
const vipLabel = settingStore.vipLabel;
|
2024-09-01 04:49:26 +08:00
|
|
|
|
const map = {
|
2024-11-30 01:57:09 +08:00
|
|
|
|
isComm: {
|
|
|
|
|
|
comm: {
|
2025-06-25 20:09:29 +02:00
|
|
|
|
name: t("vip.comm.name", { vipLabel }),
|
|
|
|
|
|
title: t("vip.comm.title", { expire: expireTime.value }),
|
2024-11-30 01:57:09 +08:00
|
|
|
|
},
|
|
|
|
|
|
button: {
|
2025-06-25 20:09:29 +02:00
|
|
|
|
name: t("vip.comm.name", { vipLabel }),
|
|
|
|
|
|
title: t("vip.comm.title", { expire: expireTime.value }),
|
2024-11-30 01:57:09 +08:00
|
|
|
|
},
|
|
|
|
|
|
icon: {
|
|
|
|
|
|
name: "",
|
2025-06-25 20:09:29 +02:00
|
|
|
|
title: t("vip.comm.name", { vipLabel }),
|
2024-11-30 01:57:09 +08:00
|
|
|
|
},
|
|
|
|
|
|
nav: {
|
2025-06-25 20:09:29 +02:00
|
|
|
|
name: t("vip.comm.nav", { vipLabel }),
|
|
|
|
|
|
title: t("vip.comm.title", { expire: expireTime.value }),
|
2025-04-27 22:51:47 +08:00
|
|
|
|
},
|
2024-11-30 01:57:09 +08:00
|
|
|
|
},
|
2024-09-01 04:49:26 +08:00
|
|
|
|
isPlus: {
|
2024-11-30 01:57:09 +08:00
|
|
|
|
comm: {
|
2025-06-25 20:09:29 +02:00
|
|
|
|
name: t("vip.plus.name"),
|
|
|
|
|
|
title: t("vip.plus.title"),
|
2024-11-30 01:57:09 +08:00
|
|
|
|
},
|
2024-09-01 04:49:26 +08:00
|
|
|
|
button: {
|
2025-06-25 20:09:29 +02:00
|
|
|
|
name: t("vip.comm.name", { vipLabel }),
|
|
|
|
|
|
title: t("vip.comm.title", { expire: expireTime.value }),
|
2024-09-01 04:49:26 +08:00
|
|
|
|
},
|
|
|
|
|
|
icon: {
|
|
|
|
|
|
name: "",
|
2025-06-25 20:09:29 +02:00
|
|
|
|
title: t("vip.comm.name", { vipLabel }),
|
2024-09-01 04:49:26 +08:00
|
|
|
|
},
|
|
|
|
|
|
nav: {
|
2025-06-25 20:09:29 +02:00
|
|
|
|
name: t("vip.comm.nav", { vipLabel }),
|
|
|
|
|
|
title: t("vip.comm.title", { expire: expireTime.value }),
|
2025-04-27 22:51:47 +08:00
|
|
|
|
},
|
2024-09-01 04:49:26 +08:00
|
|
|
|
},
|
|
|
|
|
|
free: {
|
2024-11-30 01:57:09 +08:00
|
|
|
|
comm: {
|
2025-06-25 20:09:29 +02:00
|
|
|
|
name: t("vip.free.comm.name"),
|
|
|
|
|
|
title: t("vip.free.comm.title"),
|
2024-11-30 01:57:09 +08:00
|
|
|
|
},
|
2024-09-01 04:49:26 +08:00
|
|
|
|
button: {
|
2025-06-25 20:09:29 +02:00
|
|
|
|
name: t("vip.free.button.name"),
|
|
|
|
|
|
title: t("vip.free.button.title"),
|
2024-09-01 04:49:26 +08:00
|
|
|
|
},
|
|
|
|
|
|
icon: {
|
|
|
|
|
|
name: "",
|
2025-06-25 20:09:29 +02:00
|
|
|
|
title: t("vip.free.button.name"),
|
2024-09-01 04:49:26 +08:00
|
|
|
|
},
|
|
|
|
|
|
nav: {
|
2025-06-25 20:09:29 +02:00
|
|
|
|
name: t("vip.free.nav.name"),
|
|
|
|
|
|
title: t("vip.free.nav.title"),
|
2025-04-27 22:51:47 +08:00
|
|
|
|
},
|
|
|
|
|
|
},
|
2024-09-01 04:49:26 +08:00
|
|
|
|
};
|
2024-11-30 01:57:09 +08:00
|
|
|
|
if (settingStore.isComm) {
|
|
|
|
|
|
return map.isComm[props.mode];
|
|
|
|
|
|
} else if (settingStore.isPlus) {
|
2024-09-01 04:49:26 +08:00
|
|
|
|
return map.isPlus[props.mode];
|
2024-08-24 23:48:26 +08:00
|
|
|
|
} else {
|
2024-09-01 04:49:26 +08:00
|
|
|
|
return map.free[props.mode];
|
2024-08-24 23:48:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2024-08-25 01:55:34 +08:00
|
|
|
|
const expireTime = computed(() => {
|
2024-10-05 01:46:25 +08:00
|
|
|
|
if (settingStore.isPlus) {
|
2025-08-10 02:07:48 +08:00
|
|
|
|
return settingStore.expiresText;
|
2024-08-25 01:55:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
return "";
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const expiredDays = computed(() => {
|
2024-10-05 01:46:25 +08:00
|
|
|
|
if (settingStore.plusInfo?.isPlus && !settingStore.isPlus) {
|
2024-08-25 01:55:34 +08:00
|
|
|
|
//已过期多少天
|
2024-10-05 01:46:25 +08:00
|
|
|
|
const days = dayjs().diff(dayjs(settingStore.plusInfo.expireTime), "day");
|
|
|
|
|
|
return `${settingStore.vipLabel}已过期${days}天`;
|
2024-08-25 01:55:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
return "";
|
|
|
|
|
|
});
|
2024-08-14 21:24:12 +08:00
|
|
|
|
|
|
|
|
|
|
const formState = reactive({
|
2024-12-09 00:12:15 +08:00
|
|
|
|
code: "",
|
2025-04-27 22:51:47 +08:00
|
|
|
|
inviteCode: "",
|
2024-08-14 21:24:12 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
2024-09-24 02:42:08 +08:00
|
|
|
|
const router = useRouter();
|
2024-08-14 21:24:12 +08:00
|
|
|
|
async function doActive() {
|
|
|
|
|
|
if (!formState.code) {
|
2025-06-26 00:08:13 +02:00
|
|
|
|
message.error(t("vip.enterCode"));
|
|
|
|
|
|
throw new Error(t("vip.enterCode"));
|
2024-08-14 21:24:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
const res = await api.doActive(formState);
|
|
|
|
|
|
if (res) {
|
2024-10-14 11:52:37 +08:00
|
|
|
|
await settingStore.init();
|
2024-10-05 01:46:25 +08:00
|
|
|
|
const vipLabel = settingStore.vipLabel;
|
2024-08-14 21:24:12 +08:00
|
|
|
|
Modal.success({
|
2025-06-26 00:08:13 +02:00
|
|
|
|
title: t("vip.successTitle"),
|
|
|
|
|
|
content: t("vip.successContent", {
|
|
|
|
|
|
vipLabel,
|
|
|
|
|
|
expireDate: dayjs(settingStore.plusInfo.expireTime).format("YYYY-MM-DD"),
|
|
|
|
|
|
}),
|
2024-09-24 02:42:08 +08:00
|
|
|
|
onOk() {
|
|
|
|
|
|
if (!(settingStore.installInfo.bindUserId > 0)) {
|
|
|
|
|
|
Modal.confirm({
|
2025-06-26 00:08:13 +02:00
|
|
|
|
title: t("vip.bindAccountTitle"),
|
|
|
|
|
|
content: t("vip.bindAccountContent"),
|
2024-09-24 02:42:08 +08:00
|
|
|
|
onOk() {
|
|
|
|
|
|
router.push("/sys/account");
|
2025-04-27 22:51:47 +08:00
|
|
|
|
},
|
2024-09-24 02:42:08 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
2025-04-27 22:51:47 +08:00
|
|
|
|
},
|
2024-08-14 21:24:12 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-08-25 01:55:34 +08:00
|
|
|
|
|
|
|
|
|
|
const computedSiteId = computed(() => settingStore.installInfo?.siteId);
|
2024-08-14 21:24:12 +08:00
|
|
|
|
const [modal, contextHolder] = Modal.useModal();
|
2024-10-05 01:46:25 +08:00
|
|
|
|
const userStore = useUserStore();
|
2024-11-08 17:33:30 +08:00
|
|
|
|
|
|
|
|
|
|
function goAccount() {
|
|
|
|
|
|
Modal.destroyAll();
|
|
|
|
|
|
router.push("/sys/account");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-15 00:11:48 +08:00
|
|
|
|
async function getVipTrial(vipType = "plus") {
|
|
|
|
|
|
const res = await api.getVipTrial(vipType);
|
2025-06-29 14:09:09 +08:00
|
|
|
|
message.success(t("vip.congratulations_vip_trial", { duration: res.duration }));
|
2024-11-17 01:06:27 +08:00
|
|
|
|
await settingStore.init();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-15 00:11:48 +08:00
|
|
|
|
function openTrialModal(vipType = "plus") {
|
2024-11-08 17:33:30 +08:00
|
|
|
|
Modal.destroyAll();
|
|
|
|
|
|
|
|
|
|
|
|
modal.confirm({
|
2025-06-29 14:09:09 +08:00
|
|
|
|
title: t("vip.trial_modal_title"),
|
|
|
|
|
|
okText: t("vip.trial_modal_ok_text"),
|
2024-11-08 17:33:30 +08:00
|
|
|
|
onOk() {
|
2025-08-15 00:11:48 +08:00
|
|
|
|
getVipTrial(vipType);
|
2024-11-08 17:33:30 +08:00
|
|
|
|
},
|
|
|
|
|
|
width: 600,
|
|
|
|
|
|
content: () => {
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div class="flex-col mt-10 mb-10">
|
2025-06-29 14:09:09 +08:00
|
|
|
|
<div>{t("vip.trial_modal_thanks")}</div>
|
2025-08-15 00:11:48 +08:00
|
|
|
|
<div>{t("vip.trial_modal_click_confirm", { vipType })}</div>
|
2024-11-08 17:33:30 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
);
|
2025-04-27 22:51:47 +08:00
|
|
|
|
},
|
2024-11-08 17:33:30 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-15 00:11:48 +08:00
|
|
|
|
function openStarModal(vipType: string) {
|
|
|
|
|
|
if (settingStore.isPlus) {
|
|
|
|
|
|
message.error(t("vip.already_vip"));
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2024-11-08 17:33:30 +08:00
|
|
|
|
Modal.destroyAll();
|
|
|
|
|
|
const goGithub = () => {
|
|
|
|
|
|
window.open("https://github.com/certd/certd/");
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
modal.confirm({
|
2025-06-26 00:08:13 +02:00
|
|
|
|
title: t("vip.get_7_day_pro_trial"),
|
|
|
|
|
|
okText: t("vip.star_now"),
|
2024-11-08 17:33:30 +08:00
|
|
|
|
onOk() {
|
|
|
|
|
|
goGithub();
|
2025-08-15 00:11:48 +08:00
|
|
|
|
openTrialModal(vipType);
|
2024-11-08 17:33:30 +08:00
|
|
|
|
},
|
|
|
|
|
|
width: 600,
|
|
|
|
|
|
content: () => {
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div class="flex mt-10 mb-10">
|
2025-06-26 00:08:13 +02:00
|
|
|
|
<div>{t("vip.please_help_star")}</div>
|
2024-11-08 17:33:30 +08:00
|
|
|
|
<img class="ml-5" src="https://img.shields.io/github/stars/certd/certd?logo=github" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
2025-04-27 22:51:47 +08:00
|
|
|
|
},
|
2024-11-08 17:33:30 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-08-14 21:24:12 +08:00
|
|
|
|
function openUpgrade() {
|
2025-06-29 14:09:09 +08:00
|
|
|
|
if (!userStore.isAdmin) {
|
|
|
|
|
|
message.info(t("vip.admin_only_operation"));
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
const placeholder = t("vip.enter_activation_code");
|
|
|
|
|
|
const isPlus = settingStore.isPlus;
|
|
|
|
|
|
let title = t("vip.activate_pro_business");
|
|
|
|
|
|
if (settingStore.isComm) {
|
|
|
|
|
|
title = t("vip.renew_business");
|
|
|
|
|
|
} else if (settingStore.isPlus) {
|
|
|
|
|
|
title = t("vip.renew_pro_upgrade_business");
|
|
|
|
|
|
}
|
2025-06-26 00:08:13 +02:00
|
|
|
|
|
2025-08-09 23:41:59 +08:00
|
|
|
|
// const goBuyUrl = "https://afdian.com/a/greper"
|
|
|
|
|
|
const subjectId = settingStore.installInfo.siteId;
|
|
|
|
|
|
const appKey = settingStore.installInfo.appKey;
|
2025-08-10 23:48:40 +08:00
|
|
|
|
const location = window.location;
|
|
|
|
|
|
const callbackUrl = encodeURIComponent(`${location.origin}${location.pathname}#/sys/account`);
|
|
|
|
|
|
const goBuyUrl = `${env.VIP_PRODUCT_URL}?appKey=${appKey}&subjectId=${subjectId}&callback=${callbackUrl}`;
|
2025-08-11 02:02:30 +08:00
|
|
|
|
const goBuyCommUrl = `${goBuyUrl}&vipType=comm`;
|
2025-06-29 14:09:09 +08:00
|
|
|
|
const productInfo = settingStore.productInfo;
|
2025-11-09 00:12:31 +08:00
|
|
|
|
|
|
|
|
|
|
function checkPerpetualPlus() {
|
|
|
|
|
|
if (settingStore.isPerpetual) {
|
|
|
|
|
|
Modal.warn({
|
|
|
|
|
|
title: t("vip.already_perpetual_plus"),
|
|
|
|
|
|
okText: t("vip.confirm"),
|
|
|
|
|
|
});
|
|
|
|
|
|
throw new Error(t("vip.already_perpetual_plus"));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
function goBuyPlusPage() {
|
|
|
|
|
|
checkPerpetualPlus();
|
|
|
|
|
|
if (settingStore.isComm) {
|
|
|
|
|
|
Modal.warn({
|
|
|
|
|
|
title: t("vip.already_comm"),
|
|
|
|
|
|
okText: t("vip.confirm"),
|
|
|
|
|
|
});
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
window.open(goBuyUrl);
|
|
|
|
|
|
}
|
|
|
|
|
|
function goBuyCommPage() {
|
|
|
|
|
|
checkPerpetualPlus();
|
|
|
|
|
|
if (settingStore.isPlus && !settingStore.isComm) {
|
|
|
|
|
|
Modal.confirm({
|
|
|
|
|
|
title: t("vip.already_plus"),
|
|
|
|
|
|
okText: t("vip.confirm"),
|
|
|
|
|
|
onOk() {
|
|
|
|
|
|
window.open(goBuyCommUrl);
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
window.open(goBuyCommUrl);
|
|
|
|
|
|
}
|
2025-06-29 14:09:09 +08:00
|
|
|
|
const vipTypeDefine = {
|
|
|
|
|
|
free: {
|
|
|
|
|
|
title: t("vip.basic_edition"),
|
|
|
|
|
|
desc: t("vip.community_free_version"),
|
|
|
|
|
|
type: "free",
|
|
|
|
|
|
icon: "lucide:package-open",
|
|
|
|
|
|
privilege: [t("vip.unlimited_certificate_application"), t("vip.unlimited_domain_count"), t("vip.unlimited_certificate_pipelines"), t("vip.common_deployment_plugins"), t("vip.email_webhook_notifications")],
|
2024-11-08 16:53:45 +08:00
|
|
|
|
},
|
2025-06-29 14:09:09 +08:00
|
|
|
|
plus: {
|
|
|
|
|
|
title: t("vip.professional_edition"),
|
|
|
|
|
|
desc: t("vip.open_source_support"),
|
|
|
|
|
|
type: "plus",
|
|
|
|
|
|
privilege: [t("vip.vip_group_priority"), t("vip.unlimited_site_certificate_monitoring"), t("vip.more_notification_methods"), t("vip.plugins_fully_open")],
|
|
|
|
|
|
trial: {
|
|
|
|
|
|
title: t("vip.click_to_get_7_day_trial"),
|
|
|
|
|
|
click: () => {
|
2025-08-15 00:11:48 +08:00
|
|
|
|
openStarModal("plus");
|
2025-06-29 14:09:09 +08:00
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
icon: "stash:thumb-up",
|
|
|
|
|
|
price: productInfo.plus.price,
|
|
|
|
|
|
price3: `¥${productInfo.plus.price3}/3${t("vip.years")}`,
|
|
|
|
|
|
tooltip: productInfo.plus.tooltip,
|
|
|
|
|
|
get() {
|
|
|
|
|
|
return (
|
|
|
|
|
|
<a-tooltip title={t("vip.afdian_support_vip")}>
|
2025-11-09 00:12:31 +08:00
|
|
|
|
<a-button size="small" type="primary" onClick={goBuyPlusPage}>
|
2025-06-29 14:09:09 +08:00
|
|
|
|
{t("vip.get_after_support")}
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
</a-tooltip>
|
|
|
|
|
|
);
|
|
|
|
|
|
},
|
2025-04-27 22:51:47 +08:00
|
|
|
|
},
|
2025-06-29 14:09:09 +08:00
|
|
|
|
comm: {
|
|
|
|
|
|
title: t("vip.business_edition"),
|
|
|
|
|
|
desc: t("vip.commercial_license"),
|
|
|
|
|
|
type: "comm",
|
|
|
|
|
|
icon: "vaadin:handshake",
|
|
|
|
|
|
privilege: [t("vip.all_pro_privileges"), t("vip.allow_commercial_use_modify_logo_title"), t("vip.data_statistics"), t("vip.plugin_management"), t("vip.unlimited_multi_users"), t("vip.support_user_payment")],
|
|
|
|
|
|
price: productInfo.comm.price,
|
|
|
|
|
|
price3: `¥${productInfo.comm.price3}/3${t("vip.years")}`,
|
|
|
|
|
|
tooltip: productInfo.comm.tooltip,
|
2025-08-15 00:11:48 +08:00
|
|
|
|
trial: {
|
|
|
|
|
|
title: t("vip.click_to_get_7_day_trial"),
|
|
|
|
|
|
click: () => {
|
|
|
|
|
|
openStarModal("comm");
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
2025-06-29 14:09:09 +08:00
|
|
|
|
get() {
|
2025-08-11 02:02:30 +08:00
|
|
|
|
return (
|
2025-11-09 00:12:31 +08:00
|
|
|
|
<a-button size="small" type="primary" onClick={goBuyCommPage}>
|
|
|
|
|
|
{t("vip.buy")}
|
2025-08-11 02:02:30 +08:00
|
|
|
|
</a-button>
|
|
|
|
|
|
);
|
2025-06-29 14:09:09 +08:00
|
|
|
|
},
|
2024-08-14 21:24:12 +08:00
|
|
|
|
},
|
2025-06-29 14:09:09 +08:00
|
|
|
|
};
|
2025-06-26 00:08:13 +02:00
|
|
|
|
|
2025-11-09 00:12:31 +08:00
|
|
|
|
const manualActiveFlag = ref();
|
|
|
|
|
|
function showManualActivation() {
|
|
|
|
|
|
manualActiveFlag.value = true;
|
|
|
|
|
|
}
|
2025-11-09 14:38:38 +08:00
|
|
|
|
|
|
|
|
|
|
function goBindAccount() {
|
|
|
|
|
|
modalRef?.destroy();
|
|
|
|
|
|
router.push({
|
|
|
|
|
|
path: "/sys/account",
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2025-11-09 00:12:31 +08:00
|
|
|
|
const modalRef = modal.success({
|
2025-06-29 14:09:09 +08:00
|
|
|
|
title,
|
|
|
|
|
|
maskClosable: true,
|
2025-11-09 00:12:31 +08:00
|
|
|
|
okText: t("vip.close"),
|
2025-06-29 17:41:54 +08:00
|
|
|
|
width: 1100,
|
2025-06-29 14:09:09 +08:00
|
|
|
|
content: () => {
|
2025-11-09 00:12:31 +08:00
|
|
|
|
let manualActiveBlock: any = "";
|
|
|
|
|
|
if (manualActiveFlag.value) {
|
|
|
|
|
|
manualActiveBlock = (
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<div class="mt-10">
|
|
|
|
|
|
<a-input-search class="w-2/6" v-model:value={formState.code} placeholder={placeholder} enter-button={t("vip.activate")} onSearch={doActive}></a-input-search>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="mt-10">
|
|
|
|
|
|
{t("vip.activation_code_one_use")}
|
|
|
|
|
|
<a onClick={goAccount}>{t("vip.bind_account")}</a>,{t("vip.transfer_vip")}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2025-06-29 14:09:09 +08:00
|
|
|
|
const vipLabel = settingStore.vipLabel;
|
2025-11-09 00:12:31 +08:00
|
|
|
|
let plusInfo: any = "";
|
|
|
|
|
|
if (isPlus) {
|
|
|
|
|
|
plusInfo = (
|
|
|
|
|
|
<div class="mt-10">
|
|
|
|
|
|
{t("vip.current")} {vipLabel} {t("vip.activated_expire_time")}
|
|
|
|
|
|
{settingStore.expiresText}
|
2025-11-09 14:38:38 +08:00
|
|
|
|
<a class="ml-2" onClick={goBindAccount}>
|
|
|
|
|
|
没有生效?
|
|
|
|
|
|
</a>
|
2025-11-09 00:12:31 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-29 14:09:09 +08:00
|
|
|
|
const slots = [];
|
|
|
|
|
|
for (const key in vipTypeDefine) {
|
|
|
|
|
|
// @ts-ignore
|
|
|
|
|
|
const item = vipTypeDefine[key];
|
|
|
|
|
|
const vipBlockClass = `vip-block ${key === settingStore.plusInfo.vipType ? "current" : ""}`;
|
|
|
|
|
|
slots.push(
|
|
|
|
|
|
<a-col span={8}>
|
|
|
|
|
|
<div class={vipBlockClass}>
|
|
|
|
|
|
<h3 class="block-header ">
|
|
|
|
|
|
<span class="flex-o">{item.title}</span>
|
|
|
|
|
|
{item.trial && (
|
|
|
|
|
|
<span class="trial">
|
|
|
|
|
|
<a-tooltip title={item.trial.message}>
|
|
|
|
|
|
<a onClick={item.trial.click}>{item.trial.title}</a>
|
2024-11-08 16:53:45 +08:00
|
|
|
|
</a-tooltip>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
)}
|
2025-06-29 14:09:09 +08:00
|
|
|
|
</h3>
|
|
|
|
|
|
<div style="color:green" class="flex-o">
|
|
|
|
|
|
<fs-icon icon={item.icon} class="fs-16 flex-o" />
|
|
|
|
|
|
{item.desc}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<ul class="flex-1 privilege">
|
|
|
|
|
|
{item.privilege.map((p: string) => (
|
|
|
|
|
|
<li class="flex-baseline">
|
|
|
|
|
|
<fs-icon class="color-green" icon="ion:checkmark-sharp" />
|
|
|
|
|
|
{p}
|
|
|
|
|
|
</li>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</ul>
|
|
|
|
|
|
<div class="footer flex-between flex-vc">
|
|
|
|
|
|
<div class="price-show">
|
|
|
|
|
|
{item.price && (
|
|
|
|
|
|
<span class="flex">
|
|
|
|
|
|
<span class="-text">¥{item.price}</span>
|
|
|
|
|
|
<span>/</span>
|
|
|
|
|
|
{t("vip.year")}
|
|
|
|
|
|
<a-tooltip class="ml-5" title={item.price3}>
|
|
|
|
|
|
<fs-icon class="pointer color-red" icon="ic:outline-discount"></fs-icon>
|
|
|
|
|
|
</a-tooltip>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
)}
|
|
|
|
|
|
{!item.price && (
|
|
|
|
|
|
<span>
|
|
|
|
|
|
<span class="price-text">{t("vip.freee")}</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="get-show">{item.get && <div>{item.get()}</div>}</div>
|
2024-12-23 23:33:13 +08:00
|
|
|
|
</div>
|
2024-10-05 01:46:25 +08:00
|
|
|
|
</div>
|
2025-06-29 14:09:09 +08:00
|
|
|
|
</a-col>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div class="mt-10 mb-10 vip-active-modal">
|
|
|
|
|
|
{productInfo.notice && (
|
|
|
|
|
|
<div class="mb-10">
|
|
|
|
|
|
<a-alert type="error" message={productInfo.notice}></a-alert>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)}
|
|
|
|
|
|
<div class="vip-type-vs">
|
|
|
|
|
|
<a-row gutter={20}>{slots}</a-row>
|
2024-08-21 12:38:09 +08:00
|
|
|
|
</div>
|
2024-10-05 01:46:25 +08:00
|
|
|
|
<div class="mt-10">
|
2025-11-09 00:12:31 +08:00
|
|
|
|
<div class="flex-o w-100">
|
|
|
|
|
|
<span>{t("vip.site_id")}:</span>
|
|
|
|
|
|
<fs-copyable v-model={computedSiteId.value}></fs-copyable>
|
2025-06-29 14:09:09 +08:00
|
|
|
|
</div>
|
2024-08-14 21:24:12 +08:00
|
|
|
|
</div>
|
2025-11-09 00:12:31 +08:00
|
|
|
|
{plusInfo}
|
|
|
|
|
|
<div class="mt-10">
|
|
|
|
|
|
{t("vip.have_activation_code")}
|
|
|
|
|
|
<span>
|
|
|
|
|
|
<a onClick={showManualActivation}>{t("vip.manual_activation")}</a>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="mt-10">{manualActiveBlock}</div>
|
2024-08-14 21:24:12 +08:00
|
|
|
|
</div>
|
2025-06-29 14:09:09 +08:00
|
|
|
|
);
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
2024-08-14 21:24:12 +08:00
|
|
|
|
}
|
2024-11-30 01:57:09 +08:00
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
mitter.on("openVipModal", () => {
|
|
|
|
|
|
if (props.mode === "nav" && !settingStore.isPlus) {
|
|
|
|
|
|
openUpgrade();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
2024-08-14 21:24:12 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="less">
|
|
|
|
|
|
.layout-vip {
|
2025-06-29 14:09:09 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
cursor: pointer;
|
2024-09-01 04:49:26 +08:00
|
|
|
|
|
2025-06-29 14:09:09 +08:00
|
|
|
|
&.isPlus {
|
|
|
|
|
|
color: #c5913f;
|
2025-08-10 02:07:48 +08:00
|
|
|
|
|
|
|
|
|
|
&.isForever {
|
|
|
|
|
|
color: #ff2e83;
|
|
|
|
|
|
}
|
2025-06-29 14:09:09 +08:00
|
|
|
|
}
|
2024-08-14 21:24:12 +08:00
|
|
|
|
|
2025-06-29 14:09:09 +08:00
|
|
|
|
.text {
|
|
|
|
|
|
}
|
2024-08-14 21:24:12 +08:00
|
|
|
|
}
|
2024-10-03 22:03:49 +08:00
|
|
|
|
|
|
|
|
|
|
.vip-active-modal {
|
2025-06-29 14:09:09 +08:00
|
|
|
|
.vip-block {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
padding: 10px;
|
|
|
|
|
|
border: 1px solid #eee;
|
|
|
|
|
|
border-radius: 5px;
|
2025-06-29 17:41:54 +08:00
|
|
|
|
height: 275px;
|
2025-08-10 02:21:32 +08:00
|
|
|
|
line-height: 24px;
|
|
|
|
|
|
|
|
|
|
|
|
.privilege {
|
|
|
|
|
|
margin-top: 5px;
|
|
|
|
|
|
}
|
2025-06-29 14:09:09 +08:00
|
|
|
|
|
|
|
|
|
|
//background-color: rgba(250, 237, 167, 0.79);
|
|
|
|
|
|
&.current {
|
|
|
|
|
|
border-color: green;
|
|
|
|
|
|
}
|
2024-10-05 01:46:25 +08:00
|
|
|
|
|
2025-06-29 14:09:09 +08:00
|
|
|
|
.block-header {
|
|
|
|
|
|
padding: 0px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
2025-06-26 00:08:13 +02:00
|
|
|
|
|
2025-06-29 14:09:09 +08:00
|
|
|
|
.trial {
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
font-wight: 400;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-06-26 00:08:13 +02:00
|
|
|
|
|
2025-06-29 14:09:09 +08:00
|
|
|
|
.footer {
|
|
|
|
|
|
padding-top: 5px;
|
|
|
|
|
|
margin-top: 0px;
|
|
|
|
|
|
border-top: 1px solid #eee;
|
2025-06-26 00:08:13 +02:00
|
|
|
|
|
2025-06-29 14:09:09 +08:00
|
|
|
|
.price-text {
|
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
color: red;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-06-26 00:08:13 +02:00
|
|
|
|
|
2025-06-29 14:09:09 +08:00
|
|
|
|
ul {
|
|
|
|
|
|
list-style-type: unset;
|
|
|
|
|
|
margin-left: 0px;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
}
|
2025-06-26 00:08:13 +02:00
|
|
|
|
|
2025-06-29 14:09:09 +08:00
|
|
|
|
.color-green {
|
|
|
|
|
|
color: green;
|
|
|
|
|
|
}
|
2025-06-26 00:08:13 +02:00
|
|
|
|
|
2025-06-29 14:09:09 +08:00
|
|
|
|
.vip-type-vs {
|
|
|
|
|
|
.privilege {
|
|
|
|
|
|
.fs-icon {
|
|
|
|
|
|
color: green;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-06-26 00:08:13 +02:00
|
|
|
|
|
2025-06-29 14:09:09 +08:00
|
|
|
|
.fs-icon {
|
|
|
|
|
|
margin-right: 5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-10-03 22:03:49 +08:00
|
|
|
|
}
|
2024-08-14 21:24:12 +08:00
|
|
|
|
</style>
|