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

368 lines
9.5 KiB
Vue
Raw Normal View History

2024-08-14 21:24:12 +08:00
<template>
2024-10-11 03:23:03 +08:00
<div v-if="!settingStore.isComm || userStore.isAdmin" class="layout-vip isPlus" @click="openUpgrade">
2024-08-14 21:24:12 +08:00
<contextHolder />
2024-09-01 04:49:26 +08:00
<fs-icon icon="mingcute:vip-1-line" :title="text.title" />
<div v-if="mode !== 'icon'" class="text">
<a-tooltip>
<template #title> {{ text.title }}</template>
<span>{{ text.name }}</span>
</a-tooltip>
2024-08-14 21:24:12 +08:00
</div>
</div>
</template>
<script lang="tsx" setup>
import { computed, reactive } 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";
import { useSettingStore } from "/@/store/modules/settings";
2024-09-24 02:42:08 +08:00
import { useRouter } from "vue-router";
2024-10-05 01:46:25 +08:00
import { useUserStore } from "/@/store/modules/user";
2024-10-05 01:46:25 +08:00
const settingStore = useSettingStore();
2024-09-01 04:49:26 +08:00
const props = withDefaults(
defineProps<{
mode?: "button" | "nav" | "icon";
}>(),
{
mode: "button"
}
);
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 = {
isPlus: {
button: {
2024-10-03 01:29:12 +08:00
name: `${vipLabel}已开通`,
2024-09-01 04:49:26 +08:00
title: "到期时间:" + expireTime.value
},
icon: {
name: "",
2024-10-03 01:29:12 +08:00
title: `${vipLabel}已开通`
2024-09-01 04:49:26 +08:00
},
nav: {
2024-10-03 01:29:12 +08:00
name: `${vipLabel}`,
2024-09-01 04:49:26 +08:00
title: "到期时间:" + expireTime.value
}
},
free: {
button: {
name: "此为专业版功能",
title: "升级专业版享受更多VIP特权"
},
icon: {
name: "",
title: "此为专业版功能"
},
nav: {
name: "基础版",
2024-09-01 04:49:26 +08:00
title: "升级专业版享受更多VIP特权"
}
}
};
2024-10-05 01:46:25 +08:00
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
}
});
const expireTime = computed(() => {
2024-10-05 01:46:25 +08:00
if (settingStore.isPlus) {
return dayjs(settingStore.plusInfo.expireTime).format("YYYY-MM-DD");
}
return "";
});
const expiredDays = computed(() => {
2024-10-05 01:46:25 +08:00
if (settingStore.plusInfo?.isPlus && !settingStore.isPlus) {
//已过期多少天
2024-10-05 01:46:25 +08:00
const days = dayjs().diff(dayjs(settingStore.plusInfo.expireTime), "day");
return `${settingStore.vipLabel}已过期${days}`;
}
return "";
});
2024-08-14 21:24:12 +08:00
const formState = reactive({
code: ""
});
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) {
message.error("请输入激活码");
throw new Error("请输入激活码");
}
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({
title: "激活成功",
2024-10-05 01:46:25 +08:00
content: `您已成功激活${vipLabel},有效期至:${dayjs(settingStore.plusInfo.expireTime).format("YYYY-MM-DD")}`,
2024-09-24 02:42:08 +08:00
onOk() {
if (!(settingStore.installInfo.bindUserId > 0)) {
//未绑定账号
Modal.confirm({
title: "是否绑定袖手账号",
2024-10-03 01:29:12 +08:00
content: "绑定账号后可以避免License丢失强烈建议绑定",
2024-09-24 02:42:08 +08:00
onOk() {
router.push("/sys/account");
}
});
}
}
2024-08-14 21:24:12 +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");
}
async function getVipTrial() {
const res = await api.getVipTrial();
message.success(`恭喜,您已获得专业版${res.duration}天试用`);
await settingStore.init();
}
2024-11-08 17:33:30 +08:00
function openTrialModal() {
Modal.destroyAll();
modal.confirm({
title: "7天专业版试用获取",
okText: "立即获取",
2024-11-08 17:33:30 +08:00
onOk() {
getVipTrial();
2024-11-08 17:33:30 +08:00
},
width: 600,
content: () => {
return (
<div class="flex-col mt-10 mb-10">
<div>感谢您对开源项目的支持</div>
<div>点击确认即可获取7天专业版试用</div>
2024-11-08 17:33:30 +08:00
</div>
);
}
});
}
function openStarModal() {
Modal.destroyAll();
const goGithub = () => {
window.open("https://github.com/certd/certd/");
};
modal.confirm({
title: "7天专业版试用获取",
okText: "立即去Star",
onOk() {
goGithub();
openTrialModal();
},
width: 600,
content: () => {
return (
<div class="flex mt-10 mb-10">
<div>可以先请您帮忙点个star吗感谢感谢</div>
<img class="ml-5" src="https://img.shields.io/github/stars/certd/certd?logo=github" />
</div>
);
}
});
}
2024-08-14 21:24:12 +08:00
function openUpgrade() {
2024-09-02 01:02:41 +08:00
if (!userStore.isAdmin) {
message.info("仅限管理员操作");
return;
}
2024-08-14 21:24:12 +08:00
const placeholder = "请输入激活码";
2024-10-05 01:46:25 +08:00
const isPlus = settingStore.isPlus;
2024-10-03 01:29:12 +08:00
let title = "激活专业版/商业版";
2024-10-05 01:46:25 +08:00
if (settingStore.isComm) {
2024-10-03 01:29:12 +08:00
title = "续期商业版";
2024-10-05 01:46:25 +08:00
} else if (settingStore.isPlus) {
2024-10-03 01:29:12 +08:00
title = "续期专业版/升级商业版";
}
2024-11-08 16:53:45 +08:00
const vipTypeDefine = {
free: {
title: "基础版",
type: "free",
privilege: ["证书申请功能无限制", "证书流水线数量10条", "常用的主机、cdn等部署插件"]
},
plus: {
title: "专业版",
type: "plus",
privilege: ["可加VIP群需求优先实现", "证书流水线数量无限制", "免配置发邮件功能", "支持宝塔、易盾、群晖、1Panel、cdnfly等部署插件"],
trial: {
title: "7天试用",
click: () => {
2024-11-08 17:33:30 +08:00
openStarModal();
2024-11-08 16:53:45 +08:00
}
}
},
comm: {
title: "商业版",
type: "comm",
privilege: ["拥有专业版所有特权", "允许商用可修改logo、标题", "数据统计", "插件管理", "多用户无限制", "支持用户支付(敬请期待)"]
}
};
const modalRef = modal.confirm({
2024-10-03 01:29:12 +08:00
title,
2024-08-14 21:24:12 +08:00
async onOk() {
2024-08-21 12:38:09 +08:00
return await doActive();
2024-08-14 21:24:12 +08:00
},
2024-10-01 23:52:44 +08:00
maskClosable: true,
2024-08-21 12:38:09 +08:00
okText: "激活",
2024-10-03 01:49:38 +08:00
width: 900,
2024-08-14 21:24:12 +08:00
content: () => {
2024-10-10 18:38:22 +08:00
let activationCodeGetWay: any = null;
if (settingStore.siteEnv.agent.enabled != null) {
const agent = settingStore.siteEnv.agent;
if (agent.enabled === false) {
activationCodeGetWay = (
2024-10-10 22:22:08 +08:00
<span>
<a href="https://afdian.com/a/greper" target="_blank">
爱发电赞助VIP会员后获取专业版
</a>
<span> 商业版请直接联系作者</span>
</span>
2024-10-10 18:38:22 +08:00
);
} else {
activationCodeGetWay = (
<a href={agent.contactLink} target="_blank">
{agent.contactText}
</a>
);
}
}
2024-10-05 01:46:25 +08:00
const vipLabel = settingStore.vipLabel;
const slots = [];
for (const key in vipTypeDefine) {
2024-10-10 18:38:22 +08:00
// @ts-ignore
2024-10-05 01:46:25 +08:00
const item = vipTypeDefine[key];
const vipBlockClass = `vip-block ${key === settingStore.plusInfo.vipType ? "current" : ""}`;
slots.push(
<a-col span={8}>
<div class={vipBlockClass}>
2024-11-08 16:53:45 +08:00
<h3 class="block-header">
<span>{item.title}</span>
{item.trial && (
<span class="trial">
<a-tooltip title={item.trial.message}>
<a onClick={item.trial.click}>{item.trial.title}</a>
</a-tooltip>
</span>
)}
</h3>
2024-10-05 01:46:25 +08:00
<ul>
2024-10-10 18:38:22 +08:00
{item.privilege.map((p: string) => (
2024-10-05 01:46:25 +08:00
<li>
<fs-icon class="color-green" icon="ion:checkmark-sharp" />
{p}
</li>
))}
</ul>
</div>
</a-col>
);
}
2024-08-14 21:24:12 +08:00
return (
2024-10-03 22:03:49 +08:00
<div class="mt-10 mb-10 vip-active-modal">
<div class="vip-type-vs">
2024-10-05 01:46:25 +08:00
<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">
2024-09-02 23:55:38 +08:00
<h3 class="block-header">{isPlus ? "续期" : "立刻激活"}</h3>
2024-10-05 01:46:25 +08:00
<div>{isPlus ? `当前${vipLabel}已激活,到期时间` + dayjs(settingStore.plusInfo.expireTime).format("YYYY-MM-DD") : ""}</div>
2024-08-21 12:38:09 +08:00
<div class="mt-10">
<div class="flex-o w-100">
<span>站点ID</span>
<fs-copyable class="flex-1" v-model={computedSiteId.value}></fs-copyable>
</div>
<a-input class="mt-10" v-model:value={formState.code} placeholder={placeholder} />
2024-08-21 12:38:09 +08:00
</div>
<div class="mt-10">
没有激活码
2024-10-10 18:38:22 +08:00
{activationCodeGetWay}
2024-08-21 12:38:09 +08:00
</div>
<div class="mt-10">
激活码使用过一次之后不可再次使用如果要更换站点<a onClick={goAccount}>绑定账号</a>然后"转移VIP"即可
</div>
2024-08-14 21:24:12 +08:00
</div>
</div>
);
}
});
}
</script>
<style lang="less">
.layout-vip {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
2024-08-24 23:48:26 +08:00
cursor: pointer;
2024-09-01 04:49:26 +08:00
2024-08-14 21:24:12 +08:00
&.isPlus {
color: #c5913f;
}
.text {
margin-left: 5px;
}
}
2024-10-03 22:03:49 +08:00
.vip-active-modal {
2024-10-05 01:46:25 +08:00
.vip-block {
padding: 10px;
border: 1px solid #eee;
border-radius: 5px;
2024-10-31 16:19:35 +08:00
height: 170px;
2024-10-05 01:46:25 +08:00
//background-color: rgba(250, 237, 167, 0.79);
&.current {
border-color: green;
}
.block-header {
padding: 0px;
2024-11-08 16:53:45 +08:00
display: flex;
justify-content: space-between;
.trial {
font-size: 12px;
font-wight: 400;
}
2024-10-05 01:46:25 +08:00
}
}
2024-10-03 22:03:49 +08:00
ul {
list-style-type: unset;
margin-left: 0px;
padding: 0;
}
.color-green {
color: green;
}
2024-10-03 22:03:49 +08:00
.vip-type-vs {
.fs-icon {
margin-right: 5px;
color: green;
}
}
}
2024-08-14 21:24:12 +08:00
</style>