mirror of https://github.com/certd/certd
First translation step
parent
f1a25b21a6
commit
3ab99647aa
|
@ -8,8 +8,6 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import zhCN from "ant-design-vue/es/locale/zh_CN";
|
|
||||||
import enUS from "ant-design-vue/es/locale/en_US";
|
|
||||||
import { computed, onMounted, provide, ref } from "vue";
|
import { computed, onMounted, provide, ref } from "vue";
|
||||||
import "dayjs/locale/zh-cn";
|
import "dayjs/locale/zh-cn";
|
||||||
import "dayjs/locale/en";
|
import "dayjs/locale/en";
|
||||||
|
@ -27,26 +25,6 @@ defineOptions({
|
||||||
});
|
});
|
||||||
const [modal, contextHolder] = Modal.useModal();
|
const [modal, contextHolder] = Modal.useModal();
|
||||||
provide("modal", modal);
|
provide("modal", modal);
|
||||||
//刷新页面方法
|
|
||||||
const locale = ref(zhCN);
|
|
||||||
async function reload() {}
|
|
||||||
localeChanged("zh-cn");
|
|
||||||
provide("fn:router.reload", reload);
|
|
||||||
provide("fn:locale.changed", localeChanged);
|
|
||||||
//刷新页面方法
|
|
||||||
function localeChanged(value: any) {
|
|
||||||
console.log("locale changed:", value);
|
|
||||||
if (value === "zh-cn") {
|
|
||||||
locale.value = zhCN;
|
|
||||||
dayjs.locale("zh-cn");
|
|
||||||
} else if (value === "en") {
|
|
||||||
locale.value = enUS;
|
|
||||||
dayjs.locale("en");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
localeChanged("zh-cn");
|
|
||||||
provide("fn:router.reload", reload);
|
|
||||||
provide("fn:locale.changed", localeChanged);
|
|
||||||
|
|
||||||
|
|
||||||
const { isDark } = usePreferences();
|
const { isDark } = usePreferences();
|
||||||
|
@ -65,13 +43,5 @@ const tokenTheme = computed(() => {
|
||||||
token: tokens,
|
token: tokens,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
//其他初始化
|
|
||||||
// const resourceStore = useResourceStore();
|
|
||||||
// resourceStore.init();
|
|
||||||
// const pageStore = usePageStore();
|
|
||||||
// pageStore.init();
|
|
||||||
// const settingStore = useSettingStore();
|
|
||||||
// settingStore.init();
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -16,18 +16,23 @@ const slots = defineSlots();
|
||||||
<template>
|
<template>
|
||||||
<div class="tutorial-button pointer" @click="open">
|
<div class="tutorial-button pointer" @click="open">
|
||||||
<template v-if="!slots.default">
|
<template v-if="!slots.default">
|
||||||
<fs-icon v-if="showIcon === false" icon="ant-design:question-circle-outlined" class="mr-0.5"></fs-icon>
|
<fs-icon
|
||||||
<div class="hidden md:block">使用教程</div>
|
v-if="showIcon === false"
|
||||||
|
icon="ant-design:question-circle-outlined"
|
||||||
|
class="mr-0.5"
|
||||||
|
></fs-icon>
|
||||||
|
<div class="hidden md:block">{{$t('tutorial.title')}}</div>
|
||||||
</template>
|
</template>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
<a-modal v-model:open="openedRef" class="tutorial-modal" width="90%">
|
<a-modal v-model:open="openedRef" class="tutorial-modal" width="90%">
|
||||||
<template #title> 使用教程 </template>
|
<template #title>{{$t('tutorial.title')}}</template>
|
||||||
<tutorial-steps v-if="openedRef" />
|
<tutorial-steps v-if="openedRef" />
|
||||||
<template #footer></template>
|
<template #footer></template>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
.tutorial-modal {
|
.tutorial-modal {
|
||||||
top: 50px;
|
top: 50px;
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
type Step = {
|
type Step = {
|
||||||
title: string;
|
title: string;
|
||||||
|
@ -13,15 +16,9 @@ type Step = {
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
|
|
||||||
const steps = ref<Step[]>([
|
const steps = ref<Step[]>([
|
||||||
{
|
{ title: t('certd.steps.createPipeline') },
|
||||||
title: "创建证书流水线"
|
{ title: t('certd.steps.addTask') },
|
||||||
},
|
{ title: t('certd.steps.scheduledRun') }
|
||||||
{
|
|
||||||
title: "添加部署任务"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "定时运行"
|
|
||||||
}
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
<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"
|
||||||
|
@click="openUpgrade"
|
||||||
|
>
|
||||||
<contextHolder />
|
<contextHolder />
|
||||||
<fs-icon icon="mingcute:vip-1-line" :title="text.title" />
|
<fs-icon icon="mingcute:vip-1-line" :title="text.title" />
|
||||||
|
|
||||||
|
@ -20,6 +24,9 @@ import { useSettingStore } from "/@/store/settings";
|
||||||
import { useRouter } from "vue-router";
|
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";
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
|
@ -39,56 +46,56 @@ const text = computed<Text>(() => {
|
||||||
const map = {
|
const map = {
|
||||||
isComm: {
|
isComm: {
|
||||||
comm: {
|
comm: {
|
||||||
name: `${vipLabel}已开通`,
|
name: t("vip.comm.name", { vipLabel }),
|
||||||
title: "到期时间:" + expireTime.value,
|
title: t("vip.comm.title", { expire: expireTime.value }),
|
||||||
},
|
},
|
||||||
button: {
|
button: {
|
||||||
name: `${vipLabel}已开通`,
|
name: t("vip.comm.name", { vipLabel }),
|
||||||
title: "到期时间:" + expireTime.value,
|
title: t("vip.comm.title", { expire: expireTime.value }),
|
||||||
},
|
},
|
||||||
icon: {
|
icon: {
|
||||||
name: "",
|
name: "",
|
||||||
title: `${vipLabel}已开通`,
|
title: t("vip.comm.name", { vipLabel }),
|
||||||
},
|
},
|
||||||
nav: {
|
nav: {
|
||||||
name: `${vipLabel}`,
|
name: t("vip.comm.nav", { vipLabel }),
|
||||||
title: "到期时间:" + expireTime.value,
|
title: t("vip.comm.title", { expire: expireTime.value }),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
isPlus: {
|
isPlus: {
|
||||||
comm: {
|
comm: {
|
||||||
name: "商业版功能",
|
name: t("vip.plus.name"),
|
||||||
title: "升级商业版,获取商业授权",
|
title: t("vip.plus.title"),
|
||||||
},
|
},
|
||||||
button: {
|
button: {
|
||||||
name: `${vipLabel}已开通`,
|
name: t("vip.comm.name", { vipLabel }),
|
||||||
title: "到期时间:" + expireTime.value,
|
title: t("vip.comm.title", { expire: expireTime.value }),
|
||||||
},
|
},
|
||||||
icon: {
|
icon: {
|
||||||
name: "",
|
name: "",
|
||||||
title: `${vipLabel}已开通`,
|
title: t("vip.comm.name", { vipLabel }),
|
||||||
},
|
},
|
||||||
nav: {
|
nav: {
|
||||||
name: `${vipLabel}`,
|
name: t("vip.comm.nav", { vipLabel }),
|
||||||
title: "到期时间:" + expireTime.value,
|
title: t("vip.comm.title", { expire: expireTime.value }),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
free: {
|
free: {
|
||||||
comm: {
|
comm: {
|
||||||
name: "商业版功能",
|
name: t("vip.free.comm.name"),
|
||||||
title: "升级商业版,获取商业授权",
|
title: t("vip.free.comm.title"),
|
||||||
},
|
},
|
||||||
button: {
|
button: {
|
||||||
name: "专业版功能",
|
name: t("vip.free.button.name"),
|
||||||
title: "升级专业版,享受更多VIP特权",
|
title: t("vip.free.button.title"),
|
||||||
},
|
},
|
||||||
icon: {
|
icon: {
|
||||||
name: "",
|
name: "",
|
||||||
title: "专业版功能",
|
title: t("vip.free.button.name"),
|
||||||
},
|
},
|
||||||
nav: {
|
nav: {
|
||||||
name: "基础版",
|
name: t("vip.free.nav.name"),
|
||||||
title: "升级专业版,享受更多VIP特权",
|
title: t("vip.free.nav.title"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -101,6 +108,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 dayjs(settingStore.plusInfo.expireTime).format("YYYY-MM-DD");
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
import en from "./locale/en";
|
|
||||||
import zh from "./locale/zh_CN";
|
|
||||||
import { SupportedLanguagesType } from "/@/vben/locales";
|
|
||||||
export const messages = {
|
|
||||||
"en-US": {
|
|
||||||
label: "English",
|
|
||||||
...en
|
|
||||||
},
|
|
||||||
"zh-CN": {
|
|
||||||
label: "简体中文",
|
|
||||||
...zh
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// export default createI18n({
|
|
||||||
// legacy: false,
|
|
||||||
// locale: "zh-cn",
|
|
||||||
// fallbackLocale: "zh-cn",
|
|
||||||
// messages
|
|
||||||
// });
|
|
||||||
|
|
||||||
export async function loadMessages(lang: SupportedLanguagesType) {
|
|
||||||
return messages[lang];
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
export default {
|
|
||||||
app: { crud: { i18n: { name: "name", city: "city", status: "status" } } },
|
|
||||||
fs: {
|
|
||||||
rowHandle: {
|
|
||||||
title: "Operation"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,14 +0,0 @@
|
||||||
export default {
|
|
||||||
app: {
|
|
||||||
crud: { i18n: { name: "姓名", city: "城市", status: "状态" } },
|
|
||||||
login: {
|
|
||||||
logoutTip: "确认",
|
|
||||||
logoutMessage: "确定要注销登录吗?",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
fs: {
|
|
||||||
rowHandle: {
|
|
||||||
title: "操作列",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -1,13 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<a-dropdown>
|
<a-dropdown>
|
||||||
<div class="fs-user-info">您好,{{ userStore.getUserInfo?.nickName || userStore.getUserInfo?.username }}</div>
|
<div class="fs-user-info">{{ t('user.greeting') }},{{ userStore.getUserInfo?.nickName || userStore.getUserInfo?.username }}</div>
|
||||||
<template #overlay>
|
<template #overlay>
|
||||||
<a-menu>
|
<a-menu>
|
||||||
<a-menu-item>
|
<a-menu-item>
|
||||||
<div @click="goUserProfile">账号信息</div>
|
<div @click="goUserProfile">{{ t('user.profile') }}</div>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item>
|
<a-menu-item>
|
||||||
<div @click="doLogout">注销登录</div>
|
<div @click="doLogout">{{ t('user.logout') }}</div>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
</a-menu>
|
</a-menu>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
import type { App } from "vue";
|
||||||
|
import type { Locale } from "vue-i18n";
|
||||||
|
|
||||||
|
import type { ImportLocaleFn, LoadMessageFn, LocaleSetupOptions, SupportedLanguagesType } from "./typing";
|
||||||
|
|
||||||
|
import { unref } from "vue";
|
||||||
|
import { createI18n } from "vue-i18n";
|
||||||
|
import en_US from './langs/en-US/index';
|
||||||
|
import zh_CH from './langs/zh-CN/index';
|
||||||
|
|
||||||
|
import { useSimpleLocale } from "/@/vben/composables";
|
||||||
|
|
||||||
|
const i18n = createI18n({
|
||||||
|
globalInjection: true,
|
||||||
|
legacy: false,
|
||||||
|
fallbackLocale: 'en_US',
|
||||||
|
locale: 'en_US',
|
||||||
|
messages: {
|
||||||
|
zh_CH: zh_CH,
|
||||||
|
en_US: en_US
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const modules = import.meta.glob("./langs/**/*.json");
|
||||||
|
|
||||||
|
const { setSimpleLocale } = useSimpleLocale();
|
||||||
|
|
||||||
|
const localesMap = loadLocalesMapFromDir(/\.\/langs\/([^/]+)\/(.*)\.json$/, modules);
|
||||||
|
let loadMessages: LoadMessageFn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load locale modules
|
||||||
|
* @param modules
|
||||||
|
*/
|
||||||
|
function loadLocalesMap(modules: Record<string, () => Promise<unknown>>) {
|
||||||
|
const localesMap: Record<Locale, ImportLocaleFn> = {};
|
||||||
|
|
||||||
|
for (const [path, loadLocale] of Object.entries(modules)) {
|
||||||
|
const key = path.match(/([\w-]*)\.(json)/)?.[1];
|
||||||
|
if (key) {
|
||||||
|
localesMap[key] = loadLocale as ImportLocaleFn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return localesMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load locale modules with directory structure
|
||||||
|
* @param regexp - Regular expression to match language and file names
|
||||||
|
* @param modules - The modules object containing paths and import functions
|
||||||
|
* @returns A map of locales to their corresponding import functions
|
||||||
|
*/
|
||||||
|
function loadLocalesMapFromDir(regexp: RegExp, modules: Record<string, () => Promise<unknown>>): Record<Locale, ImportLocaleFn> {
|
||||||
|
const localesRaw: Record<Locale, Record<string, () => Promise<unknown>>> = {};
|
||||||
|
const localesMap: Record<Locale, ImportLocaleFn> = {};
|
||||||
|
|
||||||
|
// Iterate over the modules to extract language and file names
|
||||||
|
for (const path in modules) {
|
||||||
|
const match = path.match(regexp);
|
||||||
|
if (match) {
|
||||||
|
const [_, locale, fileName] = match;
|
||||||
|
if (locale && fileName) {
|
||||||
|
if (!localesRaw[locale]) {
|
||||||
|
localesRaw[locale] = {};
|
||||||
|
}
|
||||||
|
if (modules[path]) {
|
||||||
|
localesRaw[locale][fileName] = modules[path];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert raw locale data into async import functions
|
||||||
|
for (const [locale, files] of Object.entries(localesRaw)) {
|
||||||
|
localesMap[locale] = async () => {
|
||||||
|
const messages: Record<string, any> = {};
|
||||||
|
for (const [fileName, importFn] of Object.entries(files)) {
|
||||||
|
messages[fileName] = ((await importFn()) as any)?.default;
|
||||||
|
}
|
||||||
|
return { default: messages };
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return localesMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set i18n language
|
||||||
|
* @param locale
|
||||||
|
*/
|
||||||
|
function setI18nLanguage(locale: Locale) {
|
||||||
|
i18n.global.locale.value = locale;
|
||||||
|
|
||||||
|
document?.querySelector("html")?.setAttribute("lang", locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setupI18n(app: App, options: LocaleSetupOptions = {}) {
|
||||||
|
const { defaultLocale = "en-US" } = options;
|
||||||
|
// app可以自行扩展一些第三方库和组件库的国际化
|
||||||
|
loadMessages = options.loadMessages || (async () => ({}));
|
||||||
|
app.use(i18n);
|
||||||
|
await loadLocaleMessages(defaultLocale);
|
||||||
|
|
||||||
|
// 在控制台打印警告
|
||||||
|
i18n.global.setMissingHandler((locale, key) => {
|
||||||
|
if (options.missingWarn && key.includes(".")) {
|
||||||
|
console.warn(`[intlify] Not found '${key}' key in '${locale}' locale messages.`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load locale messages
|
||||||
|
* @param lang
|
||||||
|
*/
|
||||||
|
async function loadLocaleMessages(lang: SupportedLanguagesType) {
|
||||||
|
if (unref(i18n.global.locale) === lang) {
|
||||||
|
return setI18nLanguage(lang);
|
||||||
|
}
|
||||||
|
setSimpleLocale(lang);
|
||||||
|
|
||||||
|
const message = await localesMap[lang]?.();
|
||||||
|
|
||||||
|
if (message?.default) {
|
||||||
|
i18n.global.setLocaleMessage(lang, message.default);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mergeMessage = await loadMessages(lang);
|
||||||
|
i18n.global.mergeLocaleMessage(lang, mergeMessage);
|
||||||
|
|
||||||
|
return setI18nLanguage(lang);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { i18n, loadLocaleMessages, loadLocalesMap, loadLocalesMapFromDir, setupI18n };
|
||||||
|
export default i18n;
|
|
@ -0,0 +1,80 @@
|
||||||
|
export default {
|
||||||
|
"welcomeBack": "Welcome Back",
|
||||||
|
"pageTitle": "Plug-and-play Admin system",
|
||||||
|
"pageDesc": "Efficient, versatile frontend template",
|
||||||
|
"loginSuccess": "Login Successful",
|
||||||
|
"loginSuccessDesc": "Welcome Back",
|
||||||
|
"loginSubtitle": "Enter your account details to manage your projects",
|
||||||
|
"selectAccount": "Quick Select Account",
|
||||||
|
"username": "Username",
|
||||||
|
"password": "Password",
|
||||||
|
"usernameTip": "Please enter username",
|
||||||
|
"passwordErrorTip": "Password is incorrect",
|
||||||
|
"passwordTip": "Please enter password",
|
||||||
|
"verifyRequiredTip": "Please complete the verification first",
|
||||||
|
"rememberMe": "Remember Me",
|
||||||
|
"createAnAccount": "Create an Account",
|
||||||
|
"createAccount": "Create Account",
|
||||||
|
"alreadyHaveAccount": "Already have an account?",
|
||||||
|
"accountTip": "Don't have an account?",
|
||||||
|
"signUp": "Sign Up",
|
||||||
|
"signUpSubtitle": "Make managing your applications simple and fun",
|
||||||
|
"confirmPassword": "Confirm Password",
|
||||||
|
"confirmPasswordTip": "The passwords do not match",
|
||||||
|
"agree": "I agree to",
|
||||||
|
"privacyPolicy": "Privacy-policy",
|
||||||
|
"terms": "Terms",
|
||||||
|
"agreeTip": "Please agree to the Privacy Policy and Terms",
|
||||||
|
"goToLogin": "Login instead",
|
||||||
|
"passwordStrength": "Use 8 or more characters with a mix of letters, numbers & symbols",
|
||||||
|
"forgetPassword": "Forget Password?",
|
||||||
|
"forgetPasswordSubtitle": "Enter your email and we'll send you instructions to reset your password",
|
||||||
|
"emailTip": "Please enter email",
|
||||||
|
"emailValidErrorTip": "The email format you entered is incorrect",
|
||||||
|
"sendResetLink": "Send Reset Link",
|
||||||
|
"email": "Email",
|
||||||
|
"qrcodeSubtitle": "Scan the QR code with your phone to login",
|
||||||
|
"qrcodePrompt": "Click 'Confirm' after scanning to complete login",
|
||||||
|
"qrcodeLogin": "QR Code Login",
|
||||||
|
"codeSubtitle": "Enter your phone number to start managing your project",
|
||||||
|
"code": "Security code",
|
||||||
|
"codeTip": "Security code required {0} characters",
|
||||||
|
"mobile": "Mobile",
|
||||||
|
"mobileLogin": "Mobile Login",
|
||||||
|
"mobileTip": "Please enter mobile number",
|
||||||
|
"mobileErrortip": "The phone number format is incorrect",
|
||||||
|
"sendCode": "Get Security code",
|
||||||
|
"sendText": "Resend in {0}s",
|
||||||
|
"thirdPartyLogin": "Or continue with",
|
||||||
|
"loginAgainTitle": "Please Log In Again",
|
||||||
|
"loginAgainSubTitle": "Your login session has expired. Please log in again to continue.",
|
||||||
|
"layout": {
|
||||||
|
"center": "Align Center",
|
||||||
|
"alignLeft": "Align Left",
|
||||||
|
"alignRight": "Align Right"
|
||||||
|
},
|
||||||
|
usernamePlaceholder: 'Please enter username/email/phone number',
|
||||||
|
passwordPlaceholder: 'Please enter your password',
|
||||||
|
mobilePlaceholder: 'Please enter your mobile number',
|
||||||
|
loginButton: 'Log In',
|
||||||
|
forgotAdminPassword: 'Forgot admin password?',
|
||||||
|
registerLink: 'Register',
|
||||||
|
|
||||||
|
smsTab: 'Login via SMS code',
|
||||||
|
passwordTab: 'Password login',
|
||||||
|
title: 'Change Password',
|
||||||
|
weakPasswordWarning: 'For your account security, please change your password immediately',
|
||||||
|
changeNow: 'Change Now',
|
||||||
|
successMessage: 'Changed successfully',
|
||||||
|
oldPassword: 'Old Password',
|
||||||
|
oldPasswordRequired: 'Please enter the old password',
|
||||||
|
newPassword: 'New Password',
|
||||||
|
newPasswordRequired: 'Please enter the new password',
|
||||||
|
confirmNewPassword: 'Confirm New Password',
|
||||||
|
confirmNewPasswordRequired: 'Please confirm the new password',
|
||||||
|
changePasswordButton: 'Change Password',
|
||||||
|
enterPassword: "Please enter the password",
|
||||||
|
newPasswordNotSameOld: "The new password cannot be the same as the old password",
|
||||||
|
enterPasswordAgain: "Please enter the password again",
|
||||||
|
passwordsNotMatch: "The two passwords do not match!",
|
||||||
|
}
|
|
@ -0,0 +1,153 @@
|
||||||
|
export default {
|
||||||
|
app: {
|
||||||
|
crud: {
|
||||||
|
i18n: {
|
||||||
|
name: "name", city: "city", status: "status"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fs: {
|
||||||
|
rowHandle: {
|
||||||
|
title: "Operation"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
order: {
|
||||||
|
confirmTitle: 'Order Confirmation',
|
||||||
|
package: 'Package',
|
||||||
|
description: 'Description',
|
||||||
|
specifications: 'Specifications',
|
||||||
|
pipeline: 'Pipeline',
|
||||||
|
domain: 'Domain',
|
||||||
|
deployTimes: 'Deployments',
|
||||||
|
duration: 'Duration',
|
||||||
|
price: 'Price',
|
||||||
|
paymentMethod: 'Payment Method',
|
||||||
|
free: 'Free',
|
||||||
|
unit: {
|
||||||
|
pieces: 'pieces',
|
||||||
|
count: 'count',
|
||||||
|
times: 'times',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
framework: {
|
||||||
|
title: "Framework",
|
||||||
|
home: "Home",
|
||||||
|
},
|
||||||
|
title: "Certificate Automation",
|
||||||
|
pipeline: "Pipeline",
|
||||||
|
pipelineEdit: "Edit Pipeline",
|
||||||
|
history: "Execution History",
|
||||||
|
certStore: "Certificate Repository",
|
||||||
|
siteMonitor: "Site Certificate Monitor",
|
||||||
|
settings: "Settings",
|
||||||
|
accessManager: "Access Management",
|
||||||
|
cnameRecord: "CNAME Record Management",
|
||||||
|
subDomain: "Subdomain Delegation Settings",
|
||||||
|
pipelineGroup: "Pipeline Group Management",
|
||||||
|
openKey: "Open API Key",
|
||||||
|
notification: "Notification Settings",
|
||||||
|
siteMonitorSetting: "Site Monitor Settings",
|
||||||
|
userSecurity: "Security Settings",
|
||||||
|
userProfile: "Account Info",
|
||||||
|
suite: "Suite",
|
||||||
|
mySuite: "My Suite",
|
||||||
|
suiteBuy: "Suite Purchase",
|
||||||
|
myTrade: "My Orders",
|
||||||
|
paymentReturn: "Payment Return",
|
||||||
|
user: {
|
||||||
|
greeting: "Hello",
|
||||||
|
profile: "Account Info",
|
||||||
|
logout: "Logout",
|
||||||
|
},
|
||||||
|
dashboard: {
|
||||||
|
greeting: "Hello, {name}, welcome to 【{site}】",
|
||||||
|
latestVersion: "Latest version: {version}",
|
||||||
|
validUntil: "Valid until:",
|
||||||
|
tutorialTooltip: "Click to view detailed tutorial",
|
||||||
|
tutorialText: "Only 3 steps to automatically apply and deploy certificates",
|
||||||
|
alertMessage: "Certificates and credentials are sensitive. Do not use untrusted online Certd services or images. Always self-host and use official release channels:",
|
||||||
|
helpDoc: "Help Docs",
|
||||||
|
pipelineCount: "Number of Certificate Pipelines",
|
||||||
|
noPipeline: "You have no certificate pipelines yet",
|
||||||
|
createNow: "Create Now",
|
||||||
|
managePipeline: "Manage Pipelines",
|
||||||
|
pipelineStatus: "Pipeline Status",
|
||||||
|
recentRun: "Recent Run Statistics",
|
||||||
|
runCount: "Run Count",
|
||||||
|
expiringCerts: "Soon-to-Expire Certificates",
|
||||||
|
supportedTasks: "Overview of Supported Deployment Tasks",
|
||||||
|
},
|
||||||
|
steps: {
|
||||||
|
createPipeline: "Create Certificate Pipeline",
|
||||||
|
addTask: "Add Deployment Task",
|
||||||
|
scheduledRun: "Scheduled Run"
|
||||||
|
},
|
||||||
|
customPipeline: "Custom Pipeline",
|
||||||
|
createCertdPipeline: "Create Certificate Pipeline",
|
||||||
|
commercialCertHosting: "Commercial Certificate Hosting",
|
||||||
|
tooltip: {
|
||||||
|
manualUploadOwnCert: "Manually upload your own certificate for automatic deployment",
|
||||||
|
noAutoApplyCommercialCert: "Does not automatically apply for commercial certificates",
|
||||||
|
manualUploadOnUpdate: "Must manually upload once when the certificate is updated",
|
||||||
|
},
|
||||||
|
table: {
|
||||||
|
confirmDeleteTitle: "Are you sure you want to delete?",
|
||||||
|
confirmDeleteMessage: "This will delete all data related to the pipeline, including execution history, certificate files, and certificate repository records.",
|
||||||
|
},
|
||||||
|
play: {
|
||||||
|
runPipeline: "Run Pipeline",
|
||||||
|
confirm: "Confirm",
|
||||||
|
confirmTrigger: "Are you sure you want to trigger the run?",
|
||||||
|
pipelineStarted: "Pipeline has started running",
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
editPipeline: "Edit Pipeline",
|
||||||
|
editConfigGroup: "Modify Configuration/Group",
|
||||||
|
viewCertificate: "View Certificate",
|
||||||
|
downloadCertificate: "Download Certificate",
|
||||||
|
},
|
||||||
|
fields: {
|
||||||
|
userId: "User ID",
|
||||||
|
pipelineName: "Pipeline Name",
|
||||||
|
keyword: "Keyword",
|
||||||
|
required: "This field is required",
|
||||||
|
pipelineContent: "Pipeline Content",
|
||||||
|
scheduledTaskCount: "Scheduled Task Count",
|
||||||
|
deployTaskCount: "Deployment Task Count",
|
||||||
|
remainingValidity: "Remaining Validity",
|
||||||
|
expiryTime: "Expiry Time",
|
||||||
|
status: "Status",
|
||||||
|
lastRun: "Last Run",
|
||||||
|
enabled: "Enabled",
|
||||||
|
enabledLabel: "Enabled",
|
||||||
|
disabledLabel: "Disabled",
|
||||||
|
group: "Group",
|
||||||
|
type: "Type",
|
||||||
|
order: "Order Number",
|
||||||
|
keepHistoryCount: "History Record Retention Count",
|
||||||
|
keepHistoryHelper: "Number of history records to keep; excess will be deleted",
|
||||||
|
createTime: "Creation Time",
|
||||||
|
updateTime: "Update Time",
|
||||||
|
triggerType: "Trigger Type",
|
||||||
|
pipelineId: "Pipeline Id",
|
||||||
|
},
|
||||||
|
types: {
|
||||||
|
certApply: "Certificate Application",
|
||||||
|
certUpload: "Certificate Upload",
|
||||||
|
custom: "Custom",
|
||||||
|
},
|
||||||
|
myPipelines: "My Pipelines",
|
||||||
|
selectedCount: "Selected {count} items",
|
||||||
|
batchDelete: "Batch Delete",
|
||||||
|
batchForceRerun: "Force Rerun",
|
||||||
|
applyCertificate: "Apply for Certificate",
|
||||||
|
pipelineExecutionRecords: "Pipeline Execution Records",
|
||||||
|
confirm: "Confirm",
|
||||||
|
confirmBatchDeleteContent: "Are you sure you want to batch delete these {count} records?",
|
||||||
|
deleteSuccess: "Delete successful",
|
||||||
|
pleaseSelectRecords: "Please select records first",
|
||||||
|
triggerTypes: {
|
||||||
|
manual: "Manual Execution",
|
||||||
|
timer: "Scheduled Execution",
|
||||||
|
},
|
||||||
|
};
|
|
@ -0,0 +1,15 @@
|
||||||
|
import certd from './certd';
|
||||||
|
import authentication from './authentication';
|
||||||
|
import vip from './vip';
|
||||||
|
import tutorial from './tutorial';
|
||||||
|
import preferences from './preferences';
|
||||||
|
import ui from './ui';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
certd,
|
||||||
|
authentication,
|
||||||
|
vip,
|
||||||
|
ui,
|
||||||
|
tutorial,
|
||||||
|
preferences
|
||||||
|
};
|
|
@ -0,0 +1,186 @@
|
||||||
|
export default {
|
||||||
|
"title": "Preferences",
|
||||||
|
"subtitle": "Customize Preferences & Preview in Real Time",
|
||||||
|
"resetTip": "Data has changed, click to reset",
|
||||||
|
"resetTitle": "Reset Preferences",
|
||||||
|
"resetSuccess": "Preferences reset successfully",
|
||||||
|
"appearance": "Appearance",
|
||||||
|
"layout": "Layout",
|
||||||
|
"content": "Content",
|
||||||
|
"other": "Other",
|
||||||
|
"wide": "Wide",
|
||||||
|
"compact": "Fixed",
|
||||||
|
"followSystem": "Follow System",
|
||||||
|
"vertical": "Vertical",
|
||||||
|
"verticalTip": "Side vertical menu mode",
|
||||||
|
"horizontal": "Horizontal",
|
||||||
|
"horizontalTip": "Horizontal menu mode, all menus displayed at the top",
|
||||||
|
"twoColumn": "Two Column",
|
||||||
|
"twoColumnTip": "Vertical Two Column Menu Mode",
|
||||||
|
"headerSidebarNav": "Header Vertical",
|
||||||
|
"headerSidebarNavTip": "Header Full Width, Sidebar Navigation Mode",
|
||||||
|
"headerTwoColumn": "Header Two Column",
|
||||||
|
"headerTwoColumnTip": "Header Navigation & Sidebar Two Column co-exists",
|
||||||
|
"mixedMenu": "Mixed Menu",
|
||||||
|
"mixedMenuTip": "Vertical & Horizontal Menu Co-exists",
|
||||||
|
"fullContent": "Full Content",
|
||||||
|
"fullContentTip": "Only display content body, hide all menus",
|
||||||
|
"normal": "Normal",
|
||||||
|
"plain": "Plain",
|
||||||
|
"rounded": "Rounded",
|
||||||
|
"copyPreferences": "Copy Preferences",
|
||||||
|
"copyPreferencesSuccessTitle": "Copy successful",
|
||||||
|
"copyPreferencesSuccess": "Copy successful, please override in `src/preferences.ts` under app",
|
||||||
|
"clearAndLogout": "Clear Cache & Logout",
|
||||||
|
"mode": "Mode",
|
||||||
|
"general": "General",
|
||||||
|
"language": "Language",
|
||||||
|
"dynamicTitle": "Dynamic Title",
|
||||||
|
"watermark": "Watermark",
|
||||||
|
"checkUpdates": "Periodic update check",
|
||||||
|
"position": {
|
||||||
|
"title": "Preferences Postion",
|
||||||
|
"header": "Header",
|
||||||
|
"auto": "Auto",
|
||||||
|
"fixed": "Fixed"
|
||||||
|
},
|
||||||
|
"sidebar": {
|
||||||
|
"title": "Sidebar",
|
||||||
|
"width": "Width",
|
||||||
|
"visible": "Show Sidebar",
|
||||||
|
"collapsed": "Collpase Menu",
|
||||||
|
"collapsedShowTitle": "Show Menu Title",
|
||||||
|
"autoActivateChild": "Auto Activate SubMenu",
|
||||||
|
"autoActivateChildTip": "`Enabled` to automatically activate the submenu while click menu.",
|
||||||
|
"expandOnHover": "Expand On Hover",
|
||||||
|
"expandOnHoverTip": "When the mouse hovers over menu, \n `Enabled` to expand children menus \n `Disabled` to expand whole sidebar."
|
||||||
|
},
|
||||||
|
"tabbar": {
|
||||||
|
"title": "Tabbar",
|
||||||
|
"enable": "Enable Tab Bar",
|
||||||
|
"icon": "Show Tabbar Icon",
|
||||||
|
"showMore": "Show More Button",
|
||||||
|
"showMaximize": "Show Maximize Button",
|
||||||
|
"persist": "Persist Tabs",
|
||||||
|
"maxCount": "Max Count of Tabs",
|
||||||
|
"maxCountTip": "When the number of tabs exceeds the maximum,\nthe oldest tab will be closed.\n Set to 0 to disable count checking.",
|
||||||
|
"draggable": "Enable Draggable Sort",
|
||||||
|
"wheelable": "Support Mouse Wheel",
|
||||||
|
"middleClickClose": "Close Tab when Mouse Middle Button Click",
|
||||||
|
"wheelableTip": "When enabled, the Tabbar area responds to vertical scrolling events of the scroll wheel.",
|
||||||
|
"styleType": {
|
||||||
|
"title": "Tabs Style",
|
||||||
|
"chrome": "Chrome",
|
||||||
|
"card": "Card",
|
||||||
|
"plain": "Plain",
|
||||||
|
"brisk": "Brisk"
|
||||||
|
},
|
||||||
|
"contextMenu": {
|
||||||
|
"reload": "Reload",
|
||||||
|
"close": "Close",
|
||||||
|
"pin": "Pin",
|
||||||
|
"unpin": "Unpin",
|
||||||
|
"closeLeft": "Close Left Tabs",
|
||||||
|
"closeRight": "Close Right Tabs",
|
||||||
|
"closeOther": "Close Other Tabs",
|
||||||
|
"closeAll": "Close All Tabs",
|
||||||
|
"openInNewWindow": "Open in New Window",
|
||||||
|
"maximize": "Maximize",
|
||||||
|
"restoreMaximize": "Restore"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"navigationMenu": {
|
||||||
|
"title": "Navigation Menu",
|
||||||
|
"style": "Navigation Menu Style",
|
||||||
|
"accordion": "Sidebar Accordion Menu",
|
||||||
|
"split": "Navigation Menu Separation",
|
||||||
|
"splitTip": "When enabled, the sidebar displays the top bar's submenu"
|
||||||
|
},
|
||||||
|
"breadcrumb": {
|
||||||
|
"title": "Breadcrumb",
|
||||||
|
"home": "Show Home Button",
|
||||||
|
"enable": "Enable Breadcrumb",
|
||||||
|
"icon": "Show Breadcrumb Icon",
|
||||||
|
"background": "background",
|
||||||
|
"style": "Breadcrumb Style",
|
||||||
|
"hideOnlyOne": "Hidden when only one"
|
||||||
|
},
|
||||||
|
"animation": {
|
||||||
|
"title": "Animation",
|
||||||
|
"loading": "Page Loading",
|
||||||
|
"transition": "Page Transition",
|
||||||
|
"progress": "Page Progress"
|
||||||
|
},
|
||||||
|
"theme": {
|
||||||
|
"title": "Theme",
|
||||||
|
"radius": "Radius",
|
||||||
|
"light": "Light",
|
||||||
|
"dark": "Dark",
|
||||||
|
"darkSidebar": "Semi Dark Sidebar",
|
||||||
|
"darkHeader": "Semi Dark Header",
|
||||||
|
"weakMode": "Weak Mode",
|
||||||
|
"grayMode": "Gray Mode",
|
||||||
|
"builtin": {
|
||||||
|
"title": "Built-in",
|
||||||
|
"default": "Default",
|
||||||
|
"violet": "Violet",
|
||||||
|
"pink": "Pink",
|
||||||
|
"rose": "Rose",
|
||||||
|
"skyBlue": "Sky Blue",
|
||||||
|
"deepBlue": "Deep Blue",
|
||||||
|
"green": "Green",
|
||||||
|
"deepGreen": "Deep Green",
|
||||||
|
"orange": "Orange",
|
||||||
|
"yellow": "Yellow",
|
||||||
|
"zinc": "Zinc",
|
||||||
|
"neutral": "Neutral",
|
||||||
|
"slate": "Slate",
|
||||||
|
"gray": "Gray",
|
||||||
|
"custom": "Custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"header": {
|
||||||
|
"title": "Header",
|
||||||
|
"visible": "Show Header",
|
||||||
|
"modeStatic": "Static",
|
||||||
|
"modeFixed": "Fixed",
|
||||||
|
"modeAuto": "Auto hide & Show",
|
||||||
|
"modeAutoScroll": "Scroll to Hide & Show",
|
||||||
|
"menuAlign": "Menu Align",
|
||||||
|
"menuAlignStart": "Start",
|
||||||
|
"menuAlignEnd": "End",
|
||||||
|
"menuAlignCenter": "Center"
|
||||||
|
},
|
||||||
|
"footer": {
|
||||||
|
"title": "Footer",
|
||||||
|
"visible": "Show Footer",
|
||||||
|
"fixed": "Fixed at Bottom"
|
||||||
|
},
|
||||||
|
"copyright": {
|
||||||
|
"title": "Copyright",
|
||||||
|
"enable": "Enable Copyright",
|
||||||
|
"companyName": "Company Name",
|
||||||
|
"companySiteLink": "Company Site Link",
|
||||||
|
"date": "Date",
|
||||||
|
"icp": "ICP License Number",
|
||||||
|
"icpLink": "ICP Site Link"
|
||||||
|
},
|
||||||
|
"shortcutKeys": {
|
||||||
|
"title": "Shortcut Keys",
|
||||||
|
"global": "Global",
|
||||||
|
"search": "Global Search",
|
||||||
|
"logout": "Logout",
|
||||||
|
"preferences": "Preferences"
|
||||||
|
},
|
||||||
|
"widget": {
|
||||||
|
"title": "Widget",
|
||||||
|
"globalSearch": "Enable Global Search",
|
||||||
|
"fullscreen": "Enable Fullscreen",
|
||||||
|
"themeToggle": "Enable Theme Toggle",
|
||||||
|
"languageToggle": "Enable Language Toggle",
|
||||||
|
"notification": "Enable Notification",
|
||||||
|
"sidebarToggle": "Enable Sidebar Toggle",
|
||||||
|
"lockScreen": "Enable Lock Screen",
|
||||||
|
"refresh": "Enable Refresh"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
export default {
|
||||||
|
title: 'Tutorial',
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
export default {
|
||||||
|
"formRules": {
|
||||||
|
"required": "Please enter {0}",
|
||||||
|
"selectRequired": "Please select {0}",
|
||||||
|
"minLength": "{0} must be at least {1} characters",
|
||||||
|
"maxLength": "{0} can be at most {1} characters",
|
||||||
|
"length": "{0} must be {1} characters long",
|
||||||
|
"alreadyExists": "{0} `{1}` already exists",
|
||||||
|
"startWith": "{0} must start with `{1}`",
|
||||||
|
"invalidURL": "Please input a valid URL"
|
||||||
|
},
|
||||||
|
"actionTitle": {
|
||||||
|
"edit": "Modify {0}",
|
||||||
|
"create": "Create {0}",
|
||||||
|
"delete": "Delete {0}",
|
||||||
|
"view": "View {0}"
|
||||||
|
},
|
||||||
|
"actionMessage": {
|
||||||
|
"deleteConfirm": "Are you sure to delete {0}?",
|
||||||
|
"deleting": "Deleting {0} ...",
|
||||||
|
"deleteSuccess": "{0} deleted successfully",
|
||||||
|
"operationSuccess": "Operation succeeded",
|
||||||
|
"operationFailed": "Operation failed"
|
||||||
|
},
|
||||||
|
"placeholder": {
|
||||||
|
"input": "Please enter",
|
||||||
|
"select": "Please select"
|
||||||
|
},
|
||||||
|
"captcha": {
|
||||||
|
"title": "Please complete the security verification",
|
||||||
|
"sliderSuccessText": "Passed",
|
||||||
|
"sliderDefaultText": "Slider and drag",
|
||||||
|
"alt": "Supports img tag src attribute value",
|
||||||
|
"sliderRotateDefaultTip": "Click picture to refresh",
|
||||||
|
"sliderRotateFailTip": "Validation failed",
|
||||||
|
"sliderRotateSuccessTip": "Validation successful, time {0} seconds",
|
||||||
|
"refreshAriaLabel": "Refresh captcha",
|
||||||
|
"confirmAriaLabel": "Confirm selection",
|
||||||
|
"confirm": "Confirm",
|
||||||
|
"pointAriaLabel": "Click point",
|
||||||
|
"clickInOrder": "Please click in order"
|
||||||
|
},
|
||||||
|
"iconPicker": {
|
||||||
|
"placeholder": "Select an icon",
|
||||||
|
"search": "Search icon..."
|
||||||
|
},
|
||||||
|
"jsonViewer": {
|
||||||
|
"copy": "Copy",
|
||||||
|
"copied": "Copied"
|
||||||
|
},
|
||||||
|
"fallback": {
|
||||||
|
"pageNotFound": "Oops! Page Not Found",
|
||||||
|
"pageNotFoundDesc": "Sorry, we couldn't find the page you were looking for.",
|
||||||
|
"forbidden": "Oops! Access Denied",
|
||||||
|
"forbiddenDesc": "Sorry, but you don't have permission to access this page.",
|
||||||
|
"internalError": "Oops! Something Went Wrong",
|
||||||
|
"internalErrorDesc": "Sorry, but the server encountered an error.",
|
||||||
|
"offline": "Offline Page",
|
||||||
|
"offlineError": "Oops! Network Error",
|
||||||
|
"offlineErrorDesc": "Sorry, can't connect to the internet. Check your connection.",
|
||||||
|
"comingSoon": "Coming Soon",
|
||||||
|
"http": {
|
||||||
|
"requestTimeout": "The request timed out. Please try again later.",
|
||||||
|
"networkError": "A network error occurred. Please check your internet connection and try again.",
|
||||||
|
"badRequest": "Bad Request. Please check your input and try again.",
|
||||||
|
"unauthorized": "Unauthorized. Please log in to continue.",
|
||||||
|
"forbidden": "Forbidden. You do not have permission to access this resource.",
|
||||||
|
"notFound": "Not Found. The requested resource could not be found.",
|
||||||
|
"internalServerError": "Internal Server Error. Something went wrong on our end. Please try again later."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"widgets": {
|
||||||
|
"document": "Document",
|
||||||
|
"qa": "Q&A",
|
||||||
|
"setting": "Settings",
|
||||||
|
"logoutTip": "Do you want to logout?",
|
||||||
|
"viewAll": "View All Messages",
|
||||||
|
"notifications": "Notifications",
|
||||||
|
"markAllAsRead": "Make All as Read",
|
||||||
|
"clearNotifications": "Clear",
|
||||||
|
"checkUpdatesTitle": "New Version Available",
|
||||||
|
"checkUpdatesDescription": "Click to refresh and get the latest version",
|
||||||
|
"search": {
|
||||||
|
"title": "Search",
|
||||||
|
"searchNavigate": "Search Navigation",
|
||||||
|
"select": "Select",
|
||||||
|
"navigate": "Navigate",
|
||||||
|
"close": "Close",
|
||||||
|
"noResults": "No Search Results Found",
|
||||||
|
"noRecent": "No Search History",
|
||||||
|
"recent": "Search History"
|
||||||
|
},
|
||||||
|
"lockScreen": {
|
||||||
|
"title": "Lock Screen",
|
||||||
|
"screenButton": "Locking",
|
||||||
|
"password": "Password",
|
||||||
|
"placeholder": "Please enter password",
|
||||||
|
"unlock": "Click to unlock",
|
||||||
|
"errorPasswordTip": "Password error, please re-enter",
|
||||||
|
"backToLogin": "Back to login",
|
||||||
|
"entry": "Enter the system"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
export default {
|
||||||
|
comm: {
|
||||||
|
name: "{vipLabel} Activated",
|
||||||
|
title: "Expires on: {expire}",
|
||||||
|
nav: "{vipLabel}",
|
||||||
|
},
|
||||||
|
plus: {
|
||||||
|
name: "Pro Features",
|
||||||
|
title: "Upgrade to Pro for commercial license",
|
||||||
|
},
|
||||||
|
free: {
|
||||||
|
comm: {
|
||||||
|
name: "Pro Features",
|
||||||
|
title: "Upgrade to Pro for commercial license",
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
name: "Advanced Features",
|
||||||
|
title: "Upgrade to Advanced for more VIP privileges",
|
||||||
|
},
|
||||||
|
nav: {
|
||||||
|
name: "Basic Version",
|
||||||
|
title: "Upgrade to Advanced for more VIP privileges",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
export default {
|
||||||
|
"welcomeBack": "欢迎回来",
|
||||||
|
"pageTitle": "开箱即用的大型中后台管理系统",
|
||||||
|
"pageDesc": "工程化、高性能、跨组件库的前端模版",
|
||||||
|
"loginSuccess": "登录成功",
|
||||||
|
"loginSuccessDesc": "欢迎回来",
|
||||||
|
"loginSubtitle": "请输入您的帐户信息以开始管理您的项目",
|
||||||
|
"selectAccount": "快速选择账号",
|
||||||
|
"username": "账号",
|
||||||
|
"password": "密码",
|
||||||
|
"usernameTip": "请输入用户名",
|
||||||
|
"passwordTip": "请输入密码",
|
||||||
|
"verifyRequiredTip": "请先完成验证",
|
||||||
|
"passwordErrorTip": "密码错误",
|
||||||
|
"rememberMe": "记住账号",
|
||||||
|
"createAnAccount": "创建一个账号",
|
||||||
|
"createAccount": "创建账号",
|
||||||
|
"alreadyHaveAccount": "已经有账号了?",
|
||||||
|
"accountTip": "还没有账号?",
|
||||||
|
"signUp": "注册",
|
||||||
|
"signUpSubtitle": "让您的应用程序管理变得简单而有趣",
|
||||||
|
"confirmPassword": "确认密码",
|
||||||
|
"confirmPasswordTip": "两次输入的密码不一致",
|
||||||
|
"agree": "我同意",
|
||||||
|
"privacyPolicy": "隐私政策",
|
||||||
|
"terms": "条款",
|
||||||
|
"agreeTip": "请同意隐私政策和条款",
|
||||||
|
"goToLogin": "去登录",
|
||||||
|
"passwordStrength": "使用 8 个或更多字符,混合字母、数字和符号",
|
||||||
|
"forgetPassword": "忘记密码?",
|
||||||
|
"forgetPasswordSubtitle": "输入您的电子邮件,我们将向您发送重置密码的连接",
|
||||||
|
"emailTip": "请输入邮箱",
|
||||||
|
"emailValidErrorTip": "你输入的邮箱格式不正确",
|
||||||
|
"sendResetLink": "发送重置链接",
|
||||||
|
"email": "邮箱",
|
||||||
|
"qrcodeSubtitle": "请用手机扫描二维码登录",
|
||||||
|
"qrcodePrompt": "扫码后点击 '确认',即可完成登录",
|
||||||
|
"qrcodeLogin": "扫码登录",
|
||||||
|
"codeSubtitle": "请输入您的手机号码以开始管理您的项目",
|
||||||
|
"code": "验证码",
|
||||||
|
"codeTip": "请输入{0}位验证码",
|
||||||
|
"mobile": "手机号码",
|
||||||
|
"mobileTip": "请输入手机号",
|
||||||
|
"mobileErrortip": "手机号码格式错误",
|
||||||
|
"mobileLogin": "手机号登录",
|
||||||
|
"sendCode": "获取验证码",
|
||||||
|
"sendText": "{0}秒后重新获取",
|
||||||
|
"thirdPartyLogin": "其他登录方式",
|
||||||
|
"loginAgainTitle": "重新登录",
|
||||||
|
"loginAgainSubTitle": "您的登录状态已过期,请重新登录以继续。",
|
||||||
|
"layout": {
|
||||||
|
"center": "居中",
|
||||||
|
"alignLeft": "居左",
|
||||||
|
"alignRight": "居右"
|
||||||
|
},
|
||||||
|
usernamePlaceholder: '请输入用户名/邮箱/手机号',
|
||||||
|
passwordPlaceholder: '请输入密码',
|
||||||
|
mobilePlaceholder: '请输入手机号',
|
||||||
|
loginButton: '登录',
|
||||||
|
forgotAdminPassword: '忘记管理员密码?',
|
||||||
|
registerLink: '注册',
|
||||||
|
|
||||||
|
smsTab: '短信验证码登录',
|
||||||
|
passwordTab: '密码登录',
|
||||||
|
|
||||||
|
title: '修改密码',
|
||||||
|
weakPasswordWarning: '为了您的账户安全,请立即修改密码',
|
||||||
|
changeNow: '立即修改',
|
||||||
|
successMessage: '修改成功',
|
||||||
|
oldPassword: '旧密码',
|
||||||
|
oldPasswordRequired: '请输入旧密码',
|
||||||
|
newPassword: '新密码',
|
||||||
|
newPasswordRequired: '请输入新密码',
|
||||||
|
confirmNewPassword: '确认新密码',
|
||||||
|
confirmNewPasswordRequired: '请输入确认密码',
|
||||||
|
changePasswordButton: '修改密码',
|
||||||
|
enterPassword: "请输入密码",
|
||||||
|
newPasswordNotSameOld: "新密码不能和旧密码相同",
|
||||||
|
enterPasswordAgain: "请再次输入密码",
|
||||||
|
passwordsNotMatch: "两次输入密码不一致!",
|
||||||
|
}
|
|
@ -0,0 +1,159 @@
|
||||||
|
export default {
|
||||||
|
app: {
|
||||||
|
crud: {
|
||||||
|
i18n: {
|
||||||
|
name: "姓名", city: "城市", status: "状态"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
login: {
|
||||||
|
logoutTip: "确认",
|
||||||
|
logoutMessage: "确定要注销登录吗?",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fs: {
|
||||||
|
rowHandle: {
|
||||||
|
title: "操作列",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
order: {
|
||||||
|
confirmTitle: '订单确认',
|
||||||
|
package: '套餐',
|
||||||
|
description: '说明',
|
||||||
|
specifications: '规格',
|
||||||
|
pipeline: '流水线',
|
||||||
|
domain: '域名',
|
||||||
|
deployTimes: '部署次数',
|
||||||
|
duration: '时长',
|
||||||
|
price: '价格',
|
||||||
|
paymentMethod: '支付方式',
|
||||||
|
free: '免费',
|
||||||
|
unit: {
|
||||||
|
pieces: '条',
|
||||||
|
count: '个',
|
||||||
|
times: '次',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
framework: {
|
||||||
|
title: "框架",
|
||||||
|
home: "首页",
|
||||||
|
},
|
||||||
|
certd: {
|
||||||
|
title: "证书自动化",
|
||||||
|
pipeline: "证书自动化流水线",
|
||||||
|
pipelineEdit: "编辑流水线",
|
||||||
|
history: "执行历史记录",
|
||||||
|
certStore: "证书仓库",
|
||||||
|
siteMonitor: "站点证书监控",
|
||||||
|
settings: "设置",
|
||||||
|
accessManager: "授权管理",
|
||||||
|
cnameRecord: "CNAME记录管理",
|
||||||
|
subDomain: "子域名托管设置",
|
||||||
|
pipelineGroup: "流水线分组管理",
|
||||||
|
openKey: "开放接口密钥",
|
||||||
|
notification: "通知设置",
|
||||||
|
siteMonitorSetting: "站点监控设置",
|
||||||
|
userSecurity: "认证安全设置",
|
||||||
|
userProfile: "账号信息",
|
||||||
|
suite: "套餐",
|
||||||
|
mySuite: "我的套餐",
|
||||||
|
suiteBuy: "套餐购买",
|
||||||
|
myTrade: "我的订单",
|
||||||
|
paymentReturn: "支付返回",
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
greeting: "您好",
|
||||||
|
profile: "账号信息",
|
||||||
|
logout: "注销登录",
|
||||||
|
},
|
||||||
|
dashboard: {
|
||||||
|
greeting: "您好,{name},欢迎使用 【{site}】",
|
||||||
|
latestVersion: "最新版本: {version}",
|
||||||
|
validUntil: "账户有效期:",
|
||||||
|
tutorialTooltip: "点击查看详细教程",
|
||||||
|
tutorialText: "仅需3步,全自动申请部署证书",
|
||||||
|
alertMessage: "证书和授权为敏感信息,不要使用来历不明的在线Certd服务和镜像,以免泄露;请务必私有化部署使用,认准官方版本发布渠道:",
|
||||||
|
helpDoc: "帮助文档",
|
||||||
|
pipelineCount: "证书流水线数量",
|
||||||
|
noPipeline: "您还没有证书流水线",
|
||||||
|
createNow: "立即创建",
|
||||||
|
managePipeline: "管理流水线",
|
||||||
|
pipelineStatus: "流水线状态",
|
||||||
|
recentRun: "最近运行统计",
|
||||||
|
runCount: "运行次数",
|
||||||
|
expiringCerts: "最快到期证书",
|
||||||
|
supportedTasks: "已支持的部署任务总览",
|
||||||
|
},
|
||||||
|
steps: {
|
||||||
|
createPipeline: "创建证书流水线",
|
||||||
|
addTask: "添加部署任务",
|
||||||
|
scheduledRun: "定时运行"
|
||||||
|
},
|
||||||
|
customPipeline: "自定义流水线",
|
||||||
|
createCertdPipeline: "创建证书流水线",
|
||||||
|
commercialCertHosting: "商用证书托管",
|
||||||
|
tooltip: {
|
||||||
|
manualUploadOwnCert: "手动上传自有证书,执行自动部署",
|
||||||
|
noAutoApplyCommercialCert: "并不能自动申请商业证书",
|
||||||
|
manualUploadOnUpdate: "证书有更新时,都需要手动上传一次",
|
||||||
|
},
|
||||||
|
table: {
|
||||||
|
confirmDeleteTitle: "确定要删除吗?",
|
||||||
|
confirmDeleteMessage: "将删除该流水线相关的所有数据,包括执行历史、证书文件、证书仓库记录等",
|
||||||
|
},
|
||||||
|
play: {
|
||||||
|
runPipeline: "运行流水线",
|
||||||
|
confirm: "确认",
|
||||||
|
confirmTrigger: "确定要触发运行吗?",
|
||||||
|
pipelineStarted: "管道已经开始运行",
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
editPipeline: "编辑流水线",
|
||||||
|
editConfigGroup: "修改配置/分组",
|
||||||
|
viewCertificate: "查看证书",
|
||||||
|
downloadCertificate: "下载证书",
|
||||||
|
},
|
||||||
|
fields: {
|
||||||
|
userId: "用户Id",
|
||||||
|
pipelineName: "流水线名称",
|
||||||
|
keyword: "关键字",
|
||||||
|
required: "此项必填",
|
||||||
|
pipelineContent: "流水线内容",
|
||||||
|
scheduledTaskCount: "定时任务数",
|
||||||
|
deployTaskCount: "部署任务数",
|
||||||
|
remainingValidity: "到期剩余",
|
||||||
|
expiryTime: "过期时间",
|
||||||
|
status: "状态",
|
||||||
|
lastRun: "最后运行",
|
||||||
|
enabled: "启用",
|
||||||
|
enabledLabel: "启用",
|
||||||
|
disabledLabel: "禁用",
|
||||||
|
group: "分组",
|
||||||
|
type: "类型",
|
||||||
|
order: "排序号",
|
||||||
|
keepHistoryCount: "历史记录保持数",
|
||||||
|
keepHistoryHelper: "历史记录保持条数,多余的会被删除",
|
||||||
|
createTime: "创建时间",
|
||||||
|
updateTime: "更新时间",
|
||||||
|
triggerType: "触发类型",
|
||||||
|
pipelineId: "流水线Id",
|
||||||
|
},
|
||||||
|
types: {
|
||||||
|
certApply: "证书申请",
|
||||||
|
certUpload: "证书上传",
|
||||||
|
custom: "自定义",
|
||||||
|
},
|
||||||
|
myPipelines: "我的流水线",
|
||||||
|
selectedCount: "已选择 {count} 项",
|
||||||
|
batchDelete: "批量删除",
|
||||||
|
batchForceRerun: "强制重新运行",
|
||||||
|
applyCertificate: "申请证书",
|
||||||
|
pipelineExecutionRecords: "流水线执行记录",
|
||||||
|
confirm: "确认",
|
||||||
|
confirmBatchDeleteContent: "确定要批量删除这{count}条记录吗",
|
||||||
|
deleteSuccess: "删除成功",
|
||||||
|
pleaseSelectRecords: "请先勾选记录",
|
||||||
|
triggerTypes: {
|
||||||
|
manual: "手动执行",
|
||||||
|
timer: "定时执行",
|
||||||
|
},
|
||||||
|
};
|
|
@ -0,0 +1,15 @@
|
||||||
|
import certd from './certd';
|
||||||
|
import authentication from './authentication';
|
||||||
|
import vip from './vip';
|
||||||
|
import tutorial from './tutorial';
|
||||||
|
import preferences from './preferences';
|
||||||
|
import ui from './ui';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
certd,
|
||||||
|
authentication,
|
||||||
|
vip,
|
||||||
|
ui,
|
||||||
|
tutorial,
|
||||||
|
preferences
|
||||||
|
};
|
|
@ -0,0 +1,186 @@
|
||||||
|
export default {
|
||||||
|
"title": "偏好设置",
|
||||||
|
"subtitle": "自定义偏好设置 & 实时预览",
|
||||||
|
"resetTitle": "重置偏好设置",
|
||||||
|
"resetTip": "数据有变化,点击可进行重置",
|
||||||
|
"resetSuccess": "重置偏好设置成功",
|
||||||
|
"appearance": "外观",
|
||||||
|
"layout": "布局",
|
||||||
|
"content": "内容",
|
||||||
|
"other": "其它",
|
||||||
|
"wide": "流式",
|
||||||
|
"compact": "定宽",
|
||||||
|
"followSystem": "跟随系统",
|
||||||
|
"vertical": "垂直",
|
||||||
|
"verticalTip": "侧边垂直菜单模式",
|
||||||
|
"horizontal": "水平",
|
||||||
|
"horizontalTip": "水平菜单模式,菜单全部显示在顶部",
|
||||||
|
"twoColumn": "双列菜单",
|
||||||
|
"twoColumnTip": "垂直双列菜单模式",
|
||||||
|
"headerSidebarNav": "侧边导航",
|
||||||
|
"headerSidebarNavTip": "顶部通栏,侧边导航模式",
|
||||||
|
"headerTwoColumn": "混合双列",
|
||||||
|
"headerTwoColumnTip": "双列、水平菜单共存模式",
|
||||||
|
"mixedMenu": "混合垂直",
|
||||||
|
"mixedMenuTip": "垂直水平菜单共存",
|
||||||
|
"fullContent": "内容全屏",
|
||||||
|
"fullContentTip": "不显示任何菜单,只显示内容主体",
|
||||||
|
"normal": "常规",
|
||||||
|
"plain": "朴素",
|
||||||
|
"rounded": "圆润",
|
||||||
|
"copyPreferences": "复制偏好设置",
|
||||||
|
"copyPreferencesSuccessTitle": "复制成功",
|
||||||
|
"copyPreferencesSuccess": "复制成功,请在 app 下的 `src/preferences.ts`内进行覆盖",
|
||||||
|
"clearAndLogout": "清空缓存 & 退出登录",
|
||||||
|
"mode": "模式",
|
||||||
|
"general": "通用",
|
||||||
|
"language": "语言",
|
||||||
|
"dynamicTitle": "动态标题",
|
||||||
|
"watermark": "水印",
|
||||||
|
"checkUpdates": "定时检查更新",
|
||||||
|
"position": {
|
||||||
|
"title": "偏好设置位置",
|
||||||
|
"header": "顶栏",
|
||||||
|
"auto": "自动",
|
||||||
|
"fixed": "固定"
|
||||||
|
},
|
||||||
|
"sidebar": {
|
||||||
|
"title": "侧边栏",
|
||||||
|
"width": "宽度",
|
||||||
|
"visible": "显示侧边栏",
|
||||||
|
"collapsed": "折叠菜单",
|
||||||
|
"collapsedShowTitle": "折叠显示菜单名",
|
||||||
|
"autoActivateChild": "自动激活子菜单",
|
||||||
|
"autoActivateChildTip": "点击顶层菜单时,自动激活第一个子菜单或者上一次激活的子菜单",
|
||||||
|
"expandOnHover": "鼠标悬停展开",
|
||||||
|
"expandOnHoverTip": "鼠标在折叠区域悬浮时,`启用`则展开当前子菜单,`禁用`则展开整个侧边栏"
|
||||||
|
},
|
||||||
|
"tabbar": {
|
||||||
|
"title": "标签栏",
|
||||||
|
"enable": "启用标签栏",
|
||||||
|
"icon": "显示标签栏图标",
|
||||||
|
"showMore": "显示更多按钮",
|
||||||
|
"showMaximize": "显示最大化按钮",
|
||||||
|
"persist": "持久化标签页",
|
||||||
|
"maxCount": "最大标签数",
|
||||||
|
"maxCountTip": "每次打开新的标签时如果超过最大标签数,\n会自动关闭一个最先打开的标签\n设置为 0 则不限制",
|
||||||
|
"draggable": "启动拖拽排序",
|
||||||
|
"wheelable": "启用纵向滚轮响应",
|
||||||
|
"middleClickClose": "点击鼠标中键关闭标签页",
|
||||||
|
"wheelableTip": "开启后,标签栏区域可以响应滚轮的纵向滚动事件。\n关闭时,只能响应系统的横向滚动事件(需要按下Shift再滚动滚轮)",
|
||||||
|
"styleType": {
|
||||||
|
"title": "标签页风格",
|
||||||
|
"chrome": "谷歌",
|
||||||
|
"card": "卡片",
|
||||||
|
"plain": "朴素",
|
||||||
|
"brisk": "轻快"
|
||||||
|
},
|
||||||
|
"contextMenu": {
|
||||||
|
"reload": "重新加载",
|
||||||
|
"close": "关闭",
|
||||||
|
"pin": "固定",
|
||||||
|
"unpin": "取消固定",
|
||||||
|
"closeLeft": "关闭左侧标签页",
|
||||||
|
"closeRight": "关闭右侧标签页",
|
||||||
|
"closeOther": "关闭其它标签页",
|
||||||
|
"closeAll": "关闭全部标签页",
|
||||||
|
"openInNewWindow": "在新窗口打开",
|
||||||
|
"maximize": "最大化",
|
||||||
|
"restoreMaximize": "还原"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"navigationMenu": {
|
||||||
|
"title": "导航菜单",
|
||||||
|
"style": "导航菜单风格",
|
||||||
|
"accordion": "侧边导航菜单手风琴模式",
|
||||||
|
"split": "导航菜单分离",
|
||||||
|
"splitTip": "开启时,侧边栏显示顶栏对应菜单的子菜单"
|
||||||
|
},
|
||||||
|
"breadcrumb": {
|
||||||
|
"title": "面包屑导航",
|
||||||
|
"enable": "开启面包屑导航",
|
||||||
|
"icon": "显示面包屑图标",
|
||||||
|
"home": "显示首页按钮",
|
||||||
|
"style": "面包屑风格",
|
||||||
|
"hideOnlyOne": "仅有一个时隐藏",
|
||||||
|
"background": "背景"
|
||||||
|
},
|
||||||
|
"animation": {
|
||||||
|
"title": "动画",
|
||||||
|
"loading": "页面切换 Loading",
|
||||||
|
"transition": "页面切换动画",
|
||||||
|
"progress": "页面切换进度条"
|
||||||
|
},
|
||||||
|
"theme": {
|
||||||
|
"title": "主题",
|
||||||
|
"radius": "圆角",
|
||||||
|
"light": "浅色",
|
||||||
|
"dark": "深色",
|
||||||
|
"darkSidebar": "深色侧边栏",
|
||||||
|
"darkHeader": "深色顶栏",
|
||||||
|
"weakMode": "色弱模式",
|
||||||
|
"grayMode": "灰色模式",
|
||||||
|
"builtin": {
|
||||||
|
"title": "内置主题",
|
||||||
|
"default": "默认",
|
||||||
|
"violet": "紫罗兰",
|
||||||
|
"pink": "樱花粉",
|
||||||
|
"rose": "玫瑰红",
|
||||||
|
"skyBlue": "天蓝色",
|
||||||
|
"deepBlue": "深蓝色",
|
||||||
|
"green": "浅绿色",
|
||||||
|
"deepGreen": "深绿色",
|
||||||
|
"orange": "橙黄色",
|
||||||
|
"yellow": "柠檬黄",
|
||||||
|
"zinc": "锌色灰",
|
||||||
|
"neutral": "中性色",
|
||||||
|
"slate": "石板灰",
|
||||||
|
"gray": "中灰色",
|
||||||
|
"custom": "自定义"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"header": {
|
||||||
|
"title": "顶栏",
|
||||||
|
"modeStatic": "静止",
|
||||||
|
"modeFixed": "固定",
|
||||||
|
"modeAuto": "自动隐藏和显示",
|
||||||
|
"modeAutoScroll": "滚动隐藏和显示",
|
||||||
|
"visible": "显示顶栏",
|
||||||
|
"menuAlign": "菜单位置",
|
||||||
|
"menuAlignStart": "左侧",
|
||||||
|
"menuAlignEnd": "右侧",
|
||||||
|
"menuAlignCenter": "居中"
|
||||||
|
},
|
||||||
|
"footer": {
|
||||||
|
"title": "底栏",
|
||||||
|
"visible": "显示底栏",
|
||||||
|
"fixed": "固定在底部"
|
||||||
|
},
|
||||||
|
"copyright": {
|
||||||
|
"title": "版权",
|
||||||
|
"enable": "启用版权",
|
||||||
|
"companyName": "公司名",
|
||||||
|
"companySiteLink": "公司主页",
|
||||||
|
"date": "日期",
|
||||||
|
"icp": "ICP 备案号",
|
||||||
|
"icpLink": "ICP 网站链接"
|
||||||
|
},
|
||||||
|
"shortcutKeys": {
|
||||||
|
"title": "快捷键",
|
||||||
|
"global": "全局",
|
||||||
|
"search": "全局搜索",
|
||||||
|
"logout": "退出登录",
|
||||||
|
"preferences": "偏好设置"
|
||||||
|
},
|
||||||
|
"widget": {
|
||||||
|
"title": "小部件",
|
||||||
|
"globalSearch": "启用全局搜索",
|
||||||
|
"fullscreen": "启用全屏",
|
||||||
|
"themeToggle": "启用主题切换",
|
||||||
|
"languageToggle": "启用语言切换",
|
||||||
|
"notification": "启用通知",
|
||||||
|
"sidebarToggle": "启用侧边栏切换",
|
||||||
|
"lockScreen": "启用锁屏",
|
||||||
|
"refresh": "启用刷新"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
export default {
|
||||||
|
title: '使用教程',
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
export default {
|
||||||
|
"formRules": {
|
||||||
|
"required": "请输入{0}",
|
||||||
|
"selectRequired": "请选择{0}",
|
||||||
|
"minLength": "{0}至少{1}个字符",
|
||||||
|
"maxLength": "{0}最多{1}个字符",
|
||||||
|
"length": "{0}长度必须为{1}个字符",
|
||||||
|
"alreadyExists": "{0} `{1}` 已存在",
|
||||||
|
"startWith": "{0}必须以 {1} 开头",
|
||||||
|
"invalidURL": "请输入有效的链接"
|
||||||
|
},
|
||||||
|
"actionTitle": {
|
||||||
|
"edit": "修改{0}",
|
||||||
|
"create": "新增{0}",
|
||||||
|
"delete": "删除{0}",
|
||||||
|
"view": "查看{0}"
|
||||||
|
},
|
||||||
|
"actionMessage": {
|
||||||
|
"deleteConfirm": "确定删除 {0} 吗?",
|
||||||
|
"deleting": "正在删除 {0} ...",
|
||||||
|
"deleteSuccess": "{0} 删除成功",
|
||||||
|
"operationSuccess": "操作成功",
|
||||||
|
"operationFailed": "操作失败"
|
||||||
|
},
|
||||||
|
"placeholder": {
|
||||||
|
"input": "请输入",
|
||||||
|
"select": "请选择"
|
||||||
|
},
|
||||||
|
"captcha": {
|
||||||
|
"title": "请完成安全验证",
|
||||||
|
"sliderSuccessText": "验证通过",
|
||||||
|
"sliderDefaultText": "请按住滑块拖动",
|
||||||
|
"sliderRotateDefaultTip": "点击图片可刷新",
|
||||||
|
"sliderRotateFailTip": "验证失败",
|
||||||
|
"sliderRotateSuccessTip": "验证成功,耗时{0}秒",
|
||||||
|
"alt": "支持img标签src属性值",
|
||||||
|
"refreshAriaLabel": "刷新验证码",
|
||||||
|
"confirmAriaLabel": "确认选择",
|
||||||
|
"confirm": "确认",
|
||||||
|
"pointAriaLabel": "点击点",
|
||||||
|
"clickInOrder": "请依次点击"
|
||||||
|
},
|
||||||
|
"iconPicker": {
|
||||||
|
"placeholder": "选择一个图标",
|
||||||
|
"search": "搜索图标..."
|
||||||
|
},
|
||||||
|
"jsonViewer": {
|
||||||
|
"copy": "复制",
|
||||||
|
"copied": "已复制"
|
||||||
|
},
|
||||||
|
"fallback": {
|
||||||
|
"pageNotFound": "哎呀!未找到页面",
|
||||||
|
"pageNotFoundDesc": "抱歉,我们无法找到您要找的页面。",
|
||||||
|
"forbidden": "哎呀!访问被拒绝",
|
||||||
|
"forbiddenDesc": "抱歉,您没有权限访问此页面。",
|
||||||
|
"internalError": "哎呀!出错了",
|
||||||
|
"internalErrorDesc": "抱歉,服务器遇到错误。",
|
||||||
|
"offline": "离线页面",
|
||||||
|
"offlineError": "哎呀!网络错误",
|
||||||
|
"offlineErrorDesc": "抱歉,无法连接到互联网,请检查您的网络连接并重试。",
|
||||||
|
"comingSoon": "即将推出",
|
||||||
|
"http": {
|
||||||
|
"requestTimeout": "请求超时,请稍后再试。",
|
||||||
|
"networkError": "网络异常,请检查您的网络连接后重试。",
|
||||||
|
"badRequest": "请求错误。请检查您的输入并重试。",
|
||||||
|
"unauthorized": "登录认证过期,请重新登录后继续。",
|
||||||
|
"forbidden": "禁止访问, 您没有权限访问此资源。",
|
||||||
|
"notFound": "未找到, 请求的资源不存在。",
|
||||||
|
"internalServerError": "内部服务器错误,请稍后再试。"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"widgets": {
|
||||||
|
"document": "文档",
|
||||||
|
"qa": "问题 & 帮助",
|
||||||
|
"setting": "设置",
|
||||||
|
"logoutTip": "是否退出登录?",
|
||||||
|
"viewAll": "查看所有消息",
|
||||||
|
"notifications": "通知",
|
||||||
|
"markAllAsRead": "全部标记为已读",
|
||||||
|
"clearNotifications": "清空",
|
||||||
|
"checkUpdatesTitle": "新版本可用",
|
||||||
|
"checkUpdatesDescription": "点击刷新以获取最新版本",
|
||||||
|
"search": {
|
||||||
|
"title": "搜索",
|
||||||
|
"searchNavigate": "搜索导航菜单",
|
||||||
|
"select": "选择",
|
||||||
|
"navigate": "导航",
|
||||||
|
"close": "关闭",
|
||||||
|
"noResults": "未找到搜索结果",
|
||||||
|
"noRecent": "没有搜索历史",
|
||||||
|
"recent": "搜索历史"
|
||||||
|
},
|
||||||
|
"lockScreen": {
|
||||||
|
"title": "锁定屏幕",
|
||||||
|
"screenButton": "锁定",
|
||||||
|
"password": "密码",
|
||||||
|
"placeholder": "请输入锁屏密码",
|
||||||
|
"unlock": "点击解锁",
|
||||||
|
"errorPasswordTip": "密码错误,请重新输入",
|
||||||
|
"backToLogin": "返回登录",
|
||||||
|
"entry": "进入系统"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
export default {
|
||||||
|
comm: {
|
||||||
|
name: "{vipLabel}已开通",
|
||||||
|
title: "到期时间:{expire}",
|
||||||
|
nav: "{vipLabel}",
|
||||||
|
},
|
||||||
|
plus: {
|
||||||
|
name: "商业版功能",
|
||||||
|
title: "升级商业版,获取商业授权",
|
||||||
|
},
|
||||||
|
free: {
|
||||||
|
comm: {
|
||||||
|
name: "商业版功能",
|
||||||
|
title: "升级商业版,获取商业授权",
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
name: "专业版功能",
|
||||||
|
title: "升级专业版,享受更多VIP特权",
|
||||||
|
},
|
||||||
|
nav: {
|
||||||
|
name: "基础版",
|
||||||
|
title: "升级专业版,享受更多VIP特权",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,8 +3,7 @@ import App from "./App.vue";
|
||||||
// import Antd from "ant-design-vue";
|
// import Antd from "ant-design-vue";
|
||||||
import Antd from "./plugin/antdv-async/index";
|
import Antd from "./plugin/antdv-async/index";
|
||||||
import "./style/common.less";
|
import "./style/common.less";
|
||||||
import { loadMessages } from "./i18n";
|
import { i18n, loadLocaleMessages } from "/@/locales"
|
||||||
import { i18n } from "/@/vben/locales";
|
|
||||||
import components from "./components";
|
import components from "./components";
|
||||||
import router from "./router";
|
import router from "./router";
|
||||||
import plugin from "./plugin/";
|
import plugin from "./plugin/";
|
||||||
|
@ -16,15 +15,15 @@ import { initPreferences } from "/@/vben/preferences";
|
||||||
// import "./components/code-editor/import-works";
|
// import "./components/code-editor/import-works";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
// app.use(Antd);
|
// app.use(Antd);
|
||||||
app.use(Antd);
|
app.use(Antd);
|
||||||
await setupVben(app, { loadMessages, router });
|
await setupVben(app, { loadLocaleMessages, router });
|
||||||
app.use(router);
|
app.use(router);
|
||||||
// app.use(i18n);
|
// app.use(i18n);
|
||||||
// app.use(store);
|
// app.use(store);
|
||||||
app.use(components);
|
app.use(components);
|
||||||
app.use(plugin, { i18n });
|
app.use(plugin, { i18n });
|
||||||
|
|
||||||
const envMode = util.env.MODE;
|
const envMode = util.env.MODE;
|
||||||
const namespace = `${import.meta.env.VITE_APP_NAMESPACE}-${envMode}`;
|
const namespace = `${import.meta.env.VITE_APP_NAMESPACE}-${envMode}`;
|
||||||
|
|
|
@ -1,42 +1,44 @@
|
||||||
import LayoutBasic from "/@/layout/layout-basic.vue";
|
import LayoutBasic from "/@/layout/layout-basic.vue";
|
||||||
|
|
||||||
import type { RouteRecordRaw } from "vue-router";
|
import type { RouteRecordRaw } from "vue-router";
|
||||||
|
import i18n from '../../locales/i18n';
|
||||||
|
|
||||||
import { mergeRouteModules } from "/@/vben/utils";
|
import { mergeRouteModules } from "/@/vben/utils";
|
||||||
const dynamicRouteFiles = import.meta.glob("./modules/**/*.ts*", {
|
const dynamicRouteFiles = import.meta.glob("./modules/**/*.ts*", {
|
||||||
eager: true,
|
eager: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
/** 动态路由 */
|
/** 动态路由 */
|
||||||
const dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles);
|
const dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles);
|
||||||
export const frameworkResource = [
|
export const frameworkResource = [
|
||||||
{
|
{
|
||||||
title: "框架",
|
title: i18n.global.t("certd.framework.title"),
|
||||||
name: "root",
|
name: "root",
|
||||||
path: "/",
|
path: "/",
|
||||||
redirect: "/index",
|
redirect: "/index",
|
||||||
component: LayoutBasic,
|
component: LayoutBasic,
|
||||||
meta: {
|
meta: {
|
||||||
icon: "ion:accessibility",
|
icon: "ion:accessibility",
|
||||||
hideInBreadcrumb: true,
|
hideInBreadcrumb: true,
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
title: "首页",
|
title: i18n.global.t("certd.framework.home"),
|
||||||
name: "index",
|
name: "index",
|
||||||
path: "/index",
|
path: "/index",
|
||||||
component: "/framework/home/index.vue",
|
component: "/framework/home/index.vue",
|
||||||
meta: {
|
meta: {
|
||||||
fixedAside: true,
|
fixedAside: true,
|
||||||
showOnHeader: false,
|
showOnHeader: false,
|
||||||
icon: "ion:home-outline",
|
icon: "ion:home-outline",
|
||||||
auth: true,
|
auth: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|
||||||
...dynamicRoutes,
|
...dynamicRoutes,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
console.assert(frameworkResource.length === 1, "frameworkResource数组长度只能为1,你只能配置framework路由的子路由");
|
console.assert(frameworkResource.length === 1, "frameworkResource数组长度只能为1,你只能配置framework路由的子路由");
|
||||||
|
|
|
@ -1,267 +1,256 @@
|
||||||
import { useSettingStore } from "/@/store/settings";
|
import { useSettingStore } from "/@/store/settings";
|
||||||
import aboutResource from "/@/router/source/modules/about";
|
import aboutResource from "/@/router/source/modules/about";
|
||||||
|
import i18n from '/@/locales/i18n';
|
||||||
|
|
||||||
export const certdResources = [
|
export const certdResources = [
|
||||||
{
|
{
|
||||||
title: "证书自动化",
|
title: i18n.global.t("certd.title"),
|
||||||
name: "CertdRoot",
|
name: "CertdRoot",
|
||||||
path: "/certd",
|
path: "/certd",
|
||||||
redirect: "/certd/pipeline",
|
redirect: "/certd/pipeline",
|
||||||
meta: {
|
meta: {
|
||||||
icon: "ion:key-outline",
|
icon: "ion:key-outline",
|
||||||
auth: true,
|
auth: true,
|
||||||
order: 0,
|
order: 0,
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
title: "证书自动化流水线",
|
title: i18n.global.t("certd.pipeline"),
|
||||||
name: "PipelineManager",
|
name: "PipelineManager",
|
||||||
path: "/certd/pipeline",
|
path: "/certd/pipeline",
|
||||||
component: "/certd/pipeline/index.vue",
|
component: "/certd/pipeline/index.vue",
|
||||||
meta: {
|
meta: {
|
||||||
icon: "ion:analytics-sharp",
|
icon: "ion:analytics-sharp",
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "编辑流水线",
|
title: i18n.global.t("certd.pipelineEdit"),
|
||||||
name: "PipelineEdit",
|
name: "PipelineEdit",
|
||||||
path: "/certd/pipeline/detail",
|
path: "/certd/pipeline/detail",
|
||||||
component: "/certd/pipeline/detail.vue",
|
component: "/certd/pipeline/detail.vue",
|
||||||
meta: {
|
meta: {
|
||||||
isMenu: false,
|
isMenu: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "执行历史记录",
|
title: i18n.global.t("certd.history"),
|
||||||
name: "PipelineHistory",
|
name: "PipelineHistory",
|
||||||
path: "/certd/history",
|
path: "/certd/history",
|
||||||
component: "/certd/history/index.vue",
|
component: "/certd/history/index.vue",
|
||||||
meta: {
|
meta: {
|
||||||
icon: "ion:timer-outline",
|
icon: "ion:timer-outline",
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "证书仓库",
|
title: i18n.global.t("certd.certStore"),
|
||||||
name: "CertStore",
|
name: "CertStore",
|
||||||
path: "/certd/monitor/cert",
|
path: "/certd/monitor/cert",
|
||||||
component: "/certd/monitor/cert/index.vue",
|
component: "/certd/monitor/cert/index.vue",
|
||||||
meta: {
|
meta: {
|
||||||
icon: "ion:shield-checkmark-outline",
|
icon: "ion:shield-checkmark-outline",
|
||||||
auth: true,
|
auth: true,
|
||||||
isMenu: true,
|
isMenu: true,
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "站点证书监控",
|
title: i18n.global.t("certd.siteMonitor"),
|
||||||
name: "SiteCertMonitor",
|
name: "SiteCertMonitor",
|
||||||
path: "/certd/monitor/site",
|
path: "/certd/monitor/site",
|
||||||
component: "/certd/monitor/site/index.vue",
|
component: "/certd/monitor/site/index.vue",
|
||||||
meta: {
|
meta: {
|
||||||
icon: "ion:videocam-outline",
|
icon: "ion:videocam-outline",
|
||||||
auth: true,
|
auth: true,
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "设置",
|
title: i18n.global.t("certd.settings"),
|
||||||
name: "MineSetting",
|
name: "MineSetting",
|
||||||
path: "/certd/setting",
|
path: "/certd/setting",
|
||||||
redirect: "/certd/access",
|
redirect: "/certd/access",
|
||||||
meta: {
|
meta: {
|
||||||
icon: "ion:settings-outline",
|
icon: "ion:settings-outline",
|
||||||
auth: true,
|
auth: true,
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
title: "授权管理",
|
title: i18n.global.t("certd.accessManager"),
|
||||||
name: "AccessManager",
|
name: "AccessManager",
|
||||||
path: "/certd/access",
|
path: "/certd/access",
|
||||||
component: "/certd/access/index.vue",
|
component: "/certd/access/index.vue",
|
||||||
meta: {
|
meta: {
|
||||||
icon: "ion:disc-outline",
|
icon: "ion:disc-outline",
|
||||||
auth: true,
|
auth: true,
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "CNAME记录管理",
|
title: i18n.global.t("certd.cnameRecord"),
|
||||||
name: "CnameRecord",
|
name: "CnameRecord",
|
||||||
path: "/certd/cname/record",
|
path: "/certd/cname/record",
|
||||||
component: "/certd/cname/record/index.vue",
|
component: "/certd/cname/record/index.vue",
|
||||||
meta: {
|
meta: {
|
||||||
icon: "ion:link-outline",
|
icon: "ion:link-outline",
|
||||||
auth: true,
|
auth: true,
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "子域名托管设置",
|
title: i18n.global.t("certd.subDomain"),
|
||||||
name: "SubDomain",
|
name: "SubDomain",
|
||||||
path: "/certd/pipeline/subDomain",
|
path: "/certd/pipeline/subDomain",
|
||||||
component: "/certd/pipeline/sub-domain/index.vue",
|
component: "/certd/pipeline/sub-domain/index.vue",
|
||||||
meta: {
|
meta: {
|
||||||
icon: "material-symbols:approval-delegation-outline",
|
icon: "material-symbols:approval-delegation-outline",
|
||||||
auth: true,
|
auth: true,
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "流水线分组管理",
|
title: i18n.global.t("certd.pipelineGroup"),
|
||||||
name: "PipelineGroupManager",
|
name: "PipelineGroupManager",
|
||||||
path: "/certd/pipeline/group",
|
path: "/certd/pipeline/group",
|
||||||
component: "/certd/pipeline/group/index.vue",
|
component: "/certd/pipeline/group/index.vue",
|
||||||
meta: {
|
meta: {
|
||||||
icon: "mdi:format-list-group",
|
icon: "mdi:format-list-group",
|
||||||
auth: true,
|
auth: true,
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
{
|
title: i18n.global.t("certd.openKey"),
|
||||||
title: "开放接口密钥",
|
name: "OpenKey",
|
||||||
name: "OpenKey",
|
path: "/certd/open/openkey",
|
||||||
path: "/certd/open/openkey",
|
component: "/certd/open/openkey/index.vue",
|
||||||
component: "/certd/open/openkey/index.vue",
|
meta: {
|
||||||
meta: {
|
icon: "hugeicons:api",
|
||||||
icon: "hugeicons:api",
|
auth: true,
|
||||||
auth: true,
|
keepAlive: true,
|
||||||
keepAlive: true,
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
title: i18n.global.t("certd.notification"),
|
||||||
title: "通知设置",
|
name: "NotificationManager",
|
||||||
name: "NotificationManager",
|
path: "/certd/notification",
|
||||||
path: "/certd/notification",
|
component: "/certd/notification/index.vue",
|
||||||
component: "/certd/notification/index.vue",
|
meta: {
|
||||||
meta: {
|
icon: "ion:megaphone-outline",
|
||||||
icon: "ion:megaphone-outline",
|
auth: true,
|
||||||
auth: true,
|
keepAlive: true,
|
||||||
keepAlive: true,
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
title: i18n.global.t("certd.siteMonitorSetting"),
|
||||||
title: "站点监控设置",
|
name: "SiteMonitorSetting",
|
||||||
name: "SiteMonitorSetting",
|
path: "/certd/monitor/setting",
|
||||||
path: "/certd/monitor/setting",
|
component: "/certd/monitor/site/setting/index.vue",
|
||||||
component: "/certd/monitor/site/setting/index.vue",
|
meta: {
|
||||||
meta: {
|
icon: "ion:videocam-outline",
|
||||||
icon: "ion:videocam-outline",
|
auth: true,
|
||||||
auth: true,
|
isMenu: true,
|
||||||
isMenu: true,
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
title: i18n.global.t("certd.userSecurity"),
|
||||||
title: "认证安全设置",
|
name: "UserSecurity",
|
||||||
name: "UserSecurity",
|
path: "/certd/mine/security",
|
||||||
path: "/certd/mine/security",
|
component: "/certd/mine/security/index.vue",
|
||||||
component: "/certd/mine/security/index.vue",
|
meta: {
|
||||||
meta: {
|
icon: "fluent:shield-keyhole-16-regular",
|
||||||
icon: "fluent:shield-keyhole-16-regular",
|
auth: true,
|
||||||
auth: true,
|
isMenu: true,
|
||||||
isMenu: true,
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
title: i18n.global.t("certd.userProfile"),
|
||||||
title: "账号信息",
|
name: "UserProfile",
|
||||||
name: "UserProfile",
|
path: "/certd/mine/user-profile",
|
||||||
path: "/certd/mine/user-profile",
|
component: "/certd/mine/user-profile.vue",
|
||||||
component: "/certd/mine/user-profile.vue",
|
meta: {
|
||||||
meta: {
|
icon: "ion:person-outline",
|
||||||
icon: "ion:person-outline",
|
auth: true,
|
||||||
auth: true,
|
isMenu: false,
|
||||||
isMenu: false,
|
},
|
||||||
},
|
},
|
||||||
},
|
],
|
||||||
],
|
},
|
||||||
},
|
{
|
||||||
|
title: i18n.global.t("certd.suite"),
|
||||||
{
|
name: "SuiteProduct",
|
||||||
title: "套餐",
|
path: "/certd/suite",
|
||||||
name: "SuiteProduct",
|
redirect: "/certd/suite/mine",
|
||||||
path: "/certd/suite",
|
meta: {
|
||||||
redirect: "/certd/suite/mine",
|
show: () => {
|
||||||
meta: {
|
const settingStore = useSettingStore();
|
||||||
show: () => {
|
return settingStore.isComm && settingStore.isSuiteEnabled;
|
||||||
const settingStore = useSettingStore();
|
},
|
||||||
return settingStore.isComm && settingStore.isSuiteEnabled;
|
icon: "ion:cart-outline",
|
||||||
},
|
auth: true,
|
||||||
icon: "ion:cart-outline",
|
},
|
||||||
auth: true,
|
children: [
|
||||||
},
|
{
|
||||||
children: [
|
title: i18n.global.t("certd.mySuite"),
|
||||||
{
|
name: "MySuite",
|
||||||
title: "我的套餐",
|
path: "/certd/suite/mine",
|
||||||
name: "MySuite",
|
component: "/certd/suite/mine/index.vue",
|
||||||
path: "/certd/suite/mine",
|
meta: {
|
||||||
component: "/certd/suite/mine/index.vue",
|
show: () => {
|
||||||
meta: {
|
const settingStore = useSettingStore();
|
||||||
show: () => {
|
return settingStore.isComm;
|
||||||
const settingStore = useSettingStore();
|
},
|
||||||
return settingStore.isComm;
|
icon: "ion:gift-outline",
|
||||||
},
|
auth: true,
|
||||||
icon: "ion:gift-outline",
|
},
|
||||||
auth: true,
|
},
|
||||||
},
|
{
|
||||||
},
|
title: i18n.global.t("certd.suiteBuy"),
|
||||||
{
|
name: "SuiteProductBuy",
|
||||||
title: "套餐购买",
|
path: "/certd/suite/buy",
|
||||||
name: "SuiteProductBuy",
|
component: "/certd/suite/buy.vue",
|
||||||
path: "/certd/suite/buy",
|
meta: {
|
||||||
component: "/certd/suite/buy.vue",
|
show: () => {
|
||||||
meta: {
|
const settingStore = useSettingStore();
|
||||||
show: () => {
|
return settingStore.isComm;
|
||||||
const settingStore = useSettingStore();
|
},
|
||||||
return settingStore.isComm;
|
icon: "ion:cart-outline",
|
||||||
},
|
auth: true,
|
||||||
icon: "ion:cart-outline",
|
},
|
||||||
auth: true,
|
},
|
||||||
},
|
{
|
||||||
},
|
title: i18n.global.t("certd.myTrade"),
|
||||||
{
|
name: "MyTrade",
|
||||||
title: "我的订单",
|
path: "/certd/trade",
|
||||||
name: "MyTrade",
|
component: "/certd/trade/index.vue",
|
||||||
path: "/certd/trade",
|
meta: {
|
||||||
component: "/certd/trade/index.vue",
|
show: () => {
|
||||||
meta: {
|
const settingStore = useSettingStore();
|
||||||
show: () => {
|
return settingStore.isComm;
|
||||||
const settingStore = useSettingStore();
|
},
|
||||||
return settingStore.isComm;
|
icon: "ion:bag-check-outline",
|
||||||
},
|
auth: true,
|
||||||
icon: "ion:bag-check-outline",
|
keepAlive: true,
|
||||||
auth: true,
|
},
|
||||||
keepAlive: true,
|
},
|
||||||
},
|
{
|
||||||
},
|
title: i18n.global.t("certd.paymentReturn"),
|
||||||
{
|
name: "PaymentReturn",
|
||||||
title: "支付返回",
|
path: "/certd/payment/return/:type",
|
||||||
name: "PaymentReturn",
|
component: "/certd/payment/return.vue",
|
||||||
path: "/certd/payment/return/:type",
|
meta: {
|
||||||
component: "/certd/payment/return.vue",
|
icon: "ant-design:pay-circle-outlined",
|
||||||
meta: {
|
auth: false,
|
||||||
icon: "ant-design:pay-circle-outlined",
|
isMenu: false,
|
||||||
auth: false,
|
},
|
||||||
isMenu: false,
|
},
|
||||||
},
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
// {
|
|
||||||
// title: "邮箱设置",
|
|
||||||
// name: "EmailSetting",
|
|
||||||
// path: "/sys/settings/email",
|
|
||||||
// component: "/sys/settings/email-setting.vue",
|
|
||||||
// meta: {
|
|
||||||
// icon: "ion:mail-outline",
|
|
||||||
// auth: true
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
export default certdResources;
|
export default certdResources;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import type { CaptchaPoint, PointSelectionCaptchaProps } from '../types';
|
import type { CaptchaPoint, PointSelectionCaptchaProps } from '../types';
|
||||||
|
|
||||||
import { RotateCw } from '/@/vben/icons';
|
import { RotateCw } from '/@/vben/icons';
|
||||||
import { $t } from '/@/vben/locales';
|
import { $t } from '/@/locales';
|
||||||
|
|
||||||
import { VbenButton, VbenIconButton } from '/@/vben/shadcn-ui';
|
import { VbenButton, VbenIconButton } from '/@/vben/shadcn-ui';
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import type { PointSelectionCaptchaCardProps } from '../types';
|
||||||
|
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
||||||
import { $t } from '/@/vben/locales';
|
import { $t } from '/@/locales';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
|
|
|
@ -7,7 +7,7 @@ import type {
|
||||||
|
|
||||||
import { reactive, unref, useTemplateRef, watch, watchEffect } from 'vue';
|
import { reactive, unref, useTemplateRef, watch, watchEffect } from 'vue';
|
||||||
|
|
||||||
import { $t } from '/@/vben/locales';
|
import { $t } from '/@/locales';
|
||||||
|
|
||||||
import { cn } from '/@/vben/shared/utils';
|
import { cn } from '/@/vben/shared/utils';
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ import type {
|
||||||
|
|
||||||
import { computed, reactive, unref, useTemplateRef, watch } from 'vue';
|
import { computed, reactive, unref, useTemplateRef, watch } from 'vue';
|
||||||
|
|
||||||
import { $t } from '/@/vben/locales';
|
import { $t } from '/@/locales';
|
||||||
|
|
||||||
import { useTimeoutFn } from '@vueuse/core';
|
import { useTimeoutFn } from '@vueuse/core';
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { computed, ref, watch, watchEffect } from 'vue';
|
||||||
|
|
||||||
import { usePagination } from '/@/vben/hooks';
|
import { usePagination } from '/@/vben/hooks';
|
||||||
import { EmptyIcon, Grip, listIcons } from '/@/vben/icons';
|
import { EmptyIcon, Grip, listIcons } from '/@/vben/icons';
|
||||||
import { $t } from '/@/vben/locales';
|
import { $t } from '/@/locales';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
|
|
|
@ -14,7 +14,7 @@ import { computed, useAttrs } from 'vue';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import VueJsonViewer from 'vue-json-viewer';
|
import VueJsonViewer from 'vue-json-viewer';
|
||||||
|
|
||||||
import { $t } from '/@/vben/locales';
|
import { $t } from '/@/locales';
|
||||||
|
|
||||||
import { isBoolean } from '/@/vben/shared/utils';
|
import { isBoolean } from '/@/vben/shared/utils';
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import type { VbenFormSchema } from '/@/vben/form-ui';
|
||||||
import { computed, reactive } from 'vue';
|
import { computed, reactive } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
import { $t } from '/@/vben/locales';
|
import { $t } from '/@/locales';
|
||||||
|
|
||||||
import { useVbenForm } from '/@/vben/form-ui';
|
import { useVbenForm } from '/@/vben/form-ui';
|
||||||
import { VbenButton } from '/@/vben/shadcn-ui';
|
import { VbenButton } from '/@/vben/shadcn-ui';
|
||||||
|
|
|
@ -4,7 +4,7 @@ import type { VbenFormSchema } from '/@/vben/form-ui';
|
||||||
import { computed, reactive } from 'vue';
|
import { computed, reactive } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
import { $t } from '/@/vben/locales';
|
import { $t } from '/@/locales';
|
||||||
|
|
||||||
import { useVbenForm } from '/@/vben/form-ui';
|
import { useVbenForm } from '/@/vben/form-ui';
|
||||||
import { VbenButton } from '/@/vben/shadcn-ui';
|
import { VbenButton } from '/@/vben/shadcn-ui';
|
||||||
|
|
|
@ -8,7 +8,7 @@ import type { AuthenticationProps } from './types';
|
||||||
import { computed, onMounted, reactive, ref } from 'vue';
|
import { computed, onMounted, reactive, ref } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
import { $t } from '/@/vben/locales';
|
import { $t } from '/@/locales';
|
||||||
|
|
||||||
import { useVbenForm } from '/@/vben/form-ui';
|
import { useVbenForm } from '/@/vben/form-ui';
|
||||||
import { VbenButton, VbenCheckbox } from '/@/vben/shadcn-ui';
|
import { VbenButton, VbenCheckbox } from '/@/vben/shadcn-ui';
|
||||||
|
|
|
@ -6,7 +6,7 @@ import type { VbenFormSchema } from '/@/vben/form-ui';
|
||||||
import { computed, reactive } from 'vue';
|
import { computed, reactive } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
import { $t } from '/@/vben/locales';
|
import { $t } from '/@/locales';
|
||||||
|
|
||||||
import { useVbenForm } from '/@/vben/form-ui';
|
import { useVbenForm } from '/@/vben/form-ui';
|
||||||
import { VbenButton } from '/@/vben/shadcn-ui';
|
import { VbenButton } from '/@/vben/shadcn-ui';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { MdiGithub, MdiGoogle, MdiQqchat, MdiWechat } from '/@/vben/icons';
|
import { MdiGithub, MdiGoogle, MdiQqchat, MdiWechat } from '/@/vben/icons';
|
||||||
import { $t } from '/@/vben/locales';
|
import { $t } from '/@/locales';
|
||||||
|
|
||||||
import { VbenIconButton } from '/@/vben/shadcn-ui';
|
import { VbenIconButton } from '/@/vben/shadcn-ui';
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { computed, defineAsyncComponent } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
import { ArrowLeft, RotateCw } from '/@/vben/icons';
|
import { ArrowLeft, RotateCw } from '/@/vben/icons';
|
||||||
import { $t } from '/@/vben/locales';
|
import { $t } from '/@/locales';
|
||||||
|
|
||||||
import { VbenButton } from '/@/vben/shadcn-ui';
|
import { VbenButton } from '/@/vben/shadcn-ui';
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import "./styles";
|
||||||
import "./styles/antd/index.css";
|
import "./styles/antd/index.css";
|
||||||
|
|
||||||
import { useTitle } from "@vueuse/core";
|
import { useTitle } from "@vueuse/core";
|
||||||
import { setupI18n } from "/@/vben/locales";
|
import { setupI18n } from "../locales";
|
||||||
import { useSettingStore } from "/@/store/settings";
|
import { useSettingStore } from "/@/store/settings";
|
||||||
|
|
||||||
export async function setupVben(app: any, { loadMessages, router }: any) {
|
export async function setupVben(app: any, { loadMessages, router }: any) {
|
||||||
|
|
|
@ -6,7 +6,7 @@ import type { MenuRecordRaw } from "../../types";
|
||||||
import { computed, useSlots, watch } from "vue";
|
import { computed, useSlots, watch } from "vue";
|
||||||
|
|
||||||
import { useRefresh } from "../../hooks";
|
import { useRefresh } from "../../hooks";
|
||||||
import { $t, i18n } from "../../locales";
|
import { $t, i18n } from "/@/locales";
|
||||||
import { preferences, updatePreferences, usePreferences } from "../../preferences";
|
import { preferences, updatePreferences, usePreferences } from "../../preferences";
|
||||||
import { useLockStore } from "../../stores";
|
import { useLockStore } from "../../stores";
|
||||||
import { cloneDeep, mapTree } from "../../utils";
|
import { cloneDeep, mapTree } from "../../utils";
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { useRoute, useRouter } from "vue-router";
|
||||||
|
|
||||||
import { useContentMaximize, useTabs } from "../../../hooks";
|
import { useContentMaximize, useTabs } from "../../../hooks";
|
||||||
import { ArrowLeftToLine, ArrowRightLeft, ArrowRightToLine, ExternalLink, FoldHorizontal, Fullscreen, Minimize2, Pin, PinOff, RotateCw, X } from "../../../icons";
|
import { ArrowLeftToLine, ArrowRightLeft, ArrowRightToLine, ExternalLink, FoldHorizontal, Fullscreen, Minimize2, Pin, PinOff, RotateCw, X } from "../../../icons";
|
||||||
import { $t, useI18n } from "../../../locales";
|
import { $t, useI18n } from "/@/locales";
|
||||||
import { useAccessStore, useTabbarStore } from "../../../stores";
|
import { useAccessStore, useTabbarStore } from "../../../stores";
|
||||||
import { filterTree } from "../../../utils";
|
import { filterTree } from "../../../utils";
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import type { IBreadcrumb } from "/@/vben//shadcn-ui";
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
|
|
||||||
import { $t } from "/@/vben/locales";
|
import { $t } from "/@/locales";
|
||||||
|
|
||||||
import { VbenBreadcrumbView } from "/@/vben//shadcn-ui";
|
import { VbenBreadcrumbView } from "/@/vben//shadcn-ui";
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, onUnmounted, ref } from "vue";
|
import { onMounted, onUnmounted, ref } from "vue";
|
||||||
|
|
||||||
import { $t } from "../../../locales";
|
import { $t } from "/@/locales";
|
||||||
|
|
||||||
import { useVbenModal } from "../../../popup-ui";
|
import { useVbenModal } from "../../../popup-ui";
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import type { MenuRecordRaw } from "../../../types";
|
||||||
import { nextTick, onMounted, onUnmounted, ref, watch } from "vue";
|
import { nextTick, onMounted, onUnmounted, ref, watch } from "vue";
|
||||||
|
|
||||||
import { ArrowDown, ArrowUp, CornerDownLeft, MdiKeyboardEsc, Search } from "../../../icons";
|
import { ArrowDown, ArrowUp, CornerDownLeft, MdiKeyboardEsc, Search } from "../../../icons";
|
||||||
import { $t } from "../../../locales";
|
import { $t } from "/@/locales";
|
||||||
import { isWindowsOs } from "../../../utils";
|
import { isWindowsOs } from "../../../utils";
|
||||||
|
|
||||||
import { useVbenModal } from "../../../popup-ui";
|
import { useVbenModal } from "../../../popup-ui";
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { nextTick, onMounted, ref, shallowRef, watch } from "vue";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
|
|
||||||
import { SearchX, X } from "../../../icons";
|
import { SearchX, X } from "../../../icons";
|
||||||
import { $t } from "../../../locales";
|
import { $t } from "/@/locales";
|
||||||
import { mapTree, traverseTreeValues, uniqueByField } from "../../../utils";
|
import { mapTree, traverseTreeValues, uniqueByField } from "../../../utils";
|
||||||
|
|
||||||
import { VbenIcon, VbenScrollbar } from "../../../shadcn-ui";
|
import { VbenIcon, VbenScrollbar } from "../../../shadcn-ui";
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { SupportedLanguagesType } from "/@/vben/locales";
|
import type { SupportedLanguagesType } from "/@/locales";
|
||||||
|
|
||||||
import { SUPPORT_LANGUAGES } from "/@/vben/constants";
|
import { SUPPORT_LANGUAGES } from "/@/vben/constants";
|
||||||
import { Languages } from "/@/vben/icons";
|
import { Languages } from "/@/vben/icons";
|
||||||
import { loadLocaleMessages } from "/@/vben/locales";
|
import { loadLocaleMessages } from "/@/locales";
|
||||||
import { preferences, updatePreferences } from "/@/vben/preferences";
|
import { preferences, updatePreferences } from "/@/vben/preferences";
|
||||||
|
|
||||||
import { VbenDropdownRadioMenu, VbenIconButton } from "/@/vben//shadcn-ui";
|
import { VbenDropdownRadioMenu, VbenIconButton } from "/@/vben//shadcn-ui";
|
||||||
|
|
|
@ -6,7 +6,7 @@ import type { VbenDropdownMenuItem } from "/@/vben//shadcn-ui";
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
|
|
||||||
import { InspectionPanel, PanelLeft, PanelRight } from "/@/vben/icons";
|
import { InspectionPanel, PanelLeft, PanelRight } from "/@/vben/icons";
|
||||||
import { $t } from "/@/vben/locales";
|
import { $t } from "/@/locales";
|
||||||
import { preferences, updatePreferences, usePreferences } from "/@/vben/preferences";
|
import { preferences, updatePreferences, usePreferences } from "/@/vben/preferences";
|
||||||
|
|
||||||
import { VbenDropdownRadioMenu, VbenIconButton } from "/@/vben//shadcn-ui";
|
import { VbenDropdownRadioMenu, VbenIconButton } from "/@/vben//shadcn-ui";
|
||||||
|
|
|
@ -3,7 +3,7 @@ import type { Recordable } from "../../../types";
|
||||||
|
|
||||||
import { computed, reactive } from "vue";
|
import { computed, reactive } from "vue";
|
||||||
|
|
||||||
import { $t } from "../../../locales";
|
import { $t } from "/@/locales";
|
||||||
|
|
||||||
import { useVbenForm, z } from "../../../form-ui";
|
import { useVbenForm, z } from "../../../form-ui";
|
||||||
import { useVbenModal } from "../../../popup-ui";
|
import { useVbenModal } from "../../../popup-ui";
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import { computed, reactive, ref } from "vue";
|
import { computed, reactive, ref } from "vue";
|
||||||
|
|
||||||
import { LockKeyhole } from "../../../icons";
|
import { LockKeyhole } from "../../../icons";
|
||||||
import { $t, useI18n } from "../../../locales";
|
import { $t, useI18n } from "/@/locales";
|
||||||
import { storeToRefs, useLockStore } from "../../../stores";
|
import { storeToRefs, useLockStore } from "../../../stores";
|
||||||
|
|
||||||
import { useScrollLock } from "../../../composables";
|
import { useScrollLock } from "../../../composables";
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import type { NotificationItem } from "./types";
|
import type { NotificationItem } from "./types";
|
||||||
|
|
||||||
import { Bell, MailCheck } from "/@/vben/icons";
|
import { Bell, MailCheck } from "/@/vben/icons";
|
||||||
import { $t } from "/@/vben/locales";
|
import { $t } from "/@/locales";
|
||||||
|
|
||||||
import { VbenButton, VbenIconButton, VbenPopover, VbenScrollbar } from "/@/vben//shadcn-ui";
|
import { VbenButton, VbenIconButton, VbenPopover, VbenScrollbar } from "/@/vben//shadcn-ui";
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { $t } from "/@/vben/locales";
|
import { $t } from "/@/locales";
|
||||||
|
|
||||||
import SwitchItem from "../switch-item.vue";
|
import SwitchItem from "../switch-item.vue";
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { SUPPORT_LANGUAGES } from "/@/vben/constants";
|
import { SUPPORT_LANGUAGES } from "/@/vben/constants";
|
||||||
import { $t } from "/@/vben/locales";
|
import { $t } from "/@/locales";
|
||||||
|
|
||||||
import SelectItem from "../select-item.vue";
|
import SelectItem from "../select-item.vue";
|
||||||
import SwitchItem from "../switch-item.vue";
|
import SwitchItem from "../switch-item.vue";
|
||||||
|
|
|
@ -3,7 +3,7 @@ import type { SelectOption } from "/@/vben/types";
|
||||||
|
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
|
|
||||||
import { $t } from "/@/vben/locales";
|
import { $t } from "/@/locales";
|
||||||
|
|
||||||
import SwitchItem from "../switch-item.vue";
|
import SwitchItem from "../switch-item.vue";
|
||||||
import ToggleItem from "../toggle-item.vue";
|
import ToggleItem from "../toggle-item.vue";
|
||||||
|
|
|
@ -3,7 +3,7 @@ import type { Component } from "vue";
|
||||||
|
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
|
|
||||||
import { $t } from "/@/vben/locales";
|
import { $t } from "/@/locales";
|
||||||
|
|
||||||
import { ContentCompact, ContentWide } from "../../icons";
|
import { ContentCompact, ContentWide } from "../../icons";
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
|
|
||||||
import { $t } from "/@/vben/locales";
|
import { $t } from "/@/locales";
|
||||||
|
|
||||||
import InputItem from "../input-item.vue";
|
import InputItem from "../input-item.vue";
|
||||||
import SwitchItem from "../switch-item.vue";
|
import SwitchItem from "../switch-item.vue";
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { $t } from "/@/vben/locales";
|
import { $t } from "/@/locales";
|
||||||
|
|
||||||
import SwitchItem from "../switch-item.vue";
|
import SwitchItem from "../switch-item.vue";
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import type {
|
||||||
SelectOption,
|
SelectOption,
|
||||||
} from '/@/vben/types';
|
} from '/@/vben/types';
|
||||||
|
|
||||||
import { $t } from '/@/vben/locales';
|
import { $t } from '/@/locales';
|
||||||
|
|
||||||
import SelectItem from '../select-item.vue';
|
import SelectItem from '../select-item.vue';
|
||||||
import SwitchItem from '../switch-item.vue';
|
import SwitchItem from '../switch-item.vue';
|
||||||
|
|
|
@ -6,107 +6,102 @@ import type { LayoutType } from '/@/vben/types';
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
||||||
import { CircleHelp } from '/@/vben/icons';
|
import { CircleHelp } from '/@/vben/icons';
|
||||||
import { $t } from '/@/vben/locales';
|
import { $t } from '/@/locales';
|
||||||
|
|
||||||
import { VbenTooltip } from '/@/vben//shadcn-ui';
|
import { VbenTooltip } from '/@/vben//shadcn-ui';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
FullContent,
|
FullContent,
|
||||||
HeaderMixedNav,
|
HeaderMixedNav,
|
||||||
HeaderNav,
|
HeaderNav,
|
||||||
HeaderSidebarNav,
|
HeaderSidebarNav,
|
||||||
MixedNav,
|
MixedNav,
|
||||||
SidebarMixedNav,
|
SidebarMixedNav,
|
||||||
SidebarNav,
|
SidebarNav,
|
||||||
} from '../../icons';
|
} from '../../icons';
|
||||||
|
|
||||||
interface PresetItem {
|
interface PresetItem {
|
||||||
name: string;
|
name: string;
|
||||||
tip: string;
|
tip: string;
|
||||||
type: LayoutType;
|
type: LayoutType;
|
||||||
}
|
}
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'PreferenceLayout',
|
name: 'PreferenceLayout',
|
||||||
});
|
});
|
||||||
|
|
||||||
const modelValue = defineModel<LayoutType>({ default: 'sidebar-nav' });
|
const modelValue = defineModel<LayoutType>({ default: 'sidebar-nav' });
|
||||||
|
|
||||||
const components: Record<LayoutType, Component> = {
|
const components: Record<LayoutType, Component> = {
|
||||||
'full-content': FullContent,
|
'full-content': FullContent,
|
||||||
'header-nav': HeaderNav,
|
'header-nav': HeaderNav,
|
||||||
'mixed-nav': MixedNav,
|
'mixed-nav': MixedNav,
|
||||||
'sidebar-mixed-nav': SidebarMixedNav,
|
'sidebar-mixed-nav': SidebarMixedNav,
|
||||||
'sidebar-nav': SidebarNav,
|
'sidebar-nav': SidebarNav,
|
||||||
'header-mixed-nav': HeaderMixedNav,
|
'header-mixed-nav': HeaderMixedNav,
|
||||||
'header-sidebar-nav': HeaderSidebarNav,
|
'header-sidebar-nav': HeaderSidebarNav,
|
||||||
};
|
};
|
||||||
|
|
||||||
const PRESET = computed((): PresetItem[] => [
|
const PRESET = computed((): PresetItem[] => [
|
||||||
{
|
{
|
||||||
name: $t('preferences.vertical'),
|
name: $t('preferences.vertical'),
|
||||||
tip: $t('preferences.verticalTip'),
|
tip: $t('preferences.verticalTip'),
|
||||||
type: 'sidebar-nav',
|
type: 'sidebar-nav',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: $t('preferences.twoColumn'),
|
name: $t('preferences.twoColumn'),
|
||||||
tip: $t('preferences.twoColumnTip'),
|
tip: $t('preferences.twoColumnTip'),
|
||||||
type: 'sidebar-mixed-nav',
|
type: 'sidebar-mixed-nav',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: $t('preferences.horizontal'),
|
name: $t('preferences.horizontal'),
|
||||||
tip: $t('preferences.horizontalTip'),
|
tip: $t('preferences.horizontalTip'),
|
||||||
type: 'header-nav',
|
type: 'header-nav',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: $t('preferences.headerSidebarNav'),
|
name: $t('preferences.headerSidebarNav'),
|
||||||
tip: $t('preferences.headerSidebarNavTip'),
|
tip: $t('preferences.headerSidebarNavTip'),
|
||||||
type: 'header-sidebar-nav',
|
type: 'header-sidebar-nav',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: $t('preferences.mixedMenu'),
|
name: $t('preferences.mixedMenu'),
|
||||||
tip: $t('preferences.mixedMenuTip'),
|
tip: $t('preferences.mixedMenuTip'),
|
||||||
type: 'mixed-nav',
|
type: 'mixed-nav',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: $t('preferences.headerTwoColumn'),
|
name: $t('preferences.headerTwoColumn'),
|
||||||
tip: $t('preferences.headerTwoColumnTip'),
|
tip: $t('preferences.headerTwoColumnTip'),
|
||||||
type: 'header-mixed-nav',
|
type: 'header-mixed-nav',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: $t('preferences.fullContent'),
|
name: $t('preferences.fullContent'),
|
||||||
tip: $t('preferences.fullContentTip'),
|
tip: $t('preferences.fullContentTip'),
|
||||||
type: 'full-content',
|
type: 'full-content',
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
function activeClass(theme: string): string[] {
|
function activeClass(theme: string): string[] {
|
||||||
return theme === modelValue.value ? ['outline-box-active'] : [];
|
return theme === modelValue.value ? ['outline-box-active'] : [];
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex w-full flex-wrap gap-5">
|
<div class="flex w-full flex-wrap gap-5">
|
||||||
<template v-for="theme in PRESET" :key="theme.name">
|
<template v-for="theme in PRESET" :key="theme.name">
|
||||||
<div
|
<div class="flex w-[100px] cursor-pointer flex-col" @click="modelValue = theme.type">
|
||||||
class="flex w-[100px] cursor-pointer flex-col"
|
<div :class="activeClass(theme.type)" class="outline-box flex-center">
|
||||||
@click="modelValue = theme.type"
|
<component :is="components[theme.type]" />
|
||||||
>
|
</div>
|
||||||
<div :class="activeClass(theme.type)" class="outline-box flex-center">
|
<div class="text-muted-foreground flex-center hover:text-foreground mt-2 text-center text-xs">
|
||||||
<component :is="components[theme.type]" />
|
{{ theme.name }}
|
||||||
</div>
|
<VbenTooltip v-if="theme.tip" side="bottom">
|
||||||
<div
|
<template #trigger>
|
||||||
class="text-muted-foreground flex-center hover:text-foreground mt-2 text-center text-xs"
|
<CircleHelp class="ml-1 size-3 cursor-help" />
|
||||||
>
|
</template>
|
||||||
{{ theme.name }}
|
{{ theme.tip }}
|
||||||
<VbenTooltip v-if="theme.tip" side="bottom">
|
</VbenTooltip>
|
||||||
<template #trigger>
|
</div>
|
||||||
<CircleHelp class="ml-1 size-3 cursor-help" />
|
</div>
|
||||||
</template>
|
</template>
|
||||||
{{ theme.tip }}
|
</div>
|
||||||
</VbenTooltip>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { SelectOption } from '/@/vben/types';
|
import type { SelectOption } from '/@/vben/types';
|
||||||
|
|
||||||
import { $t } from '/@/vben/locales';
|
import { $t } from '/@/locales';
|
||||||
|
|
||||||
import SwitchItem from '../switch-item.vue';
|
import SwitchItem from '../switch-item.vue';
|
||||||
import ToggleItem from '../toggle-item.vue';
|
import ToggleItem from '../toggle-item.vue';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { LayoutType } from '/@/vben/types';
|
import type { LayoutType } from '/@/vben/types';
|
||||||
|
|
||||||
import { $t } from '/@/vben/locales';
|
import { $t } from '/@/locales';
|
||||||
|
|
||||||
import NumberFieldItem from '../number-field-item.vue';
|
import NumberFieldItem from '../number-field-item.vue';
|
||||||
import SwitchItem from '../switch-item.vue';
|
import SwitchItem from '../switch-item.vue';
|
||||||
|
|
|
@ -3,7 +3,7 @@ import type { SelectOption } from '/@/vben/types';
|
||||||
|
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
||||||
import { $t } from '/@/vben/locales';
|
import { $t } from '/@/locales';
|
||||||
|
|
||||||
import NumberFieldItem from '../number-field-item.vue';
|
import NumberFieldItem from '../number-field-item.vue';
|
||||||
import SelectItem from '../select-item.vue';
|
import SelectItem from '../select-item.vue';
|
||||||
|
|
|
@ -3,7 +3,7 @@ import type { SelectOption } from '/@/vben/types';
|
||||||
|
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
||||||
import { $t } from '/@/vben/locales';
|
import { $t } from '/@/locales';
|
||||||
|
|
||||||
import SelectItem from '../select-item.vue';
|
import SelectItem from '../select-item.vue';
|
||||||
import SwitchItem from '../switch-item.vue';
|
import SwitchItem from '../switch-item.vue';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
||||||
import { $t } from '/@/vben/locales';
|
import { $t } from '/@/locales';
|
||||||
import { isWindowsOs } from '/@/vben/utils';
|
import { isWindowsOs } from '/@/vben/utils';
|
||||||
|
|
||||||
import SwitchItem from '../switch-item.vue';
|
import SwitchItem from '../switch-item.vue';
|
||||||
|
|
|
@ -5,7 +5,7 @@ import type { BuiltinThemeType } from '/@/vben/types';
|
||||||
import { computed, ref, watch } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
|
|
||||||
import { UserRoundPen } from '/@/vben/icons';
|
import { UserRoundPen } from '/@/vben/icons';
|
||||||
import { $t } from '/@/vben/locales';
|
import { $t } from '/@/locales';
|
||||||
import { BUILT_IN_THEME_PRESETS } from '/@/vben/preferences';
|
import { BUILT_IN_THEME_PRESETS } from '/@/vben/preferences';
|
||||||
import { convertToHsl, TinyColor } from '/@/vben/utils';
|
import { convertToHsl, TinyColor } from '/@/vben/utils';
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { $t } from '/@/vben/locales';
|
import { $t } from '/@/locales';
|
||||||
|
|
||||||
import SwitchItem from '../switch-item.vue';
|
import SwitchItem from '../switch-item.vue';
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import type { Component } from 'vue';
|
||||||
import type { ThemeModeType } from '/@/vben/types';
|
import type { ThemeModeType } from '/@/vben/types';
|
||||||
|
|
||||||
import { MoonStar, Sun, SunMoon } from '/@/vben/icons';
|
import { MoonStar, Sun, SunMoon } from '/@/vben/icons';
|
||||||
import { $t } from '/@/vben/locales';
|
import { $t } from '/@/locales';
|
||||||
|
|
||||||
import SwitchItem from '../switch-item.vue';
|
import SwitchItem from '../switch-item.vue';
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { SupportedLanguagesType } from "/@/vben/locales";
|
import type { SupportedLanguagesType } from "/@/locales";
|
||||||
import type {
|
import type {
|
||||||
BreadcrumbStyleType,
|
BreadcrumbStyleType,
|
||||||
BuiltinThemeType,
|
BuiltinThemeType,
|
||||||
|
@ -17,7 +17,7 @@ import type { SegmentedItem } from "/@/vben//shadcn-ui";
|
||||||
import { computed, ref } from "vue";
|
import { computed, ref } from "vue";
|
||||||
|
|
||||||
import { Copy, RotateCw, X } from "/@/vben/icons";
|
import { Copy, RotateCw, X } from "/@/vben/icons";
|
||||||
import { $t, loadLocaleMessages } from "/@/vben/locales";
|
import { $t, loadLocaleMessages } from "/@/locales";
|
||||||
import { clearPreferencesCache, preferences, resetPreferences, usePreferences } from "/@/vben/preferences";
|
import { clearPreferencesCache, preferences, resetPreferences, usePreferences } from "/@/vben/preferences";
|
||||||
|
|
||||||
import { useVbenDrawer } from "/@/vben//popup-ui";
|
import { useVbenDrawer } from "/@/vben//popup-ui";
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
|
|
||||||
import { Settings } from "/@/vben/icons";
|
import { Settings } from "/@/vben/icons";
|
||||||
import { $t, loadLocaleMessages } from "/@/vben/locales";
|
import { $t, loadLocaleMessages } from "/@/locales";
|
||||||
import { preferences, updatePreferences } from "/@/vben/preferences";
|
import { preferences, updatePreferences } from "/@/vben/preferences";
|
||||||
import { capitalizeFirstLetter } from "/@/vben/utils";
|
import { capitalizeFirstLetter } from "/@/vben/utils";
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import type { ThemeModeType } from "/@/vben/types";
|
import type { ThemeModeType } from "/@/vben/types";
|
||||||
|
|
||||||
import { MoonStar, Sun, SunMoon } from "/@/vben/icons";
|
import { MoonStar, Sun, SunMoon } from "/@/vben/icons";
|
||||||
import { $t } from "/@/vben/locales";
|
import { $t } from "/@/locales";
|
||||||
import { preferences, updatePreferences, usePreferences } from "/@/vben/preferences";
|
import { preferences, updatePreferences, usePreferences } from "/@/vben/preferences";
|
||||||
|
|
||||||
import { ToggleGroup, ToggleGroupItem, VbenTooltip } from "/@/vben//shadcn-ui";
|
import { ToggleGroup, ToggleGroupItem, VbenTooltip } from "/@/vben//shadcn-ui";
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { computed, useTemplateRef, watch } from "vue";
|
||||||
|
|
||||||
import { useHoverToggle } from "/@/vben/hooks";
|
import { useHoverToggle } from "/@/vben/hooks";
|
||||||
import { LockKeyhole, LogOut } from "/@/vben/icons";
|
import { LockKeyhole, LogOut } from "/@/vben/icons";
|
||||||
import { $t } from "/@/vben/locales";
|
import { $t } from "/@/locales";
|
||||||
import { preferences, usePreferences } from "/@/vben/preferences";
|
import { preferences, usePreferences } from "/@/vben/preferences";
|
||||||
import { useLockStore } from "/@/vben/stores";
|
import { useLockStore } from "/@/vben/stores";
|
||||||
import { isWindowsOs } from "/@/vben/utils";
|
import { isWindowsOs } from "/@/vben/utils";
|
||||||
|
|
|
@ -1,128 +0,0 @@
|
||||||
import type { App } from "vue";
|
|
||||||
import type { Locale } from "vue-i18n";
|
|
||||||
|
|
||||||
import type { ImportLocaleFn, LoadMessageFn, LocaleSetupOptions, SupportedLanguagesType } from "./typing";
|
|
||||||
|
|
||||||
import { unref } from "vue";
|
|
||||||
import { createI18n } from "vue-i18n";
|
|
||||||
|
|
||||||
import { useSimpleLocale } from "/@/vben/composables";
|
|
||||||
|
|
||||||
const i18n = createI18n({
|
|
||||||
globalInjection: true,
|
|
||||||
legacy: false,
|
|
||||||
locale: "",
|
|
||||||
messages: {}
|
|
||||||
});
|
|
||||||
|
|
||||||
const modules = import.meta.glob("./langs/**/*.json");
|
|
||||||
|
|
||||||
const { setSimpleLocale } = useSimpleLocale();
|
|
||||||
|
|
||||||
const localesMap = loadLocalesMapFromDir(/\.\/langs\/([^/]+)\/(.*)\.json$/, modules);
|
|
||||||
let loadMessages: LoadMessageFn;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load locale modules
|
|
||||||
* @param modules
|
|
||||||
*/
|
|
||||||
function loadLocalesMap(modules: Record<string, () => Promise<unknown>>) {
|
|
||||||
const localesMap: Record<Locale, ImportLocaleFn> = {};
|
|
||||||
|
|
||||||
for (const [path, loadLocale] of Object.entries(modules)) {
|
|
||||||
const key = path.match(/([\w-]*)\.(json)/)?.[1];
|
|
||||||
if (key) {
|
|
||||||
localesMap[key] = loadLocale as ImportLocaleFn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return localesMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load locale modules with directory structure
|
|
||||||
* @param regexp - Regular expression to match language and file names
|
|
||||||
* @param modules - The modules object containing paths and import functions
|
|
||||||
* @returns A map of locales to their corresponding import functions
|
|
||||||
*/
|
|
||||||
function loadLocalesMapFromDir(regexp: RegExp, modules: Record<string, () => Promise<unknown>>): Record<Locale, ImportLocaleFn> {
|
|
||||||
const localesRaw: Record<Locale, Record<string, () => Promise<unknown>>> = {};
|
|
||||||
const localesMap: Record<Locale, ImportLocaleFn> = {};
|
|
||||||
|
|
||||||
// Iterate over the modules to extract language and file names
|
|
||||||
for (const path in modules) {
|
|
||||||
const match = path.match(regexp);
|
|
||||||
if (match) {
|
|
||||||
const [_, locale, fileName] = match;
|
|
||||||
if (locale && fileName) {
|
|
||||||
if (!localesRaw[locale]) {
|
|
||||||
localesRaw[locale] = {};
|
|
||||||
}
|
|
||||||
if (modules[path]) {
|
|
||||||
localesRaw[locale][fileName] = modules[path];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert raw locale data into async import functions
|
|
||||||
for (const [locale, files] of Object.entries(localesRaw)) {
|
|
||||||
localesMap[locale] = async () => {
|
|
||||||
const messages: Record<string, any> = {};
|
|
||||||
for (const [fileName, importFn] of Object.entries(files)) {
|
|
||||||
messages[fileName] = ((await importFn()) as any)?.default;
|
|
||||||
}
|
|
||||||
return { default: messages };
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return localesMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set i18n language
|
|
||||||
* @param locale
|
|
||||||
*/
|
|
||||||
function setI18nLanguage(locale: Locale) {
|
|
||||||
i18n.global.locale.value = locale;
|
|
||||||
|
|
||||||
document?.querySelector("html")?.setAttribute("lang", locale);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function setupI18n(app: App, options: LocaleSetupOptions = {}) {
|
|
||||||
const { defaultLocale = "zh-CN" } = options;
|
|
||||||
// app可以自行扩展一些第三方库和组件库的国际化
|
|
||||||
loadMessages = options.loadMessages || (async () => ({}));
|
|
||||||
app.use(i18n);
|
|
||||||
await loadLocaleMessages(defaultLocale);
|
|
||||||
|
|
||||||
// 在控制台打印警告
|
|
||||||
i18n.global.setMissingHandler((locale, key) => {
|
|
||||||
if (options.missingWarn && key.includes(".")) {
|
|
||||||
console.warn(`[intlify] Not found '${key}' key in '${locale}' locale messages.`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load locale messages
|
|
||||||
* @param lang
|
|
||||||
*/
|
|
||||||
async function loadLocaleMessages(lang: SupportedLanguagesType) {
|
|
||||||
if (unref(i18n.global.locale) === lang) {
|
|
||||||
return setI18nLanguage(lang);
|
|
||||||
}
|
|
||||||
setSimpleLocale(lang);
|
|
||||||
|
|
||||||
const message = await localesMap[lang]?.();
|
|
||||||
|
|
||||||
if (message?.default) {
|
|
||||||
i18n.global.setLocaleMessage(lang, message.default);
|
|
||||||
}
|
|
||||||
|
|
||||||
const mergeMessage = await loadMessages(lang);
|
|
||||||
i18n.global.mergeLocaleMessage(lang, mergeMessage);
|
|
||||||
|
|
||||||
return setI18nLanguage(lang);
|
|
||||||
}
|
|
||||||
|
|
||||||
export { i18n, loadLocaleMessages, loadLocalesMap, loadLocalesMapFromDir, setupI18n };
|
|
|
@ -1,56 +0,0 @@
|
||||||
{
|
|
||||||
"welcomeBack": "Welcome Back",
|
|
||||||
"pageTitle": "Plug-and-play Admin system",
|
|
||||||
"pageDesc": "Efficient, versatile frontend template",
|
|
||||||
"loginSuccess": "Login Successful",
|
|
||||||
"loginSuccessDesc": "Welcome Back",
|
|
||||||
"loginSubtitle": "Enter your account details to manage your projects",
|
|
||||||
"selectAccount": "Quick Select Account",
|
|
||||||
"username": "Username",
|
|
||||||
"password": "Password",
|
|
||||||
"usernameTip": "Please enter username",
|
|
||||||
"passwordErrorTip": "Password is incorrect",
|
|
||||||
"passwordTip": "Please enter password",
|
|
||||||
"verifyRequiredTip": "Please complete the verification first",
|
|
||||||
"rememberMe": "Remember Me",
|
|
||||||
"createAnAccount": "Create an Account",
|
|
||||||
"createAccount": "Create Account",
|
|
||||||
"alreadyHaveAccount": "Already have an account?",
|
|
||||||
"accountTip": "Don't have an account?",
|
|
||||||
"signUp": "Sign Up",
|
|
||||||
"signUpSubtitle": "Make managing your applications simple and fun",
|
|
||||||
"confirmPassword": "Confirm Password",
|
|
||||||
"confirmPasswordTip": "The passwords do not match",
|
|
||||||
"agree": "I agree to",
|
|
||||||
"privacyPolicy": "Privacy-policy",
|
|
||||||
"terms": "Terms",
|
|
||||||
"agreeTip": "Please agree to the Privacy Policy and Terms",
|
|
||||||
"goToLogin": "Login instead",
|
|
||||||
"passwordStrength": "Use 8 or more characters with a mix of letters, numbers & symbols",
|
|
||||||
"forgetPassword": "Forget Password?",
|
|
||||||
"forgetPasswordSubtitle": "Enter your email and we'll send you instructions to reset your password",
|
|
||||||
"emailTip": "Please enter email",
|
|
||||||
"emailValidErrorTip": "The email format you entered is incorrect",
|
|
||||||
"sendResetLink": "Send Reset Link",
|
|
||||||
"email": "Email",
|
|
||||||
"qrcodeSubtitle": "Scan the QR code with your phone to login",
|
|
||||||
"qrcodePrompt": "Click 'Confirm' after scanning to complete login",
|
|
||||||
"qrcodeLogin": "QR Code Login",
|
|
||||||
"codeSubtitle": "Enter your phone number to start managing your project",
|
|
||||||
"code": "Security code",
|
|
||||||
"codeTip": "Security code required {0} characters",
|
|
||||||
"mobile": "Mobile",
|
|
||||||
"mobileLogin": "Mobile Login",
|
|
||||||
"mobileTip": "Please enter mobile number",
|
|
||||||
"mobileErrortip": "The phone number format is incorrect",
|
|
||||||
"sendCode": "Get Security code",
|
|
||||||
"sendText": "Resend in {0}s",
|
|
||||||
"thirdPartyLogin": "Or continue with",
|
|
||||||
"loginAgainTitle": "Please Log In Again",
|
|
||||||
"loginAgainSubTitle": "Your login session has expired. Please log in again to continue.",
|
|
||||||
"layout": {
|
|
||||||
"center": "Align Center",
|
|
||||||
"alignLeft": "Align Left",
|
|
||||||
"alignRight": "Align Right"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,186 +0,0 @@
|
||||||
{
|
|
||||||
"title": "Preferences",
|
|
||||||
"subtitle": "Customize Preferences & Preview in Real Time",
|
|
||||||
"resetTip": "Data has changed, click to reset",
|
|
||||||
"resetTitle": "Reset Preferences",
|
|
||||||
"resetSuccess": "Preferences reset successfully",
|
|
||||||
"appearance": "Appearance",
|
|
||||||
"layout": "Layout",
|
|
||||||
"content": "Content",
|
|
||||||
"other": "Other",
|
|
||||||
"wide": "Wide",
|
|
||||||
"compact": "Fixed",
|
|
||||||
"followSystem": "Follow System",
|
|
||||||
"vertical": "Vertical",
|
|
||||||
"verticalTip": "Side vertical menu mode",
|
|
||||||
"horizontal": "Horizontal",
|
|
||||||
"horizontalTip": "Horizontal menu mode, all menus displayed at the top",
|
|
||||||
"twoColumn": "Two Column",
|
|
||||||
"twoColumnTip": "Vertical Two Column Menu Mode",
|
|
||||||
"headerSidebarNav": "Header Vertical",
|
|
||||||
"headerSidebarNavTip": "Header Full Width, Sidebar Navigation Mode",
|
|
||||||
"headerTwoColumn": "Header Two Column",
|
|
||||||
"headerTwoColumnTip": "Header Navigation & Sidebar Two Column co-exists",
|
|
||||||
"mixedMenu": "Mixed Menu",
|
|
||||||
"mixedMenuTip": "Vertical & Horizontal Menu Co-exists",
|
|
||||||
"fullContent": "Full Content",
|
|
||||||
"fullContentTip": "Only display content body, hide all menus",
|
|
||||||
"normal": "Normal",
|
|
||||||
"plain": "Plain",
|
|
||||||
"rounded": "Rounded",
|
|
||||||
"copyPreferences": "Copy Preferences",
|
|
||||||
"copyPreferencesSuccessTitle": "Copy successful",
|
|
||||||
"copyPreferencesSuccess": "Copy successful, please override in `src/preferences.ts` under app",
|
|
||||||
"clearAndLogout": "Clear Cache & Logout",
|
|
||||||
"mode": "Mode",
|
|
||||||
"general": "General",
|
|
||||||
"language": "Language",
|
|
||||||
"dynamicTitle": "Dynamic Title",
|
|
||||||
"watermark": "Watermark",
|
|
||||||
"checkUpdates": "Periodic update check",
|
|
||||||
"position": {
|
|
||||||
"title": "Preferences Postion",
|
|
||||||
"header": "Header",
|
|
||||||
"auto": "Auto",
|
|
||||||
"fixed": "Fixed"
|
|
||||||
},
|
|
||||||
"sidebar": {
|
|
||||||
"title": "Sidebar",
|
|
||||||
"width": "Width",
|
|
||||||
"visible": "Show Sidebar",
|
|
||||||
"collapsed": "Collpase Menu",
|
|
||||||
"collapsedShowTitle": "Show Menu Title",
|
|
||||||
"autoActivateChild": "Auto Activate SubMenu",
|
|
||||||
"autoActivateChildTip": "`Enabled` to automatically activate the submenu while click menu.",
|
|
||||||
"expandOnHover": "Expand On Hover",
|
|
||||||
"expandOnHoverTip": "When the mouse hovers over menu, \n `Enabled` to expand children menus \n `Disabled` to expand whole sidebar."
|
|
||||||
},
|
|
||||||
"tabbar": {
|
|
||||||
"title": "Tabbar",
|
|
||||||
"enable": "Enable Tab Bar",
|
|
||||||
"icon": "Show Tabbar Icon",
|
|
||||||
"showMore": "Show More Button",
|
|
||||||
"showMaximize": "Show Maximize Button",
|
|
||||||
"persist": "Persist Tabs",
|
|
||||||
"maxCount": "Max Count of Tabs",
|
|
||||||
"maxCountTip": "When the number of tabs exceeds the maximum,\nthe oldest tab will be closed.\n Set to 0 to disable count checking.",
|
|
||||||
"draggable": "Enable Draggable Sort",
|
|
||||||
"wheelable": "Support Mouse Wheel",
|
|
||||||
"middleClickClose": "Close Tab when Mouse Middle Button Click",
|
|
||||||
"wheelableTip": "When enabled, the Tabbar area responds to vertical scrolling events of the scroll wheel.",
|
|
||||||
"styleType": {
|
|
||||||
"title": "Tabs Style",
|
|
||||||
"chrome": "Chrome",
|
|
||||||
"card": "Card",
|
|
||||||
"plain": "Plain",
|
|
||||||
"brisk": "Brisk"
|
|
||||||
},
|
|
||||||
"contextMenu": {
|
|
||||||
"reload": "Reload",
|
|
||||||
"close": "Close",
|
|
||||||
"pin": "Pin",
|
|
||||||
"unpin": "Unpin",
|
|
||||||
"closeLeft": "Close Left Tabs",
|
|
||||||
"closeRight": "Close Right Tabs",
|
|
||||||
"closeOther": "Close Other Tabs",
|
|
||||||
"closeAll": "Close All Tabs",
|
|
||||||
"openInNewWindow": "Open in New Window",
|
|
||||||
"maximize": "Maximize",
|
|
||||||
"restoreMaximize": "Restore"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"navigationMenu": {
|
|
||||||
"title": "Navigation Menu",
|
|
||||||
"style": "Navigation Menu Style",
|
|
||||||
"accordion": "Sidebar Accordion Menu",
|
|
||||||
"split": "Navigation Menu Separation",
|
|
||||||
"splitTip": "When enabled, the sidebar displays the top bar's submenu"
|
|
||||||
},
|
|
||||||
"breadcrumb": {
|
|
||||||
"title": "Breadcrumb",
|
|
||||||
"home": "Show Home Button",
|
|
||||||
"enable": "Enable Breadcrumb",
|
|
||||||
"icon": "Show Breadcrumb Icon",
|
|
||||||
"background": "background",
|
|
||||||
"style": "Breadcrumb Style",
|
|
||||||
"hideOnlyOne": "Hidden when only one"
|
|
||||||
},
|
|
||||||
"animation": {
|
|
||||||
"title": "Animation",
|
|
||||||
"loading": "Page Loading",
|
|
||||||
"transition": "Page Transition",
|
|
||||||
"progress": "Page Progress"
|
|
||||||
},
|
|
||||||
"theme": {
|
|
||||||
"title": "Theme",
|
|
||||||
"radius": "Radius",
|
|
||||||
"light": "Light",
|
|
||||||
"dark": "Dark",
|
|
||||||
"darkSidebar": "Semi Dark Sidebar",
|
|
||||||
"darkHeader": "Semi Dark Header",
|
|
||||||
"weakMode": "Weak Mode",
|
|
||||||
"grayMode": "Gray Mode",
|
|
||||||
"builtin": {
|
|
||||||
"title": "Built-in",
|
|
||||||
"default": "Default",
|
|
||||||
"violet": "Violet",
|
|
||||||
"pink": "Pink",
|
|
||||||
"rose": "Rose",
|
|
||||||
"skyBlue": "Sky Blue",
|
|
||||||
"deepBlue": "Deep Blue",
|
|
||||||
"green": "Green",
|
|
||||||
"deepGreen": "Deep Green",
|
|
||||||
"orange": "Orange",
|
|
||||||
"yellow": "Yellow",
|
|
||||||
"zinc": "Zinc",
|
|
||||||
"neutral": "Neutral",
|
|
||||||
"slate": "Slate",
|
|
||||||
"gray": "Gray",
|
|
||||||
"custom": "Custom"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"header": {
|
|
||||||
"title": "Header",
|
|
||||||
"visible": "Show Header",
|
|
||||||
"modeStatic": "Static",
|
|
||||||
"modeFixed": "Fixed",
|
|
||||||
"modeAuto": "Auto hide & Show",
|
|
||||||
"modeAutoScroll": "Scroll to Hide & Show",
|
|
||||||
"menuAlign": "Menu Align",
|
|
||||||
"menuAlignStart": "Start",
|
|
||||||
"menuAlignEnd": "End",
|
|
||||||
"menuAlignCenter": "Center"
|
|
||||||
},
|
|
||||||
"footer": {
|
|
||||||
"title": "Footer",
|
|
||||||
"visible": "Show Footer",
|
|
||||||
"fixed": "Fixed at Bottom"
|
|
||||||
},
|
|
||||||
"copyright": {
|
|
||||||
"title": "Copyright",
|
|
||||||
"enable": "Enable Copyright",
|
|
||||||
"companyName": "Company Name",
|
|
||||||
"companySiteLink": "Company Site Link",
|
|
||||||
"date": "Date",
|
|
||||||
"icp": "ICP License Number",
|
|
||||||
"icpLink": "ICP Site Link"
|
|
||||||
},
|
|
||||||
"shortcutKeys": {
|
|
||||||
"title": "Shortcut Keys",
|
|
||||||
"global": "Global",
|
|
||||||
"search": "Global Search",
|
|
||||||
"logout": "Logout",
|
|
||||||
"preferences": "Preferences"
|
|
||||||
},
|
|
||||||
"widget": {
|
|
||||||
"title": "Widget",
|
|
||||||
"globalSearch": "Enable Global Search",
|
|
||||||
"fullscreen": "Enable Fullscreen",
|
|
||||||
"themeToggle": "Enable Theme Toggle",
|
|
||||||
"languageToggle": "Enable Language Toggle",
|
|
||||||
"notification": "Enable Notification",
|
|
||||||
"sidebarToggle": "Enable Sidebar Toggle",
|
|
||||||
"lockScreen": "Enable Lock Screen",
|
|
||||||
"refresh": "Enable Refresh"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,104 +0,0 @@
|
||||||
{
|
|
||||||
"formRules": {
|
|
||||||
"required": "Please enter {0}",
|
|
||||||
"selectRequired": "Please select {0}",
|
|
||||||
"minLength": "{0} must be at least {1} characters",
|
|
||||||
"maxLength": "{0} can be at most {1} characters",
|
|
||||||
"length": "{0} must be {1} characters long",
|
|
||||||
"alreadyExists": "{0} `{1}` already exists",
|
|
||||||
"startWith": "{0} must start with `{1}`",
|
|
||||||
"invalidURL": "Please input a valid URL"
|
|
||||||
},
|
|
||||||
"actionTitle": {
|
|
||||||
"edit": "Modify {0}",
|
|
||||||
"create": "Create {0}",
|
|
||||||
"delete": "Delete {0}",
|
|
||||||
"view": "View {0}"
|
|
||||||
},
|
|
||||||
"actionMessage": {
|
|
||||||
"deleteConfirm": "Are you sure to delete {0}?",
|
|
||||||
"deleting": "Deleting {0} ...",
|
|
||||||
"deleteSuccess": "{0} deleted successfully",
|
|
||||||
"operationSuccess": "Operation succeeded",
|
|
||||||
"operationFailed": "Operation failed"
|
|
||||||
},
|
|
||||||
"placeholder": {
|
|
||||||
"input": "Please enter",
|
|
||||||
"select": "Please select"
|
|
||||||
},
|
|
||||||
"captcha": {
|
|
||||||
"title": "Please complete the security verification",
|
|
||||||
"sliderSuccessText": "Passed",
|
|
||||||
"sliderDefaultText": "Slider and drag",
|
|
||||||
"alt": "Supports img tag src attribute value",
|
|
||||||
"sliderRotateDefaultTip": "Click picture to refresh",
|
|
||||||
"sliderRotateFailTip": "Validation failed",
|
|
||||||
"sliderRotateSuccessTip": "Validation successful, time {0} seconds",
|
|
||||||
"refreshAriaLabel": "Refresh captcha",
|
|
||||||
"confirmAriaLabel": "Confirm selection",
|
|
||||||
"confirm": "Confirm",
|
|
||||||
"pointAriaLabel": "Click point",
|
|
||||||
"clickInOrder": "Please click in order"
|
|
||||||
},
|
|
||||||
"iconPicker": {
|
|
||||||
"placeholder": "Select an icon",
|
|
||||||
"search": "Search icon..."
|
|
||||||
},
|
|
||||||
"jsonViewer": {
|
|
||||||
"copy": "Copy",
|
|
||||||
"copied": "Copied"
|
|
||||||
},
|
|
||||||
"fallback": {
|
|
||||||
"pageNotFound": "Oops! Page Not Found",
|
|
||||||
"pageNotFoundDesc": "Sorry, we couldn't find the page you were looking for.",
|
|
||||||
"forbidden": "Oops! Access Denied",
|
|
||||||
"forbiddenDesc": "Sorry, but you don't have permission to access this page.",
|
|
||||||
"internalError": "Oops! Something Went Wrong",
|
|
||||||
"internalErrorDesc": "Sorry, but the server encountered an error.",
|
|
||||||
"offline": "Offline Page",
|
|
||||||
"offlineError": "Oops! Network Error",
|
|
||||||
"offlineErrorDesc": "Sorry, can't connect to the internet. Check your connection.",
|
|
||||||
"comingSoon": "Coming Soon",
|
|
||||||
"http": {
|
|
||||||
"requestTimeout": "The request timed out. Please try again later.",
|
|
||||||
"networkError": "A network error occurred. Please check your internet connection and try again.",
|
|
||||||
"badRequest": "Bad Request. Please check your input and try again.",
|
|
||||||
"unauthorized": "Unauthorized. Please log in to continue.",
|
|
||||||
"forbidden": "Forbidden. You do not have permission to access this resource.",
|
|
||||||
"notFound": "Not Found. The requested resource could not be found.",
|
|
||||||
"internalServerError": "Internal Server Error. Something went wrong on our end. Please try again later."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"widgets": {
|
|
||||||
"document": "Document",
|
|
||||||
"qa": "Q&A",
|
|
||||||
"setting": "Settings",
|
|
||||||
"logoutTip": "Do you want to logout?",
|
|
||||||
"viewAll": "View All Messages",
|
|
||||||
"notifications": "Notifications",
|
|
||||||
"markAllAsRead": "Make All as Read",
|
|
||||||
"clearNotifications": "Clear",
|
|
||||||
"checkUpdatesTitle": "New Version Available",
|
|
||||||
"checkUpdatesDescription": "Click to refresh and get the latest version",
|
|
||||||
"search": {
|
|
||||||
"title": "Search",
|
|
||||||
"searchNavigate": "Search Navigation",
|
|
||||||
"select": "Select",
|
|
||||||
"navigate": "Navigate",
|
|
||||||
"close": "Close",
|
|
||||||
"noResults": "No Search Results Found",
|
|
||||||
"noRecent": "No Search History",
|
|
||||||
"recent": "Search History"
|
|
||||||
},
|
|
||||||
"lockScreen": {
|
|
||||||
"title": "Lock Screen",
|
|
||||||
"screenButton": "Locking",
|
|
||||||
"password": "Password",
|
|
||||||
"placeholder": "Please enter password",
|
|
||||||
"unlock": "Click to unlock",
|
|
||||||
"errorPasswordTip": "Password error, please re-enter",
|
|
||||||
"backToLogin": "Back to login",
|
|
||||||
"entry": "Enter the system"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
{
|
|
||||||
"welcomeBack": "欢迎回来",
|
|
||||||
"pageTitle": "开箱即用的大型中后台管理系统",
|
|
||||||
"pageDesc": "工程化、高性能、跨组件库的前端模版",
|
|
||||||
"loginSuccess": "登录成功",
|
|
||||||
"loginSuccessDesc": "欢迎回来",
|
|
||||||
"loginSubtitle": "请输入您的帐户信息以开始管理您的项目",
|
|
||||||
"selectAccount": "快速选择账号",
|
|
||||||
"username": "账号",
|
|
||||||
"password": "密码",
|
|
||||||
"usernameTip": "请输入用户名",
|
|
||||||
"passwordTip": "请输入密码",
|
|
||||||
"verifyRequiredTip": "请先完成验证",
|
|
||||||
"passwordErrorTip": "密码错误",
|
|
||||||
"rememberMe": "记住账号",
|
|
||||||
"createAnAccount": "创建一个账号",
|
|
||||||
"createAccount": "创建账号",
|
|
||||||
"alreadyHaveAccount": "已经有账号了?",
|
|
||||||
"accountTip": "还没有账号?",
|
|
||||||
"signUp": "注册",
|
|
||||||
"signUpSubtitle": "让您的应用程序管理变得简单而有趣",
|
|
||||||
"confirmPassword": "确认密码",
|
|
||||||
"confirmPasswordTip": "两次输入的密码不一致",
|
|
||||||
"agree": "我同意",
|
|
||||||
"privacyPolicy": "隐私政策",
|
|
||||||
"terms": "条款",
|
|
||||||
"agreeTip": "请同意隐私政策和条款",
|
|
||||||
"goToLogin": "去登录",
|
|
||||||
"passwordStrength": "使用 8 个或更多字符,混合字母、数字和符号",
|
|
||||||
"forgetPassword": "忘记密码?",
|
|
||||||
"forgetPasswordSubtitle": "输入您的电子邮件,我们将向您发送重置密码的连接",
|
|
||||||
"emailTip": "请输入邮箱",
|
|
||||||
"emailValidErrorTip": "你输入的邮箱格式不正确",
|
|
||||||
"sendResetLink": "发送重置链接",
|
|
||||||
"email": "邮箱",
|
|
||||||
"qrcodeSubtitle": "请用手机扫描二维码登录",
|
|
||||||
"qrcodePrompt": "扫码后点击 '确认',即可完成登录",
|
|
||||||
"qrcodeLogin": "扫码登录",
|
|
||||||
"codeSubtitle": "请输入您的手机号码以开始管理您的项目",
|
|
||||||
"code": "验证码",
|
|
||||||
"codeTip": "请输入{0}位验证码",
|
|
||||||
"mobile": "手机号码",
|
|
||||||
"mobileTip": "请输入手机号",
|
|
||||||
"mobileErrortip": "手机号码格式错误",
|
|
||||||
"mobileLogin": "手机号登录",
|
|
||||||
"sendCode": "获取验证码",
|
|
||||||
"sendText": "{0}秒后重新获取",
|
|
||||||
"thirdPartyLogin": "其他登录方式",
|
|
||||||
"loginAgainTitle": "重新登录",
|
|
||||||
"loginAgainSubTitle": "您的登录状态已过期,请重新登录以继续。",
|
|
||||||
"layout": {
|
|
||||||
"center": "居中",
|
|
||||||
"alignLeft": "居左",
|
|
||||||
"alignRight": "居右"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,186 +0,0 @@
|
||||||
{
|
|
||||||
"title": "偏好设置",
|
|
||||||
"subtitle": "自定义偏好设置 & 实时预览",
|
|
||||||
"resetTitle": "重置偏好设置",
|
|
||||||
"resetTip": "数据有变化,点击可进行重置",
|
|
||||||
"resetSuccess": "重置偏好设置成功",
|
|
||||||
"appearance": "外观",
|
|
||||||
"layout": "布局",
|
|
||||||
"content": "内容",
|
|
||||||
"other": "其它",
|
|
||||||
"wide": "流式",
|
|
||||||
"compact": "定宽",
|
|
||||||
"followSystem": "跟随系统",
|
|
||||||
"vertical": "垂直",
|
|
||||||
"verticalTip": "侧边垂直菜单模式",
|
|
||||||
"horizontal": "水平",
|
|
||||||
"horizontalTip": "水平菜单模式,菜单全部显示在顶部",
|
|
||||||
"twoColumn": "双列菜单",
|
|
||||||
"twoColumnTip": "垂直双列菜单模式",
|
|
||||||
"headerSidebarNav": "侧边导航",
|
|
||||||
"headerSidebarNavTip": "顶部通栏,侧边导航模式",
|
|
||||||
"headerTwoColumn": "混合双列",
|
|
||||||
"headerTwoColumnTip": "双列、水平菜单共存模式",
|
|
||||||
"mixedMenu": "混合垂直",
|
|
||||||
"mixedMenuTip": "垂直水平菜单共存",
|
|
||||||
"fullContent": "内容全屏",
|
|
||||||
"fullContentTip": "不显示任何菜单,只显示内容主体",
|
|
||||||
"normal": "常规",
|
|
||||||
"plain": "朴素",
|
|
||||||
"rounded": "圆润",
|
|
||||||
"copyPreferences": "复制偏好设置",
|
|
||||||
"copyPreferencesSuccessTitle": "复制成功",
|
|
||||||
"copyPreferencesSuccess": "复制成功,请在 app 下的 `src/preferences.ts`内进行覆盖",
|
|
||||||
"clearAndLogout": "清空缓存 & 退出登录",
|
|
||||||
"mode": "模式",
|
|
||||||
"general": "通用",
|
|
||||||
"language": "语言",
|
|
||||||
"dynamicTitle": "动态标题",
|
|
||||||
"watermark": "水印",
|
|
||||||
"checkUpdates": "定时检查更新",
|
|
||||||
"position": {
|
|
||||||
"title": "偏好设置位置",
|
|
||||||
"header": "顶栏",
|
|
||||||
"auto": "自动",
|
|
||||||
"fixed": "固定"
|
|
||||||
},
|
|
||||||
"sidebar": {
|
|
||||||
"title": "侧边栏",
|
|
||||||
"width": "宽度",
|
|
||||||
"visible": "显示侧边栏",
|
|
||||||
"collapsed": "折叠菜单",
|
|
||||||
"collapsedShowTitle": "折叠显示菜单名",
|
|
||||||
"autoActivateChild": "自动激活子菜单",
|
|
||||||
"autoActivateChildTip": "点击顶层菜单时,自动激活第一个子菜单或者上一次激活的子菜单",
|
|
||||||
"expandOnHover": "鼠标悬停展开",
|
|
||||||
"expandOnHoverTip": "鼠标在折叠区域悬浮时,`启用`则展开当前子菜单,`禁用`则展开整个侧边栏"
|
|
||||||
},
|
|
||||||
"tabbar": {
|
|
||||||
"title": "标签栏",
|
|
||||||
"enable": "启用标签栏",
|
|
||||||
"icon": "显示标签栏图标",
|
|
||||||
"showMore": "显示更多按钮",
|
|
||||||
"showMaximize": "显示最大化按钮",
|
|
||||||
"persist": "持久化标签页",
|
|
||||||
"maxCount": "最大标签数",
|
|
||||||
"maxCountTip": "每次打开新的标签时如果超过最大标签数,\n会自动关闭一个最先打开的标签\n设置为 0 则不限制",
|
|
||||||
"draggable": "启动拖拽排序",
|
|
||||||
"wheelable": "启用纵向滚轮响应",
|
|
||||||
"middleClickClose": "点击鼠标中键关闭标签页",
|
|
||||||
"wheelableTip": "开启后,标签栏区域可以响应滚轮的纵向滚动事件。\n关闭时,只能响应系统的横向滚动事件(需要按下Shift再滚动滚轮)",
|
|
||||||
"styleType": {
|
|
||||||
"title": "标签页风格",
|
|
||||||
"chrome": "谷歌",
|
|
||||||
"card": "卡片",
|
|
||||||
"plain": "朴素",
|
|
||||||
"brisk": "轻快"
|
|
||||||
},
|
|
||||||
"contextMenu": {
|
|
||||||
"reload": "重新加载",
|
|
||||||
"close": "关闭",
|
|
||||||
"pin": "固定",
|
|
||||||
"unpin": "取消固定",
|
|
||||||
"closeLeft": "关闭左侧标签页",
|
|
||||||
"closeRight": "关闭右侧标签页",
|
|
||||||
"closeOther": "关闭其它标签页",
|
|
||||||
"closeAll": "关闭全部标签页",
|
|
||||||
"openInNewWindow": "在新窗口打开",
|
|
||||||
"maximize": "最大化",
|
|
||||||
"restoreMaximize": "还原"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"navigationMenu": {
|
|
||||||
"title": "导航菜单",
|
|
||||||
"style": "导航菜单风格",
|
|
||||||
"accordion": "侧边导航菜单手风琴模式",
|
|
||||||
"split": "导航菜单分离",
|
|
||||||
"splitTip": "开启时,侧边栏显示顶栏对应菜单的子菜单"
|
|
||||||
},
|
|
||||||
"breadcrumb": {
|
|
||||||
"title": "面包屑导航",
|
|
||||||
"enable": "开启面包屑导航",
|
|
||||||
"icon": "显示面包屑图标",
|
|
||||||
"home": "显示首页按钮",
|
|
||||||
"style": "面包屑风格",
|
|
||||||
"hideOnlyOne": "仅有一个时隐藏",
|
|
||||||
"background": "背景"
|
|
||||||
},
|
|
||||||
"animation": {
|
|
||||||
"title": "动画",
|
|
||||||
"loading": "页面切换 Loading",
|
|
||||||
"transition": "页面切换动画",
|
|
||||||
"progress": "页面切换进度条"
|
|
||||||
},
|
|
||||||
"theme": {
|
|
||||||
"title": "主题",
|
|
||||||
"radius": "圆角",
|
|
||||||
"light": "浅色",
|
|
||||||
"dark": "深色",
|
|
||||||
"darkSidebar": "深色侧边栏",
|
|
||||||
"darkHeader": "深色顶栏",
|
|
||||||
"weakMode": "色弱模式",
|
|
||||||
"grayMode": "灰色模式",
|
|
||||||
"builtin": {
|
|
||||||
"title": "内置主题",
|
|
||||||
"default": "默认",
|
|
||||||
"violet": "紫罗兰",
|
|
||||||
"pink": "樱花粉",
|
|
||||||
"rose": "玫瑰红",
|
|
||||||
"skyBlue": "天蓝色",
|
|
||||||
"deepBlue": "深蓝色",
|
|
||||||
"green": "浅绿色",
|
|
||||||
"deepGreen": "深绿色",
|
|
||||||
"orange": "橙黄色",
|
|
||||||
"yellow": "柠檬黄",
|
|
||||||
"zinc": "锌色灰",
|
|
||||||
"neutral": "中性色",
|
|
||||||
"slate": "石板灰",
|
|
||||||
"gray": "中灰色",
|
|
||||||
"custom": "自定义"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"header": {
|
|
||||||
"title": "顶栏",
|
|
||||||
"modeStatic": "静止",
|
|
||||||
"modeFixed": "固定",
|
|
||||||
"modeAuto": "自动隐藏和显示",
|
|
||||||
"modeAutoScroll": "滚动隐藏和显示",
|
|
||||||
"visible": "显示顶栏",
|
|
||||||
"menuAlign": "菜单位置",
|
|
||||||
"menuAlignStart": "左侧",
|
|
||||||
"menuAlignEnd": "右侧",
|
|
||||||
"menuAlignCenter": "居中"
|
|
||||||
},
|
|
||||||
"footer": {
|
|
||||||
"title": "底栏",
|
|
||||||
"visible": "显示底栏",
|
|
||||||
"fixed": "固定在底部"
|
|
||||||
},
|
|
||||||
"copyright": {
|
|
||||||
"title": "版权",
|
|
||||||
"enable": "启用版权",
|
|
||||||
"companyName": "公司名",
|
|
||||||
"companySiteLink": "公司主页",
|
|
||||||
"date": "日期",
|
|
||||||
"icp": "ICP 备案号",
|
|
||||||
"icpLink": "ICP 网站链接"
|
|
||||||
},
|
|
||||||
"shortcutKeys": {
|
|
||||||
"title": "快捷键",
|
|
||||||
"global": "全局",
|
|
||||||
"search": "全局搜索",
|
|
||||||
"logout": "退出登录",
|
|
||||||
"preferences": "偏好设置"
|
|
||||||
},
|
|
||||||
"widget": {
|
|
||||||
"title": "小部件",
|
|
||||||
"globalSearch": "启用全局搜索",
|
|
||||||
"fullscreen": "启用全屏",
|
|
||||||
"themeToggle": "启用主题切换",
|
|
||||||
"languageToggle": "启用语言切换",
|
|
||||||
"notification": "启用通知",
|
|
||||||
"sidebarToggle": "启用侧边栏切换",
|
|
||||||
"lockScreen": "启用锁屏",
|
|
||||||
"refresh": "启用刷新"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,104 +0,0 @@
|
||||||
{
|
|
||||||
"formRules": {
|
|
||||||
"required": "请输入{0}",
|
|
||||||
"selectRequired": "请选择{0}",
|
|
||||||
"minLength": "{0}至少{1}个字符",
|
|
||||||
"maxLength": "{0}最多{1}个字符",
|
|
||||||
"length": "{0}长度必须为{1}个字符",
|
|
||||||
"alreadyExists": "{0} `{1}` 已存在",
|
|
||||||
"startWith": "{0}必须以 {1} 开头",
|
|
||||||
"invalidURL": "请输入有效的链接"
|
|
||||||
},
|
|
||||||
"actionTitle": {
|
|
||||||
"edit": "修改{0}",
|
|
||||||
"create": "新增{0}",
|
|
||||||
"delete": "删除{0}",
|
|
||||||
"view": "查看{0}"
|
|
||||||
},
|
|
||||||
"actionMessage": {
|
|
||||||
"deleteConfirm": "确定删除 {0} 吗?",
|
|
||||||
"deleting": "正在删除 {0} ...",
|
|
||||||
"deleteSuccess": "{0} 删除成功",
|
|
||||||
"operationSuccess": "操作成功",
|
|
||||||
"operationFailed": "操作失败"
|
|
||||||
},
|
|
||||||
"placeholder": {
|
|
||||||
"input": "请输入",
|
|
||||||
"select": "请选择"
|
|
||||||
},
|
|
||||||
"captcha": {
|
|
||||||
"title": "请完成安全验证",
|
|
||||||
"sliderSuccessText": "验证通过",
|
|
||||||
"sliderDefaultText": "请按住滑块拖动",
|
|
||||||
"sliderRotateDefaultTip": "点击图片可刷新",
|
|
||||||
"sliderRotateFailTip": "验证失败",
|
|
||||||
"sliderRotateSuccessTip": "验证成功,耗时{0}秒",
|
|
||||||
"alt": "支持img标签src属性值",
|
|
||||||
"refreshAriaLabel": "刷新验证码",
|
|
||||||
"confirmAriaLabel": "确认选择",
|
|
||||||
"confirm": "确认",
|
|
||||||
"pointAriaLabel": "点击点",
|
|
||||||
"clickInOrder": "请依次点击"
|
|
||||||
},
|
|
||||||
"iconPicker": {
|
|
||||||
"placeholder": "选择一个图标",
|
|
||||||
"search": "搜索图标..."
|
|
||||||
},
|
|
||||||
"jsonViewer": {
|
|
||||||
"copy": "复制",
|
|
||||||
"copied": "已复制"
|
|
||||||
},
|
|
||||||
"fallback": {
|
|
||||||
"pageNotFound": "哎呀!未找到页面",
|
|
||||||
"pageNotFoundDesc": "抱歉,我们无法找到您要找的页面。",
|
|
||||||
"forbidden": "哎呀!访问被拒绝",
|
|
||||||
"forbiddenDesc": "抱歉,您没有权限访问此页面。",
|
|
||||||
"internalError": "哎呀!出错了",
|
|
||||||
"internalErrorDesc": "抱歉,服务器遇到错误。",
|
|
||||||
"offline": "离线页面",
|
|
||||||
"offlineError": "哎呀!网络错误",
|
|
||||||
"offlineErrorDesc": "抱歉,无法连接到互联网,请检查您的网络连接并重试。",
|
|
||||||
"comingSoon": "即将推出",
|
|
||||||
"http": {
|
|
||||||
"requestTimeout": "请求超时,请稍后再试。",
|
|
||||||
"networkError": "网络异常,请检查您的网络连接后重试。",
|
|
||||||
"badRequest": "请求错误。请检查您的输入并重试。",
|
|
||||||
"unauthorized": "登录认证过期,请重新登录后继续。",
|
|
||||||
"forbidden": "禁止访问, 您没有权限访问此资源。",
|
|
||||||
"notFound": "未找到, 请求的资源不存在。",
|
|
||||||
"internalServerError": "内部服务器错误,请稍后再试。"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"widgets": {
|
|
||||||
"document": "文档",
|
|
||||||
"qa": "问题 & 帮助",
|
|
||||||
"setting": "设置",
|
|
||||||
"logoutTip": "是否退出登录?",
|
|
||||||
"viewAll": "查看所有消息",
|
|
||||||
"notifications": "通知",
|
|
||||||
"markAllAsRead": "全部标记为已读",
|
|
||||||
"clearNotifications": "清空",
|
|
||||||
"checkUpdatesTitle": "新版本可用",
|
|
||||||
"checkUpdatesDescription": "点击刷新以获取最新版本",
|
|
||||||
"search": {
|
|
||||||
"title": "搜索",
|
|
||||||
"searchNavigate": "搜索导航菜单",
|
|
||||||
"select": "选择",
|
|
||||||
"navigate": "导航",
|
|
||||||
"close": "关闭",
|
|
||||||
"noResults": "未找到搜索结果",
|
|
||||||
"noRecent": "没有搜索历史",
|
|
||||||
"recent": "搜索历史"
|
|
||||||
},
|
|
||||||
"lockScreen": {
|
|
||||||
"title": "锁定屏幕",
|
|
||||||
"screenButton": "锁定",
|
|
||||||
"password": "密码",
|
|
||||||
"placeholder": "请输入锁屏密码",
|
|
||||||
"unlock": "点击解锁",
|
|
||||||
"errorPasswordTip": "密码错误,请重新输入",
|
|
||||||
"backToLogin": "返回登录",
|
|
||||||
"entry": "进入系统"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,209 +8,209 @@ import { useSettingStore } from "/@/store/settings";
|
||||||
import { statusUtil } from "/@/views/certd/pipeline/pipeline/utils/util.status";
|
import { statusUtil } from "/@/views/certd/pipeline/pipeline/utils/util.status";
|
||||||
|
|
||||||
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
|
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
|
||||||
return await api.GetList(query);
|
return await api.GetList(query);
|
||||||
};
|
};
|
||||||
const editRequest = async ({ form, row }: EditReq) => {
|
const editRequest = async ({ form, row }: EditReq) => {
|
||||||
form.id = row.id;
|
form.id = row.id;
|
||||||
const res = await api.UpdateObj(form);
|
const res = await api.UpdateObj(form);
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
const delRequest = async ({ row }: DelReq) => {
|
const delRequest = async ({ row }: DelReq) => {
|
||||||
return await api.DelObj(row.id);
|
return await api.DelObj(row.id);
|
||||||
};
|
};
|
||||||
|
|
||||||
const addRequest = async ({ form }: AddReq) => {
|
const addRequest = async ({ form }: AddReq) => {
|
||||||
const res = await api.AddObj(form);
|
const res = await api.AddObj(form);
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
const selectedRowKeys: Ref<any[]> = ref([]);
|
const selectedRowKeys: Ref<any[]> = ref([]);
|
||||||
context.selectedRowKeys = selectedRowKeys;
|
context.selectedRowKeys = selectedRowKeys;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
crudOptions: {
|
crudOptions: {
|
||||||
settings: {
|
settings: {
|
||||||
plugins: {
|
plugins: {
|
||||||
//这里使用行选择插件,生成行选择crudOptions配置,最终会与crudOptions合并
|
//这里使用行选择插件,生成行选择crudOptions配置,最终会与crudOptions合并
|
||||||
rowSelection: {
|
rowSelection: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
order: -2,
|
order: -2,
|
||||||
before: true,
|
before: true,
|
||||||
// handle: (pluginProps,useCrudProps)=>CrudOptions,
|
// handle: (pluginProps,useCrudProps)=>CrudOptions,
|
||||||
props: {
|
props: {
|
||||||
multiple: true,
|
multiple: true,
|
||||||
crossPage: true,
|
crossPage: true,
|
||||||
selectedRowKeys,
|
selectedRowKeys,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
request: {
|
request: {
|
||||||
pageRequest,
|
pageRequest,
|
||||||
addRequest,
|
addRequest,
|
||||||
editRequest,
|
editRequest,
|
||||||
delRequest,
|
delRequest,
|
||||||
},
|
},
|
||||||
actionbar: {
|
actionbar: {
|
||||||
buttons: {
|
buttons: {
|
||||||
add: {
|
add: {
|
||||||
show: false,
|
show: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
search: {
|
search: {
|
||||||
formItem: {
|
formItem: {
|
||||||
labelCol: {
|
labelCol: {
|
||||||
style: {
|
style: {
|
||||||
// width: "100px"
|
// width: "100px"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wrapperCol: {
|
wrapperCol: {
|
||||||
style: {
|
style: {
|
||||||
width: "50%",
|
width: "50%",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
rowHandle: {
|
rowHandle: {
|
||||||
minWidth: 200,
|
minWidth: 200,
|
||||||
fixed: "right",
|
fixed: "right",
|
||||||
buttons: {
|
buttons: {
|
||||||
edit: {
|
edit: {
|
||||||
show: false,
|
show: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
columns: {
|
columns: {
|
||||||
id: {
|
id: {
|
||||||
title: "ID",
|
title: "ID",
|
||||||
key: "id",
|
key: "id",
|
||||||
type: "number",
|
type: "number",
|
||||||
column: {
|
column: {
|
||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
show: false,
|
show: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
userId: {
|
userId: {
|
||||||
title: "用户Id",
|
title: t("certd.fields.userId"),
|
||||||
type: "number",
|
type: "number",
|
||||||
search: {
|
search: {
|
||||||
show: computed(() => {
|
show: computed(() => {
|
||||||
return userStore.isAdmin && settingStore.sysPublic.managerOtherUserPipeline;
|
return userStore.isAdmin && settingStore.sysPublic.managerOtherUserPipeline;
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
show: false,
|
show: false,
|
||||||
},
|
},
|
||||||
column: {
|
column: {
|
||||||
show: computed(() => {
|
show: computed(() => {
|
||||||
return userStore.isAdmin && settingStore.sysPublic.managerOtherUserPipeline;
|
return userStore.isAdmin && settingStore.sysPublic.managerOtherUserPipeline;
|
||||||
}),
|
}),
|
||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pipelineId: {
|
pipelineId: {
|
||||||
title: "流水线Id",
|
title: t("certd.fields.pipelineId"),
|
||||||
type: "number",
|
type: "number",
|
||||||
search: {
|
search: {
|
||||||
show: true,
|
show: true,
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
show: false,
|
show: false,
|
||||||
},
|
},
|
||||||
column: {
|
column: {
|
||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pipelineTitle: {
|
pipelineTitle: {
|
||||||
title: "流水线名称",
|
title: t('certd.fields.pipelineName'),
|
||||||
type: "text",
|
type: "text",
|
||||||
search: {
|
search: {
|
||||||
show: true,
|
show: true,
|
||||||
},
|
},
|
||||||
column: {
|
column: {
|
||||||
width: 300,
|
width: 300,
|
||||||
tooltip: true,
|
tooltip: true,
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
cellRender: ({ row, value }) => {
|
cellRender: ({ row, value }) => {
|
||||||
return <router-link to={{ path: "/certd/pipeline/detail", query: { id: row.pipelineId, editMode: false, historyId: row.id } }}>{value}</router-link>;
|
return <router-link to={{ path: "/certd/pipeline/detail", query: { id: row.pipelineId, editMode: false, historyId: row.id } }}>{value}</router-link>;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
triggerType: {
|
triggerType: {
|
||||||
title: "触发类型",
|
title: t("certd.fields.triggerType"),
|
||||||
type: "dict-select",
|
type: "dict-select",
|
||||||
search: {
|
search: {
|
||||||
show: true,
|
show: true,
|
||||||
},
|
},
|
||||||
dict: dict({
|
dict: dict({
|
||||||
data: [
|
data: [
|
||||||
{ value: "user", label: "手动执行" },
|
{ value: "user", label: t("certd.triggerTypes.manual") },
|
||||||
{ value: "timer", label: "定时执行" },
|
{ value: "timer", label: t("certd.triggerTypes.timer") },
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
form: {
|
form: {
|
||||||
show: false,
|
show: false,
|
||||||
value: "custom",
|
value: "custom",
|
||||||
},
|
},
|
||||||
column: {
|
column: {
|
||||||
sorter: true,
|
sorter: true,
|
||||||
width: 90,
|
width: 90,
|
||||||
align: "center",
|
align: "center",
|
||||||
show: true,
|
show: true,
|
||||||
component: {
|
component: {
|
||||||
color: "auto",
|
color: "auto",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
status: {
|
status: {
|
||||||
title: "状态",
|
title: t("certd.fields.status"),
|
||||||
type: "dict-select",
|
type: "dict-select",
|
||||||
search: {
|
search: {
|
||||||
show: true,
|
show: true,
|
||||||
},
|
},
|
||||||
dict: dict({
|
dict: dict({
|
||||||
data: statusUtil.getOptions(),
|
data: statusUtil.getOptions(),
|
||||||
}),
|
}),
|
||||||
form: {
|
form: {
|
||||||
show: false,
|
show: false,
|
||||||
},
|
},
|
||||||
column: {
|
column: {
|
||||||
sorter: true,
|
sorter: true,
|
||||||
width: 120,
|
width: 120,
|
||||||
align: "center",
|
align: "center",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
createTime: {
|
createTime: {
|
||||||
title: "创建时间",
|
title: t("certd.fields.createTime"),
|
||||||
type: "datetime",
|
type: "datetime",
|
||||||
form: {
|
form: {
|
||||||
show: false,
|
show: false,
|
||||||
},
|
},
|
||||||
column: {
|
column: {
|
||||||
sorter: true,
|
sorter: true,
|
||||||
width: 160,
|
width: 160,
|
||||||
align: "center",
|
align: "center",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
updateTime: {
|
updateTime: {
|
||||||
title: "更新时间",
|
title: t("certd.fields.updateTime"),
|
||||||
type: "datetime",
|
type: "datetime",
|
||||||
form: {
|
form: {
|
||||||
show: false,
|
show: false,
|
||||||
},
|
},
|
||||||
column: {
|
column: {
|
||||||
show: true,
|
show: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<fs-page class="page-cert">
|
<fs-page class="page-cert">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="title">流水线执行记录</div>
|
<div class="title">{{ t("certd.pipelineExecutionRecords") }}</div>
|
||||||
</template>
|
</template>
|
||||||
<fs-crud ref="crudRef" v-bind="crudBinding">
|
<fs-crud ref="crudRef" v-bind="crudBinding">
|
||||||
<template #pagination-left>
|
<template #pagination-left>
|
||||||
<a-tooltip title="批量删除">
|
<a-tooltip :title="t('certd.batchDelete')">
|
||||||
<fs-button icon="DeleteOutlined" @click="handleBatchDelete"></fs-button>
|
<fs-button icon="DeleteOutlined" @click="handleBatchDelete"></fs-button>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</template>
|
</template>
|
||||||
|
@ -13,12 +13,16 @@
|
||||||
</fs-page>
|
</fs-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onActivated, onMounted } from "vue";
|
import { onActivated, onMounted } from "vue";
|
||||||
import { useFs } from "@fast-crud/fast-crud";
|
import { useFs } from "@fast-crud/fast-crud";
|
||||||
import createCrudOptions from "./crud";
|
import createCrudOptions from "./crud";
|
||||||
import { message, Modal } from "ant-design-vue";
|
import { message, Modal } from "ant-design-vue";
|
||||||
import { DeleteBatch } from "./api";
|
import { DeleteBatch } from "./api";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: "PipelineHistory",
|
name: "PipelineHistory",
|
||||||
|
@ -29,17 +33,17 @@ const selectedRowKeys = context.selectedRowKeys;
|
||||||
const handleBatchDelete = () => {
|
const handleBatchDelete = () => {
|
||||||
if (selectedRowKeys.value?.length > 0) {
|
if (selectedRowKeys.value?.length > 0) {
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: "确认",
|
title: t("certd.confirm"),
|
||||||
content: `确定要批量删除这${selectedRowKeys.value.length}条记录吗`,
|
content: t("certd.confirmBatchDeleteContent", { count: selectedRowKeys.value.length }),
|
||||||
async onOk() {
|
async onOk() {
|
||||||
await DeleteBatch(selectedRowKeys.value);
|
await DeleteBatch(selectedRowKeys.value);
|
||||||
message.info("删除成功");
|
message.info(t("certd.deleteSuccess"));
|
||||||
crudExpose.doRefresh();
|
crudExpose.doRefresh();
|
||||||
selectedRowKeys.value = [];
|
selectedRowKeys.value = [];
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
message.error("请先勾选记录");
|
message.error(t("certd.pleaseSelectRecords"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<a-button v-if="showButton" type="primary" @click="open">修改密码</a-button>
|
<a-button v-if="showButton" type="primary" @click="open">
|
||||||
|
{{ $t("passwordForm.changePasswordButton") }}
|
||||||
|
</a-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
import { CrudOptions, useColumns, useFormWrapper } from "@fast-crud/fast-crud";
|
import { CrudOptions, useColumns, useFormWrapper } from "@fast-crud/fast-crud";
|
||||||
import * as api from "/@/views/certd/mine/api";
|
import * as api from "/@/views/certd/mine/api";
|
||||||
import { notification } from "ant-design-vue";
|
import { notification } from "ant-design-vue";
|
||||||
|
@ -17,23 +22,24 @@ let passwordFormRef = ref();
|
||||||
|
|
||||||
const validatePass1 = async (rule: any, value: any) => {
|
const validatePass1 = async (rule: any, value: any) => {
|
||||||
if (value === "") {
|
if (value === "") {
|
||||||
throw new Error("请输入密码");
|
throw new Error(t("passwordForm.enterPassword"));
|
||||||
}
|
}
|
||||||
const formData = passwordFormRef.value.getFormData();
|
const formData = passwordFormRef.value.getFormData();
|
||||||
if (formData.confirmNewPassword !== "") {
|
if (formData.confirmNewPassword !== "") {
|
||||||
passwordFormRef.value.formRef.formRef.validateFields(["confirmNewPassword"]);
|
passwordFormRef.value.formRef.formRef.validateFields(["confirmNewPassword"]);
|
||||||
}
|
}
|
||||||
if (formData.password === formData.newPassword) {
|
if (formData.password === formData.newPassword) {
|
||||||
throw new Error("新密码不能和旧密码相同");
|
throw new Error(t("passwordForm.newPasswordNotSameOld"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const validatePass2 = async (rule: any, value: any) => {
|
const validatePass2 = async (rule: any, value: any) => {
|
||||||
if (value === "") {
|
if (value === "") {
|
||||||
throw new Error("请再次输入密码");
|
throw new Error(t("passwordForm.enterPasswordAgain"));
|
||||||
} else if (value !== passwordFormRef.value.getFormData().newPassword) {
|
} else if (value !== passwordFormRef.value.getFormData().newPassword) {
|
||||||
throw new Error("两次输入密码不一致!");
|
throw new Error(t("passwordForm.passwordsNotMatch"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const { openDialog } = useFormWrapper();
|
const { openDialog } = useFormWrapper();
|
||||||
const { buildFormOptions } = useColumns();
|
const { buildFormOptions } = useColumns();
|
||||||
|
@ -43,7 +49,7 @@ const passwordFormOptions: CrudOptions = {
|
||||||
span: 24,
|
span: 24,
|
||||||
},
|
},
|
||||||
wrapper: {
|
wrapper: {
|
||||||
title: "修改密码",
|
title: t("passwordForm.title"),
|
||||||
width: "500px",
|
width: "500px",
|
||||||
},
|
},
|
||||||
async doSubmit({ form }) {
|
async doSubmit({ form }) {
|
||||||
|
@ -52,34 +58,37 @@ const passwordFormOptions: CrudOptions = {
|
||||||
await userStore.loadUserInfo();
|
await userStore.loadUserInfo();
|
||||||
},
|
},
|
||||||
async afterSubmit() {
|
async afterSubmit() {
|
||||||
notification.success({ message: "修改成功" });
|
notification.success({ message: t("passwordForm.successMessage") });
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
columns: {
|
columns: {
|
||||||
password: {
|
password: {
|
||||||
title: "旧密码",
|
title: t("passwordForm.oldPassword"),
|
||||||
type: "password",
|
type: "password",
|
||||||
form: {
|
form: {
|
||||||
rules: [{ required: true, message: "请输入旧密码" }],
|
rules: [{ required: true, message: t("passwordForm.oldPasswordRequired") }],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
newPassword: {
|
newPassword: {
|
||||||
title: "新密码",
|
title: t("passwordForm.newPassword"),
|
||||||
type: "password",
|
type: "password",
|
||||||
form: {
|
form: {
|
||||||
rules: [
|
rules: [
|
||||||
{ required: true, message: "请输入确认密码" },
|
{ required: true, message: t("passwordForm.newPasswordRequired") },
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
{ validator: validatePass1, trigger: "blur" },
|
{ validator: validatePass1, trigger: "blur" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
confirmNewPassword: {
|
confirmNewPassword: {
|
||||||
title: "确认新密码",
|
title: t("passwordForm.confirmNewPassword"),
|
||||||
type: "password",
|
type: "password",
|
||||||
form: {
|
form: {
|
||||||
rules: [
|
rules: [
|
||||||
{ required: true, message: "请输入确认密码" },
|
{
|
||||||
|
required: true,
|
||||||
|
message: t("passwordForm.confirmNewPasswordRequired"),
|
||||||
|
},
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
{ validator: validatePass2, trigger: "blur" },
|
{ validator: validatePass2, trigger: "blur" },
|
||||||
],
|
],
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,14 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<fs-page class="page-cert">
|
<fs-page class="page-cert">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="title">我的流水线</div>
|
<div class="title">{{ t("certd.myPipelines") }}</div>
|
||||||
</template>
|
</template>
|
||||||
<fs-crud ref="crudRef" v-bind="crudBinding">
|
<fs-crud ref="crudRef" v-bind="crudBinding">
|
||||||
<div v-if="selectedRowKeys.length > 0" class="batch-actions">
|
<div v-if="selectedRowKeys.length > 0" class="batch-actions">
|
||||||
<div class="batch-actions-inner">
|
<div class="batch-actions-inner">
|
||||||
<span> 已选择 {{ selectedRowKeys.length }} 项 </span>
|
<span>{{ t("certd.selectedCount", { count: selectedRowKeys.length }) }}</span>
|
||||||
<fs-button icon="ion:trash-outline" class="color-red" type="link" text="批量删除" @click="batchDelete"></fs-button>
|
<fs-button icon="ion:trash-outline" class="color-red" type="link" :text="t('certd.batchDelete')" @click="batchDelete"></fs-button>
|
||||||
<fs-button icon="icon-park-outline:replay-music" class="need-plus" type="link" text="强制重新运行" @click="batchRerun"></fs-button>
|
<fs-button icon="icon-park-outline:replay-music" class="need-plus" type="link" :text="t('certd.batchForceRerun')" @click="batchRerun"></fs-button>
|
||||||
<change-group class="color-green" :selected-row-keys="selectedRowKeys" @change="batchFinished"></change-group>
|
<change-group class="color-green" :selected-row-keys="selectedRowKeys" @change="batchFinished"></change-group>
|
||||||
<change-notification class="color-green" :selected-row-keys="selectedRowKeys" @change="batchFinished"></change-notification>
|
<change-notification class="color-green" :selected-row-keys="selectedRowKeys" @change="batchFinished"></change-notification>
|
||||||
<change-trigger class="color-green" :selected-row-keys="selectedRowKeys" @change="batchFinished"></change-trigger>
|
<change-trigger class="color-green" :selected-row-keys="selectedRowKeys" @change="batchFinished"></change-trigger>
|
||||||
|
@ -16,12 +16,13 @@
|
||||||
</div>
|
</div>
|
||||||
<template #actionbar-right> </template>
|
<template #actionbar-right> </template>
|
||||||
<template #form-bottom>
|
<template #form-bottom>
|
||||||
<div>申请证书</div>
|
<div>{{ t("certd.applyCertificate") }}</div>
|
||||||
</template>
|
</template>
|
||||||
</fs-crud>
|
</fs-crud>
|
||||||
</fs-page>
|
</fs-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onActivated, onMounted, ref } from "vue";
|
import { onActivated, onMounted, ref } from "vue";
|
||||||
import { dict, useFs } from "@fast-crud/fast-crud";
|
import { dict, useFs } from "@fast-crud/fast-crud";
|
||||||
|
@ -31,6 +32,9 @@ import ChangeGroup from "./components/change-group.vue";
|
||||||
import ChangeTrigger from "./components/change-trigger.vue";
|
import ChangeTrigger from "./components/change-trigger.vue";
|
||||||
import { Modal, notification } from "ant-design-vue";
|
import { Modal, notification } from "ant-design-vue";
|
||||||
import * as api from "./api";
|
import * as api from "./api";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
import ChangeNotification from "/@/views/certd/pipeline/components/change-notification.vue";
|
import ChangeNotification from "/@/views/certd/pipeline/components/change-notification.vue";
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
|
|
|
@ -1,32 +1,46 @@
|
||||||
<template>
|
<template>
|
||||||
<a-modal v-model:open="openRef" class="order-modal" title="订单确认" @ok="orderCreate">
|
<a-modal v-model:open="openRef" class="order-modal" :title="$t('order.confirmTitle')" @ok="orderCreate">
|
||||||
<div v-if="product" class="order-box">
|
<div v-if="product" class="order-box">
|
||||||
<div class="flex-o mt-5"><span class="label">套餐:</span>{{ product.title }}</div>
|
|
||||||
<div class="flex-o mt-5"><span class="label">说明:</span>{{ product.intro }}</div>
|
|
||||||
<div class="flex-o mt-5">
|
<div class="flex-o mt-5">
|
||||||
<span class="label">规格:</span>
|
<span class="label">{{$t('order.package')}}:</span>{{ product.title }}
|
||||||
|
</div>
|
||||||
|
<div class="flex-o mt-5">
|
||||||
|
<span class="label">{{$t('order.description')}}:</span>{{ product.intro }}
|
||||||
|
</div>
|
||||||
|
<div class="flex-o mt-5">
|
||||||
|
<span class="label">{{$t('order.specifications')}}:</span>
|
||||||
<span class="flex-o flex-wrap">
|
<span class="flex-o flex-wrap">
|
||||||
<span class="flex-o">流水线<suite-value class="ml-5" :model-value="product.content.maxPipelineCount" unit="条" />;</span>
|
<span class="flex-o">
|
||||||
<span class="flex-o">域名<suite-value class="ml-5" :model-value="product.content.maxDomainCount" unit="个" />;</span>
|
{{$t('order.pipeline')}}<suite-value class="ml-5" :model-value="product.content.maxPipelineCount" unit="{{$t('order.unit.pieces')}}" />;
|
||||||
<span class="flex-o">部署次数<suite-value class="ml-5" :model-value="product.content.maxDeployCount" unit="次" />;</span>
|
</span>
|
||||||
|
<span class="flex-o">
|
||||||
|
{{$t('order.domain')}}<suite-value class="ml-5" :model-value="product.content.maxDomainCount" unit="{{$t('order.unit.count')}}" />;
|
||||||
|
</span>
|
||||||
|
<span class="flex-o">
|
||||||
|
{{$t('order.deployTimes')}}<suite-value class="ml-5" :model-value="product.content.maxDeployCount" unit="{{$t('order.unit.times')}}" />;
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex-o mt-5">
|
<div class="flex-o mt-5">
|
||||||
<span class="label">时长:</span>
|
<span class="label">{{$t('order.duration')}}:</span>
|
||||||
<duration-value v-model="formRef.duration"></duration-value>
|
<duration-value v-model="formRef.duration"></duration-value>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-o mt-5"><span class="label">价格:</span> <price-input :edit="false" :model-value="durationSelected.price"></price-input></div>
|
<div class="flex-o mt-5">
|
||||||
|
<span class="label">{{$t('order.price')}}:</span>
|
||||||
|
<price-input :edit="false" :model-value="durationSelected.price"></price-input>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex-o mt-5">
|
<div class="flex-o mt-5">
|
||||||
<span class="label">支付方式:</span>
|
<span class="label">{{$t('order.paymentMethod')}}:</span>
|
||||||
<div v-if="durationSelected.price === 0">免费</div>
|
<div v-if="durationSelected.price === 0">{{$t('order.free')}}</div>
|
||||||
<fs-dict-select v-else v-model:value="formRef.payType" :dict="paymentsDictRef" style="width: 200px"> </fs-dict-select>
|
<fs-dict-select v-else v-model:value="formRef.payType" :dict="paymentsDictRef" style="width: 200px"> </fs-dict-select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<script setup lang="tsx">
|
<script setup lang="tsx">
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { GetPaymentTypes, OrderModalOpenReq, TradeCreate } from "/@/views/certd/suite/api";
|
import { GetPaymentTypes, OrderModalOpenReq, TradeCreate } from "/@/views/certd/suite/api";
|
||||||
|
|
|
@ -11,19 +11,21 @@
|
||||||
<div class="text">
|
<div class="text">
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<div>
|
<div>
|
||||||
<span>您好,{{ userInfo.nickName || userInfo.username }}, 欢迎使用 【{{ siteInfo.title }}】</span>
|
<span>{{ t('certd.dashboard.greeting', { name: userInfo.nickName || userInfo.username, site: siteInfo.title }) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-o flex-wrap profile-badges">
|
<div class="flex-o flex-wrap profile-badges">
|
||||||
<a-tooltip :title="deltaTimeTip">
|
<a-tooltip :title="deltaTimeTip">
|
||||||
<a-badge :dot="deltaTimeWarning">
|
<a-badge :dot="deltaTimeWarning">
|
||||||
<a-tag :color="deltaTimeWarning ? 'red' : 'green'" class="flex-inline pointer"> <fs-icon icon="ion:time-outline"></fs-icon> {{ now }}</a-tag>
|
<a-tag :color="deltaTimeWarning ? 'red' : 'green'" class="flex-inline pointer">
|
||||||
|
<fs-icon icon="ion:time-outline"></fs-icon> {{ now }}
|
||||||
|
</a-tag>
|
||||||
</a-badge>
|
</a-badge>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
|
|
||||||
<template v-if="userStore.isAdmin">
|
<template v-if="userStore.isAdmin">
|
||||||
<a-divider type="vertical" />
|
<a-divider type="vertical" />
|
||||||
<a-badge :dot="hasNewVersion">
|
<a-badge :dot="hasNewVersion">
|
||||||
<a-tag color="blue" class="flex-inline pointer mr-0" :title="'最新版本:' + latestVersion" @click="openUpgradeUrl()">
|
<a-tag color="blue" class="flex-inline pointer mr-0" :title="t('certd.dashboard.latestVersion', { version: latestVersion })" @click="openUpgradeUrl()">
|
||||||
<fs-icon icon="ion:rocket-outline" class="mr-5"></fs-icon>
|
<fs-icon icon="ion:rocket-outline" class="mr-5"></fs-icon>
|
||||||
v{{ version }}
|
v{{ version }}
|
||||||
</a-tag>
|
</a-tag>
|
||||||
|
@ -37,7 +39,7 @@
|
||||||
</template>
|
</template>
|
||||||
<template v-if="settingsStore.isPlus && settingsStore.sysPublic.userValidTimeEnabled === true && userInfo.validTime">
|
<template v-if="settingsStore.isPlus && settingsStore.sysPublic.userValidTimeEnabled === true && userInfo.validTime">
|
||||||
<a-divider type="vertical" />
|
<a-divider type="vertical" />
|
||||||
<valid-time-format class="flex-o" prefix="账户有效期:" :model-value="userInfo.validTime" />
|
<valid-time-format class="flex-o" :prefix="t('certd.dashboard.validUntil')" :model-value="userInfo.validTime" />
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -46,9 +48,9 @@
|
||||||
|
|
||||||
<div class="suggest hidden md:block">
|
<div class="suggest hidden md:block">
|
||||||
<tutorial-button class="flex-center mt-2">
|
<tutorial-button class="flex-center mt-2">
|
||||||
<a-tooltip title="点击查看详细教程">
|
<a-tooltip :title="t('certd.dashboard.tutorialTooltip')">
|
||||||
<a-tag color="blue" class="flex-center">
|
<a-tag color="blue" class="flex-center">
|
||||||
仅需3步,全自动申请部署证书
|
{{ t('certd.dashboard.tutorialText') }}
|
||||||
<fs-icon class="font-size-16 ml-5" icon="mingcute:question-line"></fs-icon>
|
<fs-icon class="font-size-16 ml-5" icon="mingcute:question-line"></fs-icon>
|
||||||
</a-tag>
|
</a-tag>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
|
@ -59,9 +61,10 @@
|
||||||
<div v-if="!settingStore.isComm" class="warning">
|
<div v-if="!settingStore.isComm" class="warning">
|
||||||
<a-alert type="warning" show-icon>
|
<a-alert type="warning" show-icon>
|
||||||
<template #message>
|
<template #message>
|
||||||
证书和授权为敏感信息,不要使用来历不明的在线Certd服务和镜像,以免泄露;请务必私有化部署使用,认准官方版本发布渠道:
|
{{ t('certd.dashboard.alertMessage') }}
|
||||||
<a class="ml-5 flex-inline" href="https://gitee.com/certd/certd" target="_blank">gitee</a>、 <a class="ml-5 flex-inline" href="https://github.com/certd/certd" target="_blank">github</a>、
|
<a class="ml-5 flex-inline" href="https://gitee.com/certd/certd" target="_blank">gitee</a>、
|
||||||
<a class="ml-5 flex-inline" href="https://certd.docmirror.cn" target="_blank">帮助文档</a>
|
<a class="ml-5 flex-inline" href="https://github.com/certd/certd" target="_blank">github</a>、
|
||||||
|
<a class="ml-5 flex-inline" href="https://certd.docmirror.cn" target="_blank">{{ t('certd.dashboard.helpDoc') }}</a>
|
||||||
</template>
|
</template>
|
||||||
</a-alert>
|
</a-alert>
|
||||||
</div>
|
</div>
|
||||||
|
@ -69,30 +72,32 @@
|
||||||
<div class="statistic-data m-20">
|
<div class="statistic-data m-20">
|
||||||
<a-row :gutter="20" class="flex-wrap">
|
<a-row :gutter="20" class="flex-wrap">
|
||||||
<a-col :md="6" :xs="24">
|
<a-col :md="6" :xs="24">
|
||||||
<statistic-card title="证书流水线数量" :count="count.pipelineCount">
|
<statistic-card :title="t('certd.dashboard.pipelineCount')" :count="count.pipelineCount">
|
||||||
<template v-if="count.pipelineCount === 0" #default>
|
<template v-if="count.pipelineCount === 0" #default>
|
||||||
<div class="flex-center flex-1 flex-col">
|
<div class="flex-center flex-1 flex-col">
|
||||||
<div style="font-size: 18px; font-weight: 700">您还没有证书流水线</div>
|
<div style="font-size: 18px; font-weight: 700">{{ t('certd.dashboard.noPipeline') }}</div>
|
||||||
<fs-button type="primary" class="mt-10" icon="ion:add-circle-outline" @click="goPipeline">立即创建</fs-button>
|
<fs-button type="primary" class="mt-10" icon="ion:add-circle-outline" @click="goPipeline">{{ t('certd.dashboard.createNow') }}</fs-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<router-link to="/certd/pipeline" class="flex"><fs-icon icon="ion:settings-outline" class="mr-5 fs-16" /> 管理流水线</router-link>
|
<router-link to="/certd/pipeline" class="flex">
|
||||||
|
<fs-icon icon="ion:settings-outline" class="mr-5 fs-16" /> {{ t('certd.dashboard.managePipeline') }}
|
||||||
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
</statistic-card>
|
</statistic-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :md="6" :xs="24">
|
<a-col :md="6" :xs="24">
|
||||||
<statistic-card title="流水线状态" :footer="false">
|
<statistic-card :title="t('certd.dashboard.pipelineStatus')" :footer="false">
|
||||||
<pie-count v-if="count.pipelineStatusCount" :data="count.pipelineStatusCount"></pie-count>
|
<pie-count v-if="count.pipelineStatusCount" :data="count.pipelineStatusCount"></pie-count>
|
||||||
</statistic-card>
|
</statistic-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :md="6" :xs="24">
|
<a-col :md="6" :xs="24">
|
||||||
<statistic-card title="最近运行统计" :footer="false">
|
<statistic-card :title="t('certd.dashboard.recentRun')" :footer="false">
|
||||||
<day-count v-if="count.historyCountPerDay" :data="count.historyCountPerDay" title="运行次数"></day-count>
|
<day-count v-if="count.historyCountPerDay" :data="count.historyCountPerDay" :title="t('certd.dashboard.runCount')"></day-count>
|
||||||
</statistic-card>
|
</statistic-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :md="6" :xs="24">
|
<a-col :md="6" :xs="24">
|
||||||
<statistic-card title="最快到期证书">
|
<statistic-card :title="t('certd.dashboard.expiringCerts')">
|
||||||
<expiring-list v-if="count.expiringList" :data="count.expiringList"></expiring-list>
|
<expiring-list v-if="count.expiringList" :data="count.expiringList"></expiring-list>
|
||||||
</statistic-card>
|
</statistic-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
|
@ -102,7 +107,8 @@
|
||||||
<div v-if="pluginGroups" class="plugin-list">
|
<div v-if="pluginGroups" class="plugin-list">
|
||||||
<a-card>
|
<a-card>
|
||||||
<template #title>
|
<template #title>
|
||||||
已支持的部署任务总览 <a-tag color="green">{{ pluginGroups.groups.all.plugins.length }}</a-tag>
|
{{ t('certd.dashboard.supportedTasks') }}
|
||||||
|
<a-tag color="green">{{ pluginGroups.groups.all.plugins.length }}</a-tag>
|
||||||
</template>
|
</template>
|
||||||
<a-row :gutter="10">
|
<a-row :gutter="10">
|
||||||
<a-col v-for="item of pluginGroups.groups.all.plugins" :key="item.name" class="plugin-item-col" :xl="4" :md="6" :xs="24">
|
<a-col v-for="item of pluginGroups.groups.all.plugins" :key="item.name" class="plugin-item-col" :xl="4" :md="6" :xs="24">
|
||||||
|
@ -130,6 +136,7 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { FsIcon } from "@fast-crud/fast-crud";
|
import { FsIcon } from "@fast-crud/fast-crud";
|
||||||
import SimpleSteps from "/@/components/tutorial/simple-steps.vue";
|
import SimpleSteps from "/@/components/tutorial/simple-steps.vue";
|
||||||
|
@ -148,6 +155,8 @@ import { UserInfoRes } from "/@/store/user/api.user";
|
||||||
import { GetStatisticCount } from "/@/views/framework/home/dashboard/api";
|
import { GetStatisticCount } from "/@/views/framework/home/dashboard/api";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import * as api from "./api";
|
import * as api from "./api";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
const { t } = useI18n();
|
||||||
import { usePluginStore } from "/@/store/plugin";
|
import { usePluginStore } from "/@/store/plugin";
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: "DashboardUser",
|
name: "DashboardUser",
|
||||||
|
|
|
@ -2,7 +2,10 @@
|
||||||
<fs-page class="home—index bg-neutral-100 dark:bg-black">
|
<fs-page class="home—index bg-neutral-100 dark:bg-black">
|
||||||
<!-- <page-content />-->
|
<!-- <page-content />-->
|
||||||
<dashboard-user />
|
<dashboard-user />
|
||||||
<change-password-button ref="changePasswordButtonRef" :show-button="false"></change-password-button>
|
<change-password-button
|
||||||
|
ref="changePasswordButtonRef"
|
||||||
|
:show-button="false"
|
||||||
|
></change-password-button>
|
||||||
</fs-page>
|
</fs-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -12,20 +15,23 @@ import { useUserStore } from "/@/store/user";
|
||||||
import ChangePasswordButton from "/@/views/certd/mine/change-password-button.vue";
|
import ChangePasswordButton from "/@/views/certd/mine/change-password-button.vue";
|
||||||
import { onMounted, ref } from "vue";
|
import { onMounted, ref } from "vue";
|
||||||
import { Modal } from "ant-design-vue";
|
import { Modal } from "ant-design-vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const changePasswordButtonRef = ref();
|
const changePasswordButtonRef = ref();
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (userStore.getUserInfo.isWeak === true) {
|
if (userStore.getUserInfo.isWeak === true) {
|
||||||
Modal.info({
|
Modal.info({
|
||||||
title: "修改密码",
|
title: t("passwordForm.title"),
|
||||||
content: "为了您的账户安全,请立即修改密码",
|
content: t("passwordForm.weakPasswordWarning"),
|
||||||
onOk: () => {
|
onOk: () => {
|
||||||
changePasswordButtonRef.value.open({
|
changePasswordButtonRef.value.open({
|
||||||
password: "123456",
|
password: "123456",
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
okText: "立即修改",
|
okText: t("passwordForm.changeNow"),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,74 +1,96 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="main login-page">
|
<div class="main login-page">
|
||||||
<a-form v-if="!twoFactor.loginId" ref="formRef" class="user-layout-login" name="custom-validation" :model="formState" v-bind="layout" @finish="handleFinish" @finish-failed="handleFinishFailed">
|
<a-form v-if="!twoFactor.loginId" ref="formRef" class="user-layout-login" name="custom-validation"
|
||||||
<!-- <div class="login-title">登录</div>-->
|
:model="formState" v-bind="layout" @finish="handleFinish" @finish-failed="handleFinishFailed">
|
||||||
<a-tabs v-model:active-key="formState.loginType" :tab-bar-style="{ textAlign: 'center', borderBottom: 'unset' }">
|
<!-- <div class="login-title">登录</div>-->
|
||||||
<a-tab-pane key="password" tab="密码登录" :disabled="sysPublicSettings.passwordLoginEnabled !== true">
|
<a-tabs v-model:active-key="formState.loginType"
|
||||||
<template v-if="formState.loginType === 'password'">
|
:tab-bar-style="{ textAlign: 'center', borderBottom: 'unset' }">
|
||||||
<!-- <div class="login-title">登录</div>-->
|
<a-tab-pane key="password" :tab="$t('authentication.passwordTab')"
|
||||||
<a-form-item required has-feedback name="username" :rules="rules.username">
|
:disabled="sysPublicSettings.passwordLoginEnabled !== true">
|
||||||
<a-input v-model:value="formState.username" placeholder="请输入用户名/邮箱/手机号" autocomplete="off">
|
<template v-if="formState.loginType === 'password'">
|
||||||
<template #prefix>
|
<!-- <div class="login-title">登录</div>-->
|
||||||
<fs-icon icon="ion:phone-portrait-outline"></fs-icon>
|
<a-form-item required has-feedback name="username" :rules="rules.username">
|
||||||
</template>
|
<a-input v-model:value="formState.username"
|
||||||
</a-input>
|
:placeholder="$t('authentication.usernamePlaceholder')" autocomplete="off">
|
||||||
</a-form-item>
|
<template #prefix>
|
||||||
<a-form-item has-feedback name="password" :rules="rules.password">
|
<fs-icon icon="ion:phone-portrait-outline"></fs-icon>
|
||||||
<a-input-password v-model:value="formState.password" placeholder="请输入密码" autocomplete="off">
|
</template>
|
||||||
<template #prefix>
|
</a-input>
|
||||||
<fs-icon icon="ion:lock-closed-outline"></fs-icon>
|
</a-form-item>
|
||||||
</template>
|
<a-form-item has-feedback name="password" :rules="rules.password">
|
||||||
</a-input-password>
|
<a-input-password v-model:value="formState.password"
|
||||||
</a-form-item>
|
:placeholder="$t('authentication.passwordPlaceholder')" autocomplete="off">
|
||||||
</template>
|
<template #prefix>
|
||||||
</a-tab-pane>
|
<fs-icon icon="ion:lock-closed-outline"></fs-icon>
|
||||||
<a-tab-pane key="sms" tab="短信验证码登录" :disabled="sysPublicSettings.smsLoginEnabled !== true">
|
</template>
|
||||||
<template v-if="formState.loginType === 'sms'">
|
</a-input-password>
|
||||||
<a-form-item has-feedback name="mobile" :rules="rules.mobile">
|
</a-form-item>
|
||||||
<a-input v-model:value="formState.mobile" placeholder="请输入手机号" autocomplete="off">
|
</template>
|
||||||
<template #prefix>
|
</a-tab-pane>
|
||||||
<fs-icon icon="ion:phone-portrait-outline"></fs-icon>
|
<a-tab-pane key="sms" :tab="$t('authentication.smsTab')"
|
||||||
</template>
|
:disabled="sysPublicSettings.smsLoginEnabled !== true">
|
||||||
</a-input>
|
<template v-if="formState.loginType === 'sms'">
|
||||||
</a-form-item>
|
<a-form-item has-feedback name="mobile" :rules="rules.mobile">
|
||||||
<a-form-item has-feedback name="imgCode">
|
<a-input v-model:value="formState.mobile"
|
||||||
<image-code v-model:value="formState.imgCode" v-model:random-str="formState.randomStr"></image-code>
|
:placeholder="$t('authentication.mobilePlaceholder')" autocomplete="off">
|
||||||
</a-form-item>
|
<template #prefix>
|
||||||
|
<fs-icon icon="ion:phone-portrait-outline"></fs-icon>
|
||||||
|
</template>
|
||||||
|
</a-input>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
<a-form-item name="smsCode" :rules="rules.smsCode">
|
<a-form-item has-feedback name="imgCode">
|
||||||
<sms-code v-model:value="formState.smsCode" :img-code="formState.imgCode" :mobile="formState.mobile" :phone-code="formState.phoneCode" :random-str="formState.randomStr" />
|
<image-code v-model:value="formState.imgCode"
|
||||||
</a-form-item>
|
v-model:random-str="formState.randomStr"></image-code>
|
||||||
</template>
|
</a-form-item>
|
||||||
</a-tab-pane>
|
|
||||||
</a-tabs>
|
|
||||||
<a-form-item>
|
|
||||||
<a-button type="primary" size="large" html-type="submit" :loading="loading" class="login-button">登录</a-button>
|
|
||||||
|
|
||||||
<div v-if="!settingStore.isComm" class="mt-2"><a href="https://certd.docmirror.cn/guide/use/forgotpasswd/" target="_blank">忘记管理员密码?</a></div>
|
<a-form-item name="smsCode" :rules="rules.smsCode">
|
||||||
</a-form-item>
|
<sms-code v-model:value="formState.smsCode" :img-code="formState.imgCode"
|
||||||
|
:mobile="formState.mobile" :phone-code="formState.phoneCode"
|
||||||
|
:random-str="formState.randomStr" />
|
||||||
|
</a-form-item>
|
||||||
|
</template>
|
||||||
|
</a-tab-pane>
|
||||||
|
</a-tabs>
|
||||||
|
<a-form-item>
|
||||||
|
<a-button type="primary" size="large" html-type="submit" :loading="loading" class="login-button">
|
||||||
|
{{ $t('authentication.loginButton') }}
|
||||||
|
</a-button>
|
||||||
|
|
||||||
<a-form-item class="user-login-other">
|
<div v-if="!settingStore.isComm" class="mt-2">
|
||||||
<router-link v-if="hasRegisterTypeEnabled()" class="register" :to="{ name: 'register' }"> 注册 </router-link>
|
<a href="https://certd.docmirror.cn/guide/use/forgotpasswd/" target="_blank">
|
||||||
</a-form-item>
|
{{ $t('authentication.forgotAdminPassword') }}
|
||||||
</a-form>
|
</a>
|
||||||
<a-form v-else ref="twoFactorFormRef" class="user-layout-login" :model="twoFactor" v-bind="layout">
|
</div>
|
||||||
<div class="mb-10 flex flex-center">请打开您的Authenticator APP,获取动态验证码。</div>
|
</a-form-item>
|
||||||
<a-form-item name="verifyCode">
|
|
||||||
<a-input ref="verifyCodeInputRef" v-model:value="twoFactor.verifyCode" placeholder="请输入动态验证码" allow-clear @keydown.enter="handleTwoFactorSubmit">
|
|
||||||
<template #prefix>
|
|
||||||
<fs-icon icon="ion:lock-closed-outline"></fs-icon>
|
|
||||||
</template>
|
|
||||||
</a-input>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item>
|
|
||||||
<loading-button type="primary" size="large" html-type="button" class="login-button" :click="handleTwoFactorSubmit">OTP验证登录</loading-button>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-form-item class="user-login-other">
|
<a-form-item class="user-login-other">
|
||||||
<a class="register" @click="twoFactor.loginId = null"> 返回 </a>
|
<router-link v-if="hasRegisterTypeEnabled()" class="register" :to="{ name: 'register' }">
|
||||||
</a-form-item>
|
{{ $t('authentication.registerLink') }}
|
||||||
</a-form>
|
</router-link>
|
||||||
</div>
|
</a-form-item>
|
||||||
|
|
||||||
|
</a-form>
|
||||||
|
<a-form v-else ref="twoFactorFormRef" class="user-layout-login" :model="twoFactor" v-bind="layout">
|
||||||
|
<div class="mb-10 flex flex-center">请打开您的Authenticator APP,获取动态验证码。</div>
|
||||||
|
<a-form-item name="verifyCode">
|
||||||
|
<a-input ref="verifyCodeInputRef" v-model:value="twoFactor.verifyCode" placeholder="请输入动态验证码"
|
||||||
|
allow-clear @keydown.enter="handleTwoFactorSubmit">
|
||||||
|
<template #prefix>
|
||||||
|
<fs-icon icon="ion:lock-closed-outline"></fs-icon>
|
||||||
|
</template>
|
||||||
|
</a-input>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item>
|
||||||
|
<loading-button type="primary" size="large" html-type="button" class="login-button"
|
||||||
|
:click="handleTwoFactorSubmit">OTP验证登录</loading-button>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item class="user-login-other">
|
||||||
|
<a class="register" @click="twoFactor.loginId = null"> 返回 </a>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, nextTick, reactive, ref, toRaw } from "vue";
|
import { defineComponent, nextTick, reactive, ref, toRaw } from "vue";
|
||||||
|
@ -79,200 +101,208 @@ import ImageCode from "/@/views/framework/login/image-code.vue";
|
||||||
import SmsCode from "/@/views/framework/login/sms-code.vue";
|
import SmsCode from "/@/views/framework/login/sms-code.vue";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "LoginPage",
|
name: "LoginPage",
|
||||||
components: { SmsCode, ImageCode },
|
components: { SmsCode, ImageCode },
|
||||||
setup() {
|
setup() {
|
||||||
const verifyCodeInputRef = ref();
|
const verifyCodeInputRef = ref();
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
const formRef = ref();
|
const formRef = ref();
|
||||||
const formState = reactive({
|
const formState = reactive({
|
||||||
username: "",
|
username: "",
|
||||||
phoneCode: "86",
|
phoneCode: "86",
|
||||||
mobile: "",
|
mobile: "",
|
||||||
password: "",
|
password: "",
|
||||||
loginType: "password", //password
|
loginType: "password", //password
|
||||||
imgCode: "",
|
imgCode: "",
|
||||||
smsCode: "",
|
smsCode: "",
|
||||||
randomStr: "",
|
randomStr: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
const rules = {
|
const rules = {
|
||||||
mobile: [
|
mobile: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: "请输入手机号",
|
message: "请输入手机号",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
username: [
|
username: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: "请输入用户名",
|
message: "请输入用户名",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
password: [
|
password: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: "请输入登录密码",
|
message: "请输入登录密码",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
smsCode: [
|
smsCode: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: "请输入短信验证码",
|
message: "请输入短信验证码",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
const layout = {
|
const layout = {
|
||||||
labelCol: {
|
labelCol: {
|
||||||
span: 0,
|
span: 0,
|
||||||
},
|
},
|
||||||
wrapperCol: {
|
wrapperCol: {
|
||||||
span: 24,
|
span: 24,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const twoFactor = reactive({
|
const twoFactor = reactive({
|
||||||
loginId: "",
|
loginId: "",
|
||||||
verifyCode: "",
|
verifyCode: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleTwoFactorSubmit = async () => {
|
const handleTwoFactorSubmit = async () => {
|
||||||
await userStore.loginByTwoFactor(twoFactor);
|
await userStore.loginByTwoFactor(twoFactor);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFinish = async (values: any) => {
|
const handleFinish = async (values: any) => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
const loginType = formState.loginType;
|
const loginType = formState.loginType;
|
||||||
await userStore.login(loginType, toRaw(formState));
|
await userStore.login(loginType, toRaw(formState));
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
if (e.code === 10020) {
|
if (e.code === 10020) {
|
||||||
//双重认证
|
//双重认证
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
twoFactor.loginId = e.data;
|
twoFactor.loginId = e.data;
|
||||||
await nextTick();
|
await nextTick();
|
||||||
verifyCodeInputRef.value.focus();
|
verifyCodeInputRef.value.focus();
|
||||||
} else {
|
} else {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFinishFailed = (errors: any) => {
|
const handleFinishFailed = (errors: any) => {
|
||||||
utils.logger.log(errors);
|
utils.logger.log(errors);
|
||||||
};
|
};
|
||||||
|
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
formRef.value.resetFields();
|
formRef.value.resetFields();
|
||||||
};
|
};
|
||||||
|
|
||||||
const isLoginError = ref();
|
const isLoginError = ref();
|
||||||
|
|
||||||
const sysPublicSettings = settingStore.getSysPublic;
|
const sysPublicSettings = settingStore.getSysPublic;
|
||||||
|
|
||||||
function hasRegisterTypeEnabled() {
|
function hasRegisterTypeEnabled() {
|
||||||
return sysPublicSettings.registerEnabled && (sysPublicSettings.usernameRegisterEnabled || sysPublicSettings.emailRegisterEnabled);
|
return sysPublicSettings.registerEnabled && (sysPublicSettings.usernameRegisterEnabled || sysPublicSettings.emailRegisterEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
loading,
|
loading,
|
||||||
formState,
|
formState,
|
||||||
formRef,
|
formRef,
|
||||||
rules,
|
rules,
|
||||||
layout,
|
layout,
|
||||||
handleFinishFailed,
|
handleFinishFailed,
|
||||||
handleFinish,
|
handleFinish,
|
||||||
resetForm,
|
resetForm,
|
||||||
isLoginError,
|
isLoginError,
|
||||||
sysPublicSettings,
|
sysPublicSettings,
|
||||||
hasRegisterTypeEnabled,
|
hasRegisterTypeEnabled,
|
||||||
twoFactor,
|
twoFactor,
|
||||||
handleTwoFactorSubmit,
|
handleTwoFactorSubmit,
|
||||||
verifyCodeInputRef,
|
verifyCodeInputRef,
|
||||||
settingStore,
|
settingStore,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
@import "../../../style/theme/index.less";
|
@import "../../../style/theme/index.less";
|
||||||
|
|
||||||
.login-page.main {
|
.login-page.main {
|
||||||
//margin: 20px !important;
|
//margin: 20px !important;
|
||||||
margin-bottom: 100px;
|
margin-bottom: 100px;
|
||||||
.user-layout-login {
|
|
||||||
//label {
|
|
||||||
// font-size: 14px;
|
|
||||||
//}
|
|
||||||
|
|
||||||
.login-title {
|
.user-layout-login {
|
||||||
color: @primary-color;
|
//label {
|
||||||
font-size: 18px;
|
// font-size: 14px;
|
||||||
text-align: center;
|
//}
|
||||||
margin: 20px;
|
|
||||||
}
|
|
||||||
.getCaptcha {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-code {
|
.login-title {
|
||||||
height: 34px;
|
color: @primary-color;
|
||||||
}
|
font-size: 18px;
|
||||||
.input-right {
|
text-align: center;
|
||||||
width: 160px;
|
margin: 20px;
|
||||||
margin-left: 10px;
|
}
|
||||||
}
|
|
||||||
.forge-password {
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.login-button {
|
.getCaptcha {
|
||||||
padding: 0 15px;
|
display: block;
|
||||||
font-size: 16px;
|
width: 100%;
|
||||||
width: 100%;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.user-login-other {
|
.image-code {
|
||||||
text-align: left;
|
height: 34px;
|
||||||
margin-top: 30px;
|
}
|
||||||
margin-bottom: 30px;
|
|
||||||
//line-height: 22px;
|
|
||||||
|
|
||||||
.item-icon {
|
.input-right {
|
||||||
font-size: 24px;
|
width: 160px;
|
||||||
color: rgba(0, 0, 0, 0.2);
|
margin-left: 10px;
|
||||||
margin-left: 16px;
|
}
|
||||||
vertical-align: middle;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: color 0.3s;
|
|
||||||
|
|
||||||
&:hover {
|
.forge-password {
|
||||||
color: @primary-color;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.register {
|
button.login-button {
|
||||||
float: right;
|
padding: 0 15px;
|
||||||
}
|
font-size: 16px;
|
||||||
}
|
width: 100%;
|
||||||
.fs-icon {
|
}
|
||||||
color: rgba(0, 0, 0, 0.45);
|
|
||||||
margin-right: 4px;
|
.user-login-other {
|
||||||
}
|
text-align: left;
|
||||||
.ant-input-affix-wrapper {
|
margin-top: 30px;
|
||||||
line-height: 1.8 !important;
|
margin-bottom: 30px;
|
||||||
font-size: 14px !important;
|
//line-height: 22px;
|
||||||
> * {
|
|
||||||
line-height: 1.8 !important;
|
.item-icon {
|
||||||
font-size: 14px !important;
|
font-size: 24px;
|
||||||
}
|
color: rgba(0, 0, 0, 0.2);
|
||||||
}
|
margin-left: 16px;
|
||||||
}
|
vertical-align: middle;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color 0.3s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: @primary-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.register {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.fs-icon {
|
||||||
|
color: rgba(0, 0, 0, 0.45);
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-input-affix-wrapper {
|
||||||
|
line-height: 1.8 !important;
|
||||||
|
font-size: 14px !important;
|
||||||
|
|
||||||
|
>* {
|
||||||
|
line-height: 1.8 !important;
|
||||||
|
font-size: 14px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue