perf: 优化中英文翻译与切换

pull/453/head
xiaojunnuo 2025-06-28 23:57:01 +08:00
parent 082f47663d
commit acaa8b1731
43 changed files with 4121 additions and 4175 deletions

View File

@ -1,5 +1,5 @@
<template> <template>
<AConfigProvider :locale="locale" :theme="tokenTheme"> <AConfigProvider :locale="antdvLocale" :theme="tokenTheme">
<FsFormProvider> <FsFormProvider>
<contextHolder /> <contextHolder />
<router-view /> <router-view />
@ -8,24 +8,22 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, onMounted, provide, ref } from "vue"; import { computed, provide, ref } from "vue";
import "dayjs/locale/zh-cn"; import { preferences, usePreferences } from "/@/vben/preferences";
import "dayjs/locale/en";
import dayjs from "dayjs";
import { usePreferences, preferences } from "/@/vben/preferences";
import { useAntdDesignTokens } from "/@/vben/hooks"; import { useAntdDesignTokens } from "/@/vben/hooks";
import { theme } from "ant-design-vue"; import { Modal, theme } from "ant-design-vue";
import AConfigProvider from "ant-design-vue/es/config-provider"; import AConfigProvider from "ant-design-vue/es/config-provider";
import { Modal } from "ant-design-vue"; import { antdvLocale } from "./locales/antdv";
import MaxKBChat from "/@/components/ai/index.vue"; import { setI18nLanguage } from "/@/locales";
import { util } from "/@/utils";
import { useSettingStore } from "/@/store/settings";
defineOptions({ defineOptions({
name: "App", name: "App",
}); });
const [modal, contextHolder] = Modal.useModal(); const [modal, contextHolder] = Modal.useModal();
provide("modal", modal); provide("modal", modal);
const locale = preferences.app.locale;
setI18nLanguage(locale);
const { isDark } = usePreferences(); const { isDark } = usePreferences();
const { tokens } = useAntdDesignTokens(); const { tokens } = useAntdDesignTokens();
@ -43,5 +41,4 @@ const tokenTheme = computed(() => {
token: tokens, token: tokens,
}; };
}); });
</script> </script>

View File

