fix(frontend): settings页面分tab拆分
This commit is contained in:
@@ -3534,6 +3534,15 @@ export default {
|
|||||||
settings: {
|
settings: {
|
||||||
title: 'System Settings',
|
title: 'System Settings',
|
||||||
description: 'Manage registration, email verification, default values, and SMTP 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: {
|
registration: {
|
||||||
title: 'Registration Settings',
|
title: 'Registration Settings',
|
||||||
description: 'Control user registration and verification',
|
description: 'Control user registration and verification',
|
||||||
@@ -3543,7 +3552,7 @@ export default {
|
|||||||
emailVerificationHint: 'Require email verification for new registrations',
|
emailVerificationHint: 'Require email verification for new registrations',
|
||||||
emailSuffixWhitelist: 'Email Domain Whitelist',
|
emailSuffixWhitelist: 'Email Domain Whitelist',
|
||||||
emailSuffixWhitelistHint:
|
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',
|
emailSuffixWhitelistPlaceholder: 'example.com',
|
||||||
emailSuffixWhitelistInputHint: 'Leave empty for no restriction',
|
emailSuffixWhitelistInputHint: 'Leave empty for no restriction',
|
||||||
promoCode: 'Promo Code',
|
promoCode: 'Promo Code',
|
||||||
|
|||||||
@@ -3703,6 +3703,15 @@ export default {
|
|||||||
settings: {
|
settings: {
|
||||||
title: '系统设置',
|
title: '系统设置',
|
||||||
description: '管理注册、邮箱验证、默认值和 SMTP 设置',
|
description: '管理注册、邮箱验证、默认值和 SMTP 设置',
|
||||||
|
tabs: {
|
||||||
|
general: '通用设置',
|
||||||
|
security: '安全与认证',
|
||||||
|
users: '用户默认值',
|
||||||
|
gateway: '网关服务',
|
||||||
|
email: '邮件设置',
|
||||||
|
},
|
||||||
|
emailTabDisabledTitle: '邮箱验证未启用',
|
||||||
|
emailTabDisabledHint: '请在「安全与认证」选项卡中启用邮箱验证后,再配置 SMTP 设置。',
|
||||||
registration: {
|
registration: {
|
||||||
title: '注册设置',
|
title: '注册设置',
|
||||||
description: '控制用户注册和验证',
|
description: '控制用户注册和验证',
|
||||||
@@ -3712,7 +3721,7 @@ export default {
|
|||||||
emailVerificationHint: '新用户注册时需要验证邮箱',
|
emailVerificationHint: '新用户注册时需要验证邮箱',
|
||||||
emailSuffixWhitelist: '邮箱域名白名单',
|
emailSuffixWhitelist: '邮箱域名白名单',
|
||||||
emailSuffixWhitelistHint:
|
emailSuffixWhitelistHint:
|
||||||
'仅允许使用指定域名的邮箱注册账号(例如 @qq.com, @gmail.com)',
|
"仅允许使用指定域名的邮箱注册账号(例如 {'@'}qq.com, {'@'}gmail.com)",
|
||||||
emailSuffixWhitelistPlaceholder: 'example.com',
|
emailSuffixWhitelistPlaceholder: 'example.com',
|
||||||
emailSuffixWhitelistInputHint: '留空则不限制',
|
emailSuffixWhitelistInputHint: '留空则不限制',
|
||||||
promoCode: '优惠码',
|
promoCode: '优惠码',
|
||||||
|
|||||||
@@ -8,6 +8,26 @@
|
|||||||
|
|
||||||
<!-- Settings Form -->
|
<!-- Settings Form -->
|
||||||
<form v-else @submit.prevent="saveSettings" class="space-y-6">
|
<form v-else @submit.prevent="saveSettings" class="space-y-6">
|
||||||
|
<!-- Tab Navigation -->
|
||||||
|
<div class="sticky top-0 z-10 overflow-x-auto scrollbar-hide">
|
||||||
|
<nav class="settings-tabs">
|
||||||
|
<button
|
||||||
|
v-for="tab in settingsTabs"
|
||||||
|
:key="tab.key"
|
||||||
|
type="button"
|
||||||
|
:class="['settings-tab', activeTab === tab.key && 'settings-tab-active']"
|
||||||
|
@click="activeTab = tab.key"
|
||||||
|
>
|
||||||
|
<span class="settings-tab-icon">
|
||||||
|
<Icon :name="tab.icon" size="sm" />
|
||||||
|
</span>
|
||||||
|
<span>{{ t(`admin.settings.tabs.${tab.key}`) }}</span>
|
||||||
|
</button>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Tab: Security — Admin API Key -->
|
||||||
|
<div v-show="activeTab === 'security'" class="space-y-6">
|
||||||
<!-- Admin API Key Settings -->
|
<!-- Admin API Key Settings -->
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="border-b border-gray-100 px-6 py-4 dark:border-dark-700">
|
<div class="border-b border-gray-100 px-6 py-4 dark:border-dark-700">
|
||||||
@@ -146,7 +166,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div><!-- /Tab: Security — Admin API Key -->
|
||||||
|
|
||||||
|
<!-- Tab: Gateway — Stream Timeout -->
|
||||||
|
<div v-show="activeTab === 'gateway'" class="space-y-6">
|
||||||
<!-- Stream Timeout Settings -->
|
<!-- Stream Timeout Settings -->
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="border-b border-gray-100 px-6 py-4 dark:border-dark-700">
|
<div class="border-b border-gray-100 px-6 py-4 dark:border-dark-700">
|
||||||
@@ -284,7 +307,10 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div><!-- /Tab: Gateway — Stream Timeout (continued below with Claude Code & Scheduling) -->
|
||||||
|
|
||||||
|
<!-- Tab: Security — Registration, Turnstile, LinuxDo -->
|
||||||
|
<div v-show="activeTab === 'security'" class="space-y-6">
|
||||||
<!-- Registration Settings -->
|
<!-- Registration Settings -->
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="border-b border-gray-100 px-6 py-4 dark:border-dark-700">
|
<div class="border-b border-gray-100 px-6 py-4 dark:border-dark-700">
|
||||||
@@ -618,7 +644,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div><!-- /Tab: Security — Registration, Turnstile, LinuxDo -->
|
||||||
|
|
||||||
|
<!-- Tab: Users -->
|
||||||
|
<div v-show="activeTab === 'users'" class="space-y-6">
|
||||||
<!-- Default Settings -->
|
<!-- Default Settings -->
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="border-b border-gray-100 px-6 py-4 dark:border-dark-700">
|
<div class="border-b border-gray-100 px-6 py-4 dark:border-dark-700">
|
||||||
@@ -757,7 +786,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div><!-- /Tab: Users -->
|
||||||
|
|
||||||
|
<!-- Tab: Gateway — Claude Code, Scheduling -->
|
||||||
|
<div v-show="activeTab === 'gateway'" class="space-y-6">
|
||||||
<!-- Claude Code Settings -->
|
<!-- Claude Code Settings -->
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="border-b border-gray-100 px-6 py-4 dark:border-dark-700">
|
<div class="border-b border-gray-100 px-6 py-4 dark:border-dark-700">
|
||||||
@@ -814,7 +846,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div><!-- /Tab: Gateway — Claude Code, Scheduling -->
|
||||||
|
|
||||||
|
<!-- Tab: General -->
|
||||||
|
<div v-show="activeTab === 'general'" class="space-y-6">
|
||||||
<!-- Site Settings -->
|
<!-- Site Settings -->
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="border-b border-gray-100 px-6 py-4 dark:border-dark-700">
|
<div class="border-b border-gray-100 px-6 py-4 dark:border-dark-700">
|
||||||
@@ -957,147 +992,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- SMTP Settings - Only show when email verification is enabled -->
|
|
||||||
<div v-if="form.email_verify_enabled" class="card">
|
|
||||||
<div
|
|
||||||
class="flex items-center justify-between border-b border-gray-100 px-6 py-4 dark:border-dark-700"
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">
|
|
||||||
{{ t('admin.settings.smtp.title') }}
|
|
||||||
</h2>
|
|
||||||
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
|
||||||
{{ t('admin.settings.smtp.description') }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
@click="testSmtpConnection"
|
|
||||||
:disabled="testingSmtp"
|
|
||||||
class="btn btn-secondary btn-sm"
|
|
||||||
>
|
|
||||||
<svg v-if="testingSmtp" class="h-4 w-4 animate-spin" fill="none" viewBox="0 0 24 24">
|
|
||||||
<circle
|
|
||||||
class="opacity-25"
|
|
||||||
cx="12"
|
|
||||||
cy="12"
|
|
||||||
r="10"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="4"
|
|
||||||
></circle>
|
|
||||||
<path
|
|
||||||
class="opacity-75"
|
|
||||||
fill="currentColor"
|
|
||||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
||||||
></path>
|
|
||||||
</svg>
|
|
||||||
{{
|
|
||||||
testingSmtp
|
|
||||||
? t('admin.settings.smtp.testing')
|
|
||||||
: t('admin.settings.smtp.testConnection')
|
|
||||||
}}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="space-y-6 p-6">
|
|
||||||
<div class="grid grid-cols-1 gap-6 md:grid-cols-2">
|
|
||||||
<div>
|
|
||||||
<label class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300">
|
|
||||||
{{ t('admin.settings.smtp.host') }}
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
v-model="form.smtp_host"
|
|
||||||
type="text"
|
|
||||||
class="input"
|
|
||||||
:placeholder="t('admin.settings.smtp.hostPlaceholder')"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300">
|
|
||||||
{{ t('admin.settings.smtp.port') }}
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
v-model.number="form.smtp_port"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
max="65535"
|
|
||||||
class="input"
|
|
||||||
:placeholder="t('admin.settings.smtp.portPlaceholder')"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300">
|
|
||||||
{{ t('admin.settings.smtp.username') }}
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
v-model="form.smtp_username"
|
|
||||||
type="text"
|
|
||||||
class="input"
|
|
||||||
:placeholder="t('admin.settings.smtp.usernamePlaceholder')"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300">
|
|
||||||
{{ t('admin.settings.smtp.password') }}
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
v-model="form.smtp_password"
|
|
||||||
type="password"
|
|
||||||
class="input"
|
|
||||||
:placeholder="
|
|
||||||
form.smtp_password_configured
|
|
||||||
? t('admin.settings.smtp.passwordConfiguredPlaceholder')
|
|
||||||
: t('admin.settings.smtp.passwordPlaceholder')
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
<p class="mt-1.5 text-xs text-gray-500 dark:text-gray-400">
|
|
||||||
{{
|
|
||||||
form.smtp_password_configured
|
|
||||||
? t('admin.settings.smtp.passwordConfiguredHint')
|
|
||||||
: t('admin.settings.smtp.passwordHint')
|
|
||||||
}}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300">
|
|
||||||
{{ t('admin.settings.smtp.fromEmail') }}
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
v-model="form.smtp_from_email"
|
|
||||||
type="email"
|
|
||||||
class="input"
|
|
||||||
:placeholder="t('admin.settings.smtp.fromEmailPlaceholder')"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300">
|
|
||||||
{{ t('admin.settings.smtp.fromName') }}
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
v-model="form.smtp_from_name"
|
|
||||||
type="text"
|
|
||||||
class="input"
|
|
||||||
:placeholder="t('admin.settings.smtp.fromNamePlaceholder')"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Use TLS Toggle -->
|
|
||||||
<div
|
|
||||||
class="flex items-center justify-between border-t border-gray-100 pt-4 dark:border-dark-700"
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<label class="font-medium text-gray-900 dark:text-white">{{
|
|
||||||
t('admin.settings.smtp.useTls')
|
|
||||||
}}</label>
|
|
||||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
|
||||||
{{ t('admin.settings.smtp.useTlsHint') }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<Toggle v-model="form.smtp_use_tls" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Purchase Subscription Page -->
|
<!-- Purchase Subscription Page -->
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="border-b border-gray-100 px-6 py-4 dark:border-dark-700">
|
<div class="border-b border-gray-100 px-6 py-4 dark:border-dark-700">
|
||||||
@@ -1309,6 +1203,168 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</div><!-- /Tab: General -->
|
||||||
|
|
||||||
|
<!-- Tab: Email -->
|
||||||
|
<div v-show="activeTab === 'email'" class="space-y-6">
|
||||||
|
<!-- Email disabled hint - show when email_verify_enabled is off -->
|
||||||
|
<div v-if="!form.email_verify_enabled" class="card">
|
||||||
|
<div class="p-6">
|
||||||
|
<div class="flex items-start gap-3">
|
||||||
|
<Icon name="mail" size="md" class="mt-0.5 flex-shrink-0 text-gray-400 dark:text-gray-500" />
|
||||||
|
<div>
|
||||||
|
<h3 class="font-medium text-gray-900 dark:text-white">
|
||||||
|
{{ t('admin.settings.emailTabDisabledTitle') }}
|
||||||
|
</h3>
|
||||||
|
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
||||||
|
{{ t('admin.settings.emailTabDisabledHint') }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- SMTP Settings - Only show when email verification is enabled -->
|
||||||
|
<div v-if="form.email_verify_enabled" class="card">
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-between border-b border-gray-100 px-6 py-4 dark:border-dark-700"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">
|
||||||
|
{{ t('admin.settings.smtp.title') }}
|
||||||
|
</h2>
|
||||||
|
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
||||||
|
{{ t('admin.settings.smtp.description') }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
@click="testSmtpConnection"
|
||||||
|
:disabled="testingSmtp"
|
||||||
|
class="btn btn-secondary btn-sm"
|
||||||
|
>
|
||||||
|
<svg v-if="testingSmtp" class="h-4 w-4 animate-spin" fill="none" viewBox="0 0 24 24">
|
||||||
|
<circle
|
||||||
|
class="opacity-25"
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="10"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="4"
|
||||||
|
></circle>
|
||||||
|
<path
|
||||||
|
class="opacity-75"
|
||||||
|
fill="currentColor"
|
||||||
|
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
{{
|
||||||
|
testingSmtp
|
||||||
|
? t('admin.settings.smtp.testing')
|
||||||
|
: t('admin.settings.smtp.testConnection')
|
||||||
|
}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-6 p-6">
|
||||||
|
<div class="grid grid-cols-1 gap-6 md:grid-cols-2">
|
||||||
|
<div>
|
||||||
|
<label class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||||
|
{{ t('admin.settings.smtp.host') }}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
v-model="form.smtp_host"
|
||||||
|
type="text"
|
||||||
|
class="input"
|
||||||
|
:placeholder="t('admin.settings.smtp.hostPlaceholder')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||||
|
{{ t('admin.settings.smtp.port') }}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
v-model.number="form.smtp_port"
|
||||||
|
type="number"
|
||||||
|
min="1"
|
||||||
|
max="65535"
|
||||||
|
class="input"
|
||||||
|
:placeholder="t('admin.settings.smtp.portPlaceholder')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||||
|
{{ t('admin.settings.smtp.username') }}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
v-model="form.smtp_username"
|
||||||
|
type="text"
|
||||||
|
class="input"
|
||||||
|
:placeholder="t('admin.settings.smtp.usernamePlaceholder')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||||
|
{{ t('admin.settings.smtp.password') }}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
v-model="form.smtp_password"
|
||||||
|
type="password"
|
||||||
|
class="input"
|
||||||
|
:placeholder="
|
||||||
|
form.smtp_password_configured
|
||||||
|
? t('admin.settings.smtp.passwordConfiguredPlaceholder')
|
||||||
|
: t('admin.settings.smtp.passwordPlaceholder')
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<p class="mt-1.5 text-xs text-gray-500 dark:text-gray-400">
|
||||||
|
{{
|
||||||
|
form.smtp_password_configured
|
||||||
|
? t('admin.settings.smtp.passwordConfiguredHint')
|
||||||
|
: t('admin.settings.smtp.passwordHint')
|
||||||
|
}}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||||
|
{{ t('admin.settings.smtp.fromEmail') }}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
v-model="form.smtp_from_email"
|
||||||
|
type="email"
|
||||||
|
class="input"
|
||||||
|
:placeholder="t('admin.settings.smtp.fromEmailPlaceholder')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||||
|
{{ t('admin.settings.smtp.fromName') }}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
v-model="form.smtp_from_name"
|
||||||
|
type="text"
|
||||||
|
class="input"
|
||||||
|
:placeholder="t('admin.settings.smtp.fromNamePlaceholder')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Use TLS Toggle -->
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-between border-t border-gray-100 pt-4 dark:border-dark-700"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<label class="font-medium text-gray-900 dark:text-white">{{
|
||||||
|
t('admin.settings.smtp.useTls')
|
||||||
|
}}</label>
|
||||||
|
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||||
|
{{ t('admin.settings.smtp.useTlsHint') }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Toggle v-model="form.smtp_use_tls" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Send Test Email - Only show when email verification is enabled -->
|
<!-- Send Test Email - Only show when email verification is enabled -->
|
||||||
<div v-if="form.email_verify_enabled" class="card">
|
<div v-if="form.email_verify_enabled" class="card">
|
||||||
<div class="border-b border-gray-100 px-6 py-4 dark:border-dark-700">
|
<div class="border-b border-gray-100 px-6 py-4 dark:border-dark-700">
|
||||||
@@ -1367,6 +1423,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div><!-- /Tab: Email -->
|
||||||
|
|
||||||
<!-- Save Button -->
|
<!-- Save Button -->
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
@@ -1424,6 +1481,16 @@ import {
|
|||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
const adminSettingsStore = useAdminSettingsStore()
|
const adminSettingsStore = useAdminSettingsStore()
|
||||||
|
|
||||||
|
type SettingsTab = 'general' | 'security' | 'users' | 'gateway' | 'email'
|
||||||
|
const activeTab = ref<SettingsTab>('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 { copyToClipboard } = useClipboard()
|
||||||
|
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
@@ -1975,4 +2042,56 @@ onMounted(() => {
|
|||||||
.default-sub-delete-btn {
|
.default-sub-delete-btn {
|
||||||
@apply h-[42px];
|
@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;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user