Files
certd/packages/ui/certd-client/src/components/vip-button/index.vue
T

290 lines
7.3 KiB
Vue
Raw Normal View History

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>
import { message, Modal } from "ant-design-vue";
import dayjs from "dayjs";
import { computed, onMounted, ref } from "vue";
import { useI18n } from "vue-i18n";
import { useRouter } from "vue-router";
2024-08-14 21:24:12 +08:00
import * as api from "./api";
import { useSettingStore } from "/src/store/settings/index";
2025-04-12 23:59:03 +08:00
import { useUserStore } from "/@/store/user";
2025-08-09 23:41:59 +08:00
import { env } from "/@/utils/util.env";
import { mitter } from "/@/utils/util.mitt";
import VipModalContent from "./vip-modal-content.vue";
2025-06-25 20:09:29 +02:00
const { t } = useI18n();
2024-11-17 01:06:27 +08:00
defineOptions({
name: "VipButton",
});
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;
2026-02-02 16:54:23 +08:00
const plusMessage = settingStore.plusInfo?.message;
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"),
2026-02-02 16:54:23 +08:00
title: plusMessage || 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) {
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
2024-09-24 02:42:08 +08:00
const router = useRouter();
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
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"));
}
}
2025-11-09 00:12:31 +08:00
function goBuyPlusPage() {
checkPerpetualPlus();
if (settingStore.isComm) {
Modal.warn({
title: t("vip.already_comm"),
okText: t("vip.confirm"),
});
return;
}
window.open(goBuyUrl);
}
2025-11-09 00:12:31 +08:00
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);
}
const modalRef = modal.success({
2025-06-29 14:09:09 +08:00
title,
2026-01-13 00:30:30 +08:00
class: "vip-modal",
2025-06-29 14:09:09 +08:00
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: () => {
return <VipModalContent placeholder={placeholder} isPlus={isPlus} productInfo={productInfo} goBuyPlusPage={goBuyPlusPage} goBuyCommPage={goBuyCommPage} openStarModal={openStarModal} modalRef={modalRef} />;
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">
2026-01-13 00:30:30 +08:00
.vip-modal {
.ant-modal-confirm-content {
margin-inline-start: 10px !important;
}
}
2024-08-14 21:24:12 +08:00
.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
}
</style>