@ -33,7 +33,6 @@ const menus = computed(() => [
}, },
]); ]);
const avatar = computed(() => { const avatar = computed(() => {
const avt = userStore.getUserInfo?.avatar; const avt = userStore.getUserInfo?.avatar;
return avt ? `/api/basic/file/download?key=${avt}` : ""; return avt ? `/api/basic/file/download?key=${avt}` : "";
@ -77,16 +76,13 @@ provide("fn:ai.open", openChat);
<template> <template>
<BasicLayout @clear-preferences-and-logout="handleLogout"> <BasicLayout @clear-preferences-and-logout="handleLogout">
<template #user-dropdown> <template #user-dropdown>
<UserDropdown :avatar="avatar" :menus="menus" <UserDropdown :avatar="avatar" :menus="menus" :text="userStore.userInfo?.nickName || userStore.userInfo?.username" description="" tag-text="" @logout="handleLogout" />
:text="userStore.userInfo?.nickName || userStore.userInfo?.username" description="" tag-text=""
@logout="handleLogout" />
</template> </template>
<template #lock-screen> <template #lock-screen>
<LockScreen :avatar @to-login="handleLogout" /> <LockScreen :avatar @to-login="handleLogout" />
</template> </template>
<template #header-right-0> <template #header-right-0>
<div v-if="!settingStore.isComm" <div v-if="!settingStore.isComm" class="hover:bg-accent ml-1 mr-2 cursor-pointer rounded-full hidden md:block">
class="hover:bg-accent ml-1 mr-2 cursor-pointer rounded-full hidden md:block">
<tutorial-button class="flex-center header-btn" /> <tutorial-button class="flex-center header-btn" />
</div> </div>
<div class="hover:bg-accent ml-1 mr-2 cursor-pointer rounded-full"> <div class="hover:bg-accent ml-1 mr-2 cursor-pointer rounded-full">

View File

@ -0,0 +1,18 @@
import { ref } from "vue";
import "dayjs/locale/zh-cn";
import "dayjs/locale/en";
import zhCN from "ant-design-vue/es/locale/zh_CN";
import enUS from "ant-design-vue/es/locale/en_US";
import dayjs from "dayjs";
export const antdvLocale = ref(zhCN);
export async function setAntdvLocale(value: string) {
console.log("locale changed:", value);
if (value.startsWith("zh")) {
dayjs.locale("zh-cn");
antdvLocale.value = zhCN;
} else {
dayjs.locale("en");
antdvLocale.value = enUS;
}
}

View File

@ -1,24 +1,24 @@
import type { App } from "vue"; import type { App } from "vue";
import type { Locale } from "vue-i18n"; import type { Locale } from "vue-i18n";
import { setAntdvLocale } from "./antdv";
import type { ImportLocaleFn, LoadMessageFn, LocaleSetupOptions, SupportedLanguagesType } from "./typing"; import type { ImportLocaleFn, LoadMessageFn, LocaleSetupOptions, SupportedLanguagesType } from "./typing";
import { unref } from "vue"; import { unref } from "vue";
import { createI18n } from "vue-i18n"; import { createI18n } from "vue-i18n";
import en_US from './langs/en-US/index'; import en_US from "./langs/en-US/index";
import zh_CH from './langs/zh-CN/index'; import zh_CN from "./langs/zh-CN/index";
import { useSimpleLocale } from "/@/vben/composables"; import { useSimpleLocale } from "/@/vben/composables";
const i18n = createI18n({ const i18n = createI18n({
globalInjection: true, globalInjection: true,
legacy: false, legacy: false,
fallbackLocale: 'en_US', fallbackLocale: "en-US",
locale: 'en_US', locale: "en-US",
messages: { messages: {
zh_CH: zh_CH, "zh-CN": zh_CN,
en_US: en_US "en-US": en_US,
} },
}); });
const modules = import.meta.glob("./langs/**/*.json"); const modules = import.meta.glob("./langs/**/*.json");
@ -89,6 +89,8 @@ function loadLocalesMapFromDir(regexp: RegExp, modules: Record<string, () => Pro
* @param locale * @param locale
*/ */
function setI18nLanguage(locale: Locale) { function setI18nLanguage(locale: Locale) {
// setAntdvLocale(locale);
//@ts-ignore
i18n.global.locale.value = locale; i18n.global.locale.value = locale;
document?.querySelector("html")?.setAttribute("lang", locale); document?.querySelector("html")?.setAttribute("lang", locale);
@ -122,6 +124,7 @@ async function loadLocaleMessages(lang: SupportedLanguagesType) {
const message = await localesMap[lang]?.(); const message = await localesMap[lang]?.();
if (message?.default) { if (message?.default) {
//@ts-ignore
i18n.global.setLocaleMessage(lang, message.default); i18n.global.setLocaleMessage(lang, message.default);
} }
@ -130,6 +133,5 @@ async function loadLocaleMessages(lang: SupportedLanguagesType) {
return setI18nLanguage(lang); return setI18nLanguage(lang);
} }
export { i18n, loadLocaleMessages, loadLocalesMap, loadLocalesMapFromDir, setupI18n, setI18nLanguage };
export { i18n, loadLocaleMessages, loadLocalesMap, loadLocalesMapFromDir, setupI18n };
export default i18n; export default i18n;

View File

@ -1,9 +1,9 @@
import { i18n, loadLocaleMessages, loadLocalesMap, loadLocalesMapFromDir, setupI18n } from "./i18n"; import { i18n, loadLocaleMessages, loadLocalesMap, loadLocalesMapFromDir, setupI18n, setI18nLanguage } from "./i18n";
const $t = i18n.global.t; const $t = i18n.global.t;
const $te = i18n.global.te; const $te = i18n.global.te;
export { $t, $te, i18n, loadLocaleMessages, loadLocalesMap, loadLocalesMapFromDir, setupI18n }; export { $t, $te, i18n, loadLocaleMessages, loadLocalesMap, loadLocalesMapFromDir, setupI18n, setI18nLanguage };
export { type ImportLocaleFn, type LocaleSetupOptions, type SupportedLanguagesType } from "./typing"; export { type ImportLocaleFn, type LocaleSetupOptions, type SupportedLanguagesType } from "./typing";
// export type { CompileError } from "@intlify/core-base"; // export type { CompileError } from "@intlify/core-base";

View File

@ -1,78 +1,78 @@
export default { export default {
"welcomeBack": "Welcome Back", welcomeBack: "Welcome Back",
"pageTitle": "Plug-and-play Admin system", pageTitle: "Plug-and-play Admin system",
"pageDesc": "Efficient, versatile frontend template", pageDesc: "Efficient, versatile frontend template",
"loginSuccess": "Login Successful", loginSuccess: "Login Successful",
"loginSuccessDesc": "Welcome Back", loginSuccessDesc: "Welcome Back",
"loginSubtitle": "Enter your account details to manage your projects", loginSubtitle: "Enter your account details to manage your projects",
"selectAccount": "Quick Select Account", selectAccount: "Quick Select Account",
"username": "Username", username: "Username",
"password": "Password", password: "Password",
"usernameTip": "Please enter username", usernameTip: "Please enter username",
"passwordErrorTip": "Password is incorrect", passwordErrorTip: "Password is incorrect",
"passwordTip": "Please enter password", passwordTip: "Please enter password",
"verifyRequiredTip": "Please complete the verification first", verifyRequiredTip: "Please complete the verification first",
"rememberMe": "Remember Me", rememberMe: "Remember Me",
"createAnAccount": "Create an Account", createAnAccount: "Create an Account",
"createAccount": "Create Account", createAccount: "Create Account",
"alreadyHaveAccount": "Already have an account?", alreadyHaveAccount: "Already have an account?",
"accountTip": "Don't have an account?", accountTip: "Don't have an account?",
"signUp": "Sign Up", signUp: "Sign Up",
"signUpSubtitle": "Make managing your applications simple and fun", signUpSubtitle: "Make managing your applications simple and fun",
"confirmPassword": "Confirm Password", confirmPassword: "Confirm Password",
"confirmPasswordTip": "The passwords do not match", confirmPasswordTip: "The passwords do not match",
"agree": "I agree to", agree: "I agree to",
"privacyPolicy": "Privacy-policy", privacyPolicy: "Privacy-policy",
"terms": "Terms", terms: "Terms",
"agreeTip": "Please agree to the Privacy Policy and Terms", agreeTip: "Please agree to the Privacy Policy and Terms",
"goToLogin": "Login instead", goToLogin: "Login instead",
"passwordStrength": "Use 8 or more characters with a mix of letters, numbers & symbols", passwordStrength: "Use 8 or more characters with a mix of letters, numbers & symbols",
"forgetPassword": "Forget Password?", forgetPassword: "Forget Password?",
"forgetPasswordSubtitle": "Enter your email and we'll send you instructions to reset your password", forgetPasswordSubtitle: "Enter your email and we'll send you instructions to reset your password",
"emailTip": "Please enter email", emailTip: "Please enter email",
"emailValidErrorTip": "The email format you entered is incorrect", emailValidErrorTip: "The email format you entered is incorrect",
"sendResetLink": "Send Reset Link", sendResetLink: "Send Reset Link",
"email": "Email", email: "Email",
"qrcodeSubtitle": "Scan the QR code with your phone to login", qrcodeSubtitle: "Scan the QR code with your phone to login",
"qrcodePrompt": "Click 'Confirm' after scanning to complete login", qrcodePrompt: "Click 'Confirm' after scanning to complete login",
"qrcodeLogin": "QR Code Login", qrcodeLogin: "QR Code Login",
"codeSubtitle": "Enter your phone number to start managing your project", codeSubtitle: "Enter your phone number to start managing your project",
"code": "Security code", code: "Security code",
"codeTip": "Security code required {0} characters", codeTip: "Security code required {0} characters",
"mobile": "Mobile", mobile: "Mobile",
"mobileLogin": "Mobile Login", mobileLogin: "Mobile Login",
"mobileTip": "Please enter mobile number", mobileTip: "Please enter mobile number",
"mobileErrortip": "The phone number format is incorrect", mobileErrortip: "The phone number format is incorrect",
"sendCode": "Get Security code", sendCode: "Get Security code",
"sendText": "Resend in {0}s", sendText: "Resend in {0}s",
"thirdPartyLogin": "Or continue with", thirdPartyLogin: "Or continue with",
"loginAgainTitle": "Please Log In Again", loginAgainTitle: "Please Log In Again",
"loginAgainSubTitle": "Your login session has expired. Please log in again to continue.", loginAgainSubTitle: "Your login session has expired. Please log in again to continue.",
"layout": { layout: {
"center": "Align Center", center: "Align Center",
"alignLeft": "Align Left", alignLeft: "Align Left",
"alignRight": "Align Right" alignRight: "Align Right",
}, },
usernamePlaceholder: 'Please enter username/email/phone number', usernamePlaceholder: "Please enter username/email/phone number",
passwordPlaceholder: 'Please enter your password', passwordPlaceholder: "Please enter your password",
mobilePlaceholder: 'Please enter your mobile number', mobilePlaceholder: "Please enter your mobile number",
loginButton: 'Log In', loginButton: "Log In",
forgotAdminPassword: 'Forgot admin password?', forgotAdminPassword: "Forgot admin password?",
registerLink: 'Register', registerLink: "Register",
smsTab: 'Login via SMS code', smsTab: "Login via SMS code",
passwordTab: 'Password login', passwordTab: "Password login",
title: 'Change Password', title: "Change Password",
weakPasswordWarning: 'For your account security, please change your password immediately', weakPasswordWarning: "For your account security, please change your password immediately",
changeNow: 'Change Now', changeNow: "Change Now",
successMessage: 'Changed successfully', successMessage: "Changed successfully",
oldPassword: 'Old Password', oldPassword: "Old Password",
oldPasswordRequired: 'Please enter the old password', oldPasswordRequired: "Please enter the old password",
newPassword: 'New Password', newPassword: "New Password",
newPasswordRequired: 'Please enter the new password', newPasswordRequired: "Please enter the new password",
confirmNewPassword: 'Confirm New Password', confirmNewPassword: "Confirm New Password",
confirmNewPasswordRequired: 'Please confirm the new password', confirmNewPasswordRequired: "Please confirm the new password",
changePasswordButton: 'Change Password', changePasswordButton: "Change Password",
enterPassword: "Please enter the password", enterPassword: "Please enter the password",
newPasswordNotSameOld: "The new password cannot be the same as the old password", newPasswordNotSameOld: "The new password cannot be the same as the old password",
enterPasswordAgain: "Please enter the password again", enterPasswordAgain: "Please enter the password again",
@ -81,4 +81,4 @@ export default {
nickName: "Nickname", nickName: "Nickname",
phoneNumber: "Phone Number", phoneNumber: "Phone Number",
changePassword: "Change Password", changePassword: "Change Password",
} };

View File

@ -2,31 +2,33 @@ export default {
app: { app: {
crud: { crud: {
i18n: { i18n: {
name: "name", city: "city", status: "status" name: "name",
} city: "city",
} status: "status",
},
},
}, },
fs: { fs: {
rowHandle: { rowHandle: {
title: "Operation" title: "Operation",
} },
}, },
order: { order: {
confirmTitle: 'Order Confirmation', confirmTitle: "Order Confirmation",
package: 'Package', package: "Package",
description: 'Description', description: "Description",
specifications: 'Specifications', specifications: "Specifications",
pipeline: 'Pipeline', pipeline: "Pipeline",
domain: 'Domain', domain: "Domain",
deployTimes: 'Deployments', deployTimes: "Deployments",
duration: 'Duration', duration: "Duration",
price: 'Price', price: "Price",
paymentMethod: 'Payment Method', paymentMethod: "Payment Method",
free: 'Free', free: "Free",
unit: { unit: {
pieces: 'pieces', pieces: "pieces",
count: 'count', count: "count",
times: 'times', times: "times",
}, },
}, },
framework: { framework: {
@ -80,7 +82,7 @@ export default {
steps: { steps: {
createPipeline: "Create Certificate Pipeline", createPipeline: "Create Certificate Pipeline",
addTask: "Add Deployment Task", addTask: "Add Deployment Task",
scheduledRun: "Scheduled Run" scheduledRun: "Scheduled Run",
}, },
customPipeline: "Custom Pipeline", customPipeline: "Custom Pipeline",
createCertdPipeline: "Create Certificate Pipeline", createCertdPipeline: "Create Certificate Pipeline",
@ -173,17 +175,17 @@ export default {
}, },
certificateRepo: { certificateRepo: {
title: "Certificate Repository", title: "Certificate Repository",
sub: "Certificates generated from pipeline" sub: "Certificates generated from pipeline",
}, },
certificateNotGenerated: "Certificate not yet generated, please run the pipeline first", certificateNotGenerated: "Certificate not yet generated, please run the pipeline first",
viewCertificateTitle: "View Certificate", viewCertificateTitle: "View Certificate",
close: "Close", close: "Close",
viewCert: { viewCert: {
title: "View Certificate" title: "View Certificate",
}, },
download: { download: {
title: "Download Certificate" title: "Download Certificate",
}, },
source: "Source Code", source: "Source Code",
github: "GitHub", github: "GitHub",
@ -191,22 +193,22 @@ export default {
cron: { cron: {
clearTip: "Clear Selection", clearTip: "Clear Selection",
nextTrigger: "Next Trigger Time", nextTrigger: "Next Trigger Time",
tip: "Please set a valid cron expression first" tip: "Please set a valid cron expression first",
}, },
cronForm: { cronForm: {
title: "Scheduled Script", title: "Scheduled Script",
helper: "Click the button above to select the time for daily execution.\nIt is recommended to run once a day. Tasks will be skipped if the certificate is not expiring.", helper: "Click the button above to select the time for daily execution.\nIt is recommended to run once a day. Tasks will be skipped if the certificate is not expiring.",
required: "This field is required" required: "This field is required",
}, },
email: { email: {
title: "Recipient Email", title: "Recipient Email",
helper: "Enter your recipient email addresses. Multiple addresses are supported.", helper: "Enter your recipient email addresses. Multiple addresses are supported.",
required: "This field is required" required: "This field is required",
}, },
plugin: { plugin: {
selectTitle: "Certificate Apply Plugin", selectTitle: "Certificate Apply Plugin",
jsAcme: "JS-ACME: Easy to use, powerful features [Recommended]", jsAcme: "JS-ACME: Easy to use, powerful features [Recommended]",
legoAcme: "Lego-ACME: Based on Lego, supports a wide range of DNS providers, suitable for users familiar with Lego" legoAcme: "Lego-ACME: Based on Lego, supports a wide range of DNS providers, suitable for users familiar with Lego",
}, },
pipelineForm: { pipelineForm: {
createTitle: "Create Certificate Pipeline", createTitle: "Create Certificate Pipeline",
@ -216,7 +218,7 @@ export default {
"Click the button above to choose a daily execution time.\nIt is recommended to trigger once per day. The task will be skipped if the certificate has not expired and will not be executed repeatedly.", "Click the button above to choose a daily execution time.\nIt is recommended to trigger once per day. The task will be skipped if the certificate has not expired and will not be executed repeatedly.",
notificationTitle: "Failure Notification", notificationTitle: "Failure Notification",
notificationHelper: "Get real-time alerts when the task fails", notificationHelper: "Get real-time alerts when the task fails",
groupIdTitle: "Pipeline Group" groupIdTitle: "Pipeline Group",
}, },
notificationDefault: "Use Default Notification", notificationDefault: "Use Default Notification",
monitor: { monitor: {

View File

@ -1,22 +1,22 @@
export default { export default {
"back": "Back", back: "Back",
"backToHome": "Back To Home", backToHome: "Back To Home",
"login": "Login", login: "Login",
"logout": "Logout", logout: "Logout",
"prompt": "Prompt", prompt: "Prompt",
"cancel": "Cancel", cancel: "Cancel",
"confirm": "Confirm", confirm: "Confirm",
"reset": "Reset", reset: "Reset",
"noData": "No Data", noData: "No Data",
"refresh": "Refresh", refresh: "Refresh",
"loadingMenu": "Loading Menu", loadingMenu: "Loading Menu",
"query": "Search", query: "Search",
"search": "Search", search: "Search",
"enabled": "Enabled", enabled: "Enabled",
"disabled": "Disabled", disabled: "Disabled",
"edit": "Edit", edit: "Edit",
"delete": "Delete", delete: "Delete",
"create": "Create", create: "Create",
"yes": "Yes", yes: "Yes",
"no": "No" no: "No",
} };

View File

@ -67,5 +67,5 @@ export default {
basicVersionNeedsMailServer: "(basic version requires configuring mail server)", basicVersionNeedsMailServer: "(basic version requires configuring mail server)",
tutorialEndTitle: "Tutorial End", tutorialEndTitle: "Tutorial End",
thanksForWatching: "Thank you for watching, hope it helps you", thanksForWatching: "Thank you for watching, hope it helps you",
} },
} };

View File

@ -1,11 +1,11 @@
import certd from './certd'; import certd from "./certd";
import authentication from './authentication'; import authentication from "./authentication";
import vip from './vip'; import vip from "./vip";
import tutorial from './tutorial'; import tutorial from "./tutorial";
import preferences from './preferences'; import preferences from "./preferences";
import ui from './ui'; import ui from "./ui";
import guide from './guide'; import guide from "./guide";
import common from './common'; import common from "./common";
export default { export default {
certd, certd,
@ -15,5 +15,5 @@ export default {
tutorial, tutorial,
preferences, preferences,
guide, guide,
common common,
}; };

View File

@ -1,186 +1,186 @@
export default { export default {
"title": "Preferences", title: "Preferences",
"subtitle": "Customize Preferences & Preview in Real Time", subtitle: "Customize Preferences & Preview in Real Time",
"resetTip": "Data has changed, click to reset", resetTip: "Data has changed, click to reset",
"resetTitle": "Reset Preferences", resetTitle: "Reset Preferences",
"resetSuccess": "Preferences reset successfully", resetSuccess: "Preferences reset successfully",
"appearance": "Appearance", appearance: "Appearance",
"layout": "Layout", layout: "Layout",
"content": "Content", content: "Content",
"other": "Other", other: "Other",
"wide": "Wide", wide: "Wide",
"compact": "Fixed", compact: "Fixed",
"followSystem": "Follow System", followSystem: "Follow System",
"vertical": "Vertical", vertical: "Vertical",
"verticalTip": "Side vertical menu mode", verticalTip: "Side vertical menu mode",
"horizontal": "Horizontal", horizontal: "Horizontal",
"horizontalTip": "Horizontal menu mode, all menus displayed at the top", horizontalTip: "Horizontal menu mode, all menus displayed at the top",
"twoColumn": "Two Column", twoColumn: "Two Column",
"twoColumnTip": "Vertical Two Column Menu Mode", twoColumnTip: "Vertical Two Column Menu Mode",
"headerSidebarNav": "Header Vertical", headerSidebarNav: "Header Vertical",
"headerSidebarNavTip": "Header Full Width, Sidebar Navigation Mode", headerSidebarNavTip: "Header Full Width, Sidebar Navigation Mode",
"headerTwoColumn": "Header Two Column", headerTwoColumn: "Header Two Column",
"headerTwoColumnTip": "Header Navigation & Sidebar Two Column co-exists", headerTwoColumnTip: "Header Navigation & Sidebar Two Column co-exists",
"mixedMenu": "Mixed Menu", mixedMenu: "Mixed Menu",
"mixedMenuTip": "Vertical & Horizontal Menu Co-exists", mixedMenuTip: "Vertical & Horizontal Menu Co-exists",
"fullContent": "Full Content", fullContent: "Full Content",
"fullContentTip": "Only display content body, hide all menus", fullContentTip: "Only display content body, hide all menus",
"normal": "Normal", normal: "Normal",
"plain": "Plain", plain: "Plain",
"rounded": "Rounded", rounded: "Rounded",
"copyPreferences": "Copy Preferences", copyPreferences: "Copy Preferences",
"copyPreferencesSuccessTitle": "Copy successful", copyPreferencesSuccessTitle: "Copy successful",
"copyPreferencesSuccess": "Copy successful, please override in `src/preferences.ts` under app", copyPreferencesSuccess: "Copy successful, please override in `src/preferences.ts` under app",
"clearAndLogout": "Clear Cache & Logout", clearAndLogout: "Clear Cache & Logout",
"mode": "Mode", mode: "Mode",
"general": "General", general: "General",
"language": "Language", language: "Language",
"dynamicTitle": "Dynamic Title", dynamicTitle: "Dynamic Title",
"watermark": "Watermark", watermark: "Watermark",
"checkUpdates": "Periodic update check", checkUpdates: "Periodic update check",
"position": { position: {
"title": "Preferences Postion", title: "Preferences Postion",
"header": "Header", header: "Header",
"auto": "Auto", auto: "Auto",
"fixed": "Fixed" fixed: "Fixed",
}, },
"sidebar": { sidebar: {
"title": "Sidebar", title: "Sidebar",
"width": "Width", width: "Width",
"visible": "Show Sidebar", visible: "Show Sidebar",
"collapsed": "Collpase Menu", collapsed: "Collpase Menu",
"collapsedShowTitle": "Show Menu Title", collapsedShowTitle: "Show Menu Title",
"autoActivateChild": "Auto Activate SubMenu", autoActivateChild: "Auto Activate SubMenu",
"autoActivateChildTip": "`Enabled` to automatically activate the submenu while click menu.", autoActivateChildTip: "`Enabled` to automatically activate the submenu while click menu.",
"expandOnHover": "Expand On Hover", expandOnHover: "Expand On Hover",
"expandOnHoverTip": "When the mouse hovers over menu, \n `Enabled` to expand children menus \n `Disabled` to expand whole sidebar." expandOnHoverTip: "When the mouse hovers over menu, \n `Enabled` to expand children menus \n `Disabled` to expand whole sidebar.",
}, },
"tabbar": { tabbar: {
"title": "Tabbar", title: "Tabbar",
"enable": "Enable Tab Bar", enable: "Enable Tab Bar",
"icon": "Show Tabbar Icon", icon: "Show Tabbar Icon",
"showMore": "Show More Button", showMore: "Show More Button",
"showMaximize": "Show Maximize Button", showMaximize: "Show Maximize Button",
"persist": "Persist Tabs", persist: "Persist Tabs",
"maxCount": "Max Count of 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.", 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", draggable: "Enable Draggable Sort",
"wheelable": "Support Mouse Wheel", wheelable: "Support Mouse Wheel",
"middleClickClose": "Close Tab when Mouse Middle Button Click", middleClickClose: "Close Tab when Mouse Middle Button Click",
"wheelableTip": "When enabled, the Tabbar area responds to vertical scrolling events of the scroll wheel.", wheelableTip: "When enabled, the Tabbar area responds to vertical scrolling events of the scroll wheel.",
"styleType": { styleType: {
"title": "Tabs Style", title: "Tabs Style",
"chrome": "Chrome", chrome: "Chrome",
"card": "Card", card: "Card",
"plain": "Plain", plain: "Plain",
"brisk": "Brisk" brisk: "Brisk",
}, },
"contextMenu": { contextMenu: {
"reload": "Reload", reload: "Reload",
"close": "Close", close: "Close",
"pin": "Pin", pin: "Pin",
"unpin": "Unpin", unpin: "Unpin",
"closeLeft": "Close Left Tabs", closeLeft: "Close Left Tabs",
"closeRight": "Close Right Tabs", closeRight: "Close Right Tabs",
"closeOther": "Close Other Tabs", closeOther: "Close Other Tabs",
"closeAll": "Close All Tabs", closeAll: "Close All Tabs",
"openInNewWindow": "Open in New Window", openInNewWindow: "Open in New Window",
"maximize": "Maximize", maximize: "Maximize",
"restoreMaximize": "Restore" 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": { navigationMenu: {
"title": "Breadcrumb", title: "Navigation Menu",
"home": "Show Home Button", style: "Navigation Menu Style",
"enable": "Enable Breadcrumb", accordion: "Sidebar Accordion Menu",
"icon": "Show Breadcrumb Icon", split: "Navigation Menu Separation",
"background": "background", splitTip: "When enabled, the sidebar displays the top bar's submenu",
"style": "Breadcrumb Style",
"hideOnlyOne": "Hidden when only one"
}, },
"animation": { breadcrumb: {
"title": "Animation", title: "Breadcrumb",
"loading": "Page Loading", home: "Show Home Button",
"transition": "Page Transition", enable: "Enable Breadcrumb",
"progress": "Page Progress" icon: "Show Breadcrumb Icon",
background: "background",
style: "Breadcrumb Style",
hideOnlyOne: "Hidden when only one",
}, },
"theme": { animation: {
"title": "Theme", title: "Animation",
"radius": "Radius", loading: "Page Loading",
"light": "Light", transition: "Page Transition",
"dark": "Dark", progress: "Page Progress",
"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": { theme: {
"title": "Header", title: "Theme",
"visible": "Show Header", radius: "Radius",
"modeStatic": "Static", light: "Light",
"modeFixed": "Fixed", dark: "Dark",
"modeAuto": "Auto hide & Show", darkSidebar: "Semi Dark Sidebar",
"modeAutoScroll": "Scroll to Hide & Show", darkHeader: "Semi Dark Header",
"menuAlign": "Menu Align", weakMode: "Weak Mode",
"menuAlignStart": "Start", grayMode: "Gray Mode",
"menuAlignEnd": "End", builtin: {
"menuAlignCenter": "Center" 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",
}, },
"footer": {
"title": "Footer",
"visible": "Show Footer",
"fixed": "Fixed at Bottom"
}, },
"copyright": { header: {
"title": "Copyright", title: "Header",
"enable": "Enable Copyright", visible: "Show Header",
"companyName": "Company Name", modeStatic: "Static",
"companySiteLink": "Company Site Link", modeFixed: "Fixed",
"date": "Date", modeAuto: "Auto hide & Show",
"icp": "ICP License Number", modeAutoScroll: "Scroll to Hide & Show",
"icpLink": "ICP Site Link" menuAlign: "Menu Align",
menuAlignStart: "Start",
menuAlignEnd: "End",
menuAlignCenter: "Center",
}, },
"shortcutKeys": { footer: {
"title": "Shortcut Keys", title: "Footer",
"global": "Global", visible: "Show Footer",
"search": "Global Search", fixed: "Fixed at Bottom",
"logout": "Logout",
"preferences": "Preferences"
}, },
"widget": { copyright: {
"title": "Widget", title: "Copyright",
"globalSearch": "Enable Global Search", enable: "Enable Copyright",
"fullscreen": "Enable Fullscreen", companyName: "Company Name",
"themeToggle": "Enable Theme Toggle", companySiteLink: "Company Site Link",
"languageToggle": "Enable Language Toggle", date: "Date",
"notification": "Enable Notification", icp: "ICP License Number",
"sidebarToggle": "Enable Sidebar Toggle", icpLink: "ICP Site Link",
"lockScreen": "Enable Lock Screen", },
"refresh": "Enable Refresh" 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",
},
};

View File

@ -1,3 +1,3 @@
export default { export default {
title: 'Tutorial', title: "Tutorial",
} };

View File

@ -1,104 +1,104 @@
export default { export default {
"formRules": { formRules: {
"required": "Please enter {0}", required: "Please enter {0}",
"selectRequired": "Please select {0}", selectRequired: "Please select {0}",
"minLength": "{0} must be at least {1} characters", minLength: "{0} must be at least {1} characters",
"maxLength": "{0} can be at most {1} characters", maxLength: "{0} can be at most {1} characters",
"length": "{0} must be {1} characters long", length: "{0} must be {1} characters long",
"alreadyExists": "{0} `{1}` already exists", alreadyExists: "{0} `{1}` already exists",
"startWith": "{0} must start with `{1}`", startWith: "{0} must start with `{1}`",
"invalidURL": "Please input a valid URL" invalidURL: "Please input a valid URL",
}, },
"actionTitle": { actionTitle: {
"edit": "Modify {0}", edit: "Modify {0}",
"create": "Create {0}", create: "Create {0}",
"delete": "Delete {0}", delete: "Delete {0}",
"view": "View {0}" view: "View {0}",
}, },
"actionMessage": { actionMessage: {
"deleteConfirm": "Are you sure to delete {0}?", deleteConfirm: "Are you sure to delete {0}?",
"deleting": "Deleting {0} ...", deleting: "Deleting {0} ...",
"deleteSuccess": "{0} deleted successfully", deleteSuccess: "{0} deleted successfully",
"operationSuccess": "Operation succeeded", operationSuccess: "Operation succeeded",
"operationFailed": "Operation failed" operationFailed: "Operation failed",
}, },
"placeholder": { placeholder: {
"input": "Please enter", input: "Please enter",
"select": "Please select" select: "Please select",
}, },
"captcha": { captcha: {
"title": "Please complete the security verification", title: "Please complete the security verification",
"sliderSuccessText": "Passed", sliderSuccessText: "Passed",
"sliderDefaultText": "Slider and drag", sliderDefaultText: "Slider and drag",
"alt": "Supports img tag src attribute value", alt: "Supports img tag src attribute value",
"sliderRotateDefaultTip": "Click picture to refresh", sliderRotateDefaultTip: "Click picture to refresh",
"sliderRotateFailTip": "Validation failed", sliderRotateFailTip: "Validation failed",
"sliderRotateSuccessTip": "Validation successful, time {0} seconds", sliderRotateSuccessTip: "Validation successful, time {0} seconds",
"refreshAriaLabel": "Refresh captcha", refreshAriaLabel: "Refresh captcha",
"confirmAriaLabel": "Confirm selection", confirmAriaLabel: "Confirm selection",
"confirm": "Confirm", confirm: "Confirm",
"pointAriaLabel": "Click point", pointAriaLabel: "Click point",
"clickInOrder": "Please click in order" clickInOrder: "Please click in order",
}, },
"iconPicker": { iconPicker: {
"placeholder": "Select an icon", placeholder: "Select an icon",
"search": "Search icon..." search: "Search icon...",
}, },
"jsonViewer": { jsonViewer: {
"copy": "Copy", copy: "Copy",
"copied": "Copied" copied: "Copied",
}, },
"fallback": { fallback: {
"pageNotFound": "Oops! Page Not Found", pageNotFound: "Oops! Page Not Found",
"pageNotFoundDesc": "Sorry, we couldn't find the page you were looking for.", pageNotFoundDesc: "Sorry, we couldn't find the page you were looking for.",
"forbidden": "Oops! Access Denied", forbidden: "Oops! Access Denied",
"forbiddenDesc": "Sorry, but you don't have permission to access this page.", forbiddenDesc: "Sorry, but you don't have permission to access this page.",
"internalError": "Oops! Something Went Wrong", internalError: "Oops! Something Went Wrong",
"internalErrorDesc": "Sorry, but the server encountered an error.", internalErrorDesc: "Sorry, but the server encountered an error.",
"offline": "Offline Page", offline: "Offline Page",
"offlineError": "Oops! Network Error", offlineError: "Oops! Network Error",
"offlineErrorDesc": "Sorry, can't connect to the internet. Check your connection.", offlineErrorDesc: "Sorry, can't connect to the internet. Check your connection.",
"comingSoon": "Coming Soon", comingSoon: "Coming Soon",
"http": { http: {
"requestTimeout": "The request timed out. Please try again later.", requestTimeout: "The request timed out. Please try again later.",
"networkError": "A network error occurred. Please check your internet connection and try again.", networkError: "A network error occurred. Please check your internet connection and try again.",
"badRequest": "Bad Request. Please check your input and try again.", badRequest: "Bad Request. Please check your input and try again.",
"unauthorized": "Unauthorized. Please log in to continue.", unauthorized: "Unauthorized. Please log in to continue.",
"forbidden": "Forbidden. You do not have permission to access this resource.", forbidden: "Forbidden. You do not have permission to access this resource.",
"notFound": "Not Found. The requested resource could not be found.", notFound: "Not Found. The requested resource could not be found.",
"internalServerError": "Internal Server Error. Something went wrong on our end. Please try again later." 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": { widgets: {
"title": "Lock Screen", document: "Document",
"screenButton": "Locking", qa: "Q&A",
"password": "Password", setting: "Settings",
"placeholder": "Please enter password", logoutTip: "Do you want to logout?",
"unlock": "Click to unlock", viewAll: "View All Messages",
"errorPasswordTip": "Password error, please re-enter", notifications: "Notifications",
"backToLogin": "Back to login", markAllAsRead: "Make All as Read",
"entry": "Enter the system" 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",
},
},
};

View File

@ -27,11 +27,11 @@ export default {
successContent: "You have successfully activated {vipLabel}, valid until: {expireDate}", successContent: "You have successfully activated {vipLabel}, valid until: {expireDate}",
bindAccountTitle: "Bind Your Account", bindAccountTitle: "Bind Your Account",
bindAccountContent: "Binding your account helps prevent license loss. Strongly recommended.", bindAccountContent: "Binding your account helps prevent license loss. Strongly recommended.",
congratulations_vip_trial: 'Congratulations, you have received a Pro version {duration} days trial', congratulations_vip_trial: "Congratulations, you have received a Pro version {duration} days trial",
trial_modal_title: '7-day Pro version trial acquisition', trial_modal_title: "7-day Pro version trial acquisition",
trial_modal_ok_text: 'Get now', trial_modal_ok_text: "Get now",
trial_modal_thanks: 'Thank you for supporting the open source project', trial_modal_thanks: "Thank you for supporting the open source project",
trial_modal_click_confirm: 'Click confirm to get a 7-day Pro version trial', trial_modal_click_confirm: "Click confirm to get a 7-day Pro version trial",
get_7_day_pro_trial: "7-day professional version trial", get_7_day_pro_trial: "7-day professional version trial",
star_now: "Star Now", star_now: "Star Now",
please_help_star: "Could you please help by starring? Thanks a lot!", please_help_star: "Could you please help by starring? Thanks a lot!",
@ -83,4 +83,4 @@ export default {
activation_code_one_use: "Activation code can only be used once. To change site, please ", activation_code_one_use: "Activation code can only be used once. To change site, please ",
bind_account: "bind account", bind_account: "bind account",
transfer_vip: ' then "Transfer VIP"', transfer_vip: ' then "Transfer VIP"',
} };

View File

@ -1,79 +1,79 @@
export default { export default {
"welcomeBack": "欢迎回来", welcomeBack: "欢迎回来",
"pageTitle": "开箱即用的大型中后台管理系统", pageTitle: "开箱即用的大型中后台管理系统",
"pageDesc": "工程化、高性能、跨组件库的前端模版", pageDesc: "工程化、高性能、跨组件库的前端模版",
"loginSuccess": "登录成功", loginSuccess: "登录成功",
"loginSuccessDesc": "欢迎回来", loginSuccessDesc: "欢迎回来",
"loginSubtitle": "请输入您的帐户信息以开始管理您的项目", loginSubtitle: "请输入您的帐户信息以开始管理您的项目",
"selectAccount": "快速选择账号", selectAccount: "快速选择账号",
"username": "账号", username: "账号",
"password": "密码", password: "密码",
"usernameTip": "请输入用户名", usernameTip: "请输入用户名",
"passwordTip": "请输入密码", passwordTip: "请输入密码",
"verifyRequiredTip": "请先完成验证", verifyRequiredTip: "请先完成验证",
"passwordErrorTip": "密码错误", passwordErrorTip: "密码错误",
"rememberMe": "记住账号", rememberMe: "记住账号",
"createAnAccount": "创建一个账号", createAnAccount: "创建一个账号",
"createAccount": "创建账号", createAccount: "创建账号",
"alreadyHaveAccount": "已经有账号了?", alreadyHaveAccount: "已经有账号了?",
"accountTip": "还没有账号?", accountTip: "还没有账号?",
"signUp": "注册", signUp: "注册",
"signUpSubtitle": "让您的应用程序管理变得简单而有趣", signUpSubtitle: "让您的应用程序管理变得简单而有趣",
"confirmPassword": "确认密码", confirmPassword: "确认密码",
"confirmPasswordTip": "两次输入的密码不一致", confirmPasswordTip: "两次输入的密码不一致",
"agree": "我同意", agree: "我同意",
"privacyPolicy": "隐私政策", privacyPolicy: "隐私政策",
"terms": "条款", terms: "条款",
"agreeTip": "请同意隐私政策和条款", agreeTip: "请同意隐私政策和条款",
"goToLogin": "去登录", goToLogin: "去登录",
"passwordStrength": "使用 8 个或更多字符,混合字母、数字和符号", passwordStrength: "使用 8 个或更多字符,混合字母、数字和符号",
"forgetPassword": "忘记密码?", forgetPassword: "忘记密码?",
"forgetPasswordSubtitle": "输入您的电子邮件,我们将向您发送重置密码的连接", forgetPasswordSubtitle: "输入您的电子邮件,我们将向您发送重置密码的连接",
"emailTip": "请输入邮箱", emailTip: "请输入邮箱",
"emailValidErrorTip": "你输入的邮箱格式不正确", emailValidErrorTip: "你输入的邮箱格式不正确",
"sendResetLink": "发送重置链接", sendResetLink: "发送重置链接",
"email": "邮箱", email: "邮箱",
"qrcodeSubtitle": "请用手机扫描二维码登录", qrcodeSubtitle: "请用手机扫描二维码登录",
"qrcodePrompt": "扫码后点击 '确认',即可完成登录", qrcodePrompt: "扫码后点击 '确认',即可完成登录",
"qrcodeLogin": "扫码登录", qrcodeLogin: "扫码登录",
"codeSubtitle": "请输入您的手机号码以开始管理您的项目", codeSubtitle: "请输入您的手机号码以开始管理您的项目",
"code": "验证码", code: "验证码",
"codeTip": "请输入{0}位验证码", codeTip: "请输入{0}位验证码",
"mobile": "手机号码", mobile: "手机号码",
"mobileTip": "请输入手机号", mobileTip: "请输入手机号",
"mobileErrortip": "手机号码格式错误", mobileErrortip: "手机号码格式错误",
"mobileLogin": "手机号登录", mobileLogin: "手机号登录",
"sendCode": "获取验证码", sendCode: "获取验证码",
"sendText": "{0}秒后重新获取", sendText: "{0}秒后重新获取",
"thirdPartyLogin": "其他登录方式", thirdPartyLogin: "其他登录方式",
"loginAgainTitle": "重新登录", loginAgainTitle: "重新登录",
"loginAgainSubTitle": "您的登录状态已过期,请重新登录以继续。", loginAgainSubTitle: "您的登录状态已过期,请重新登录以继续。",
"layout": { layout: {
"center": "居中", center: "居中",
"alignLeft": "居左", alignLeft: "居左",
"alignRight": "居右" alignRight: "居右",
}, },
usernamePlaceholder: '请输入用户名/邮箱/手机号', usernamePlaceholder: "请输入用户名/邮箱/手机号",
passwordPlaceholder: '请输入密码', passwordPlaceholder: "请输入密码",
mobilePlaceholder: '请输入手机号', mobilePlaceholder: "请输入手机号",
loginButton: '登录', loginButton: "登录",
forgotAdminPassword: '忘记管理员密码?', forgotAdminPassword: "忘记管理员密码?",
registerLink: '注册', registerLink: "注册",
smsTab: '短信验证码登录', smsTab: "短信验证码登录",
passwordTab: '密码登录', passwordTab: "密码登录",
title: '修改密码', title: "修改密码",
weakPasswordWarning: '为了您的账户安全,请立即修改密码', weakPasswordWarning: "为了您的账户安全,请立即修改密码",
changeNow: '立即修改', changeNow: "立即修改",
successMessage: '修改成功', successMessage: "修改成功",
oldPassword: '旧密码', oldPassword: "旧密码",
oldPasswordRequired: '请输入旧密码', oldPasswordRequired: "请输入旧密码",
newPassword: '新密码', newPassword: "新密码",
newPasswordRequired: '请输入新密码', newPasswordRequired: "请输入新密码",
confirmNewPassword: '确认新密码', confirmNewPassword: "确认新密码",
confirmNewPasswordRequired: '请输入确认密码', confirmNewPasswordRequired: "请输入确认密码",
changePasswordButton: '修改密码', changePasswordButton: "修改密码",
enterPassword: "请输入密码", enterPassword: "请输入密码",
newPasswordNotSameOld: "新密码不能和旧密码相同", newPasswordNotSameOld: "新密码不能和旧密码相同",
enterPasswordAgain: "请再次输入密码", enterPasswordAgain: "请再次输入密码",
@ -82,4 +82,4 @@ export default {
nickName: "昵称", nickName: "昵称",
phoneNumber: "手机号", phoneNumber: "手机号",
changePassword: "修改密码", changePassword: "修改密码",
} };

View File

@ -2,8 +2,10 @@ export default {
app: { app: {
crud: { crud: {
i18n: { i18n: {
name: "姓名", city: "城市", status: "状态" name: "姓名",
} city: "城市",
status: "状态",
},
}, },
login: { login: {
logoutTip: "确认", logoutTip: "确认",
@ -16,21 +18,21 @@ export default {
}, },
}, },
order: { order: {
confirmTitle: '订单确认', confirmTitle: "订单确认",
package: '套餐', package: "套餐",
description: '说明', description: "说明",
specifications: '规格', specifications: "规格",
pipeline: '流水线', pipeline: "流水线",
domain: '域名', domain: "域名",
deployTimes: '部署次数', deployTimes: "部署次数",
duration: '时长', duration: "时长",
price: '价格', price: "价格",
paymentMethod: '支付方式', paymentMethod: "支付方式",
free: '免费', free: "免费",
unit: { unit: {
pieces: '条', pieces: "条",
count: '个', count: "个",
times: '次', times: "次",
}, },
}, },
framework: { framework: {
@ -86,7 +88,7 @@ export default {
steps: { steps: {
createPipeline: "创建证书流水线", createPipeline: "创建证书流水线",
addTask: "添加部署任务", addTask: "添加部署任务",
scheduledRun: "定时运行" scheduledRun: "定时运行",
}, },
customPipeline: "自定义流水线", customPipeline: "自定义流水线",
createCertdPipeline: "创建证书流水线", createCertdPipeline: "创建证书流水线",
@ -179,17 +181,17 @@ export default {
}, },
certificateRepo: { certificateRepo: {
title: "证书仓库", title: "证书仓库",
sub: "从流水线生成的证书" sub: "从流水线生成的证书",
}, },
certificateNotGenerated: "证书还未生成,请先运行流水线", certificateNotGenerated: "证书还未生成,请先运行流水线",
viewCertificateTitle: "查看证书", viewCertificateTitle: "查看证书",
close: "关闭", close: "关闭",
viewCert: { viewCert: {
title: "查看证书" title: "查看证书",
}, },
download: { download: {
title: "下载证书" title: "下载证书",
}, },
source: "源码", source: "源码",
github: "github", github: "github",
@ -197,32 +199,31 @@ export default {
cron: { cron: {
clearTip: "清除选择", clearTip: "清除选择",
nextTrigger: "下次触发时间", nextTrigger: "下次触发时间",
tip: "请先设置正确的cron表达式" tip: "请先设置正确的cron表达式",
}, },
cronForm: { cronForm: {
title: "定时脚本", title: "定时脚本",
helper: "点击上面的按钮,选择每天几点定时执行。\n建议设置为每天触发一次证书未到期之前任务会跳过不会重复执行", helper: "点击上面的按钮,选择每天几点定时执行。\n建议设置为每天触发一次证书未到期之前任务会跳过不会重复执行",
required: "此项必填" required: "此项必填",
}, },
email: { email: {
title: "收件邮箱", title: "收件邮箱",
helper: "输入你的收件邮箱地址,支持多个邮箱", helper: "输入你的收件邮箱地址,支持多个邮箱",
required: "此项必填" required: "此项必填",
}, },
plugin: { plugin: {
selectTitle: "证书申请插件", selectTitle: "证书申请插件",
jsAcme: "JS-ACME使用简单方便功能强大【推荐】", jsAcme: "JS-ACME使用简单方便功能强大【推荐】",
legoAcme: "Lego-ACME基于Lego实现支持海量DNS提供商熟悉LEGO的用户可以使用" legoAcme: "Lego-ACME基于Lego实现支持海量DNS提供商熟悉LEGO的用户可以使用",
}, },
pipelineForm: { pipelineForm: {
createTitle: "创建证书流水线", createTitle: "创建证书流水线",
moreParams: "更多参数", moreParams: "更多参数",
triggerCronTitle: "定时触发", triggerCronTitle: "定时触发",
triggerCronHelper: triggerCronHelper: "点击上面的按钮,选择每天几点定时执行。\n建议设置为每天触发一次证书未到期之前任务会跳过不会重复执行",
"点击上面的按钮,选择每天几点定时执行。\n建议设置为每天触发一次证书未到期之前任务会跳过不会重复执行",
notificationTitle: "失败通知", notificationTitle: "失败通知",
notificationHelper: "任务执行失败实时提醒", notificationHelper: "任务执行失败实时提醒",
groupIdTitle: "流水线分组" groupIdTitle: "流水线分组",
}, },
notificationDefault: "使用默认通知", notificationDefault: "使用默认通知",
monitor: { monitor: {
@ -669,16 +670,14 @@ export default {
remark: "备注", remark: "备注",
roles: "角色", roles: "角色",
cnameTitle: "CNAME服务配置", cnameTitle: "CNAME服务配置",
cnameDescription: cnameDescription: "此处配置的域名作为其他域名校验的代理当别的域名需要申请证书时通过CNAME映射到此域名上来验证所有权。好处是任何域名都可以通过此方式申请证书也无需填写AccessSecret。",
"此处配置的域名作为其他域名校验的代理当别的域名需要申请证书时通过CNAME映射到此域名上来验证所有权。好处是任何域名都可以通过此方式申请证书也无需填写AccessSecret。",
cnameLinkText: "CNAME功能原理及使用说明", cnameLinkText: "CNAME功能原理及使用说明",
confirmTitle: "确认", confirmTitle: "确认",
confirmDeleteBatch: "确定要批量删除这{count}条记录吗", confirmDeleteBatch: "确定要批量删除这{count}条记录吗",
selectRecordsFirst: "请先勾选记录", selectRecordsFirst: "请先勾选记录",
cnameDomain: "CNAME域名", cnameDomain: "CNAME域名",
cnameDomainPlaceholder: "cname.handsfree.work", cnameDomainPlaceholder: "cname.handsfree.work",
cnameDomainHelper: cnameDomainHelper: "需要一个右边DNS提供商注册的域名也可以将其他域名的dns服务器转移到这几家来。\nCNAME域名一旦确定不可修改建议使用一级子域名",
"需要一个右边DNS提供商注册的域名也可以将其他域名的dns服务器转移到这几家来。\nCNAME域名一旦确定不可修改建议使用一级子域名",
dnsProvider: "DNS提供商", dnsProvider: "DNS提供商",
dnsProviderAuthorization: "DNS提供商授权", dnsProviderAuthorization: "DNS提供商授权",
setDefault: "设置默认", setDefault: "设置默认",
@ -686,5 +685,4 @@ export default {
setAsDefault: "设为默认", setAsDefault: "设为默认",
disabledLabel: "禁用", disabledLabel: "禁用",
confirmToggleStatus: "确定要{action}吗?", confirmToggleStatus: "确定要{action}吗?",
}; };

View File

@ -1,22 +1,22 @@
export default { export default {
"back": "返回", back: "返回",
"backToHome": "返回首页", backToHome: "返回首页",
"login": "登录", login: "登录",
"logout": "退出登录", logout: "退出登录",
"prompt": "提示", prompt: "提示",
"cancel": "取消", cancel: "取消",
"confirm": "确认", confirm: "确认",
"reset": "重置", reset: "重置",
"noData": "暂无数据", noData: "暂无数据",
"refresh": "刷新", refresh: "刷新",
"loadingMenu": "加载菜单中", loadingMenu: "加载菜单中",
"query": "查询", query: "查询",
"search": "搜索", search: "搜索",
"enabled": "已启用", enabled: "已启用",
"disabled": "已禁用", disabled: "已禁用",
"edit": "修改", edit: "修改",
"delete": "删除", delete: "删除",
"create": "新增", create: "新增",
"yes": "是", yes: "是",
"no": "否" no: "否",
} };

View File

@ -67,5 +67,5 @@ export default {
basicVersionNeedsMailServer: "(基础版需要配置邮件服务器)", basicVersionNeedsMailServer: "(基础版需要配置邮件服务器)",
tutorialEndTitle: "教程结束", tutorialEndTitle: "教程结束",
thanksForWatching: "感谢观看,希望对你有所帮助", thanksForWatching: "感谢观看,希望对你有所帮助",
} },
} };

View File

@ -1,11 +1,11 @@
import certd from './certd'; import certd from "./certd";
import authentication from './authentication'; import authentication from "./authentication";
import vip from './vip'; import vip from "./vip";
import tutorial from './tutorial'; import tutorial from "./tutorial";
import preferences from './preferences'; import preferences from "./preferences";
import ui from './ui'; import ui from "./ui";
import guide from './guide'; import guide from "./guide";
import common from './common'; import common from "./common";
export default { export default {
certd, certd,
@ -15,5 +15,5 @@ export default {
tutorial, tutorial,
preferences, preferences,
guide, guide,
common common,
}; };

View File

@ -1,186 +1,186 @@
export default { export default {
"title": "偏好设置", title: "偏好设置",
"subtitle": "自定义偏好设置 & 实时预览", subtitle: "自定义偏好设置 & 实时预览",
"resetTitle": "重置偏好设置", resetTitle: "重置偏好设置",
"resetTip": "数据有变化,点击可进行重置", resetTip: "数据有变化,点击可进行重置",
"resetSuccess": "重置偏好设置成功", resetSuccess: "重置偏好设置成功",
"appearance": "外观", appearance: "外观",
"layout": "布局", layout: "布局",
"content": "内容", content: "内容",
"other": "其它", other: "其它",
"wide": "流式", wide: "流式",
"compact": "定宽", compact: "定宽",
"followSystem": "跟随系统", followSystem: "跟随系统",
"vertical": "垂直", vertical: "垂直",
"verticalTip": "侧边垂直菜单模式", verticalTip: "侧边垂直菜单模式",
"horizontal": "水平", horizontal: "水平",
"horizontalTip": "水平菜单模式,菜单全部显示在顶部", horizontalTip: "水平菜单模式,菜单全部显示在顶部",
"twoColumn": "双列菜单", twoColumn: "双列菜单",
"twoColumnTip": "垂直双列菜单模式", twoColumnTip: "垂直双列菜单模式",
"headerSidebarNav": "侧边导航", headerSidebarNav: "侧边导航",
"headerSidebarNavTip": "顶部通栏,侧边导航模式", headerSidebarNavTip: "顶部通栏,侧边导航模式",
"headerTwoColumn": "混合双列", headerTwoColumn: "混合双列",
"headerTwoColumnTip": "双列、水平菜单共存模式", headerTwoColumnTip: "双列、水平菜单共存模式",
"mixedMenu": "混合垂直", mixedMenu: "混合垂直",
"mixedMenuTip": "垂直水平菜单共存", mixedMenuTip: "垂直水平菜单共存",
"fullContent": "内容全屏", fullContent: "内容全屏",
"fullContentTip": "不显示任何菜单,只显示内容主体", fullContentTip: "不显示任何菜单,只显示内容主体",
"normal": "常规", normal: "常规",
"plain": "朴素", plain: "朴素",
"rounded": "圆润", rounded: "圆润",
"copyPreferences": "复制偏好设置", copyPreferences: "复制偏好设置",
"copyPreferencesSuccessTitle": "复制成功", copyPreferencesSuccessTitle: "复制成功",
"copyPreferencesSuccess": "复制成功,请在 app 下的 `src/preferences.ts`内进行覆盖", copyPreferencesSuccess: "复制成功,请在 app 下的 `src/preferences.ts`内进行覆盖",
"clearAndLogout": "清空缓存 & 退出登录", clearAndLogout: "清空缓存 & 退出登录",
"mode": "模式", mode: "模式",
"general": "通用", general: "通用",
"language": "语言", language: "语言",
"dynamicTitle": "动态标题", dynamicTitle: "动态标题",
"watermark": "水印", watermark: "水印",
"checkUpdates": "定时检查更新", checkUpdates: "定时检查更新",
"position": { position: {
"title": "偏好设置位置", title: "偏好设置位置",
"header": "顶栏", header: "顶栏",
"auto": "自动", auto: "自动",
"fixed": "固定" fixed: "固定",
}, },
"sidebar": { sidebar: {
"title": "侧边栏", title: "侧边栏",
"width": "宽度", width: "宽度",
"visible": "显示侧边栏", visible: "显示侧边栏",
"collapsed": "折叠菜单", collapsed: "折叠菜单",
"collapsedShowTitle": "折叠显示菜单名", collapsedShowTitle: "折叠显示菜单名",
"autoActivateChild": "自动激活子菜单", autoActivateChild: "自动激活子菜单",
"autoActivateChildTip": "点击顶层菜单时,自动激活第一个子菜单或者上一次激活的子菜单", autoActivateChildTip: "点击顶层菜单时,自动激活第一个子菜单或者上一次激活的子菜单",
"expandOnHover": "鼠标悬停展开", expandOnHover: "鼠标悬停展开",
"expandOnHoverTip": "鼠标在折叠区域悬浮时,`启用`则展开当前子菜单,`禁用`则展开整个侧边栏" expandOnHoverTip: "鼠标在折叠区域悬浮时,`启用`则展开当前子菜单,`禁用`则展开整个侧边栏",
}, },
"tabbar": { tabbar: {
"title": "标签栏", title: "标签栏",
"enable": "启用标签栏", enable: "启用标签栏",
"icon": "显示标签栏图标", icon: "显示标签栏图标",
"showMore": "显示更多按钮", showMore: "显示更多按钮",
"showMaximize": "显示最大化按钮", showMaximize: "显示最大化按钮",
"persist": "持久化标签页", persist: "持久化标签页",
"maxCount": "最大标签数", maxCount: "最大标签数",
"maxCountTip": "每次打开新的标签时如果超过最大标签数,\n会自动关闭一个最先打开的标签\n设置为 0 则不限制", maxCountTip: "每次打开新的标签时如果超过最大标签数,\n会自动关闭一个最先打开的标签\n设置为 0 则不限制",
"draggable": "启动拖拽排序", draggable: "启动拖拽排序",
"wheelable": "启用纵向滚轮响应", wheelable: "启用纵向滚轮响应",
"middleClickClose": "点击鼠标中键关闭标签页", middleClickClose: "点击鼠标中键关闭标签页",
"wheelableTip": "开启后,标签栏区域可以响应滚轮的纵向滚动事件。\n关闭时只能响应系统的横向滚动事件需要按下Shift再滚动滚轮", wheelableTip: "开启后,标签栏区域可以响应滚轮的纵向滚动事件。\n关闭时只能响应系统的横向滚动事件需要按下Shift再滚动滚轮",
"styleType": { styleType: {
"title": "标签页风格", title: "标签页风格",
"chrome": "谷歌", chrome: "谷歌",
"card": "卡片", card: "卡片",
"plain": "朴素", plain: "朴素",
"brisk": "轻快" brisk: "轻快",
}, },
"contextMenu": { contextMenu: {
"reload": "重新加载", reload: "重新加载",
"close": "关闭", close: "关闭",
"pin": "固定", pin: "固定",
"unpin": "取消固定", unpin: "取消固定",
"closeLeft": "关闭左侧标签页", closeLeft: "关闭左侧标签页",
"closeRight": "关闭右侧标签页", closeRight: "关闭右侧标签页",
"closeOther": "关闭其它标签页", closeOther: "关闭其它标签页",
"closeAll": "关闭全部标签页", closeAll: "关闭全部标签页",
"openInNewWindow": "在新窗口打开", openInNewWindow: "在新窗口打开",
"maximize": "最大化", maximize: "最大化",
"restoreMaximize": "还原" restoreMaximize: "还原",
}
}, },
"navigationMenu": {
"title": "导航菜单",
"style": "导航菜单风格",
"accordion": "侧边导航菜单手风琴模式",
"split": "导航菜单分离",
"splitTip": "开启时,侧边栏显示顶栏对应菜单的子菜单"
}, },
"breadcrumb": { navigationMenu: {
"title": "面包屑导航", title: "导航菜单",
"enable": "开启面包屑导航", style: "导航菜单风格",
"icon": "显示面包屑图标", accordion: "侧边导航菜单手风琴模式",
"home": "显示首页按钮", split: "导航菜单分离",
"style": "面包屑风格", splitTip: "开启时,侧边栏显示顶栏对应菜单的子菜单",
"hideOnlyOne": "仅有一个时隐藏",
"background": "背景"
}, },
"animation": { breadcrumb: {
"title": "动画", title: "面包屑导航",
"loading": "页面切换 Loading", enable: "开启面包屑导航",
"transition": "页面切换动画", icon: "显示面包屑图标",
"progress": "页面切换进度条" home: "显示首页按钮",
style: "面包屑风格",
hideOnlyOne: "仅有一个时隐藏",
background: "背景",
}, },
"theme": { animation: {
"title": "主题", title: "动画",
"radius": "圆角", loading: "页面切换 Loading",
"light": "浅色", transition: "页面切换动画",
"dark": "深色", progress: "页面切换进度条",
"darkSidebar": "深色侧边栏",
"darkHeader": "深色顶栏",
"weakMode": "色弱模式",
"grayMode": "灰色模式",
"builtin": {
"title": "内置主题",
"default": "默认",
"violet": "紫罗兰",
"pink": "樱花粉",
"rose": "玫瑰红",
"skyBlue": "天蓝色",
"deepBlue": "深蓝色",
"green": "浅绿色",
"deepGreen": "深绿色",
"orange": "橙黄色",
"yellow": "柠檬黄",
"zinc": "锌色灰",
"neutral": "中性色",
"slate": "石板灰",
"gray": "中灰色",
"custom": "自定义"
}
}, },
"header": { theme: {
"title": "顶栏", title: "主题",
"modeStatic": "静止", radius: "圆角",
"modeFixed": "固定", light: "浅色",
"modeAuto": "自动隐藏和显示", dark: "深色",
"modeAutoScroll": "滚动隐藏和显示", darkSidebar: "深色侧边栏",
"visible": "显示顶栏", darkHeader: "深色顶栏",
"menuAlign": "菜单位置", weakMode: "色弱模式",
"menuAlignStart": "左侧", grayMode: "灰色模式",
"menuAlignEnd": "右侧", builtin: {
"menuAlignCenter": "居中" title: "内置主题",
default: "默认",
violet: "紫罗兰",
pink: "樱花粉",
rose: "玫瑰红",
skyBlue: "天蓝色",
deepBlue: "深蓝色",
green: "浅绿色",
deepGreen: "深绿色",
orange: "橙黄色",
yellow: "柠檬黄",
zinc: "锌色灰",
neutral: "中性色",
slate: "石板灰",
gray: "中灰色",
custom: "自定义",
}, },
"footer": {
"title": "底栏",
"visible": "显示底栏",
"fixed": "固定在底部"
}, },
"copyright": { header: {
"title": "版权", title: "顶栏",
"enable": "启用版权", modeStatic: "静止",
"companyName": "公司名", modeFixed: "固定",
"companySiteLink": "公司主页", modeAuto: "自动隐藏和显示",
"date": "日期", modeAutoScroll: "滚动隐藏和显示",
"icp": "ICP 备案号", visible: "显示顶栏",
"icpLink": "ICP 网站链接" menuAlign: "菜单位置",
menuAlignStart: "左侧",
menuAlignEnd: "右侧",
menuAlignCenter: "居中",
}, },
"shortcutKeys": { footer: {
"title": "快捷键", title: "底栏",
"global": "全局", visible: "显示底栏",
"search": "全局搜索", fixed: "固定在底部",
"logout": "退出登录",
"preferences": "偏好设置"
}, },
"widget": { copyright: {
"title": "小部件", title: "版权",
"globalSearch": "启用全局搜索", enable: "启用版权",
"fullscreen": "启用全屏", companyName: "公司名",
"themeToggle": "启用主题切换", companySiteLink: "公司主页",
"languageToggle": "启用语言切换", date: "日期",
"notification": "启用通知", icp: "ICP 备案号",
"sidebarToggle": "启用侧边栏切换", icpLink: "ICP 网站链接",
"lockScreen": "启用锁屏", },
"refresh": "启用刷新" shortcutKeys: {
} title: "快捷键",
} global: "全局",
search: "全局搜索",
logout: "退出登录",
preferences: "偏好设置",
},
widget: {
title: "小部件",
globalSearch: "启用全局搜索",
fullscreen: "启用全屏",
themeToggle: "启用主题切换",
languageToggle: "启用语言切换",
notification: "启用通知",
sidebarToggle: "启用侧边栏切换",
lockScreen: "启用锁屏",
refresh: "启用刷新",
},
};

View File

@ -1,3 +1,3 @@
export default { export default {
title: '使用教程', title: "使用教程",
} };

View File

@ -1,104 +1,104 @@
export default { export default {
"formRules": { formRules: {
"required": "请输入{0}", required: "请输入{0}",
"selectRequired": "请选择{0}", selectRequired: "请选择{0}",
"minLength": "{0}至少{1}个字符", minLength: "{0}至少{1}个字符",
"maxLength": "{0}最多{1}个字符", maxLength: "{0}最多{1}个字符",
"length": "{0}长度必须为{1}个字符", length: "{0}长度必须为{1}个字符",
"alreadyExists": "{0} `{1}` 已存在", alreadyExists: "{0} `{1}` 已存在",
"startWith": "{0}必须以 {1} 开头", startWith: "{0}必须以 {1} 开头",
"invalidURL": "请输入有效的链接" invalidURL: "请输入有效的链接",
}, },
"actionTitle": { actionTitle: {
"edit": "修改{0}", edit: "修改{0}",
"create": "新增{0}", create: "新增{0}",
"delete": "删除{0}", delete: "删除{0}",
"view": "查看{0}" view: "查看{0}",
}, },
"actionMessage": { actionMessage: {
"deleteConfirm": "确定删除 {0} 吗?", deleteConfirm: "确定删除 {0} 吗?",
"deleting": "正在删除 {0} ...", deleting: "正在删除 {0} ...",
"deleteSuccess": "{0} 删除成功", deleteSuccess: "{0} 删除成功",
"operationSuccess": "操作成功", operationSuccess: "操作成功",
"operationFailed": "操作失败" operationFailed: "操作失败",
}, },
"placeholder": { placeholder: {
"input": "请输入", input: "请输入",
"select": "请选择" select: "请选择",
}, },
"captcha": { captcha: {
"title": "请完成安全验证", title: "请完成安全验证",
"sliderSuccessText": "验证通过", sliderSuccessText: "验证通过",
"sliderDefaultText": "请按住滑块拖动", sliderDefaultText: "请按住滑块拖动",
"sliderRotateDefaultTip": "点击图片可刷新", sliderRotateDefaultTip: "点击图片可刷新",
"sliderRotateFailTip": "验证失败", sliderRotateFailTip: "验证失败",
"sliderRotateSuccessTip": "验证成功,耗时{0}秒", sliderRotateSuccessTip: "验证成功,耗时{0}秒",
"alt": "支持img标签src属性值", alt: "支持img标签src属性值",
"refreshAriaLabel": "刷新验证码", refreshAriaLabel: "刷新验证码",
"confirmAriaLabel": "确认选择", confirmAriaLabel: "确认选择",
"confirm": "确认", confirm: "确认",
"pointAriaLabel": "点击点", pointAriaLabel: "点击点",
"clickInOrder": "请依次点击" clickInOrder: "请依次点击",
}, },
"iconPicker": { iconPicker: {
"placeholder": "选择一个图标", placeholder: "选择一个图标",
"search": "搜索图标..." search: "搜索图标...",
}, },
"jsonViewer": { jsonViewer: {
"copy": "复制", copy: "复制",
"copied": "已复制" copied: "已复制",
}, },
"fallback": { fallback: {
"pageNotFound": "哎呀!未找到页面", pageNotFound: "哎呀!未找到页面",
"pageNotFoundDesc": "抱歉,我们无法找到您要找的页面。", pageNotFoundDesc: "抱歉,我们无法找到您要找的页面。",
"forbidden": "哎呀!访问被拒绝", forbidden: "哎呀!访问被拒绝",
"forbiddenDesc": "抱歉,您没有权限访问此页面。", forbiddenDesc: "抱歉,您没有权限访问此页面。",
"internalError": "哎呀!出错了", internalError: "哎呀!出错了",
"internalErrorDesc": "抱歉,服务器遇到错误。", internalErrorDesc: "抱歉,服务器遇到错误。",
"offline": "离线页面", offline: "离线页面",
"offlineError": "哎呀!网络错误", offlineError: "哎呀!网络错误",
"offlineErrorDesc": "抱歉,无法连接到互联网,请检查您的网络连接并重试。", offlineErrorDesc: "抱歉,无法连接到互联网,请检查您的网络连接并重试。",
"comingSoon": "即将推出", comingSoon: "即将推出",
"http": { http: {
"requestTimeout": "请求超时,请稍后再试。", requestTimeout: "请求超时,请稍后再试。",
"networkError": "网络异常,请检查您的网络连接后重试。", networkError: "网络异常,请检查您的网络连接后重试。",
"badRequest": "请求错误。请检查您的输入并重试。", badRequest: "请求错误。请检查您的输入并重试。",
"unauthorized": "登录认证过期,请重新登录后继续。", unauthorized: "登录认证过期,请重新登录后继续。",
"forbidden": "禁止访问, 您没有权限访问此资源。", forbidden: "禁止访问, 您没有权限访问此资源。",
"notFound": "未找到, 请求的资源不存在。", notFound: "未找到, 请求的资源不存在。",
"internalServerError": "内部服务器错误,请稍后再试。" internalServerError: "内部服务器错误,请稍后再试。",
}
}, },
"widgets": {
"document": "文档",
"qa": "问题 & 帮助",
"setting": "设置",
"logoutTip": "是否退出登录?",
"viewAll": "查看所有消息",
"notifications": "通知",
"markAllAsRead": "全部标记为已读",
"clearNotifications": "清空",
"checkUpdatesTitle": "新版本可用",
"checkUpdatesDescription": "点击刷新以获取最新版本",
"search": {
"title": "搜索",
"searchNavigate": "搜索导航菜单",
"select": "选择",
"navigate": "导航",
"close": "关闭",
"noResults": "未找到搜索结果",
"noRecent": "没有搜索历史",
"recent": "搜索历史"
}, },
"lockScreen": { widgets: {
"title": "锁定屏幕", document: "文档",
"screenButton": "锁定", qa: "问题 & 帮助",
"password": "密码", setting: "设置",
"placeholder": "请输入锁屏密码", logoutTip: "是否退出登录?",
"unlock": "点击解锁", viewAll: "查看所有消息",
"errorPasswordTip": "密码错误,请重新输入", notifications: "通知",
"backToLogin": "返回登录", markAllAsRead: "全部标记为已读",
"entry": "进入系统" clearNotifications: "清空",
} checkUpdatesTitle: "新版本可用",
} checkUpdatesDescription: "点击刷新以获取最新版本",
} search: {
title: "搜索",
searchNavigate: "搜索导航菜单",
select: "选择",
navigate: "导航",
close: "关闭",
noResults: "未找到搜索结果",
noRecent: "没有搜索历史",
recent: "搜索历史",
},
lockScreen: {
title: "锁定屏幕",
screenButton: "锁定",
password: "密码",
placeholder: "请输入锁屏密码",
unlock: "点击解锁",
errorPasswordTip: "密码错误,请重新输入",
backToLogin: "返回登录",
entry: "进入系统",
},
},
};

View File

@ -27,11 +27,11 @@ export default {
successContent: "您已成功激活{vipLabel},有效期至:{expireDate}", successContent: "您已成功激活{vipLabel},有效期至:{expireDate}",
bindAccountTitle: "是否绑定袖手账号", bindAccountTitle: "是否绑定袖手账号",
bindAccountContent: "绑定账号后可以避免License丢失强烈建议绑定", bindAccountContent: "绑定账号后可以避免License丢失强烈建议绑定",
congratulations_vip_trial: '恭喜,您已获得专业版{duration}天试用', congratulations_vip_trial: "恭喜,您已获得专业版{duration}天试用",
trial_modal_title: '7天专业版试用获取', trial_modal_title: "7天专业版试用获取",
trial_modal_ok_text: '立即获取', trial_modal_ok_text: "立即获取",
trial_modal_thanks: '感谢您对开源项目的支持', trial_modal_thanks: "感谢您对开源项目的支持",
trial_modal_click_confirm: '点击确认即可获取7天专业版试用', trial_modal_click_confirm: "点击确认即可获取7天专业版试用",
get_7_day_pro_trial: "7天专业版试用获取", get_7_day_pro_trial: "7天专业版试用获取",
star_now: "立即去Star", star_now: "立即去Star",
please_help_star: "可以先请您帮忙点个star吗感谢感谢", please_help_star: "可以先请您帮忙点个star吗感谢感谢",
@ -56,7 +56,7 @@ export default {
plugins_fully_open: "插件全开放,群辉等更多插件", plugins_fully_open: "插件全开放,群辉等更多插件",
click_to_get_7_day_trial: "点击获取7天试用", click_to_get_7_day_trial: "点击获取7天试用",
years: "年", years: "年",
afdian_support_vip: '爱发电赞助“VIP会员”后获取一年期专业版激活码开源需要您的支持', afdian_support_vip: "爱发电赞助“VIP会员”后获取一年期专业版激活码开源需要您的支持",
get_after_support: "爱发电赞助后获取", get_after_support: "爱发电赞助后获取",
business_edition: "商业版", business_edition: "商业版",
@ -69,7 +69,7 @@ export default {
support_user_payment: "支持用户支付", support_user_payment: "支持用户支付",
contact_author_for_trial: "请联系作者获取试用", contact_author_for_trial: "请联系作者获取试用",
activate: "激活", activate: "激活",
get_pro_code_after_support: '爱发电赞助“VIP会员”后获取一年期专业版激活码', get_pro_code_after_support: "爱发电赞助“VIP会员”后获取一年期专业版激活码",
business_contact_author: "商业版请直接联系作者", business_contact_author: "商业版请直接联系作者",
year: "年", year: "年",
freee: "免费", freee: "免费",
@ -83,4 +83,4 @@ export default {
activation_code_one_use: "激活码使用过一次之后,不可再次使用,如果要更换站点,请", activation_code_one_use: "激活码使用过一次之后,不可再次使用,如果要更换站点,请",
bind_account: "绑定账号", bind_account: "绑定账号",
transfer_vip: ',然后"转移VIP"即可', transfer_vip: ',然后"转移VIP"即可',
} };

View File

@ -12,7 +12,7 @@ async function generateAccess(options: GenerateMenuAndRoutesOptions) {
const layoutMap: ComponentRecordType = { const layoutMap: ComponentRecordType = {
BasicLayout, BasicLayout,
IFrameView IFrameView,
} as any; } as any;
return await generateAccessible(preferences.app.accessMode, { return await generateAccessible(preferences.app.accessMode, {
@ -28,7 +28,7 @@ async function generateAccess(options: GenerateMenuAndRoutesOptions) {
forbiddenComponent, forbiddenComponent,
// 如果 route.meta.menuVisibleWithForbidden = true // 如果 route.meta.menuVisibleWithForbidden = true
layoutMap, layoutMap,
pageMap pageMap,
}); });
} }

View File

@ -1,7 +1,7 @@
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 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*", {
@ -12,7 +12,7 @@ const dynamicRouteFiles = import.meta.glob("./modules/**/*.ts*", {
const dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles); const dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles);
export const frameworkResource = [ export const frameworkResource = [
{ {
title: i18n.global.t("certd.framework.title"), title: "certd.framework.title",
name: "root", name: "root",
path: "/", path: "/",
redirect: "/index", redirect: "/index",
@ -23,7 +23,7 @@ export const frameworkResource = [
}, },
children: [ children: [
{ {
title: i18n.global.t("certd.framework.home"), title: "certd.framework.home",
name: "index", name: "index",
path: "/index", path: "/index",
component: "/framework/home/index.vue", component: "/framework/home/index.vue",

View File

@ -1,36 +1,35 @@
import i18n from '/@/locales/i18n'; import i18n from "/@/locales/i18n";
export const headerResource = [ export const headerResource = [
{ {
title: i18n.global.t("certd.helpDoc"), title: "certd.helpDoc",
path: "https://certd.docmirror.cn", path: "https://certd.docmirror.cn",
meta: { meta: {
icon: "ion:document-text-outline" icon: "ion:document-text-outline",
} },
}, },
{ {
title: i18n.global.t("certd.source"), title: "certd.source",
name: "source", name: "source",
key: "source", key: "source",
meta: { meta: {
icon: "ion:git-branch-outline" icon: "ion:git-branch-outline",
}, },
children: [ children: [
{ {
title: i18n.global.t("certd.github"), title: "certd.github",
path: "https://github.com/certd/certd", path: "https://github.com/certd/certd",
meta: { meta: {
icon: "ion:logo-github" icon: "ion:logo-github",
} },
}, },
{ {
title: i18n.global.t("certd.gitee"), title: "certd.gitee",
path: "https://gitee.com/certd/certd", path: "https://gitee.com/certd/certd",
meta: { meta: {
icon: "ion:logo-octocat" icon: "ion:logo-octocat",
} },
} },
] ],
} },
]; ];

View File

@ -2,18 +2,18 @@ import { IFrameView } from "/@/vben/layouts";
import { useSettingStore } from "/@/store/settings"; import { useSettingStore } from "/@/store/settings";
import { computed } from "vue"; import { computed } from "vue";
import TutorialButton from "/@/components/tutorial/index.vue"; import TutorialButton from "/@/components/tutorial/index.vue";
import i18n from '/@/locales/i18n'; import i18n from "/@/locales/i18n";
export const aboutResource = [ export const aboutResource = [
{ {
title: i18n.global.t("certd.dashboard.helpDoc"), title: "certd.dashboard.helpDoc",
name: "document", name: "document",
path: "/about/doc", path: "/about/doc",
component: IFrameView, component: IFrameView,
meta: { meta: {
icon: "lucide:book-open-text", icon: "lucide:book-open-text",
link: "https://certd.docmirror.cn", link: "https://certd.docmirror.cn",
title: i18n.global.t("certd.dashboard.helpDoc"), title: "certd.dashboard.helpDoc",
order: 9999, order: 9999,
show: () => { show: () => {
const settingStore = useSettingStore(); const settingStore = useSettingStore();

View File

@ -1,10 +1,10 @@
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'; import i18n from "/@/locales/i18n";
export const certdResources = [ export const certdResources = [
{ {
title: i18n.global.t("certd.title"), title: "certd.title",
name: "CertdRoot", name: "CertdRoot",
path: "/certd", path: "/certd",
redirect: "/certd/pipeline", redirect: "/certd/pipeline",
@ -15,7 +15,7 @@ export const certdResources = [
}, },
children: [ children: [
{ {
title: i18n.global.t("certd.pipeline"), title: "certd.pipeline",
name: "PipelineManager", name: "PipelineManager",
path: "/certd/pipeline", path: "/certd/pipeline",
component: "/certd/pipeline/index.vue", component: "/certd/pipeline/index.vue",
@ -25,7 +25,7 @@ export const certdResources = [
}, },
}, },
{ {
title: i18n.global.t("certd.pipelineEdit"), title: "certd.pipelineEdit",
name: "PipelineEdit", name: "PipelineEdit",
path: "/certd/pipeline/detail", path: "/certd/pipeline/detail",
component: "/certd/pipeline/detail.vue", component: "/certd/pipeline/detail.vue",
@ -34,7 +34,7 @@ export const certdResources = [
}, },
}, },
{ {
title: i18n.global.t("certd.history"), title: "certd.history",
name: "PipelineHistory", name: "PipelineHistory",
path: "/certd/history", path: "/certd/history",
component: "/certd/history/index.vue", component: "/certd/history/index.vue",
@ -44,7 +44,7 @@ export const certdResources = [
}, },
}, },
{ {
title: i18n.global.t("certd.certStore"), title: "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",
@ -56,7 +56,7 @@ export const certdResources = [
}, },
}, },
{ {
title: i18n.global.t("certd.siteMonitor"), title: "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",
@ -67,7 +67,7 @@ export const certdResources = [
}, },
}, },
{ {
title: i18n.global.t("certd.settings"), title: "certd.settings",
name: "MineSetting", name: "MineSetting",
path: "/certd/setting", path: "/certd/setting",
redirect: "/certd/access", redirect: "/certd/access",
@ -78,7 +78,7 @@ export const certdResources = [
}, },
children: [ children: [
{ {
title: i18n.global.t("certd.accessManager"), title: "certd.accessManager",
name: "AccessManager", name: "AccessManager",
path: "/certd/access", path: "/certd/access",
component: "/certd/access/index.vue", component: "/certd/access/index.vue",
@ -89,7 +89,7 @@ export const certdResources = [
}, },
}, },
{ {
title: i18n.global.t("certd.cnameRecord"), title: "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",
@ -100,7 +100,7 @@ export const certdResources = [
}, },
}, },
{ {
title: i18n.global.t("certd.subDomain"), title: "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",
@ -111,7 +111,7 @@ export const certdResources = [
}, },
}, },
{ {
title: i18n.global.t("certd.pipelineGroup"), title: "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",
@ -122,7 +122,7 @@ export const certdResources = [
}, },
}, },
{ {
title: i18n.global.t("certd.openKey"), title: "certd.openKey",
name: "OpenKey", name: "OpenKey",
path: "/certd/open/openkey", path: "/certd/open/openkey",
component: "/certd/open/openkey/index.vue", component: "/certd/open/openkey/index.vue",
@ -133,7 +133,7 @@ export const certdResources = [
}, },
}, },
{ {
title: i18n.global.t("certd.notification"), title: "certd.notification",
name: "NotificationManager", name: "NotificationManager",
path: "/certd/notification", path: "/certd/notification",
component: "/certd/notification/index.vue", component: "/certd/notification/index.vue",
@ -144,7 +144,7 @@ export const certdResources = [
}, },
}, },
{ {
title: i18n.global.t("certd.siteMonitorSetting"), title: "certd.siteMonitorSetting",
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",
@ -155,7 +155,7 @@ export const certdResources = [
}, },
}, },
{ {
title: i18n.global.t("certd.userSecurity"), title: "certd.userSecurity",
name: "UserSecurity", name: "UserSecurity",
path: "/certd/mine/security", path: "/certd/mine/security",
component: "/certd/mine/security/index.vue", component: "/certd/mine/security/index.vue",
@ -166,7 +166,7 @@ export const certdResources = [
}, },
}, },
{ {
title: i18n.global.t("certd.userProfile"), title: "certd.userProfile",
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",
@ -179,7 +179,7 @@ export const certdResources = [
], ],
}, },
{ {
title: i18n.global.t("certd.suite"), title: "certd.suite",
name: "SuiteProduct", name: "SuiteProduct",
path: "/certd/suite", path: "/certd/suite",
redirect: "/certd/suite/mine", redirect: "/certd/suite/mine",
@ -193,7 +193,7 @@ export const certdResources = [
}, },
children: [ children: [
{ {
title: i18n.global.t("certd.mySuite"), title: "certd.mySuite",
name: "MySuite", name: "MySuite",
path: "/certd/suite/mine", path: "/certd/suite/mine",
component: "/certd/suite/mine/index.vue", component: "/certd/suite/mine/index.vue",
@ -207,7 +207,7 @@ export const certdResources = [
}, },
}, },
{ {
title: i18n.global.t("certd.suiteBuy"), title: "certd.suiteBuy",
name: "SuiteProductBuy", name: "SuiteProductBuy",
path: "/certd/suite/buy", path: "/certd/suite/buy",
component: "/certd/suite/buy.vue", component: "/certd/suite/buy.vue",
@ -221,7 +221,7 @@ export const certdResources = [
}, },
}, },
{ {
title: i18n.global.t("certd.myTrade"), title: "certd.myTrade",
name: "MyTrade", name: "MyTrade",
path: "/certd/trade", path: "/certd/trade",
component: "/certd/trade/index.vue", component: "/certd/trade/index.vue",
@ -236,7 +236,7 @@ export const certdResources = [
}, },
}, },
{ {
title: i18n.global.t("certd.paymentReturn"), title: "certd.paymentReturn",
name: "PaymentReturn", name: "PaymentReturn",
path: "/certd/payment/return/:type", path: "/certd/payment/return/:type",
component: "/certd/payment/return.vue", component: "/certd/payment/return.vue",
@ -252,5 +252,4 @@ export const certdResources = [
}, },
]; ];
export default certdResources; export default certdResources;

View File

@ -1,11 +1,11 @@
import LayoutPass from "/@/layout/layout-pass.vue"; import LayoutPass from "/@/layout/layout-pass.vue";
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'; import i18n from "/@/locales/i18n";
export const sysResources = [ export const sysResources = [
{ {
title: i18n.global.t('certd.sysResources.sysRoot'), title: "certd.sysResources.sysRoot",
name: "SysRoot", name: "SysRoot",
path: "/sys", path: "/sys",
redirect: "/sys/settings", redirect: "/sys/settings",
@ -16,7 +16,7 @@ export const sysResources = [
}, },
children: [ children: [
{ {
title: i18n.global.t('certd.sysResources.sysConsole'), title: "certd.sysResources.sysConsole",
name: "SysConsole", name: "SysConsole",
path: "/sys/console", path: "/sys/console",
component: "/sys/console/index.vue", component: "/sys/console/index.vue",
@ -31,7 +31,7 @@ export const sysResources = [
}, },
{ {
title: i18n.global.t('certd.sysResources.sysSettings'), title: "certd.sysResources.sysSettings",
name: "SysSettings", name: "SysSettings",
path: "/sys/settings", path: "/sys/settings",
component: "/sys/settings/index.vue", component: "/sys/settings/index.vue",
@ -41,7 +41,7 @@ export const sysResources = [
}, },
}, },
{ {
title: i18n.global.t('certd.sysResources.cnameSetting'), title: "certd.sysResources.cnameSetting",
name: "CnameSetting", name: "CnameSetting",
path: "/sys/cname/provider", path: "/sys/cname/provider",
component: "/sys/cname/provider/index.vue", component: "/sys/cname/provider/index.vue",
@ -52,7 +52,7 @@ export const sysResources = [
}, },
}, },
{ {
title: i18n.global.t('certd.sysResources.emailSetting'), title: "certd.sysResources.emailSetting",
name: "EmailSetting", name: "EmailSetting",
path: "/sys/settings/email", path: "/sys/settings/email",
component: "/sys/settings/email/index.vue", component: "/sys/settings/email/index.vue",
@ -63,7 +63,7 @@ export const sysResources = [
}, },
}, },
{ {
title: i18n.global.t('certd.sysResources.siteSetting'), title: "certd.sysResources.siteSetting",
name: "SiteSetting", name: "SiteSetting",
path: "/sys/site", path: "/sys/site",
component: "/sys/site/index.vue", component: "/sys/site/index.vue",
@ -77,7 +77,7 @@ export const sysResources = [
}, },
}, },
{ {
title: i18n.global.t('certd.sysResources.headerMenus'), title: "certd.sysResources.headerMenus",
name: "HeaderMenus", name: "HeaderMenus",
path: "/sys/settings/header-menus", path: "/sys/settings/header-menus",
component: "/sys/settings/header-menus/index.vue", component: "/sys/settings/header-menus/index.vue",
@ -92,7 +92,7 @@ export const sysResources = [
}, },
}, },
{ {
title: i18n.global.t('certd.sysResources.sysAccess'), title: "certd.sysResources.sysAccess",
name: "SysAccess", name: "SysAccess",
path: "/sys/access", path: "/sys/access",
component: "/sys/access/index.vue", component: "/sys/access/index.vue",
@ -107,7 +107,7 @@ export const sysResources = [
}, },
}, },
{ {
title: i18n.global.t('certd.sysResources.sysPlugin'), title: "certd.sysResources.sysPlugin",
name: "SysPlugin", name: "SysPlugin",
path: "/sys/plugin", path: "/sys/plugin",
component: "/sys/plugin/index.vue", component: "/sys/plugin/index.vue",
@ -118,7 +118,7 @@ export const sysResources = [
}, },
}, },
{ {
title: i18n.global.t('certd.sysResources.sysPluginEdit'), title: "certd.sysResources.sysPluginEdit",
name: "SysPluginEdit", name: "SysPluginEdit",
path: "/sys/plugin/edit", path: "/sys/plugin/edit",
component: "/sys/plugin/edit.vue", component: "/sys/plugin/edit.vue",
@ -130,7 +130,7 @@ export const sysResources = [
}, },
}, },
{ {
title: i18n.global.t('certd.sysResources.sysPluginConfig'), title: "certd.sysResources.sysPluginConfig",
name: "SysPluginConfig", name: "SysPluginConfig",
path: "/sys/plugin/config", path: "/sys/plugin/config",
component: "/sys/plugin/config.vue", component: "/sys/plugin/config.vue",
@ -144,7 +144,7 @@ export const sysResources = [
}, },
}, },
{ {
title: i18n.global.t('certd.sysResources.accountBind'), title: "certd.sysResources.accountBind",
name: "AccountBind", name: "AccountBind",
path: "/sys/account", path: "/sys/account",
component: "/sys/account/index.vue", component: "/sys/account/index.vue",
@ -155,7 +155,7 @@ export const sysResources = [
}, },
}, },
{ {
title: i18n.global.t('certd.sysResources.permissionManager'), title: "certd.sysResources.permissionManager",
name: "PermissionManager", name: "PermissionManager",
path: "/sys/authority/permission", path: "/sys/authority/permission",
component: "/sys/authority/permission/index.vue", component: "/sys/authority/permission/index.vue",
@ -166,7 +166,7 @@ export const sysResources = [
}, },
}, },
{ {
title: i18n.global.t('certd.sysResources.roleManager'), title: "certd.sysResources.roleManager",
name: "RoleManager", name: "RoleManager",
path: "/sys/authority/role", path: "/sys/authority/role",
component: "/sys/authority/role/index.vue", component: "/sys/authority/role/index.vue",
@ -177,7 +177,7 @@ export const sysResources = [
}, },
}, },
{ {
title: i18n.global.t('certd.sysResources.userManager'), title: "certd.sysResources.userManager",
name: "UserManager", name: "UserManager",
path: "/sys/authority/user", path: "/sys/authority/user",
component: "/sys/authority/user/index.vue", component: "/sys/authority/user/index.vue",
@ -189,7 +189,7 @@ export const sysResources = [
}, },
{ {
title: i18n.global.t('certd.sysResources.suiteManager'), title: "certd.sysResources.suiteManager",
name: "SuiteManager", name: "SuiteManager",
path: "/sys/suite", path: "/sys/suite",
redirect: "/sys/suite/setting", redirect: "/sys/suite/setting",
@ -204,7 +204,7 @@ export const sysResources = [
}, },
children: [ children: [
{ {
title: i18n.global.t('certd.sysResources.suiteSetting'), title: "certd.sysResources.suiteSetting",
name: "SuiteSetting", name: "SuiteSetting",
path: "/sys/suite/setting", path: "/sys/suite/setting",
component: "/sys/suite/setting/index.vue", component: "/sys/suite/setting/index.vue",
@ -218,7 +218,7 @@ export const sysResources = [
}, },
}, },
{ {
title: i18n.global.t('certd.sysResources.orderManager'), title: "certd.sysResources.orderManager",
name: "OrderManager", name: "OrderManager",
path: "/sys/suite/trade", path: "/sys/suite/trade",
component: "/sys/suite/trade/index.vue", component: "/sys/suite/trade/index.vue",
@ -233,7 +233,7 @@ export const sysResources = [
}, },
}, },
{ {
title: i18n.global.t('certd.sysResources.userSuites'), title: "certd.sysResources.userSuites",
name: "UserSuites", name: "UserSuites",
path: "/sys/suite/user-suite", path: "/sys/suite/user-suite",
component: "/sys/suite/user-suite/index.vue", component: "/sys/suite/user-suite/index.vue",

View File

@ -10,21 +10,21 @@ export const outsideResource = [
children: [ children: [
{ {
meta: { meta: {
title: "登录" title: "登录",
}, },
name: "login", name: "login",
path: "/login", path: "/login",
component: "/framework/login/index.vue" component: "/framework/login/index.vue",
}, },
{ {
meta: { meta: {
title: "注册" title: "注册",
}, },
name: "register", name: "register",
path: "/register", path: "/register",
component: "/framework/register/index.vue" component: "/framework/register/index.vue",
}
]
}, },
...errorPage ],
},
...errorPage,
]; ];

View File

@ -1,7 +1,7 @@
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import * as api from "./api.plugin"; import * as api from "./api.plugin";
import { DynamicType, FormItemProps } from "@fast-crud/fast-crud"; import { DynamicType, FormItemProps } from "@fast-crud/fast-crud";
import { i18n } from "/src/locales/i18n";
interface PluginState { interface PluginState {
group?: PluginGroups; group?: PluginGroups;
} }
@ -31,8 +31,10 @@ export type PluginDefine = {
export class PluginGroups { export class PluginGroups {
groups!: { [key: string]: PluginGroup }; groups!: { [key: string]: PluginGroup };
map!: { [key: string]: PluginDefine }; map!: { [key: string]: PluginDefine };
t: any;
constructor(groups: { [key: string]: PluginGroup }) { constructor(groups: { [key: string]: PluginGroup }) {
this.groups = groups; this.groups = groups;
this.t = i18n.global.t;
this.initGroup(groups); this.initGroup(groups);
this.initMap(); this.initMap();
} }
@ -40,7 +42,7 @@ export class PluginGroups {
private initGroup(groups: { [p: string]: PluginGroup }) { private initGroup(groups: { [p: string]: PluginGroup }) {
const all: PluginGroup = { const all: PluginGroup = {
key: "all", key: "all",
title: t('certd.all'), title: this.t("certd.all"),
order: 0, order: 0,
plugins: [], plugins: [],
icon: "material-symbols:border-all-rounded", icon: "material-symbols:border-all-rounded",

View File

@ -1,15 +1,15 @@
<script setup lang="ts"> <script setup lang="ts">
import type { VbenFormSchema } from '/@/vben/form-ui'; 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 '/@/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";
import Title from './auth-title.vue'; import Title from "./auth-title.vue";
interface Props { interface Props {
formSchema: VbenFormSchema[]; formSchema: VbenFormSchema[];
@ -36,15 +36,15 @@ interface Props {
} }
defineOptions({ defineOptions({
name: 'ForgetPassword', name: "ForgetPassword",
}); });
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
loading: false, loading: false,
loginPath: '/auth/login', loginPath: "/auth/login",
submitButtonText: '', submitButtonText: "",
subTitle: '', subTitle: "",
title: '', title: "",
}); });
const emit = defineEmits<{ const emit = defineEmits<{
@ -59,7 +59,7 @@ const [Form, formApi] = useVbenForm(
}, },
schema: computed(() => props.formSchema), schema: computed(() => props.formSchema),
showDefaultActions: false, showDefaultActions: false,
}), })
); );
const router = useRouter(); const router = useRouter();
@ -68,7 +68,7 @@ async function handleSubmit() {
const { valid } = await formApi.validate(); const { valid } = await formApi.validate();
const values = await formApi.getValues(); const values = await formApi.getValues();
if (valid) { if (valid) {
emit('submit', values); emit("submit", values);
} }
} }
@ -84,12 +84,10 @@ defineExpose({
<template> <template>
<div> <div>
<Title> <Title>
<slot name="title"> <slot name="title"> {{ title || $t("authentication.forgetPassword") }} 🤦🏻 </slot>
{{ title || $t('authentication.forgetPassword') }} 🤦🏻
</slot>
<template #desc> <template #desc>
<slot name="subTitle"> <slot name="subTitle">
{{ subTitle || $t('authentication.forgetPasswordSubtitle') }} {{ subTitle || $t("authentication.forgetPasswordSubtitle") }}
</slot> </slot>
</template> </template>
</Title> </Title>
@ -105,11 +103,11 @@ defineExpose({
@click="handleSubmit" @click="handleSubmit"
> >
<slot name="submitButtonText"> <slot name="submitButtonText">
{{ submitButtonText || $t('authentication.sendResetLink') }} {{ submitButtonText || $t("authentication.sendResetLink") }}
</slot> </slot>
</VbenButton> </VbenButton>
<VbenButton class="mt-4 w-full" variant="outline" @click="goToLogin()"> <VbenButton class="mt-4 w-full" variant="outline" @click="goToLogin()">
{{ $t('common.back') }} {{ $t("common.back") }}
</VbenButton> </VbenButton>
</div> </div>
</div> </div>

View File

@ -1,11 +1,11 @@
export { default as Breadcrumb } from './breadcrumb.vue'; export { default as Breadcrumb } from "./breadcrumb.vue";
export * from './check-updates'; export * from "./check-updates";
export { default as AuthenticationColorToggle } from './color-toggle.vue'; export { default as AuthenticationColorToggle } from "./color-toggle.vue";
export * from './global-search'; export * from "./global-search";
export { default as LanguageToggle } from './language-toggle.vue'; export { default as LanguageToggle } from "./language-toggle.vue";
export { default as AuthenticationLayoutToggle } from './layout-toggle.vue'; export { default as AuthenticationLayoutToggle } from "./layout-toggle.vue";
export * from './lock-screen'; export * from "./lock-screen";
export * from './notification'; export * from "./notification";
export * from './preferences'; export * from "./preferences";
export * from './theme-toggle'; export * from "./theme-toggle";
export * from './user-dropdown'; export * from "./user-dropdown";

View File

@ -12,25 +12,25 @@ import { preferences, updatePreferences, usePreferences } from "/@/vben/preferen
import { VbenDropdownRadioMenu, VbenIconButton } from "/@/vben//shadcn-ui"; import { VbenDropdownRadioMenu, VbenIconButton } from "/@/vben//shadcn-ui";
defineOptions({ defineOptions({
name: "AuthenticationLayoutToggle" name: "AuthenticationLayoutToggle",
}); });
const menus = computed((): VbenDropdownMenuItem[] => [ const menus = computed((): VbenDropdownMenuItem[] => [
{ {
icon: PanelLeft, icon: PanelLeft,
label: $t("authentication.layout.alignLeft"), label: $t("authentication.layout.alignLeft"),
value: "panel-left" value: "panel-left",
}, },
{ {
icon: InspectionPanel, icon: InspectionPanel,
label: $t("authentication.layout.center"), label: $t("authentication.layout.center"),
value: "panel-center" value: "panel-center",
}, },
{ {
icon: PanelRight, icon: PanelRight,
label: $t("authentication.layout.alignRight"), label: $t("authentication.layout.alignRight"),
value: "panel-right" value: "panel-right",
} },
]); ]);
const { authPanelCenter, authPanelLeft, authPanelRight } = usePreferences(); const { authPanelCenter, authPanelLeft, authPanelRight } = usePreferences();
@ -38,8 +38,8 @@ const { authPanelCenter, authPanelLeft, authPanelRight } = usePreferences();
function handleUpdate(value: string) { function handleUpdate(value: string) {
updatePreferences({ updatePreferences({
app: { app: {
authPageLayout: value as AuthPageLayoutType authPageLayout: value as AuthPageLayoutType,
} },
}); });
} }
</script> </script>

View File

@ -1,71 +1,69 @@
<script setup lang="ts"> <script setup lang="ts">
import type { SelectOption } from '/@/vben/types'; import type { SelectOption } from "/@/vben/types";
import { computed } from 'vue'; import { computed } from "vue";
import { $t } from '/@/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";
defineOptions({ defineOptions({
name: 'PreferenceInterfaceControl', name: "PreferenceInterfaceControl",
}); });
const widgetGlobalSearch = defineModel<boolean>('widgetGlobalSearch'); const widgetGlobalSearch = defineModel<boolean>("widgetGlobalSearch");
const widgetFullscreen = defineModel<boolean>('widgetFullscreen'); const widgetFullscreen = defineModel<boolean>("widgetFullscreen");
const widgetLanguageToggle = defineModel<boolean>('widgetLanguageToggle'); const widgetLanguageToggle = defineModel<boolean>("widgetLanguageToggle");
const widgetNotification = defineModel<boolean>('widgetNotification'); const widgetNotification = defineModel<boolean>("widgetNotification");
const widgetThemeToggle = defineModel<boolean>('widgetThemeToggle'); const widgetThemeToggle = defineModel<boolean>("widgetThemeToggle");
const widgetSidebarToggle = defineModel<boolean>('widgetSidebarToggle'); const widgetSidebarToggle = defineModel<boolean>("widgetSidebarToggle");
const widgetLockScreen = defineModel<boolean>('widgetLockScreen'); const widgetLockScreen = defineModel<boolean>("widgetLockScreen");
const appPreferencesButtonPosition = defineModel<string>( const appPreferencesButtonPosition = defineModel<string>("appPreferencesButtonPosition");
'appPreferencesButtonPosition', const widgetRefresh = defineModel<boolean>("widgetRefresh");
);
const widgetRefresh = defineModel<boolean>('widgetRefresh');
const positionItems = computed((): SelectOption[] => [ const positionItems = computed((): SelectOption[] => [
{ {
label: $t('preferences.position.auto'), label: $t("preferences.position.auto"),
value: 'auto', value: "auto",
}, },
{ {
label: $t('preferences.position.header'), label: $t("preferences.position.header"),
value: 'header', value: "header",
}, },
{ {
label: $t('preferences.position.fixed'), label: $t("preferences.position.fixed"),
value: 'fixed', value: "fixed",
}, },
]); ]);
</script> </script>
<template> <template>
<SwitchItem v-model="widgetGlobalSearch"> <SwitchItem v-model="widgetGlobalSearch">
{{ $t('preferences.widget.globalSearch') }} {{ $t("preferences.widget.globalSearch") }}
</SwitchItem> </SwitchItem>
<SwitchItem v-model="widgetThemeToggle"> <SwitchItem v-model="widgetThemeToggle">
{{ $t('preferences.widget.themeToggle') }} {{ $t("preferences.widget.themeToggle") }}
</SwitchItem> </SwitchItem>
<SwitchItem v-model="widgetLanguageToggle"> <SwitchItem v-model="widgetLanguageToggle">
{{ $t('preferences.widget.languageToggle') }} {{ $t("preferences.widget.languageToggle") }}
</SwitchItem> </SwitchItem>
<SwitchItem v-model="widgetFullscreen"> <SwitchItem v-model="widgetFullscreen">
{{ $t('preferences.widget.fullscreen') }} {{ $t("preferences.widget.fullscreen") }}
</SwitchItem> </SwitchItem>
<SwitchItem v-model="widgetNotification"> <SwitchItem v-model="widgetNotification">
{{ $t('preferences.widget.notification') }} {{ $t("preferences.widget.notification") }}
</SwitchItem> </SwitchItem>
<SwitchItem v-model="widgetLockScreen"> <SwitchItem v-model="widgetLockScreen">
{{ $t('preferences.widget.lockScreen') }} {{ $t("preferences.widget.lockScreen") }}
</SwitchItem> </SwitchItem>
<SwitchItem v-model="widgetSidebarToggle"> <SwitchItem v-model="widgetSidebarToggle">
{{ $t('preferences.widget.sidebarToggle') }} {{ $t("preferences.widget.sidebarToggle") }}
</SwitchItem> </SwitchItem>
<SwitchItem v-model="widgetRefresh"> <SwitchItem v-model="widgetRefresh">
{{ $t('preferences.widget.refresh') }} {{ $t("preferences.widget.refresh") }}
</SwitchItem> </SwitchItem>
<SelectItem v-model="appPreferencesButtonPosition" :items="positionItems"> <SelectItem v-model="appPreferencesButtonPosition" :items="positionItems">
{{ $t('preferences.position.title') }} {{ $t("preferences.position.title") }}
</SelectItem> </SelectItem>
</template> </template>

View File

@ -108,7 +108,7 @@ const defaultPreferences: Preferences = {
widget: { widget: {
fullscreen: true, fullscreen: true,
globalSearch: true, globalSearch: true,
languageToggle: false, languageToggle: true,
lockScreen: true, lockScreen: true,
notification: false, notification: false,
refresh: true, refresh: true,

View File

@ -1,35 +1,23 @@
import type { Preferences } from './types'; import type { Preferences } from "./types";
import { preferencesManager } from './preferences'; import { preferencesManager } from "./preferences";
// 偏好设置(带有层级关系) // 偏好设置(带有层级关系)
const preferences: Preferences = const preferences: Preferences = preferencesManager.getPreferences.apply(preferencesManager);
preferencesManager.getPreferences.apply(preferencesManager);
// 更新偏好设置 // 更新偏好设置
const updatePreferences = const updatePreferences = preferencesManager.updatePreferences.bind(preferencesManager);
preferencesManager.updatePreferences.bind(preferencesManager);
// 重置偏好设置 // 重置偏好设置
const resetPreferences = const resetPreferences = preferencesManager.resetPreferences.bind(preferencesManager);
preferencesManager.resetPreferences.bind(preferencesManager);
const clearPreferencesCache = const clearPreferencesCache = preferencesManager.clearCache.bind(preferencesManager);
preferencesManager.clearCache.bind(preferencesManager);
// 初始化偏好设置 // 初始化偏好设置
const initPreferences = const initPreferences = preferencesManager.initPreferences.bind(preferencesManager);
preferencesManager.initPreferences.bind(preferencesManager);
export { export { clearPreferencesCache, initPreferences, preferences, preferencesManager, resetPreferences, updatePreferences };
clearPreferencesCache,
initPreferences,
preferences,
preferencesManager,
resetPreferences,
updatePreferences,
};
export * from './constants'; export * from "./constants";
export type * from './types'; export type * from "./types";
export * from './use-preferences'; export * from "./use-preferences";

View File

@ -1,22 +1,18 @@
import type { DeepPartial } from '/@/vben/typings'; import type { DeepPartial } from "/@/vben/typings";
import type { InitialOptions, Preferences } from './types'; import type { InitialOptions, Preferences } from "./types";
import { markRaw, reactive, readonly, watch } from 'vue'; import { markRaw, reactive, readonly, watch } from "vue";
import { StorageManager } from '/@/vben/shared/cache'; import { StorageManager } from "/@/vben/shared/cache";
import { isMacOs, merge } from '/@/vben/shared/utils'; import { isMacOs, merge } from "/@/vben/shared/utils";
import { import { breakpointsTailwind, useBreakpoints, useDebounceFn } from "@vueuse/core";
breakpointsTailwind,
useBreakpoints,
useDebounceFn,
} from '@vueuse/core';
import { defaultPreferences } from './config'; import { defaultPreferences } from "./config";
import { updateCSSVariables } from './update-css-variables'; import { updateCSSVariables } from "./update-css-variables";
const STORAGE_KEY = 'preferences'; const STORAGE_KEY = "preferences";
const STORAGE_KEY_LOCALE = `${STORAGE_KEY}-locale`; const STORAGE_KEY_LOCALE = `${STORAGE_KEY}-locale`;
const STORAGE_KEY_THEME = `${STORAGE_KEY}-theme`; const STORAGE_KEY_THEME = `${STORAGE_KEY}-theme`;
@ -33,14 +29,11 @@ class PreferenceManager {
this.cache = new StorageManager(); this.cache = new StorageManager();
// 避免频繁的操作缓存 // 避免频繁的操作缓存
this.savePreferences = useDebounceFn( this.savePreferences = useDebounceFn((preference: Preferences) => this._savePreferences(preference), 150);
(preference: Preferences) => this._savePreferences(preference),
150,
);
} }
clearCache() { clearCache() {
[STORAGE_KEY, STORAGE_KEY_LOCALE, STORAGE_KEY_THEME].forEach((key) => { [STORAGE_KEY, STORAGE_KEY_LOCALE, STORAGE_KEY_THEME].forEach(key => {
this.cache?.removeItem(key); this.cache?.removeItem(key);
}); });
} }
@ -73,7 +66,7 @@ class PreferenceManager {
{}, {},
// overrides, // overrides,
this.loadCachedPreferences() || {}, this.loadCachedPreferences() || {},
this.initialPreferences, this.initialPreferences
); );
// 更新偏好设置 // 更新偏好设置
@ -103,7 +96,7 @@ class PreferenceManager {
// 保存重置后的偏好设置 // 保存重置后的偏好设置
this.savePreferences(this.state); this.savePreferences(this.state);
// 从存储中移除偏好设置项 // 从存储中移除偏好设置项
[STORAGE_KEY, STORAGE_KEY_THEME, STORAGE_KEY_LOCALE].forEach((key) => { [STORAGE_KEY, STORAGE_KEY_THEME, STORAGE_KEY_LOCALE].forEach(key => {
this.cache?.removeItem(key); this.cache?.removeItem(key);
}); });
this.updatePreferences(this.state); this.updatePreferences(this.state);
@ -145,17 +138,14 @@ class PreferenceManager {
updateCSSVariables(this.state); updateCSSVariables(this.state);
} }
if ( if (Reflect.has(appUpdates, "colorGrayMode") || Reflect.has(appUpdates, "colorWeakMode")) {
Reflect.has(appUpdates, 'colorGrayMode') ||
Reflect.has(appUpdates, 'colorWeakMode')
) {
this.updateColorMode(this.state); this.updateColorMode(this.state);
} }
} }
private initPlatform() { private initPlatform() {
const dom = document.documentElement; const dom = document.documentElement;
dom.dataset.platform = isMacOs() ? 'macOs' : 'window'; dom.dataset.platform = isMacOs() ? "macOs" : "window";
} }
/** /**
@ -183,23 +173,21 @@ class PreferenceManager {
// 监听断点,判断是否移动端 // 监听断点,判断是否移动端
const breakpoints = useBreakpoints(breakpointsTailwind); const breakpoints = useBreakpoints(breakpointsTailwind);
const isMobile = breakpoints.smaller('md'); const isMobile = breakpoints.smaller("md");
watch( watch(
() => isMobile.value, () => isMobile.value,
(val) => { val => {
this.updatePreferences({ this.updatePreferences({
app: { isMobile: val }, app: { isMobile: val },
}); });
}, },
{ immediate: true }, { immediate: true }
); );
// 监听系统主题偏好设置变化 // 监听系统主题偏好设置变化
window window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", ({ matches: isDark }) => {
.matchMedia('(prefers-color-scheme: dark)')
.addEventListener('change', ({ matches: isDark }) => {
this.updatePreferences({ this.updatePreferences({
theme: { mode: isDark ? 'dark' : 'light' }, theme: { mode: isDark ? "dark" : "light" },
}); });
}); });
} }
@ -212,14 +200,10 @@ class PreferenceManager {
if (preference.app) { if (preference.app) {
const { colorGrayMode, colorWeakMode } = preference.app; const { colorGrayMode, colorWeakMode } = preference.app;
const dom = document.documentElement; const dom = document.documentElement;
const COLOR_WEAK = 'invert-mode'; const COLOR_WEAK = "invert-mode";
const COLOR_GRAY = 'grayscale-mode'; const COLOR_GRAY = "grayscale-mode";
colorWeakMode colorWeakMode ? dom.classList.add(COLOR_WEAK) : dom.classList.remove(COLOR_WEAK);
? dom.classList.add(COLOR_WEAK) colorGrayMode ? dom.classList.add(COLOR_GRAY) : dom.classList.remove(COLOR_GRAY);
: dom.classList.remove(COLOR_WEAK);
colorGrayMode
? dom.classList.add(COLOR_GRAY)
: dom.classList.remove(COLOR_GRAY);
} }
} }
} }

View File

@ -1,9 +1,9 @@
import type { Preferences } from './types'; import type { Preferences } from "./types";
import { generatorColorVariables } from '/@/vben/shared/color'; import { generatorColorVariables } from "/@/vben/shared/color";
import { updateCSSVariables as executeUpdateCSSVariables } from '/@/vben/shared/utils'; import { updateCSSVariables as executeUpdateCSSVariables } from "/@/vben/shared/utils";
import { BUILT_IN_THEME_PRESETS } from './constants'; import { BUILT_IN_THEME_PRESETS } from "./constants";
/** /**
* CSS CSS * CSS CSS
@ -21,13 +21,13 @@ function updateCSSVariables(preferences: Preferences) {
const { builtinType, mode, radius } = theme; const { builtinType, mode, radius } = theme;
// html 设置 dark 类 // html 设置 dark 类
if (Reflect.has(theme, 'mode')) { if (Reflect.has(theme, "mode")) {
const dark = isDarkTheme(mode); const dark = isDarkTheme(mode);
root.classList.toggle('dark', dark); root.classList.toggle("dark", dark);
} }
// html 设置 data-theme=[builtinType] // html 设置 data-theme=[builtinType]
if (Reflect.has(theme, 'builtinType')) { if (Reflect.has(theme, "builtinType")) {
const rootTheme = root.dataset.theme; const rootTheme = root.dataset.theme;
if (rootTheme !== builtinType) { if (rootTheme !== builtinType) {
root.dataset.theme = builtinType; root.dataset.theme = builtinType;
@ -35,36 +35,26 @@ function updateCSSVariables(preferences: Preferences) {
} }
// 获取当前的内置主题 // 获取当前的内置主题
const currentBuiltType = [...BUILT_IN_THEME_PRESETS].find( const currentBuiltType = [...BUILT_IN_THEME_PRESETS].find(item => item.type === builtinType);
(item) => item.type === builtinType,
);
let builtinTypeColorPrimary: string | undefined = ''; let builtinTypeColorPrimary: string | undefined = "";
if (currentBuiltType) { if (currentBuiltType) {
const isDark = isDarkTheme(preferences.theme.mode); const isDark = isDarkTheme(preferences.theme.mode);
// 设置不同主题的主要颜色 // 设置不同主题的主要颜色
const color = isDark const color = isDark ? currentBuiltType.darkPrimaryColor || currentBuiltType.primaryColor : currentBuiltType.primaryColor;
? currentBuiltType.darkPrimaryColor || currentBuiltType.primaryColor
: currentBuiltType.primaryColor;
builtinTypeColorPrimary = color || currentBuiltType.color; builtinTypeColorPrimary = color || currentBuiltType.color;
} }
// 如果内置主题颜色和自定义颜色都不存在,则不更新主题颜色 // 如果内置主题颜色和自定义颜色都不存在,则不更新主题颜色
if ( if (builtinTypeColorPrimary || Reflect.has(theme, "colorPrimary") || Reflect.has(theme, "colorDestructive") || Reflect.has(theme, "colorSuccess") || Reflect.has(theme, "colorWarning")) {
builtinTypeColorPrimary ||
Reflect.has(theme, 'colorPrimary') ||
Reflect.has(theme, 'colorDestructive') ||
Reflect.has(theme, 'colorSuccess') ||
Reflect.has(theme, 'colorWarning')
) {
// preferences.theme.colorPrimary = builtinTypeColorPrimary || colorPrimary; // preferences.theme.colorPrimary = builtinTypeColorPrimary || colorPrimary;
updateMainColorVariables(preferences); updateMainColorVariables(preferences);
} }
// 更新圆角 // 更新圆角
if (Reflect.has(theme, 'radius')) { if (Reflect.has(theme, "radius")) {
document.documentElement.style.setProperty('--radius', `${radius}rem`); document.documentElement.style.setProperty("--radius", `${radius}rem`);
} }
} }
@ -76,22 +66,21 @@ function updateMainColorVariables(preference: Preferences) {
if (!preference.theme) { if (!preference.theme) {
return; return;
} }
const { colorDestructive, colorPrimary, colorSuccess, colorWarning } = const { colorDestructive, colorPrimary, colorSuccess, colorWarning } = preference.theme;
preference.theme;
const colorVariables = generatorColorVariables([ const colorVariables = generatorColorVariables([
{ color: colorPrimary, name: 'primary' }, { color: colorPrimary, name: "primary" },
{ alias: 'warning', color: colorWarning, name: 'yellow' }, { alias: "warning", color: colorWarning, name: "yellow" },
{ alias: 'success', color: colorSuccess, name: 'green' }, { alias: "success", color: colorSuccess, name: "green" },
{ alias: 'destructive', color: colorDestructive, name: 'red' }, { alias: "destructive", color: colorDestructive, name: "red" },
]); ]);
// 要设置的 CSS 变量映射 // 要设置的 CSS 变量映射
const colorMappings = { const colorMappings = {
'--green-500': '--success', "--green-500": "--success",
'--primary-500': '--primary', "--primary-500": "--primary",
'--red-500': '--destructive', "--red-500": "--destructive",
'--yellow-500': '--warning', "--yellow-500": "--warning",
}; };
// 统一处理颜色变量的更新 // 统一处理颜色变量的更新
@ -106,9 +95,9 @@ function updateMainColorVariables(preference: Preferences) {
} }
function isDarkTheme(theme: string) { function isDarkTheme(theme: string) {
let dark = theme === 'dark'; let dark = theme === "dark";
if (theme === 'auto') { if (theme === "auto") {
dark = window.matchMedia('(prefers-color-scheme: dark)').matches; dark = window.matchMedia("(prefers-color-scheme: dark)").matches;
} }
return dark; return dark;
} }

View File

@ -166,7 +166,7 @@ function usePreferences() {
if (!enablePreferences) { if (!enablePreferences) {
return { return {
fixed: false, fixed: false,
header: false header: false,
}; };
} }
@ -182,7 +182,7 @@ function usePreferences() {
if (preferencesButtonPosition !== "auto") { if (preferencesButtonPosition !== "auto") {
return { return {
fixed: preferencesButtonPosition === "fixed", fixed: preferencesButtonPosition === "fixed",
header: isHeaderPosition header: isHeaderPosition,
}; };
} }
@ -191,7 +191,7 @@ function usePreferences() {
return { return {
fixed, fixed,
header: !fixed header: !fixed,
}; };
}); });
@ -219,7 +219,7 @@ function usePreferences() {
locale, locale,
preferencesButtonPosition, preferencesButtonPosition,
sidebarCollapsed, sidebarCollapsed,
theme theme,
}; };
} }

View File

@ -1,9 +1,8 @@
<template> <template>
<a-drawer v-model:open="notificationDrawerVisible" placement="right" :closable="true" width="600px" <a-drawer v-model:open="notificationDrawerVisible" placement="right" :closable="true" width="600px" class="pi-notification-form" @after-open-change="notificationDrawerOnAfterVisibleChange">
class="pi-notification-form" @after-open-change="notificationDrawerOnAfterVisibleChange">
<template #title> <template #title>
<div> <div>
{{ t('certd.edit_notification') }} {{ t("certd.edit_notification") }}
<a-button v-if="mode === 'edit'" @click="notificationDelete()"> <a-button v-if="mode === 'edit'" @click="notificationDelete()">
<template #icon> <template #icon>
<DeleteOutlined /> <DeleteOutlined />
@ -13,9 +12,11 @@
</template> </template>
<template v-if="currentNotification"> <template v-if="currentNotification">
<pi-container> <pi-container>
<a-form ref="notificationFormRef" class="notification-form" :model="currentNotification" <a-form ref="notificationFormRef" class="notification-form" :model="currentNotification" :label-col="labelCol" :wrapper-col="wrapperCol">
:label-col="labelCol" :wrapper-col="wrapperCol"> <fs-form-item
<fs-form-item v-if="currentNotification.type === 'email'" v-model="currentNotification.type" :item="{ v-if="currentNotification.type === 'email'"
v-model="currentNotification.type"
:item="{
title: t('certd.type'), title: t('certd.type'),
key: 'type', key: 'type',
value: 'email', value: 'email',
@ -29,8 +30,11 @@
], ],
}, },
rules: [{ required: true, message: t('certd.required') }], rules: [{ required: true, message: t('certd.required') }],
}" /> }"
<fs-form-item v-model="currentNotification.when" :item="{ />
<fs-form-item
v-model="currentNotification.when"
:item="{
title: t('certd.trigger_time'), title: t('certd.trigger_time'),
key: 'when', key: 'when',
value: ['error'], value: ['error'],
@ -48,11 +52,14 @@
}, },
helper: t('certd.helper_suggest_fail_only'), helper: t('certd.helper_suggest_fail_only'),
rules: [{ required: true, message: t('certd.required') }], rules: [{ required: true, message: t('certd.required') }],
}" /> }"
<pi-notification-form-email v-if="currentNotification.type === 'email'" ref="optionsRef" />
v-model:options="currentNotification.options"></pi-notification-form-email> <pi-notification-form-email v-if="currentNotification.type === 'email'" ref="optionsRef" v-model:options="currentNotification.options"></pi-notification-form-email>
<fs-form-item v-else v-model="currentNotification.notificationId" :item="{ <fs-form-item
v-else
v-model="currentNotification.notificationId"
:item="{
title: t('certd.notification_config'), title: t('certd.notification_config'),
key: 'notificationId', key: 'notificationId',
component: { component: {
@ -62,12 +69,13 @@
}, },
helper: t('certd.please_select_notification'), helper: t('certd.please_select_notification'),
rules: [{ required: true, message: t('certd.required') }], rules: [{ required: true, message: t('certd.required') }],
}" /> }"
/>
</a-form> </a-form>
<template #footer> <template #footer>
<a-form-item v-if="editMode" :wrapper-col="{ span: 14, offset: 4 }"> <a-form-item v-if="editMode" :wrapper-col="{ span: 14, offset: 4 }">
<a-button type="primary" @click="notificationSave"> {{ t('certd.confirm') }} </a-button> <a-button type="primary" @click="notificationSave"> {{ t("certd.confirm") }} </a-button>
</a-form-item> </a-form-item>
</template> </template>
</pi-container> </pi-container>
@ -75,7 +83,7 @@
</a-drawer> </a-drawer>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
import { Modal } from "ant-design-vue"; import { Modal } from "ant-design-vue";
import { ref, Ref } from "vue"; import { ref, Ref } from "vue";
import * as _ from "lodash-es"; import * as _ from "lodash-es";
@ -86,23 +94,20 @@ import { useI18n } from "vue-i18n";
const { t } = useI18n(); const { t } = useI18n();
export default { defineOptions({
name: "PiNotificationForm", name: "PiNotificationForm",
// eslint-disable-next-line vue/no-unused-components });
components: { NotificationSelector, PiNotificationFormEmail },
props: { const props = defineProps<{
editMode: { editMode: boolean;
type: Boolean, }>();
default: true,
}, const emit = defineEmits(["update"]);
},
emits: ["update"],
setup(props: any, context: any) {
/** /**
* notification drawer * notification drawer
* @returns * @returns
*/ */
function useNotificationForm() {
const mode = ref("add"); const mode = ref("add");
const callback = ref(); const callback = ref();
const currentNotification: Ref<any> = ref({ type: undefined, when: [], options: {}, notificationId: undefined, title: "" }); const currentNotification: Ref<any> = ref({ type: undefined, when: [], options: {}, notificationId: undefined, title: "" });
@ -115,21 +120,21 @@ export default {
{ {
type: "string", type: "string",
required: true, required: true,
message: t('certd.please_select_type'), message: t("certd.please_select_type"),
}, },
], ],
when: [ when: [
{ {
type: "string", type: "string",
required: true, required: true,
message: t('certd.please_select_trigger_time'), message: t("certd.please_select_trigger_time"),
}, },
], ],
notificationId: [ notificationId: [
{ {
type: "number", type: "number",
required: true, required: true,
message: t('certd.please_select_notification_config'), message: t("certd.please_select_notification_config"),
}, },
], ],
}); });
@ -186,8 +191,8 @@ export default {
const notificationDelete = () => { const notificationDelete = () => {
Modal.confirm({ Modal.confirm({
title: t('certd.confirm'), title: t("certd.confirm"),
content: t('certd.confirm_delete_trigger'), content: t("certd.confirm_delete_trigger"),
async onOk() { async onOk() {
callback.value("delete"); callback.value("delete");
notificationDrawerClose(); notificationDrawerClose();
@ -195,7 +200,6 @@ export default {
}); });
}; };
const blankFn = () => { const blankFn = () => {
return {}; return {};
}; };
@ -203,40 +207,12 @@ export default {
function onSelectedChange(node: any) { function onSelectedChange(node: any) {
currentNotification.value.title = node?.name || null; currentNotification.value.title = node?.name || null;
} }
return {
notificationFormRef,
onSelectedChange,
mode,
notificationAdd,
notificationEdit,
notificationView,
notificationDrawerShow,
notificationDrawerVisible,
notificationDrawerOnAfterVisibleChange,
currentNotification,
currentPlugin,
notificationSave,
notificationDelete,
rules,
blankFn,
optionsRef,
};
}
return { const labelCol = { span: 6 };
...useNotificationForm(), const wrapperCol = { span: 16 };
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
},
computed: {
NotificationSelector() {
return NotificationSelector;
},
},
};
</script> </script>
<style lang="less"> <style lang="less">
.pi-notification-form {} .pi-notification-form {
}
</style> </style>

View File

@ -1,6 +1,5 @@
<template> <template>
<a-drawer v-model:open="triggerDrawerVisible" placement="right" :closable="true" width="650px" <a-drawer v-model:open="triggerDrawerVisible" placement="right" :closable="true" width="650px" class="pi-trigger-form" @after-open-change="triggerDrawerOnAfterVisibleChange">
class="pi-trigger-form" @after-open-change="triggerDrawerOnAfterVisibleChange">
<template #title> <template #title>
<div> <div>
{{ t("certd.editTrigger") }} {{ t("certd.editTrigger") }}
@ -13,9 +12,10 @@
</template> </template>
<template v-if="currentTrigger"> <template v-if="currentTrigger">
<pi-container> <pi-container>
<a-form ref="triggerFormRef" class="trigger-form" :model="currentTrigger" :label-col="labelCol" <a-form ref="triggerFormRef" class="trigger-form" :model="currentTrigger" :label-col="labelCol" :wrapper-col="wrapperCol">
:wrapper-col="wrapperCol"> <fs-form-item
<fs-form-item v-model="currentTrigger.title" :item="{ v-model="currentTrigger.title"
:item="{
title: t('certd.triggerName'), title: t('certd.triggerName'),
key: 'title', key: 'title',
component: { component: {
@ -24,10 +24,12 @@
disabled: !editMode, disabled: !editMode,
}, },
rules: [{ required: true, message: t('certd.requiredField') }], rules: [{ required: true, message: t('certd.requiredField') }],
}" /> }"
/>
<fs-form-item
<fs-form-item v-model="currentTrigger.type" :item="{ v-model="currentTrigger.type"
:item="{
title: t('certd.type'), title: t('certd.type'),
key: 'type', key: 'type',
value: 'timer', value: 'timer',
@ -38,9 +40,12 @@
options: [{ value: 'timer', label: t('certd.schedule') }], options: [{ value: 'timer', label: t('certd.schedule') }],
}, },
rules: [{ required: true, message: t('certd.requiredField') }], rules: [{ required: true, message: t('certd.requiredField') }],
}" /> }"
/>
<fs-form-item v-model="currentTrigger.props.cron" :item="{ <fs-form-item
v-model="currentTrigger.props.cron"
:item="{
title: t('certd.cronForm.title'), title: t('certd.cronForm.title'),
key: 'props.cron', key: 'props.cron',
component: { component: {
@ -50,7 +55,8 @@
}, },
helper: t('certd.cronForm.helper'), helper: t('certd.cronForm.helper'),
rules: [{ required: true, message: t('certd.cronForm.required') }], rules: [{ required: true, message: t('certd.cronForm.required') }],
}" /> }"
/>
</a-form> </a-form>
<template #footer> <template #footer>
@ -67,6 +73,7 @@
import { message, Modal } from "ant-design-vue"; import { message, Modal } from "ant-design-vue";
import { inject, ref } from "vue"; import { inject, ref } from "vue";
import * as _ from "lodash-es"; import * as _ from "lodash-es";
import { useI18n } from "/src/locales/";
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
export default { export default {
name: "PiTriggerForm", name: "PiTriggerForm",
@ -82,6 +89,7 @@ export default {
* trigger drawer * trigger drawer
* @returns * @returns
*/ */
const { t } = useI18n();
function useTriggerForm() { function useTriggerForm() {
const mode = ref("add"); const mode = ref("add");
const callback = ref(); const callback = ref();
@ -99,7 +107,6 @@ export default {
], ],
}); });
const triggerDrawerShow = () => { const triggerDrawerShow = () => {
triggerDrawerVisible.value = true; triggerDrawerVisible.value = true;
}; };
@ -124,7 +131,6 @@ export default {
triggerOpen(trigger, emit); triggerOpen(trigger, emit);
}; };
const triggerEdit = (trigger, emit) => { const triggerEdit = (trigger, emit) => {
mode.value = "edit"; mode.value = "edit";
triggerOpen(trigger, emit); triggerOpen(trigger, emit);
@ -159,7 +165,6 @@ export default {
}); });
}; };
const blankFn = () => { const blankFn = () => {
return {}; return {};
}; };
@ -191,5 +196,6 @@ export default {
</script> </script>
<style lang="less"> <style lang="less">
.pi-trigger-form {} .pi-trigger-form {
}
</style> </style>

View File

@ -1,25 +1,20 @@
<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" <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">
:model="formState" v-bind="layout" @finish="handleFinish" @finish-failed="handleFinishFailed">
<!-- <div class="login-title">登录</div>--> <!-- <div class="login-title">登录</div>-->
<a-tabs v-model:active-key="formState.loginType" <a-tabs v-model:active-key="formState.loginType" :tab-bar-style="{ textAlign: 'center', borderBottom: 'unset' }">
:tab-bar-style="{ textAlign: 'center', borderBottom: 'unset' }"> <a-tab-pane key="password" :tab="t('authentication.passwordTab')" :disabled="sysPublicSettings.passwordLoginEnabled !== true">
<a-tab-pane key="password" :tab="$t('authentication.passwordTab')"
:disabled="sysPublicSettings.passwordLoginEnabled !== true">
<template v-if="formState.loginType === 'password'"> <template v-if="formState.loginType === 'password'">
<!-- <div class="login-title">登录</div>--> <!-- <div class="login-title">登录</div>-->
<a-form-item required has-feedback name="username" :rules="rules.username"> <a-form-item required has-feedback name="username" :rules="rules.username">
<a-input v-model:value="formState.username" <a-input v-model:value="formState.username" :placeholder="t('authentication.usernamePlaceholder')" autocomplete="off">
:placeholder="$t('authentication.usernamePlaceholder')" autocomplete="off">
<template #prefix> <template #prefix>
<fs-icon icon="ion:phone-portrait-outline"></fs-icon> <fs-icon icon="ion:phone-portrait-outline"></fs-icon>
</template> </template>
</a-input> </a-input>
</a-form-item> </a-form-item>
<a-form-item has-feedback name="password" :rules="rules.password"> <a-form-item has-feedback name="password" :rules="rules.password">
<a-input-password v-model:value="formState.password" <a-input-password v-model:value="formState.password" :placeholder="t('authentication.passwordPlaceholder')" autocomplete="off">
:placeholder="$t('authentication.passwordPlaceholder')" autocomplete="off">
<template #prefix> <template #prefix>
<fs-icon icon="ion:lock-closed-outline"></fs-icon> <fs-icon icon="ion:lock-closed-outline"></fs-icon>
</template> </template>
@ -27,12 +22,10 @@
</a-form-item> </a-form-item>
</template> </template>
</a-tab-pane> </a-tab-pane>
<a-tab-pane key="sms" :tab="$t('authentication.smsTab')" <a-tab-pane v-if="sysPublicSettings.smsLoginEnabled === true" key="sms" :tab="t('authentication.smsTab')">
:disabled="sysPublicSettings.smsLoginEnabled !== true">
<template v-if="formState.loginType === 'sms'"> <template v-if="formState.loginType === 'sms'">
<a-form-item has-feedback name="mobile" :rules="rules.mobile"> <a-form-item has-feedback name="mobile" :rules="rules.mobile">
<a-input v-model:value="formState.mobile" <a-input v-model:value="formState.mobile" :placeholder="t('authentication.mobilePlaceholder')" autocomplete="off">
:placeholder="$t('authentication.mobilePlaceholder')" autocomplete="off">
<template #prefix> <template #prefix>
<fs-icon icon="ion:phone-portrait-outline"></fs-icon> <fs-icon icon="ion:phone-portrait-outline"></fs-icon>
</template> </template>
@ -40,50 +33,47 @@
</a-form-item> </a-form-item>
<a-form-item has-feedback name="imgCode"> <a-form-item has-feedback name="imgCode">
<image-code v-model:value="formState.imgCode" <image-code v-model:value="formState.imgCode" v-model:random-str="formState.randomStr"></image-code>
v-model:random-str="formState.randomStr"></image-code>
</a-form-item> </a-form-item>
<a-form-item name="smsCode" :rules="rules.smsCode"> <a-form-item name="smsCode" :rules="rules.smsCode">
<sms-code v-model:value="formState.smsCode" :img-code="formState.imgCode" <sms-code v-model:value="formState.smsCode" :img-code="formState.imgCode" :mobile="formState.mobile" :phone-code="formState.phoneCode" :random-str="formState.randomStr" />
:mobile="formState.mobile" :phone-code="formState.phoneCode"
:random-str="formState.randomStr" />
</a-form-item> </a-form-item>
</template> </template>
</a-tab-pane> </a-tab-pane>
</a-tabs> </a-tabs>
<a-form-item> <a-form-item>
<a-button type="primary" size="large" html-type="submit" :loading="loading" class="login-button"> <a-button type="primary" size="large" html-type="submit" :loading="loading" class="login-button">
{{ $t('authentication.loginButton') }} {{ t("authentication.loginButton") }}
</a-button> </a-button>
<div v-if="!settingStore.isComm" class="mt-2"> <div v-if="!settingStore.isComm" class="mt-2">
<a href="https://certd.docmirror.cn/guide/use/forgotpasswd/" target="_blank"> <a href="https://certd.docmirror.cn/guide/use/forgotpasswd/" target="_blank">
{{ $t('authentication.forgotAdminPassword') }} {{ t("authentication.forgotAdminPassword") }}
</a> </a>
</div> </div>
</a-form-item> </a-form-item>
<a-form-item class="user-login-other"> <a-form-item class="user-login-other">
<div class="flex flex-between justify-between items-center">
<language-toggle class="color-blue"></language-toggle>
<router-link v-if="hasRegisterTypeEnabled()" class="register" :to="{ name: 'register' }"> <router-link v-if="hasRegisterTypeEnabled()" class="register" :to="{ name: 'register' }">
{{ $t('authentication.registerLink') }} {{ t("authentication.registerLink") }}
</router-link> </router-link>
</div>
</a-form-item> </a-form-item>
</a-form> </a-form>
<a-form v-else ref="twoFactorFormRef" class="user-layout-login" :model="twoFactor" v-bind="layout"> <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> <div class="mb-10 flex flex-center">请打开您的Authenticator APP获取动态验证码</div>
<a-form-item name="verifyCode"> <a-form-item name="verifyCode">
<a-input ref="verifyCodeInputRef" v-model:value="twoFactor.verifyCode" placeholder="请输入动态验证码" <a-input ref="verifyCodeInputRef" v-model:value="twoFactor.verifyCode" placeholder="请输入动态验证码" allow-clear @keydown.enter="handleTwoFactorSubmit">
allow-clear @keydown.enter="handleTwoFactorSubmit">
<template #prefix> <template #prefix>
<fs-icon icon="ion:lock-closed-outline"></fs-icon> <fs-icon icon="ion:lock-closed-outline"></fs-icon>
</template> </template>
</a-input> </a-input>
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<loading-button type="primary" size="large" html-type="button" class="login-button" <loading-button type="primary" size="large" html-type="button" class="login-button" :click="handleTwoFactorSubmit">OTP验证登录</loading-button>
:click="handleTwoFactorSubmit">OTP验证登录</loading-button>
</a-form-item> </a-form-item>
<a-form-item class="user-login-other"> <a-form-item class="user-login-other">
@ -99,11 +89,14 @@ import { useSettingStore } from "/@/store/settings";
import { utils } from "@fast-crud/fast-crud"; import { utils } from "@fast-crud/fast-crud";
import ImageCode from "/@/views/framework/login/image-code.vue"; 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";
import { useI18n } from "/@/locales";
import { LanguageToggle } from "/@/vben/layouts";
export default defineComponent({ export default defineComponent({
name: "LoginPage", name: "LoginPage",
components: { SmsCode, ImageCode }, components: { LanguageToggle, SmsCode, ImageCode },
setup() { setup() {
const { t } = useI18n();
const verifyCodeInputRef = ref(); const verifyCodeInputRef = ref();
const loading = ref(false); const loading = ref(false);
const userStore = useUserStore(); const userStore = useUserStore();
@ -202,6 +195,7 @@ export default defineComponent({
} }
return { return {
t,
loading, loading,
formState, formState,
formRef, formRef,