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

View File

@ -33,7 +33,6 @@ const menus = computed(() => [
},
]);
const avatar = computed(() => {
const avt = userStore.getUserInfo?.avatar;
return avt ? `/api/basic/file/download?key=${avt}` : "";
@ -77,16 +76,13 @@ provide("fn:ai.open", openChat);
<template>
<BasicLayout @clear-preferences-and-logout="handleLogout">
<template #user-dropdown>
<UserDropdown :avatar="avatar" :menus="menus"
:text="userStore.userInfo?.nickName || userStore.userInfo?.username" description="" tag-text=""
@logout="handleLogout" />
<UserDropdown :avatar="avatar" :menus="menus" :text="userStore.userInfo?.nickName || userStore.userInfo?.username" description="" tag-text="" @logout="handleLogout" />
</template>
<template #lock-screen>
<LockScreen :avatar @to-login="handleLogout" />
</template>
<template #header-right-0>
<div v-if="!settingStore.isComm"
class="hover:bg-accent ml-1 mr-2 cursor-pointer rounded-full hidden md:block">
<div v-if="!settingStore.isComm" class="hover:bg-accent ml-1 mr-2 cursor-pointer rounded-full hidden md:block">
<tutorial-button class="flex-center header-btn" />
</div>
<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 { Locale } from "vue-i18n";
import { setAntdvLocale } from "./antdv";
import type { ImportLocaleFn, LoadMessageFn, LocaleSetupOptions, SupportedLanguagesType } from "./typing";
import { unref } from "vue";
import { createI18n } from "vue-i18n";
import en_US from './langs/en-US/index';
import zh_CH from './langs/zh-CN/index';
import en_US from "./langs/en-US/index";
import zh_CN from "./langs/zh-CN/index";
import { useSimpleLocale } from "/@/vben/composables";
const i18n = createI18n({
globalInjection: true,
legacy: false,
fallbackLocale: 'en_US',
locale: 'en_US',
fallbackLocale: "en-US",
locale: "en-US",
messages: {
zh_CH: zh_CH,
en_US: en_US
}
"zh-CN": zh_CN,
"en-US": en_US,
},
});
const modules = import.meta.glob("./langs/**/*.json");
@ -89,6 +89,8 @@ function loadLocalesMapFromDir(regexp: RegExp, modules: Record<string, () => Pro
* @param locale
*/
function setI18nLanguage(locale: Locale) {
// setAntdvLocale(locale);
//@ts-ignore
i18n.global.locale.value = locale;
document?.querySelector("html")?.setAttribute("lang", locale);
@ -122,6 +124,7 @@ async function loadLocaleMessages(lang: SupportedLanguagesType) {
const message = await localesMap[lang]?.();
if (message?.default) {
//@ts-ignore
i18n.global.setLocaleMessage(lang, message.default);
}
@ -130,6 +133,5 @@ async function loadLocaleMessages(lang: SupportedLanguagesType) {
return setI18nLanguage(lang);
}
export { i18n, loadLocaleMessages, loadLocalesMap, loadLocalesMapFromDir, setupI18n };
export { i18n, loadLocaleMessages, loadLocalesMap, loadLocalesMapFromDir, setupI18n, setI18nLanguage };
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 $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 { CompileError } from "@intlify/core-base";

View File

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

View File

@ -2,31 +2,33 @@ export default {
app: {
crud: {
i18n: {
name: "name", city: "city", status: "status"
}
}
name: "name",
city: "city",
status: "status",
},
},
},
fs: {
rowHandle: {
title: "Operation"
}
title: "Operation",
},
},
order: {
confirmTitle: 'Order Confirmation',
package: 'Package',
description: 'Description',
specifications: 'Specifications',
pipeline: 'Pipeline',
domain: 'Domain',
deployTimes: 'Deployments',
duration: 'Duration',
price: 'Price',
paymentMethod: 'Payment Method',
free: 'Free',
confirmTitle: "Order Confirmation",
package: "Package",
description: "Description",
specifications: "Specifications",
pipeline: "Pipeline",
domain: "Domain",
deployTimes: "Deployments",
duration: "Duration",
price: "Price",
paymentMethod: "Payment Method",
free: "Free",
unit: {
pieces: 'pieces',
count: 'count',
times: 'times',
pieces: "pieces",
count: "count",
times: "times",
},
},
framework: {
@ -80,7 +82,7 @@ export default {
steps: {
createPipeline: "Create Certificate Pipeline",
addTask: "Add Deployment Task",
scheduledRun: "Scheduled Run"
scheduledRun: "Scheduled Run",
},
customPipeline: "Custom Pipeline",
createCertdPipeline: "Create Certificate Pipeline",
@ -173,17 +175,17 @@ export default {
},
certificateRepo: {
title: "Certificate Repository",
sub: "Certificates generated from pipeline"
sub: "Certificates generated from pipeline",
},
certificateNotGenerated: "Certificate not yet generated, please run the pipeline first",
viewCertificateTitle: "View Certificate",
close: "Close",
viewCert: {
title: "View Certificate"
title: "View Certificate",
},
download: {
title: "Download Certificate"
title: "Download Certificate",
},
source: "Source Code",
github: "GitHub",
@ -191,22 +193,22 @@ export default {
cron: {
clearTip: "Clear Selection",
nextTrigger: "Next Trigger Time",
tip: "Please set a valid cron expression first"
tip: "Please set a valid cron expression first",
},
cronForm: {
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.",
required: "This field is required"
required: "This field is required",
},
email: {
title: "Recipient Email",
helper: "Enter your recipient email addresses. Multiple addresses are supported.",
required: "This field is required"
required: "This field is required",
},
plugin: {
selectTitle: "Certificate Apply Plugin",
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: {
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.",
notificationTitle: "Failure Notification",
notificationHelper: "Get real-time alerts when the task fails",
groupIdTitle: "Pipeline Group"
groupIdTitle: "Pipeline Group",
},
notificationDefault: "Use Default Notification",
monitor: {

View File

@ -1,22 +1,22 @@
export default {
"back": "Back",
"backToHome": "Back To Home",
"login": "Login",
"logout": "Logout",
"prompt": "Prompt",
"cancel": "Cancel",
"confirm": "Confirm",
"reset": "Reset",
"noData": "No Data",
"refresh": "Refresh",
"loadingMenu": "Loading Menu",
"query": "Search",
"search": "Search",
"enabled": "Enabled",
"disabled": "Disabled",
"edit": "Edit",
"delete": "Delete",
"create": "Create",
"yes": "Yes",
"no": "No"
}
back: "Back",
backToHome: "Back To Home",
login: "Login",
logout: "Logout",
prompt: "Prompt",
cancel: "Cancel",
confirm: "Confirm",
reset: "Reset",
noData: "No Data",
refresh: "Refresh",
loadingMenu: "Loading Menu",
query: "Search",
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: "(basic version requires configuring mail server)",
tutorialEndTitle: "Tutorial End",
thanksForWatching: "Thank you for watching, hope it helps you",
}
}
},
};

View File

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

View File

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

View File

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

View File

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

View File

@ -27,11 +27,11 @@ export default {
successContent: "You have successfully activated {vipLabel}, valid until: {expireDate}",
bindAccountTitle: "Bind Your Account",
bindAccountContent: "Binding your account helps prevent license loss. Strongly recommended.",
congratulations_vip_trial: 'Congratulations, you have received a Pro version {duration} days trial',
trial_modal_title: '7-day Pro version trial acquisition',
trial_modal_ok_text: 'Get now',
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',
congratulations_vip_trial: "Congratulations, you have received a Pro version {duration} days trial",
trial_modal_title: "7-day Pro version trial acquisition",
trial_modal_ok_text: "Get now",
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",
get_7_day_pro_trial: "7-day professional version trial",
star_now: "Star Now",
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 ",
bind_account: "bind account",
transfer_vip: ' then "Transfer VIP"',
}
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
import LayoutBasic from "/@/layout/layout-basic.vue";
import type { RouteRecordRaw } from "vue-router";
import i18n from '/@/locales/i18n';
import i18n from "/@/locales/i18n";
import { mergeRouteModules } from "/@/vben/utils";
const dynamicRouteFiles = import.meta.glob("./modules/**/*.ts*", {
@ -12,7 +12,7 @@ const dynamicRouteFiles = import.meta.glob("./modules/**/*.ts*", {
const dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles);
export const frameworkResource = [
{
title: i18n.global.t("certd.framework.title"),
title: "certd.framework.title",
name: "root",
path: "/",
redirect: "/index",
@ -23,7 +23,7 @@ export const frameworkResource = [
},
children: [
{
title: i18n.global.t("certd.framework.home"),
title: "certd.framework.home",
name: "index",
path: "/index",
component: "/framework/home/index.vue",

View File

@ -1,36 +1,35 @@
import i18n from '/@/locales/i18n';
import i18n from "/@/locales/i18n";
export const headerResource = [
{
title: i18n.global.t("certd.helpDoc"),
title: "certd.helpDoc",
path: "https://certd.docmirror.cn",
meta: {
icon: "ion:document-text-outline"
}
icon: "ion:document-text-outline",
},
},
{
title: i18n.global.t("certd.source"),
title: "certd.source",
name: "source",
key: "source",
meta: {
icon: "ion:git-branch-outline"
icon: "ion:git-branch-outline",
},
children: [
{
title: i18n.global.t("certd.github"),
title: "certd.github",
path: "https://github.com/certd/certd",
meta: {
icon: "ion:logo-github"
}
icon: "ion:logo-github",
},
},
{
title: i18n.global.t("certd.gitee"),
title: "certd.gitee",
path: "https://gitee.com/certd/certd",
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 { computed } from "vue";
import TutorialButton from "/@/components/tutorial/index.vue";
import i18n from '/@/locales/i18n';
import i18n from "/@/locales/i18n";
export const aboutResource = [
{
title: i18n.global.t("certd.dashboard.helpDoc"),
title: "certd.dashboard.helpDoc",
name: "document",
path: "/about/doc",
component: IFrameView,
meta: {
icon: "lucide:book-open-text",
link: "https://certd.docmirror.cn",
title: i18n.global.t("certd.dashboard.helpDoc"),
title: "certd.dashboard.helpDoc",
order: 9999,
show: () => {
const settingStore = useSettingStore();

View File

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

View File

@ -1,11 +1,11 @@
import LayoutPass from "/@/layout/layout-pass.vue";
import { useSettingStore } from "/@/store/settings";
import aboutResource from "/@/router/source/modules/about";
import i18n from '/@/locales/i18n';
import i18n from "/@/locales/i18n";
export const sysResources = [
{
title: i18n.global.t('certd.sysResources.sysRoot'),
title: "certd.sysResources.sysRoot",
name: "SysRoot",
path: "/sys",
redirect: "/sys/settings",
@ -16,7 +16,7 @@ export const sysResources = [
},
children: [
{
title: i18n.global.t('certd.sysResources.sysConsole'),
title: "certd.sysResources.sysConsole",
name: "SysConsole",
path: "/sys/console",
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",
path: "/sys/settings",
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",
path: "/sys/cname/provider",
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",
path: "/sys/settings/email",
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",
path: "/sys/site",
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",
path: "/sys/settings/header-menus",
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",
path: "/sys/access",
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",
path: "/sys/plugin",
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",
path: "/sys/plugin/edit",
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",
path: "/sys/plugin/config",
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",
path: "/sys/account",
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",
path: "/sys/authority/permission",
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",
path: "/sys/authority/role",
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",
path: "/sys/authority/user",
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",
path: "/sys/suite",
redirect: "/sys/suite/setting",
@ -204,7 +204,7 @@ export const sysResources = [
},
children: [
{
title: i18n.global.t('certd.sysResources.suiteSetting'),
title: "certd.sysResources.suiteSetting",
name: "SuiteSetting",
path: "/sys/suite/setting",
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",
path: "/sys/suite/trade",
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",
path: "/sys/suite/user-suite",
component: "/sys/suite/user-suite/index.vue",

View File

@ -10,21 +10,21 @@ export const outsideResource = [
children: [
{
meta: {
title: "登录"
title: "登录",
},
name: "login",
path: "/login",
component: "/framework/login/index.vue"
component: "/framework/login/index.vue",
},
{
meta: {
title: "注册"
title: "注册",
},
name: "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 * as api from "./api.plugin";
import { DynamicType, FormItemProps } from "@fast-crud/fast-crud";
import { i18n } from "/src/locales/i18n";
interface PluginState {
group?: PluginGroups;
}
@ -31,8 +31,10 @@ export type PluginDefine = {
export class PluginGroups {
groups!: { [key: string]: PluginGroup };
map!: { [key: string]: PluginDefine };
t: any;
constructor(groups: { [key: string]: PluginGroup }) {
this.groups = groups;
this.t = i18n.global.t;
this.initGroup(groups);
this.initMap();
}
@ -40,7 +42,7 @@ export class PluginGroups {
private initGroup(groups: { [p: string]: PluginGroup }) {
const all: PluginGroup = {
key: "all",
title: t('certd.all'),
title: this.t("certd.all"),
order: 0,
plugins: [],
icon: "material-symbols:border-all-rounded",

View File

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

View File

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

View File

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

View File

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

View File

@ -108,7 +108,7 @@ const defaultPreferences: Preferences = {
widget: {
fullscreen: true,
globalSearch: true,
languageToggle: false,
languageToggle: true,
lockScreen: true,
notification: false,
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 =
preferencesManager.getPreferences.apply(preferencesManager);
const preferences: Preferences = preferencesManager.getPreferences.apply(preferencesManager);
// 更新偏好设置
const updatePreferences =
preferencesManager.updatePreferences.bind(preferencesManager);
const updatePreferences = preferencesManager.updatePreferences.bind(preferencesManager);
// 重置偏好设置
const resetPreferences =
preferencesManager.resetPreferences.bind(preferencesManager);
const resetPreferences = preferencesManager.resetPreferences.bind(preferencesManager);
const clearPreferencesCache =
preferencesManager.clearCache.bind(preferencesManager);
const clearPreferencesCache = preferencesManager.clearCache.bind(preferencesManager);
// 初始化偏好设置
const initPreferences =
preferencesManager.initPreferences.bind(preferencesManager);
const initPreferences = preferencesManager.initPreferences.bind(preferencesManager);
export {
clearPreferencesCache,
initPreferences,
preferences,
preferencesManager,
resetPreferences,
updatePreferences,
};
export { clearPreferencesCache, initPreferences, preferences, preferencesManager, resetPreferences, updatePreferences };
export * from './constants';
export type * from './types';
export * from './use-preferences';
export * from "./constants";
export type * from "./types";
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 { isMacOs, merge } from '/@/vben/shared/utils';
import { StorageManager } from "/@/vben/shared/cache";
import { isMacOs, merge } from "/@/vben/shared/utils";
import {
breakpointsTailwind,
useBreakpoints,
useDebounceFn,
} from '@vueuse/core';
import { breakpointsTailwind, useBreakpoints, useDebounceFn } from "@vueuse/core";
import { defaultPreferences } from './config';
import { updateCSSVariables } from './update-css-variables';
import { defaultPreferences } from "./config";
import { updateCSSVariables } from "./update-css-variables";
const STORAGE_KEY = 'preferences';
const STORAGE_KEY = "preferences";
const STORAGE_KEY_LOCALE = `${STORAGE_KEY}-locale`;
const STORAGE_KEY_THEME = `${STORAGE_KEY}-theme`;
@ -33,14 +29,11 @@ class PreferenceManager {
this.cache = new StorageManager();
// 避免频繁的操作缓存
this.savePreferences = useDebounceFn(
(preference: Preferences) => this._savePreferences(preference),
150,
);
this.savePreferences = useDebounceFn((preference: Preferences) => this._savePreferences(preference), 150);
}
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);
});
}
@ -73,7 +66,7 @@ class PreferenceManager {
{},
// overrides,
this.loadCachedPreferences() || {},
this.initialPreferences,
this.initialPreferences
);
// 更新偏好设置
@ -103,7 +96,7 @@ class PreferenceManager {
// 保存重置后的偏好设置
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.updatePreferences(this.state);
@ -145,17 +138,14 @@ class PreferenceManager {
updateCSSVariables(this.state);
}
if (
Reflect.has(appUpdates, 'colorGrayMode') ||
Reflect.has(appUpdates, 'colorWeakMode')
) {
if (Reflect.has(appUpdates, "colorGrayMode") || Reflect.has(appUpdates, "colorWeakMode")) {
this.updateColorMode(this.state);
}
}
private initPlatform() {
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 isMobile = breakpoints.smaller('md');
const isMobile = breakpoints.smaller("md");
watch(
() => isMobile.value,
(val) => {
val => {
this.updatePreferences({
app: { isMobile: val },
});
},
{ immediate: true },
{ immediate: true }
);
// 监听系统主题偏好设置变化
window
.matchMedia('(prefers-color-scheme: dark)')
.addEventListener('change', ({ matches: isDark }) => {
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", ({ matches: isDark }) => {
this.updatePreferences({
theme: { mode: isDark ? 'dark' : 'light' },
theme: { mode: isDark ? "dark" : "light" },
});
});
}
@ -212,14 +200,10 @@ class PreferenceManager {
if (preference.app) {
const { colorGrayMode, colorWeakMode } = preference.app;
const dom = document.documentElement;
const COLOR_WEAK = 'invert-mode';
const COLOR_GRAY = 'grayscale-mode';
colorWeakMode
? dom.classList.add(COLOR_WEAK)
: dom.classList.remove(COLOR_WEAK);
colorGrayMode
? dom.classList.add(COLOR_GRAY)
: dom.classList.remove(COLOR_GRAY);
const COLOR_WEAK = "invert-mode";
const COLOR_GRAY = "grayscale-mode";
colorWeakMode ? dom.classList.add(COLOR_WEAK) : 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 { updateCSSVariables as executeUpdateCSSVariables } from '/@/vben/shared/utils';
import { generatorColorVariables } from "/@/vben/shared/color";
import { updateCSSVariables as executeUpdateCSSVariables } from "/@/vben/shared/utils";
import { BUILT_IN_THEME_PRESETS } from './constants';
import { BUILT_IN_THEME_PRESETS } from "./constants";
/**
* CSS CSS
@ -21,13 +21,13 @@ function updateCSSVariables(preferences: Preferences) {
const { builtinType, mode, radius } = theme;
// html 设置 dark 类
if (Reflect.has(theme, 'mode')) {
if (Reflect.has(theme, "mode")) {
const dark = isDarkTheme(mode);
root.classList.toggle('dark', dark);
root.classList.toggle("dark", dark);
}
// html 设置 data-theme=[builtinType]
if (Reflect.has(theme, 'builtinType')) {
if (Reflect.has(theme, "builtinType")) {
const rootTheme = root.dataset.theme;
if (rootTheme !== builtinType) {
root.dataset.theme = builtinType;
@ -35,36 +35,26 @@ function updateCSSVariables(preferences: Preferences) {
}
// 获取当前的内置主题
const currentBuiltType = [...BUILT_IN_THEME_PRESETS].find(
(item) => item.type === builtinType,
);
const currentBuiltType = [...BUILT_IN_THEME_PRESETS].find(item => item.type === builtinType);
let builtinTypeColorPrimary: string | undefined = '';
let builtinTypeColorPrimary: string | undefined = "";
if (currentBuiltType) {
const isDark = isDarkTheme(preferences.theme.mode);
// 设置不同主题的主要颜色
const color = isDark
? currentBuiltType.darkPrimaryColor || currentBuiltType.primaryColor
: currentBuiltType.primaryColor;
const color = isDark ? currentBuiltType.darkPrimaryColor || currentBuiltType.primaryColor : currentBuiltType.primaryColor;
builtinTypeColorPrimary = color || currentBuiltType.color;
}
// 如果内置主题颜色和自定义颜色都不存在,则不更新主题颜色
if (
builtinTypeColorPrimary ||
Reflect.has(theme, 'colorPrimary') ||
Reflect.has(theme, 'colorDestructive') ||
Reflect.has(theme, 'colorSuccess') ||
Reflect.has(theme, 'colorWarning')
) {
if (builtinTypeColorPrimary || Reflect.has(theme, "colorPrimary") || Reflect.has(theme, "colorDestructive") || Reflect.has(theme, "colorSuccess") || Reflect.has(theme, "colorWarning")) {
// preferences.theme.colorPrimary = builtinTypeColorPrimary || colorPrimary;
updateMainColorVariables(preferences);
}
// 更新圆角
if (Reflect.has(theme, 'radius')) {
document.documentElement.style.setProperty('--radius', `${radius}rem`);
if (Reflect.has(theme, "radius")) {
document.documentElement.style.setProperty("--radius", `${radius}rem`);
}
}
@ -76,22 +66,21 @@ function updateMainColorVariables(preference: Preferences) {
if (!preference.theme) {
return;
}
const { colorDestructive, colorPrimary, colorSuccess, colorWarning } =
preference.theme;
const { colorDestructive, colorPrimary, colorSuccess, colorWarning } = preference.theme;
const colorVariables = generatorColorVariables([
{ color: colorPrimary, name: 'primary' },
{ alias: 'warning', color: colorWarning, name: 'yellow' },
{ alias: 'success', color: colorSuccess, name: 'green' },
{ alias: 'destructive', color: colorDestructive, name: 'red' },
{ color: colorPrimary, name: "primary" },
{ alias: "warning", color: colorWarning, name: "yellow" },
{ alias: "success", color: colorSuccess, name: "green" },
{ alias: "destructive", color: colorDestructive, name: "red" },
]);
// 要设置的 CSS 变量映射
const colorMappings = {
'--green-500': '--success',
'--primary-500': '--primary',
'--red-500': '--destructive',
'--yellow-500': '--warning',
"--green-500": "--success",
"--primary-500": "--primary",
"--red-500": "--destructive",
"--yellow-500": "--warning",
};
// 统一处理颜色变量的更新
@ -106,9 +95,9 @@ function updateMainColorVariables(preference: Preferences) {
}
function isDarkTheme(theme: string) {
let dark = theme === 'dark';
if (theme === 'auto') {
dark = window.matchMedia('(prefers-color-scheme: dark)').matches;
let dark = theme === "dark";
if (theme === "auto") {
dark = window.matchMedia("(prefers-color-scheme: dark)").matches;
}
return dark;
}

View File

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

View File

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

View File

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

View File

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