feat: improve system settings save workflow

This commit is contained in:
Lan
2026-06-03 03:13:04 +08:00
parent c1d882a7c0
commit 91ba43d847
4 changed files with 413 additions and 141 deletions
+318 -104
View File
@@ -1,6 +1,8 @@
<script setup lang="ts">
import { inject, onMounted } from 'vue'
import { useI18n } from 'vue-i18n'
import { RefreshCwIcon, SaveIcon } from 'lucide-vue-next'
import BaseButton from '@/components/common/BaseButton.vue'
import SettingNumberInput from '@/components/common/SettingNumberInput.vue'
import SettingSwitch from '@/components/common/SettingSwitch.vue'
import { useSystemConfig } from '@/composables'
@@ -9,6 +11,9 @@ const isDarkMode = inject('isDarkMode')
const { t } = useI18n()
const {
config,
isRefreshing,
isSaving,
isDirty,
fileSize,
sizeUnit,
saveTime,
@@ -25,11 +30,61 @@ onMounted(() => {
<template>
<div class="p-6 h-screen overflow-y-auto custom-scrollbar">
<h2 class="text-2xl font-bold mb-6" :class="[isDarkMode ? 'text-white' : 'text-gray-800']">
{{ t('admin.settings.title') }}
</h2>
<div
class="sticky top-0 z-20 -mx-6 -mt-6 mb-6 border-b px-6 py-4 backdrop-blur"
:class="[isDarkMode ? 'border-gray-700 bg-gray-900/85' : 'border-gray-200 bg-gray-50/90']"
>
<div class="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
<div>
<h2 class="text-2xl font-bold" :class="[isDarkMode ? 'text-white' : 'text-gray-800']">
{{ t('admin.settings.title') }}
</h2>
<p
class="mt-1 text-sm"
:class="[isDirty ? 'text-amber-500' : isDarkMode ? 'text-gray-400' : 'text-gray-500']"
>
{{
isDirty ? t('manage.settings.unsavedChanges') : t('manage.settings.allChangesSaved')
}}
</p>
</div>
<div class="space-y-6 rounded-lg shadow-md p-6" :class="[isDarkMode ? 'bg-gray-800 bg-opacity-70' : 'bg-white']">
<div class="flex flex-wrap items-center gap-3">
<BaseButton
variant="secondary"
:loading="isRefreshing"
:disabled="isSaving || isDirty"
:title="
isDirty ? t('manage.settings.refreshBlocked') : t('manage.settings.refreshConfig')
"
@click="refreshConfig"
>
<template #icon>
<RefreshCwIcon class="mr-2 h-4 w-4" />
</template>
{{
isRefreshing ? t('manage.settings.refreshing') : t('manage.settings.refreshConfig')
}}
</BaseButton>
<BaseButton
:loading="isSaving"
:disabled="!isDirty || isRefreshing"
@click="submitConfig"
>
<template #icon>
<SaveIcon class="mr-2 h-4 w-4" />
</template>
{{ isSaving ? t('manage.settings.saving') : t('manage.settings.saveChanges') }}
</BaseButton>
</div>
</div>
</div>
<div
class="space-y-6 rounded-lg shadow-md p-6"
:class="[isDarkMode ? 'bg-gray-800 bg-opacity-70' : 'bg-white']"
>
<!-- 基本设置 -->
<section class="space-y-4">
<h3 class="text-lg font-medium mb-4" :class="[isDarkMode ? 'text-white' : 'text-gray-800']">
@@ -39,158 +94,226 @@ onMounted(() => {
<!-- 网基本信息 -->
<div class="grid grid-cols-1 gap-6">
<div class="space-y-2">
<label class="block text-sm font-medium" :class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']">
<label
class="block text-sm font-medium"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
{{ t('admin.settings.siteName') }}
</label>
<input type="text" v-model="config.name"
<input
type="text"
v-model="config.name"
class="w-full rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white placeholder-gray-400 hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400 placeholder-gray-500'
]" />
]"
/>
</div>
<div class="space-y-2">
<label class="block text-sm font-medium" :class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']">
<label
class="block text-sm font-medium"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
{{ t('admin.settings.websiteDescription') }}
</label>
<input type="text" v-model="config.description"
<input
type="text"
v-model="config.description"
class="w-full rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white placeholder-gray-400 hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400 placeholder-gray-500'
]" />
]"
/>
</div>
<div class="space-y-2">
<label class="block text-sm font-medium" :class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']">
<label
class="block text-sm font-medium"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
{{ t('admin.settings.adminPassword') }}
</label>
<div class="relative">
<input type="password" minlength="6" v-model="config.admin_token" :placeholder="t('admin.settings.passwordPlaceholder')"
<input
type="password"
minlength="6"
v-model="config.admin_token"
:placeholder="t('admin.settings.passwordPlaceholder')"
class="w-full rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white placeholder-gray-400 hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400 placeholder-gray-500'
]" />
<div class="absolute inset-y-0 right-0 flex items-center pr-3 text-sm text-gray-400"
:class="[isDarkMode ? 'text-gray-500' : 'text-gray-400']">
]"
/>
<div
class="absolute inset-y-0 right-0 flex items-center pr-3 text-sm text-gray-400"
:class="[isDarkMode ? 'text-gray-500' : 'text-gray-400']"
>
<span class="text-xs">{{ t('admin.settings.passwordNote') }}</span>
</div>
</div>
</div>
<div class="space-y-2">
<label class="block text-sm font-medium" :class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']">
<label
class="block text-sm font-medium"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
{{ t('admin.settings.keywords') }}
</label>
<input type="text" v-model="config.keywords"
<input
type="text"
v-model="config.keywords"
class="w-full rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white placeholder-gray-400 hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400 placeholder-gray-500'
]" />
]"
/>
</div>
<!-- 主题选择 -->
<div class="space-y-2">
<label class="block text-sm font-medium" :class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']">
<label
class="block text-sm font-medium"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
{{ t('manage.settings.themeSelection') }}
</label>
<select v-model="config.themesSelect"
<select
v-model="config.themesSelect"
class="w-full rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border appearance-none bg-no-repeat bg-right focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none cursor-pointer"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400'
]" style="
]"
style="
background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2220%22%20height%3D%2220%22%20viewBox%3D%220%200%2020%2020%22%20fill%3D%22none%22%3E%3Cpath%20d%3D%22M7%208l3%203%203-3%22%20stroke%3D%22%236B7280%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fsvg%3E');
">
"
>
<option v-for="item in config.themesChoices" :value="item.key" :key="item.key">
{{ item.name }} (by {{ item.author }} V{{ item.version }})
</option>
</select>
</div>
<div class="space-y-2">
<label class="block text-sm font-medium" :class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']">
<label
class="block text-sm font-medium"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
{{ t('manage.settings.robotsFile') }}
</label>
<textarea v-model="config.robotsText" rows="3"
<textarea
v-model="config.robotsText"
rows="3"
class="w-full rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border resize-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white placeholder-gray-400 hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400 placeholder-gray-500'
]"></textarea>
]"
></textarea>
</div>
</div>
<!-- 通知设置 -->
<div class="grid grid-cols-1 gap-6 mt-8">
<div class="space-y-2">
<label class="block text-sm font-medium" :class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']">
<label
class="block text-sm font-medium"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
{{ t('manage.settings.notificationTitle') }}
</label>
<input type="text" v-model="config.notify_title"
<input
type="text"
v-model="config.notify_title"
class="w-full rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white placeholder-gray-400 hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400 placeholder-gray-500'
]" />
]"
/>
</div>
<div class="space-y-2">
<label class="block text-sm font-medium" :class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']">
<label
class="block text-sm font-medium"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
{{ t('manage.settings.notificationContent') }}
</label>
<textarea v-model="config.notify_content" rows="3"
<textarea
v-model="config.notify_content"
rows="3"
class="w-full rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border resize-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white placeholder-gray-400 hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400 placeholder-gray-500'
]"></textarea>
]"
></textarea>
</div>
</div>
<!-- 存储设置 -->
<div class="space-y-4">
<h3 class="text-lg font-medium mb-4" :class="[isDarkMode ? 'text-white' : 'text-gray-800']">
<h3
class="text-lg font-medium mb-4"
:class="[isDarkMode ? 'text-white' : 'text-gray-800']"
>
{{ t('manage.settings.storageSettings') }}
</h3>
<!-- 通知设置 -->
<div class="space-y-2">
<label class="block text-sm font-medium" :class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']">
<label
class="block text-sm font-medium"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
{{ t('manage.settings.storagePath') }}
</label>
<input type="text" :placeholder="t('manage.settings.storagePathPlaceholder')" v-model="config.storage_path"
<input
type="text"
:placeholder="t('manage.settings.storagePathPlaceholder')"
v-model="config.storage_path"
class="w-full rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white placeholder-gray-400 hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400 placeholder-gray-500'
]" />
]"
/>
</div>
<div class="space-y-4">
<div class="space-y-2">
<label class="block text-sm font-medium" :class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']">
<label
class="block text-sm font-medium"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
{{ t('manage.settings.storageMethod') }}
</label>
<select v-model="config.file_storage"
<select
v-model="config.file_storage"
class="w-full rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border appearance-none bg-no-repeat bg-right focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none cursor-pointer"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400'
]" style="
]"
style="
background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2220%22%20height%3D%2220%22%20viewBox%3D%220%200%2020%2020%22%20fill%3D%22none%22%3E%3Cpath%20d%3D%22M7%208l3%203%203-3%22%20stroke%3D%22%236B7280%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fsvg%3E');
">
"
>
<option value="local">{{ t('manage.settings.localStorage') }}</option>
<option value="s3">{{ t('manage.settings.s3Storage') }}</option>
<option value="webdav">{{ t('manage.settings.webdavStorage') }}</option>
@@ -207,42 +330,63 @@ onMounted(() => {
<div v-if="config.file_storage === 'webdav'" class="space-y-4">
<!-- 通知设置 -->
<div class="space-y-2">
<label class="block text-sm font-medium" :class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']">
<label
class="block text-sm font-medium"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
Webdav URL
</label>
<input type="text" :placeholder="t('manage.settings.webdavUrlPlaceholder')" v-model="config.webdav_url"
<input
type="text"
:placeholder="t('manage.settings.webdavUrlPlaceholder')"
v-model="config.webdav_url"
class="w-full rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white placeholder-gray-400 hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400 placeholder-gray-500'
]" />
]"
/>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="space-y-2">
<label class="block text-sm font-medium" :class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']">
<label
class="block text-sm font-medium"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
Webdav Username
</label>
<input type="text" :placeholder="t('manage.settings.webdavUsernamePlaceholder')" v-model="config.webdav_username"
<input
type="text"
:placeholder="t('manage.settings.webdavUsernamePlaceholder')"
v-model="config.webdav_username"
class="w-full rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white placeholder-gray-400 hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400 placeholder-gray-500'
]" />
]"
/>
</div>
<div class="space-y-2">
<label class="block text-sm font-medium" :class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']">
<label
class="block text-sm font-medium"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
Webdav Password
</label>
<input type="password" :placeholder="t('manage.settings.webdavPasswordPlaceholder')" v-model="config.webdav_password"
<input
type="password"
:placeholder="t('manage.settings.webdavPasswordPlaceholder')"
v-model="config.webdav_password"
class="w-full rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white placeholder-gray-400 hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400 placeholder-gray-500'
]" />
]"
/>
</div>
</div>
</div>
@@ -250,97 +394,139 @@ onMounted(() => {
<div v-if="config.file_storage === 's3'" class="space-y-4">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="space-y-2">
<label class="block text-sm font-medium" :class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']">
<label
class="block text-sm font-medium"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
{{ t('manage.settings.s3AccessKeyId') }}
</label>
<input type="text" v-model="config.s3_access_key_id"
<input
type="text"
v-model="config.s3_access_key_id"
class="w-full rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white placeholder-gray-400 hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400 placeholder-gray-500'
]" />
]"
/>
</div>
<div class="space-y-2">
<label class="block text-sm font-medium" :class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']">
<label
class="block text-sm font-medium"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
{{ t('manage.settings.s3SecretAccessKey') }}
</label>
<input type="password" v-model="config.s3_secret_access_key"
<input
type="password"
v-model="config.s3_secret_access_key"
class="w-full rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white placeholder-gray-400 hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400 placeholder-gray-500'
]" />
]"
/>
</div>
<div class="space-y-2">
<label class="block text-sm font-medium" :class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']">
<label
class="block text-sm font-medium"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
{{ t('manage.settings.s3BucketName') }}
</label>
<input type="text" v-model="config.s3_bucket_name"
<input
type="text"
v-model="config.s3_bucket_name"
class="w-full rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white placeholder-gray-400 hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400 placeholder-gray-500'
]" />
]"
/>
</div>
<div class="space-y-2">
<label class="block text-sm font-medium" :class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']">
<label
class="block text-sm font-medium"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
{{ t('manage.settings.s3EndpointUrl') }}
</label>
<input type="text" v-model="config.s3_endpoint_url"
<input
type="text"
v-model="config.s3_endpoint_url"
class="w-full rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white placeholder-gray-400 hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400 placeholder-gray-500'
]" />
]"
/>
</div>
<div class="space-y-2">
<label class="block text-sm font-medium" :class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']">
<label
class="block text-sm font-medium"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
{{ t('manage.settings.s3RegionName') }}
</label>
<input type="text" v-model="config.s3_region_name" :placeholder="t('manage.settings.autoPlaceholder')"
<input
type="text"
v-model="config.s3_region_name"
:placeholder="t('manage.settings.autoPlaceholder')"
class="w-full rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white placeholder-gray-400 hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400 placeholder-gray-500'
]" />
]"
/>
</div>
<div class="space-y-2">
<label class="block text-sm font-medium" :class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']">
<label
class="block text-sm font-medium"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
{{ t('manage.settings.s3SignatureVersion') }}
</label>
<select v-model="config.s3_signature_version"
<select
v-model="config.s3_signature_version"
class="w-full rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400'
]">
]"
>
<option value="s3v2">{{ t('manage.settings.s3v2') }}</option>
<option value="s3v4">{{ t('manage.settings.s3v4') }}</option>
</select>
</div>
<div class="space-y-2">
<label class="block text-sm font-medium" :class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']">
<label
class="block text-sm font-medium"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
{{ t('manage.settings.s3Hostname') }}
</label>
<input type="text" v-model="config.s3_hostname"
<input
type="text"
v-model="config.s3_hostname"
class="w-full rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white placeholder-gray-400 hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400 placeholder-gray-500'
]" />
]"
/>
</div>
<SettingSwitch
@@ -365,7 +551,10 @@ onMounted(() => {
<!-- 上传限制 -->
<div class="mt-8">
<h3 class="text-lg font-medium mb-4" :class="[isDarkMode ? 'text-white' : 'text-gray-800']">
<h3
class="text-lg font-medium mb-4"
:class="[isDarkMode ? 'text-white' : 'text-gray-800']"
>
{{ t('manage.settings.uploadLimits') }}
</h3>
@@ -383,48 +572,70 @@ onMounted(() => {
/>
<div class="space-y-2">
<label class="block text-sm font-medium" :class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']">
<label
class="block text-sm font-medium"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
{{ t('manage.settings.fileSizeLimit') }}
</label>
<div class="flex items-center space-x-2">
<input type="number" v-model="fileSize"
<input
type="number"
v-model="fileSize"
class="w-24 rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white placeholder-gray-400 hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400 placeholder-gray-500'
]" />
<select v-model="sizeUnit"
]"
/>
<select
v-model="sizeUnit"
class="rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400'
]">
]"
>
<option value="KB">{{ t('manage.settings.fileSizeUnits.kb') }}</option>
<option value="MB">{{ t('manage.settings.fileSizeUnits.mb') }}</option>
<option value="GB">{{ t('manage.settings.fileSizeUnits.gb') }}</option>
<option value="MB">{{ t('manage.settings.fileSizeUnits.mb') }}</option>
<option value="GB">{{ t('manage.settings.fileSizeUnits.gb') }}</option>
</select>
</div>
</div>
<div class="space-y-2">
<label class="block text-sm font-medium mb-2" :class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']">
<label
class="block text-sm font-medium mb-2"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
{{ t('manage.settings.expirationType') }}
</label>
<div class="flex flex-wrap gap-3">
<label v-for="style in ['day', 'hour', 'minute', 'forever', 'count']" :key="style"
class="relative inline-flex items-center group cursor-pointer">
<input type="checkbox" :value="style" v-model="config.expireStyle" class="peer sr-only" />
<div class="px-4 py-2 rounded-full border-2 transition-all duration-200 select-none" :class="[
config.expireStyle.includes(style)
? isDarkMode
? 'bg-indigo-600 border-indigo-600 text-white'
: 'bg-indigo-600 border-indigo-600 text-white'
: isDarkMode
? 'bg-gray-700 border-gray-600 text-gray-300 hover:border-indigo-500'
: 'bg-white border-gray-300 text-gray-700 hover:border-indigo-500'
]">
<label
v-for="style in ['day', 'hour', 'minute', 'forever', 'count']"
:key="style"
class="relative inline-flex items-center group cursor-pointer"
>
<input
type="checkbox"
:value="style"
v-model="config.expireStyle"
class="peer sr-only"
/>
<div
class="px-4 py-2 rounded-full border-2 transition-all duration-200 select-none"
:class="[
config.expireStyle.includes(style)
? isDarkMode
? 'bg-indigo-600 border-indigo-600 text-white'
: 'bg-indigo-600 border-indigo-600 text-white'
: isDarkMode
? 'bg-gray-700 border-gray-600 text-gray-300 hover:border-indigo-500'
: 'bg-white border-gray-300 text-gray-700 hover:border-indigo-500'
]"
>
{{ t(`manage.settings.expiration.${style}`) }}
</div>
</label>
@@ -432,24 +643,32 @@ onMounted(() => {
</div>
<div class="space-y-2">
<label class="block text-sm font-medium" :class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']">
<label
class="block text-sm font-medium"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
{{ t('manage.settings.maxSaveTime') }}
</label>
<div class="flex items-center space-x-2">
<input type="number" v-model="saveTime"
<input
type="number"
v-model="saveTime"
class="w-24 rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white placeholder-gray-400 hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400 placeholder-gray-500'
]" />
<select v-model="saveTimeUnit"
]"
/>
<select
v-model="saveTimeUnit"
class="rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400'
]">
]"
>
<option value="秒">{{ t('common.second') }}</option>
<option value="分">{{ t('common.minute') }}</option>
<option value="时">{{ t('common.hour') }}</option>
@@ -470,7 +689,10 @@ onMounted(() => {
<!-- 错误限制 -->
<div class="mt-8">
<h3 class="text-lg font-medium mb-4" :class="[isDarkMode ? 'text-white' : 'text-gray-800']">
<h3
class="text-lg font-medium mb-4"
:class="[isDarkMode ? 'text-white' : 'text-gray-800']"
>
{{ t('manage.settings.errorLimits') }}
</h3>
@@ -488,14 +710,6 @@ onMounted(() => {
/>
</div>
</div>
<!-- 保存按钮 -->
<div class="flex justify-end mt-8">
<button @click="submitConfig"
class="px-4 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 transition-colors duration-200">
{{ t('manage.settings.saveChanges') }}
</button>
</div>
</section>
</div>
</div>