mirror of https://github.com/certd/certd
Merge branch 'v2-dev-buy' into v2-dev
commit
c3637e731f
|
|
@ -130,12 +130,15 @@ export class PlusService {
|
||||||
return res.accessToken;
|
return res.accessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getVipTrial() {
|
async getVipTrial(vipType= "plus") {
|
||||||
await this.register();
|
await this.register();
|
||||||
const plusRequestService = await this.getPlusRequestService();
|
const plusRequestService = await this.getPlusRequestService();
|
||||||
const res = await plusRequestService.request({
|
const res = await plusRequestService.request({
|
||||||
url: '/activation/subject/vip/trialGet',
|
url: '/activation/subject/vip/trialGet',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
data:{
|
||||||
|
vipType
|
||||||
|
}
|
||||||
});
|
});
|
||||||
if (res.license) {
|
if (res.license) {
|
||||||
await this.updateLicense(res.license);
|
await this.updateLicense(res.license);
|
||||||
|
|
|
||||||
|
|
@ -10,4 +10,4 @@ VITE_APP_LOGO=static/images/logo/logo.svg
|
||||||
VITE_APP_LOGIN_LOGO=static/images/logo/rect-black.svg
|
VITE_APP_LOGIN_LOGO=static/images/logo/rect-black.svg
|
||||||
VITE_APP_PROJECT_PATH=https://github.com/certd/certd
|
VITE_APP_PROJECT_PATH=https://github.com/certd/certd
|
||||||
VITE_APP_NAMESPACE=fs
|
VITE_APP_NAMESPACE=fs
|
||||||
VITE_APP_VIP_PRODUCT_URL=http://localhost:1017/subject#/product/list
|
VITE_APP_VIP_PRODUCT_URL="http://localhost:1017/subject#/app/certd/product"
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
VITE_APP_API=api
|
VITE_APP_API=api
|
||||||
#登录与权限开启
|
#登录与权限开启
|
||||||
VITE_APP_PM_ENABLED=true
|
VITE_APP_PM_ENABLED=true
|
||||||
|
|
||||||
|
|
||||||
|
VITE_APP_VIP_PRODUCT_URL="https://app.handfree.work/subject#/app/certd/product"
|
||||||
|
|
@ -8,10 +8,10 @@ export async function doActive(form: any) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getVipTrial() {
|
export async function getVipTrial(vipType: string) {
|
||||||
return await request({
|
return await request({
|
||||||
url: "/sys/plus/getVipTrial",
|
url: "/sys/plus/getVipTrial",
|
||||||
method: "post",
|
method: "post",
|
||||||
data: {},
|
data: { vipType },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-if="!settingStore.isComm || userStore.isAdmin" class="layout-vip isPlus" @click="openUpgrade">
|
<div v-if="!settingStore.isComm || userStore.isAdmin" class="layout-vip isPlus" :class="{ isForever: settingStore.isForever }" @click="openUpgrade">
|
||||||
<contextHolder />
|
<contextHolder />
|
||||||
<fs-icon icon="mingcute:vip-1-line" :title="text.title" />
|
<fs-icon icon="mingcute:vip-1-line" :title="text.title" />
|
||||||
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="tsx" setup>
|
<script lang="tsx" setup>
|
||||||
import { computed, onMounted, reactive } from "vue";
|
import { computed, onMounted, reactive, ref } from "vue";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { message, Modal } from "ant-design-vue";
|
import { message, Modal } from "ant-design-vue";
|
||||||
import * as api from "./api";
|
import * as api from "./api";
|
||||||
|
|
@ -21,7 +21,7 @@ import { useRouter } from "vue-router";
|
||||||
import { useUserStore } from "/@/store/user";
|
import { useUserStore } from "/@/store/user";
|
||||||
import { mitter } from "/@/utils/util.mitt";
|
import { mitter } from "/@/utils/util.mitt";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { env } from "/@/utils/util.env";
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
|
|
@ -106,7 +106,7 @@ const text = computed<Text>(() => {
|
||||||
|
|
||||||
const expireTime = computed(() => {
|
const expireTime = computed(() => {
|
||||||
if (settingStore.isPlus) {
|
if (settingStore.isPlus) {
|
||||||
return dayjs(settingStore.plusInfo.expireTime).format("YYYY-MM-DD");
|
return settingStore.expiresText;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
});
|
});
|
||||||
|
|
@ -165,34 +165,38 @@ function goAccount() {
|
||||||
router.push("/sys/account");
|
router.push("/sys/account");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getVipTrial() {
|
async function getVipTrial(vipType = "plus") {
|
||||||
const res = await api.getVipTrial();
|
const res = await api.getVipTrial(vipType);
|
||||||
message.success(t("vip.congratulations_vip_trial", { duration: res.duration }));
|
message.success(t("vip.congratulations_vip_trial", { duration: res.duration }));
|
||||||
await settingStore.init();
|
await settingStore.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
function openTrialModal() {
|
function openTrialModal(vipType = "plus") {
|
||||||
Modal.destroyAll();
|
Modal.destroyAll();
|
||||||
|
|
||||||
modal.confirm({
|
modal.confirm({
|
||||||
title: t("vip.trial_modal_title"),
|
title: t("vip.trial_modal_title"),
|
||||||
okText: t("vip.trial_modal_ok_text"),
|
okText: t("vip.trial_modal_ok_text"),
|
||||||
onOk() {
|
onOk() {
|
||||||
getVipTrial();
|
getVipTrial(vipType);
|
||||||
},
|
},
|
||||||
width: 600,
|
width: 600,
|
||||||
content: () => {
|
content: () => {
|
||||||
return (
|
return (
|
||||||
<div class="flex-col mt-10 mb-10">
|
<div class="flex-col mt-10 mb-10">
|
||||||
<div>{t("vip.trial_modal_thanks")}</div>
|
<div>{t("vip.trial_modal_thanks")}</div>
|
||||||
<div>{t("vip.trial_modal_click_confirm")}</div>
|
<div>{t("vip.trial_modal_click_confirm", { vipType })}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function openStarModal() {
|
function openStarModal(vipType: string) {
|
||||||
|
if (settingStore.isPlus) {
|
||||||
|
message.error(t("vip.already_vip"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
Modal.destroyAll();
|
Modal.destroyAll();
|
||||||
const goGithub = () => {
|
const goGithub = () => {
|
||||||
window.open("https://github.com/certd/certd/");
|
window.open("https://github.com/certd/certd/");
|
||||||
|
|
@ -203,7 +207,7 @@ function openStarModal() {
|
||||||
okText: t("vip.star_now"),
|
okText: t("vip.star_now"),
|
||||||
onOk() {
|
onOk() {
|
||||||
goGithub();
|
goGithub();
|
||||||
openTrialModal();
|
openTrialModal(vipType);
|
||||||
},
|
},
|
||||||
width: 600,
|
width: 600,
|
||||||
content: () => {
|
content: () => {
|
||||||
|
|
@ -231,7 +235,49 @@ function openUpgrade() {
|
||||||
title = t("vip.renew_pro_upgrade_business");
|
title = t("vip.renew_pro_upgrade_business");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// const goBuyUrl = "https://afdian.com/a/greper"
|
||||||
|
const subjectId = settingStore.installInfo.siteId;
|
||||||
|
const appKey = settingStore.installInfo.appKey;
|
||||||
|
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}`;
|
||||||
|
const goBuyCommUrl = `${goBuyUrl}&vipType=comm`;
|
||||||
const productInfo = settingStore.productInfo;
|
const productInfo = settingStore.productInfo;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
const vipTypeDefine = {
|
const vipTypeDefine = {
|
||||||
free: {
|
free: {
|
||||||
title: t("vip.basic_edition"),
|
title: t("vip.basic_edition"),
|
||||||
|
|
@ -248,7 +294,7 @@ function openUpgrade() {
|
||||||
trial: {
|
trial: {
|
||||||
title: t("vip.click_to_get_7_day_trial"),
|
title: t("vip.click_to_get_7_day_trial"),
|
||||||
click: () => {
|
click: () => {
|
||||||
openStarModal();
|
openStarModal("plus");
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
icon: "stash:thumb-up",
|
icon: "stash:thumb-up",
|
||||||
|
|
@ -258,7 +304,7 @@ function openUpgrade() {
|
||||||
get() {
|
get() {
|
||||||
return (
|
return (
|
||||||
<a-tooltip title={t("vip.afdian_support_vip")}>
|
<a-tooltip title={t("vip.afdian_support_vip")}>
|
||||||
<a-button size="small" type="primary" href="https://afdian.com/a/greper" target="_blank">
|
<a-button size="small" type="primary" onClick={goBuyPlusPage}>
|
||||||
{t("vip.get_after_support")}
|
{t("vip.get_after_support")}
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
|
|
@ -274,30 +320,57 @@ function openUpgrade() {
|
||||||
price: productInfo.comm.price,
|
price: productInfo.comm.price,
|
||||||
price3: `¥${productInfo.comm.price3}/3${t("vip.years")}`,
|
price3: `¥${productInfo.comm.price3}/3${t("vip.years")}`,
|
||||||
tooltip: productInfo.comm.tooltip,
|
tooltip: productInfo.comm.tooltip,
|
||||||
|
trial: {
|
||||||
|
title: t("vip.click_to_get_7_day_trial"),
|
||||||
|
click: () => {
|
||||||
|
openStarModal("comm");
|
||||||
|
},
|
||||||
|
},
|
||||||
get() {
|
get() {
|
||||||
return <a-button size="small">{t("vip.contact_author_for_trial")}</a-button>;
|
return (
|
||||||
|
<a-button size="small" type="primary" onClick={goBuyCommPage}>
|
||||||
|
{t("vip.buy")}
|
||||||
|
</a-button>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const modalRef = modal.confirm({
|
const manualActiveFlag = ref();
|
||||||
|
function showManualActivation() {
|
||||||
|
manualActiveFlag.value = true;
|
||||||
|
}
|
||||||
|
const modalRef = modal.success({
|
||||||
title,
|
title,
|
||||||
async onOk() {
|
|
||||||
return await doActive();
|
|
||||||
},
|
|
||||||
maskClosable: true,
|
maskClosable: true,
|
||||||
okText: t("vip.activate"),
|
okText: t("vip.close"),
|
||||||
width: 1100,
|
width: 1100,
|
||||||
content: () => {
|
content: () => {
|
||||||
let activationCodeGetWay = (
|
let manualActiveBlock: any = "";
|
||||||
<span>
|
if (manualActiveFlag.value) {
|
||||||
<a href="https://afdian.com/a/greper" target="_blank">
|
manualActiveBlock = (
|
||||||
{t("vip.get_pro_code_after_support")}
|
<div>
|
||||||
</a>
|
<div class="mt-10">
|
||||||
<span> {t("vip.business_contact_author")}</span>
|
<a-input-search class="w-2/6" v-model:value={formState.code} placeholder={placeholder} enter-button={t("vip.activate")} onSearch={doActive}></a-input-search>
|
||||||
</span>
|
</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>
|
||||||
|
);
|
||||||
|
}
|
||||||
const vipLabel = settingStore.vipLabel;
|
const vipLabel = settingStore.vipLabel;
|
||||||
|
let plusInfo: any = "";
|
||||||
|
if (isPlus) {
|
||||||
|
plusInfo = (
|
||||||
|
<div class="mt-10">
|
||||||
|
{t("vip.current")} {vipLabel} {t("vip.activated_expire_time")}
|
||||||
|
{settingStore.expiresText}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const slots = [];
|
const slots = [];
|
||||||
for (const key in vipTypeDefine) {
|
for (const key in vipTypeDefine) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|
@ -363,26 +436,19 @@ function openUpgrade() {
|
||||||
<a-row gutter={20}>{slots}</a-row>
|
<a-row gutter={20}>{slots}</a-row>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-10">
|
<div class="mt-10">
|
||||||
<h3 class="block-header">{isPlus ? t("vip.renew") : t("vip.activate_immediately")}</h3>
|
<div class="flex-o w-100">
|
||||||
<div>{isPlus ? `${t("vip.current")} ${vipLabel} ${t("vip.activated_expire_time")}` + dayjs(settingStore.plusInfo.expireTime).format("YYYY-MM-DD") : ""}</div>
|
<span>{t("vip.site_id")}:</span>
|
||||||
<div class="mt-10">
|
<fs-copyable v-model={computedSiteId.value}></fs-copyable>
|
||||||
<div class="flex-o w-100">
|
|
||||||
<span>{t("vip.site_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} />
|
|
||||||
<a-input class="mt-10" v-model:value={formState.inviteCode} placeholder={t("vip.invite_code_optional")} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-10">
|
|
||||||
{t("vip.no_activation_code")}
|
|
||||||
{activationCodeGetWay}
|
|
||||||
</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>
|
||||||
</div>
|
</div>
|
||||||
|
{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>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -406,6 +472,10 @@ onMounted(() => {
|
||||||
|
|
||||||
&.isPlus {
|
&.isPlus {
|
||||||
color: #c5913f;
|
color: #c5913f;
|
||||||
|
|
||||||
|
&.isForever {
|
||||||
|
color: #ff2e83;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
|
|
@ -420,6 +490,11 @@ onMounted(() => {
|
||||||
border: 1px solid #eee;
|
border: 1px solid #eee;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
height: 275px;
|
height: 275px;
|
||||||
|
line-height: 24px;
|
||||||
|
|
||||||
|
.privilege {
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
//background-color: rgba(250, 237, 167, 0.79);
|
//background-color: rgba(250, 237, 167, 0.79);
|
||||||
&.current {
|
&.current {
|
||||||
|
|
|
||||||
|
|
@ -32,13 +32,14 @@ export default {
|
||||||
successContent: "You have successfully activated {vipLabel}, valid until: {expireDate}",
|
successContent: "You have successfully activated {vipLabel}, valid until: {expireDate}",
|
||||||
bindAccountTitle: "Bind Your Account",
|
bindAccountTitle: "Bind Your Account",
|
||||||
bindAccountContent: "Binding your account helps prevent license loss. Strongly recommended.",
|
bindAccountContent: "Binding your account helps prevent license loss. Strongly recommended.",
|
||||||
congratulations_vip_trial: "Congratulations, you have received a Pro version {duration} days trial",
|
congratulations_vip_trial: "Congratulations, you have received a VIP version {duration} days trial",
|
||||||
trial_modal_title: "7-day Pro version trial acquisition",
|
trial_modal_title: "7-day VIP version trial acquisition",
|
||||||
trial_modal_ok_text: "Get now",
|
trial_modal_ok_text: "Get now",
|
||||||
trial_modal_thanks: "Thank you for supporting the open source project",
|
trial_modal_thanks: "Thank you for supporting the open source project",
|
||||||
trial_modal_click_confirm: "Click confirm to get a 7-day Pro version trial",
|
trial_modal_click_confirm: "Click confirm to get a 7-day VIP({vipType}) version trial",
|
||||||
get_7_day_pro_trial: "7-day professional version trial",
|
get_7_day_pro_trial: "7-day VIP version trial",
|
||||||
star_now: "Star Now",
|
star_now: "Star Now",
|
||||||
|
already_vip: "Already VIP version, can't trial ",
|
||||||
please_help_star: "Could you please help by starring? Thanks a lot!",
|
please_help_star: "Could you please help by starring? Thanks a lot!",
|
||||||
admin_only_operation: "Admin operation only",
|
admin_only_operation: "Admin operation only",
|
||||||
enter_activation_code: "Please enter the activation code",
|
enter_activation_code: "Please enter the activation code",
|
||||||
|
|
@ -61,7 +62,7 @@ export default {
|
||||||
plugins_fully_open: "All plugins open, including Synology and more",
|
plugins_fully_open: "All plugins open, including Synology and more",
|
||||||
click_to_get_7_day_trial: "Click to get 7-day trial",
|
click_to_get_7_day_trial: "Click to get 7-day trial",
|
||||||
years: "years",
|
years: "years",
|
||||||
afdian_support_vip: 'Get a one-year professional activation code after supporting "VIP membership" on Afdian, open source needs your support',
|
afdian_support_vip: "Obtain the permanent professional version coupon",
|
||||||
get_after_support: "Get after sponsoring",
|
get_after_support: "Get after sponsoring",
|
||||||
|
|
||||||
business_edition: "Business Edition",
|
business_edition: "Business Edition",
|
||||||
|
|
@ -72,9 +73,9 @@ export default {
|
||||||
plugin_management: "Plugin management",
|
plugin_management: "Plugin management",
|
||||||
unlimited_multi_users: "Unlimited multi-users",
|
unlimited_multi_users: "Unlimited multi-users",
|
||||||
support_user_payment: "Supports user payments",
|
support_user_payment: "Supports user payments",
|
||||||
contact_author_for_trial: "Please contact the author for trial",
|
contact_author_for_trial: "Buy It Now",
|
||||||
activate: "Activate",
|
activate: "Activate",
|
||||||
get_pro_code_after_support: 'Get a one-year professional activation code after supporting "VIP membership" on Afdian',
|
get_pro_code_after_support: "Go to sponsoring",
|
||||||
business_contact_author: "Business edition please contact the author directly",
|
business_contact_author: "Business edition please contact the author directly",
|
||||||
year: "year",
|
year: "year",
|
||||||
freee: "Free",
|
freee: "Free",
|
||||||
|
|
@ -89,4 +90,12 @@ export default {
|
||||||
bind_account: "bind account",
|
bind_account: "bind account",
|
||||||
transfer_vip: ' then "Transfer VIP"',
|
transfer_vip: ' then "Transfer VIP"',
|
||||||
needVipTip: "This feature requires a professional version, please upgrade to a professional version first.",
|
needVipTip: "This feature requires a professional version, please upgrade to a professional version first.",
|
||||||
|
manual_activation: "Manual activation use code",
|
||||||
|
close: "Close",
|
||||||
|
have_activation_code: "Already have activation code?",
|
||||||
|
buy: "Buy",
|
||||||
|
already_plus: "Already Professional Edition, will upgrade to Business Edition, Professional Edition time will be lost",
|
||||||
|
already_comm: "Already Business Edition, can't change to Professional Edition",
|
||||||
|
already_perpetual_plus: "You already have a perpetual Professional Edition, can't upgrade",
|
||||||
|
confirm: "Confirm",
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -32,13 +32,14 @@ export default {
|
||||||
successContent: "您已成功激活{vipLabel},有效期至:{expireDate}",
|
successContent: "您已成功激活{vipLabel},有效期至:{expireDate}",
|
||||||
bindAccountTitle: "是否绑定袖手账号",
|
bindAccountTitle: "是否绑定袖手账号",
|
||||||
bindAccountContent: "绑定账号后,可以避免License丢失,强烈建议绑定",
|
bindAccountContent: "绑定账号后,可以避免License丢失,强烈建议绑定",
|
||||||
congratulations_vip_trial: "恭喜,您已获得专业版{duration}天试用",
|
congratulations_vip_trial: "恭喜,您已获得VIP{duration}天试用",
|
||||||
trial_modal_title: "7天专业版试用获取",
|
trial_modal_title: "7天VIP试用获取",
|
||||||
trial_modal_ok_text: "立即获取",
|
trial_modal_ok_text: "立即获取",
|
||||||
trial_modal_thanks: "感谢您对开源项目的支持",
|
trial_modal_thanks: "感谢您对开源项目的支持",
|
||||||
trial_modal_click_confirm: "点击确认,即可获取7天专业版试用",
|
trial_modal_click_confirm: "点击确认,即可获取7天VIP({vipType})试用",
|
||||||
get_7_day_pro_trial: "7天专业版试用获取",
|
get_7_day_pro_trial: "7天VIP试用获取",
|
||||||
star_now: "立即去Star",
|
star_now: "立即去Star",
|
||||||
|
already_vip: "您已经是VIP了,不能试用",
|
||||||
please_help_star: "可以先请您帮忙点个star吗?感谢感谢",
|
please_help_star: "可以先请您帮忙点个star吗?感谢感谢",
|
||||||
admin_only_operation: "仅限管理员操作",
|
admin_only_operation: "仅限管理员操作",
|
||||||
enter_activation_code: "请输入激活码",
|
enter_activation_code: "请输入激活码",
|
||||||
|
|
@ -61,8 +62,8 @@ export default {
|
||||||
plugins_fully_open: "插件全开放,群辉等更多插件",
|
plugins_fully_open: "插件全开放,群辉等更多插件",
|
||||||
click_to_get_7_day_trial: "点击获取7天试用",
|
click_to_get_7_day_trial: "点击获取7天试用",
|
||||||
years: "年",
|
years: "年",
|
||||||
afdian_support_vip: "爱发电赞助“VIP会员”后获取一年期专业版激活码,开源需要您的支持",
|
afdian_support_vip: "新用户开通永久专业版立享50优惠券",
|
||||||
get_after_support: "爱发电赞助后获取",
|
get_after_support: "立即赞助",
|
||||||
|
|
||||||
business_edition: "商业版",
|
business_edition: "商业版",
|
||||||
commercial_license: "商业授权,可对外运营",
|
commercial_license: "商业授权,可对外运营",
|
||||||
|
|
@ -72,10 +73,9 @@ export default {
|
||||||
plugin_management: "插件管理",
|
plugin_management: "插件管理",
|
||||||
unlimited_multi_users: "多用户无限制",
|
unlimited_multi_users: "多用户无限制",
|
||||||
support_user_payment: "支持用户支付",
|
support_user_payment: "支持用户支付",
|
||||||
contact_author_for_trial: "请联系作者获取试用",
|
|
||||||
activate: "激活",
|
activate: "激活",
|
||||||
get_pro_code_after_support: "爱发电赞助“VIP会员”后获取一年期专业版激活码",
|
get_pro_code_after_support: "前往获取",
|
||||||
business_contact_author: "商业版请直接联系作者",
|
business_contact_author: "",
|
||||||
year: "年",
|
year: "年",
|
||||||
freee: "免费",
|
freee: "免费",
|
||||||
renew: "续期",
|
renew: "续期",
|
||||||
|
|
@ -89,4 +89,12 @@ export default {
|
||||||
bind_account: "绑定账号",
|
bind_account: "绑定账号",
|
||||||
transfer_vip: ',然后"转移VIP"即可',
|
transfer_vip: ',然后"转移VIP"即可',
|
||||||
needVipTip: "此为专业版功能,请先开通专业版",
|
needVipTip: "此为专业版功能,请先开通专业版",
|
||||||
|
manual_activation: "激活码手动激活",
|
||||||
|
close: "关闭",
|
||||||
|
have_activation_code: "已经有激活码了?",
|
||||||
|
buy: "立即购买",
|
||||||
|
already_plus: "已经是专业版了,是否升级为商业版?注意:专业版时长将被覆盖",
|
||||||
|
already_comm: "已经是商业版了,不能降级为专业版",
|
||||||
|
already_perpetual_plus: "您已经是永久专业版了,无法继续升级",
|
||||||
|
confirm: "确认",
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import { useTitle } from "@vueuse/core";
|
||||||
import { utils } from "/@/utils";
|
import { utils } from "/@/utils";
|
||||||
import { cloneDeep, merge } from "lodash-es";
|
import { cloneDeep, merge } from "lodash-es";
|
||||||
import { useI18n } from "/src/locales";
|
import { useI18n } from "/src/locales";
|
||||||
|
import dayjs from "dayjs";
|
||||||
import { $t } from "/src/locales";
|
import { $t } from "/src/locales";
|
||||||
export interface SettingState {
|
export interface SettingState {
|
||||||
skipReset?: boolean; // 注销登录时,不清空此store的状态
|
skipReset?: boolean; // 注销登录时,不清空此store的状态
|
||||||
|
|
@ -126,12 +127,14 @@ export const useSettingStore = defineStore({
|
||||||
getInstallInfo(): SysInstallInfo {
|
getInstallInfo(): SysInstallInfo {
|
||||||
return this.installInfo;
|
return this.installInfo;
|
||||||
},
|
},
|
||||||
|
isPerpetual(): boolean {
|
||||||
|
return this.plusInfo?.isPlus && this.plusInfo?.expireTime === -1;
|
||||||
|
},
|
||||||
isPlus(): boolean {
|
isPlus(): boolean {
|
||||||
return this.plusInfo?.isPlus && this.plusInfo?.expireTime > new Date().getTime();
|
return this.plusInfo?.isPlus && (this.plusInfo?.expireTime === -1 || this.plusInfo?.expireTime > new Date().getTime());
|
||||||
// return false;
|
|
||||||
},
|
},
|
||||||
isComm(): boolean {
|
isComm(): boolean {
|
||||||
return this.plusInfo?.isComm && this.plusInfo?.expireTime > new Date().getTime();
|
return this.plusInfo?.isComm && (this.plusInfo?.expireTime === -1 || this.plusInfo?.expireTime > new Date().getTime());
|
||||||
},
|
},
|
||||||
isAgent(): boolean {
|
isAgent(): boolean {
|
||||||
return this.siteEnv?.agent?.enabled === true;
|
return this.siteEnv?.agent?.enabled === true;
|
||||||
|
|
@ -139,6 +142,18 @@ export const useSettingStore = defineStore({
|
||||||
isCommOrAgent() {
|
isCommOrAgent() {
|
||||||
return this.isComm || this.isAgent;
|
return this.isComm || this.isAgent;
|
||||||
},
|
},
|
||||||
|
expiresText() {
|
||||||
|
if (this.plusInfo?.expireTime == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (this.plusInfo?.expireTime === -1) {
|
||||||
|
return "永久";
|
||||||
|
}
|
||||||
|
return dayjs(this.plusInfo?.expireTime).format("YYYY-MM-DD");
|
||||||
|
},
|
||||||
|
isForever() {
|
||||||
|
return this.isPlus && this.plusInfo?.expireTime === -1;
|
||||||
|
},
|
||||||
vipLabel(): string {
|
vipLabel(): string {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const vipLabelMap: any = {
|
const vipLabelMap: any = {
|
||||||
|
|
|
||||||
|
|
@ -6,22 +6,28 @@ export function getEnvValue(key: string) {
|
||||||
|
|
||||||
export class EnvConfig {
|
export class EnvConfig {
|
||||||
MODE: string = import.meta.env.MODE;
|
MODE: string = import.meta.env.MODE;
|
||||||
API: string = import.meta.env.VITE_APP_API;
|
API: string;
|
||||||
STORAGE: string = import.meta.env.VITE_APP_STORAGE;
|
STORAGE: string;
|
||||||
TITLE: string = import.meta.env.VITE_APP_TITLE;
|
TITLE: string;
|
||||||
SLOGAN: string = import.meta.env.VITE_APP_SLOGAN;
|
SLOGAN: string;
|
||||||
LOGO: string = import.meta.env.VITE_APP_LOGO;
|
LOGO: string;
|
||||||
LOGIN_LOGO: string = import.meta.env.VITE_APP_LOGIN_LOGO;
|
LOGIN_LOGO: string;
|
||||||
ICP_NO: string = import.meta.env.VITE_APP_ICP_NO;
|
ICP_NO: string;
|
||||||
COPYRIGHT_YEAR: string = import.meta.env.VITE_APP_COPYRIGHT_YEAR;
|
COPYRIGHT_YEAR: string;
|
||||||
COPYRIGHT_NAME: string = import.meta.env.VITE_APP_COPYRIGHT_NAME;
|
COPYRIGHT_NAME: string;
|
||||||
COPYRIGHT_URL: string = import.meta.env.VITE_APP_COPYRIGHT_URL;
|
COPYRIGHT_URL: string;
|
||||||
PM_ENABLED: string = import.meta.env.VITE_APP_PM_ENABLED;
|
PM_ENABLED: string;
|
||||||
|
VIP_PRODUCT_URL: string;
|
||||||
|
|
||||||
init(env: any) {
|
constructor() {
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
init() {
|
||||||
|
const env = import.meta.env;
|
||||||
for (const key in this) {
|
for (const key in this) {
|
||||||
if (this.hasOwnProperty(key)) {
|
const metaKey = "VITE_APP_" + key;
|
||||||
this[key] = env[key];
|
if (this.hasOwnProperty(key) && env.hasOwnProperty(metaKey)) {
|
||||||
|
this[key] = env[metaKey];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -375,7 +375,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
createTime: {
|
createTime: {
|
||||||
title: t("certd.create_time"),
|
title: t("certd.createTime"),
|
||||||
type: "datetime",
|
type: "datetime",
|
||||||
form: {
|
form: {
|
||||||
show: false,
|
show: false,
|
||||||
|
|
@ -387,7 +387,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
updateTime: {
|
updateTime: {
|
||||||
title: t("certd.update_time"),
|
title: t("certd.updateTime"),
|
||||||
type: "datetime",
|
type: "datetime",
|
||||||
form: {
|
form: {
|
||||||
show: false,
|
show: false,
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
typeorm:
|
typeorm:
|
||||||
dataSource:
|
dataSource:
|
||||||
default:
|
default:
|
||||||
database: './data/db-plus-dev-1.sqlite'
|
database: './data/db-plus-dev.sqlite'
|
||||||
|
|
||||||
# plus server: 'http://127.0.0.1:11007'
|
# plus server: 'http://127.0.0.1:11007'
|
||||||
account:
|
account:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core';
|
import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core';
|
||||||
import { BaseController, PlusService, SysInstallInfo, SysSettingsService } from '@certd/lib-server';
|
import { BaseController, PlusService, SysInstallInfo, SysSettingsService } from '@certd/lib-server';
|
||||||
|
import { logger } from '@certd/basic';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
|
|
@ -31,15 +32,20 @@ export class SysPlusController extends BaseController {
|
||||||
installInfo.bindUrl = url;
|
installInfo.bindUrl = url;
|
||||||
await this.sysSettingsService.saveSetting(installInfo);
|
await this.sysSettingsService.saveSetting(installInfo);
|
||||||
|
|
||||||
//重新验证配置
|
//重新验证vip
|
||||||
await this.plusService.verify();
|
try{
|
||||||
|
await this.plusService.verify();
|
||||||
|
}catch(e){
|
||||||
|
logger.error(`验证配置失败:${e}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return this.ok(true);
|
return this.ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('/getVipTrial', { summary: 'sys:settings:edit' })
|
@Post('/getVipTrial', { summary: 'sys:settings:edit' })
|
||||||
async getVipTrial(@Body(ALL) body) {
|
async getVipTrial(@Body("vipType") vipType?:string) {
|
||||||
const res = await this.plusService.getVipTrial();
|
const res = await this.plusService.getVipTrial(vipType);
|
||||||
return this.ok(res);
|
return this.ok(res);
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -134,6 +134,8 @@ export class CnameRecordService extends BaseService<CnameRecordEntity> {
|
||||||
if (!param.id) {
|
if (!param.id) {
|
||||||
throw new ValidateException("id不能为空");
|
throw new ValidateException("id不能为空");
|
||||||
}
|
}
|
||||||
|
//hostRecord包含所有权校验信息,不允许用户修改hostRecord
|
||||||
|
delete param.hostRecord
|
||||||
|
|
||||||
const old = await this.info(param.id);
|
const old = await this.info(param.id);
|
||||||
if (!old) {
|
if (!old) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue