diff --git a/frontend/src/i18n/locales/en.ts b/frontend/src/i18n/locales/en.ts index f5ae2676..3963ad01 100644 --- a/frontend/src/i18n/locales/en.ts +++ b/frontend/src/i18n/locales/en.ts @@ -3534,6 +3534,15 @@ export default { settings: { title: 'System Settings', description: 'Manage registration, email verification, default values, and SMTP settings', + tabs: { + general: 'General', + security: 'Security', + users: 'Users', + gateway: 'Gateway', + email: 'Email', + }, + emailTabDisabledTitle: 'Email Verification Not Enabled', + emailTabDisabledHint: 'Enable email verification in the Security tab to configure SMTP settings.', registration: { title: 'Registration Settings', description: 'Control user registration and verification', @@ -3543,7 +3552,7 @@ export default { emailVerificationHint: 'Require email verification for new registrations', emailSuffixWhitelist: 'Email Domain Whitelist', emailSuffixWhitelistHint: - 'Only email addresses from the specified domains can register (for example, @qq.com, @gmail.com)', + "Only email addresses from the specified domains can register (for example, {'@'}qq.com, {'@'}gmail.com)", emailSuffixWhitelistPlaceholder: 'example.com', emailSuffixWhitelistInputHint: 'Leave empty for no restriction', promoCode: 'Promo Code', diff --git a/frontend/src/i18n/locales/zh.ts b/frontend/src/i18n/locales/zh.ts index 3d729ebc..a692b7f6 100644 --- a/frontend/src/i18n/locales/zh.ts +++ b/frontend/src/i18n/locales/zh.ts @@ -3703,6 +3703,15 @@ export default { settings: { title: '系统设置', description: '管理注册、邮箱验证、默认值和 SMTP 设置', + tabs: { + general: '通用设置', + security: '安全与认证', + users: '用户默认值', + gateway: '网关服务', + email: '邮件设置', + }, + emailTabDisabledTitle: '邮箱验证未启用', + emailTabDisabledHint: '请在「安全与认证」选项卡中启用邮箱验证后,再配置 SMTP 设置。', registration: { title: '注册设置', description: '控制用户注册和验证', @@ -3712,7 +3721,7 @@ export default { emailVerificationHint: '新用户注册时需要验证邮箱', emailSuffixWhitelist: '邮箱域名白名单', emailSuffixWhitelistHint: - '仅允许使用指定域名的邮箱注册账号(例如 @qq.com, @gmail.com)', + "仅允许使用指定域名的邮箱注册账号(例如 {'@'}qq.com, {'@'}gmail.com)", emailSuffixWhitelistPlaceholder: 'example.com', emailSuffixWhitelistInputHint: '留空则不限制', promoCode: '优惠码', diff --git a/frontend/src/views/admin/SettingsView.vue b/frontend/src/views/admin/SettingsView.vue index 92071d60..6f448811 100644 --- a/frontend/src/views/admin/SettingsView.vue +++ b/frontend/src/views/admin/SettingsView.vue @@ -8,6 +8,26 @@
+ +
+ +
+ + +
@@ -146,7 +166,10 @@
+ + +
@@ -284,7 +307,10 @@
+
+ +
@@ -618,7 +644,10 @@
+ + +
@@ -757,7 +786,10 @@
+ + +
@@ -814,7 +846,10 @@
+ + +
@@ -957,147 +992,6 @@
- -
-
-
-

- {{ t('admin.settings.smtp.title') }} -

-

- {{ t('admin.settings.smtp.description') }} -

-
- -
-
-
-
- - -
-
- - -
-
- - -
-
- - -

- {{ - form.smtp_password_configured - ? t('admin.settings.smtp.passwordConfiguredHint') - : t('admin.settings.smtp.passwordHint') - }} -

-
-
- - -
-
- - -
-
- - -
-
- -

- {{ t('admin.settings.smtp.useTlsHint') }} -

-
- -
-
-
-
@@ -1309,6 +1203,168 @@
+
+ + +
+ +
+
+
+ +
+

+ {{ t('admin.settings.emailTabDisabledTitle') }} +

+

+ {{ t('admin.settings.emailTabDisabledHint') }} +

+
+
+
+
+ + +
+
+
+

+ {{ t('admin.settings.smtp.title') }} +

+

+ {{ t('admin.settings.smtp.description') }} +

+
+ +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +

+ {{ + form.smtp_password_configured + ? t('admin.settings.smtp.passwordConfiguredHint') + : t('admin.settings.smtp.passwordHint') + }} +

+
+
+ + +
+
+ + +
+
+ + +
+
+ +

+ {{ t('admin.settings.smtp.useTlsHint') }} +

+
+ +
+
+
+
@@ -1367,6 +1423,7 @@
+
@@ -1424,6 +1481,16 @@ import { const { t } = useI18n() const appStore = useAppStore() const adminSettingsStore = useAdminSettingsStore() + +type SettingsTab = 'general' | 'security' | 'users' | 'gateway' | 'email' +const activeTab = ref('general') +const settingsTabs = [ + { key: 'general' as SettingsTab, icon: 'home' as const }, + { key: 'security' as SettingsTab, icon: 'shield' as const }, + { key: 'users' as SettingsTab, icon: 'user' as const }, + { key: 'gateway' as SettingsTab, icon: 'server' as const }, + { key: 'email' as SettingsTab, icon: 'mail' as const }, +] const { copyToClipboard } = useClipboard() const loading = ref(true) @@ -1975,4 +2042,56 @@ onMounted(() => { .default-sub-delete-btn { @apply h-[42px]; } + +/* ============ Settings Tab Navigation ============ */ +.settings-tabs { + @apply inline-flex min-w-full gap-1 rounded-2xl + border border-gray-100 bg-white/80 p-1.5 backdrop-blur-sm + dark:border-dark-700/50 dark:bg-dark-800/80; + box-shadow: 0 1px 3px rgb(0 0 0 / 0.04), 0 1px 2px rgb(0 0 0 / 0.02); +} + +@media (min-width: 640px) { + .settings-tabs { + @apply flex; + } +} + +.settings-tab { + @apply relative flex flex-1 items-center justify-center gap-2 + whitespace-nowrap rounded-xl px-4 py-2.5 + text-sm font-medium + text-gray-500 dark:text-dark-400 + transition-all duration-200 ease-out; +} + +.settings-tab:hover:not(.settings-tab-active) { + @apply text-gray-700 dark:text-gray-300; + background: rgb(0 0 0 / 0.03); +} + +:root.dark .settings-tab:hover:not(.settings-tab-active) { + background: rgb(255 255 255 / 0.04); +} + +.settings-tab-active { + @apply text-primary-600 dark:text-primary-400; + background: linear-gradient(135deg, rgba(20, 184, 166, 0.08), rgba(20, 184, 166, 0.03)); + box-shadow: 0 1px 2px rgba(20, 184, 166, 0.1); +} + +:root.dark .settings-tab-active { + background: linear-gradient(135deg, rgba(45, 212, 191, 0.12), rgba(45, 212, 191, 0.05)); + box-shadow: 0 1px 3px rgb(0 0 0 / 0.25); +} + +.settings-tab-icon { + @apply flex h-7 w-7 items-center justify-center rounded-lg + transition-all duration-200; +} + +.settings-tab-active .settings-tab-icon { + @apply bg-primary-500/15 text-primary-600 + dark:bg-primary-400/15 dark:text-primary-400; +}