数据结构优化

This commit is contained in:
李琦
2026-01-20 08:31:42 +08:00
parent 41b2530510
commit adb1b8ca94
3 changed files with 133 additions and 76 deletions

View File

@@ -101,6 +101,14 @@
<!-- Right: Actions -->
<div class="flex items-center gap-3">
<button
@click="refreshCurrentPage"
class="p-2 text-art-muted hover:text-white hover:bg-white/5 rounded-full transition-colors"
title="刷新当前页面"
>
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"></polyline><polyline points="1 20 1 14 7 14"></polyline><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path></svg>
</button>
<button class="p-2 text-art-muted hover:text-white hover:bg-white/5 rounded-full transition-colors relative">
<span class="absolute top-2 right-2 w-2 h-2 bg-art-accent rounded-full border-2 border-art-admin-bg"></span>
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"></path><path d="M13.73 21a2 2 0 0 1-3.46 0"></path></svg>
@@ -174,6 +182,11 @@ const handleChangePassword = () => {
isUserDropdownOpen.value = false
}
const refreshCurrentPage = () => {
// 刷新当前路由页面,不刷新整个浏览器
router.replace(router.currentRoute.value.fullPath)
}
interface MenuItem {
title: string
icon: string

View File

@@ -2,69 +2,106 @@
<div class="w-full animate-reveal">
<div class="flex items-center justify-between mb-6">
<h1 class="text-2xl font-serif italic text-white">系统配置管理</h1>
<button @click="showAddModal = true" class="admin-btn-primary flex items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg>
新增配置
</button>
</div>
<!-- 基础配置 -->
<div class="admin-card overflow-hidden">
<div class="overflow-x-auto">
<table class="admin-table">
<thead>
<tr>
<th class="w-1/4">键名</th>
<th class="w-1/3"></th>
<th>描述</th>
<th class="text-right w-32">操作</th>
</tr>
</thead>
<tbody>
<tr v-for="setting in settings" :key="setting.id" class="group transition-colors duration-200">
<td class="font-mono text-xs text-art-accent">{{ setting.keyName }}</td>
<td class="max-w-xs truncate text-white/80" :title="setting.value">{{ setting.value }}</td>
<td class="text-art-muted text-sm">{{ setting.description }}</td>
<td class="text-right">
<div class="flex items-center justify-end gap-2 opacity-0 group-hover:opacity-100 transition-opacity duration-200">
<button @click="editSetting(setting)" class="admin-btn-secondary py-1 px-3 text-xs">
编辑
</button>
<button @click="deleteSetting(setting.keyName)" class="admin-btn-danger py-1 px-3 text-xs">
删除
</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- 配置表单 -->
<div class="admin-card p-6">
<div v-if="settings.length === 0" class="p-16 text-center">
<div class="w-16 h-16 bg-white/5 rounded-full flex items-center justify-center mx-auto mb-4 text-2xl"></div>
<h3 class="text-white font-medium mb-2">暂无配置</h3>
<button @click="showAddModal = true" class="admin-btn-primary mt-4">添加第一个配置</button>
</div>
<form v-else @submit.prevent="saveAllSettings" class="space-y-6">
<div
v-for="(setting, index) in settings"
:key="setting.id"
class="p-4 border border-white/5 rounded-lg bg-white/2 hover:bg-white/5 transition-colors"
>
<div class="grid grid-cols-1 md:grid-cols-12 gap-4 items-start">
<!-- 键名只读 -->
<div class="md:col-span-3 space-y-2">
<label class="block text-xs font-medium text-art-muted uppercase tracking-wider">键名</label>
<input
type="text"
:value="setting.keyName"
disabled
class="admin-input font-mono disabled:opacity-50 disabled:cursor-not-allowed bg-white/5"
>
</div>
<!-- 可编辑 -->
<div class="md:col-span-4 space-y-2">
<label class="block text-xs font-medium text-art-muted uppercase tracking-wider"></label>
<input
type="text"
v-model="setting.value"
class="admin-input"
placeholder="配置项的值"
>
</div>
<!-- 描述可编辑 -->
<div class="md:col-span-4 space-y-2">
<label class="block text-xs font-medium text-art-muted uppercase tracking-wider">描述</label>
<textarea
v-model="setting.description"
rows="2"
class="admin-input resize-none"
placeholder="该配置项的用途说明"
></textarea>
</div>
<!-- 删除按钮 -->
<div class="md:col-span-1 space-y-2 flex items-end">
<button
type="button"
@click="deleteSetting(setting.keyName)"
class="admin-btn-danger py-2 px-3 text-xs w-full"
title="删除配置"
>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path></svg>
</button>
</div>
</div>
</div>
<!-- 保存按钮 -->
<div class="pt-4 flex justify-end gap-3 border-t border-white/5">
<button type="button" @click="fetchSettings" class="admin-btn-secondary">重置</button>
<button type="submit" class="admin-btn-primary" :disabled="isSaving">
{{ isSaving ? '保存中...' : '保存所有配置' }}
</button>
</div>
</form>
</div>
<!-- Add/Edit Modal -->
<div v-if="showModal" class="fixed inset-0 z-50 flex items-center justify-center p-4">
<div class="absolute inset-0 bg-black/80 backdrop-blur-sm transition-opacity" @click="closeModal"></div>
<!-- 新增配置 Modal -->
<div v-if="showAddModal" class="fixed inset-0 z-50 flex items-center justify-center p-4">
<div class="absolute inset-0 bg-black/80 backdrop-blur-sm transition-opacity" @click="closeAddModal"></div>
<div class="admin-card w-full max-w-lg relative z-10 flex flex-col max-h-[90vh] shadow-2xl animate-reveal">
<div class="flex items-center justify-between p-6 border-b border-white/5">
<h2 class="text-lg font-medium text-white">{{ editingSetting ? '编辑配置' : '新增配置' }}</h2>
<button @click="closeModal" class="text-white/40 hover:text-white transition-colors">
<h2 class="text-lg font-medium text-white">新增配置</h2>
<button @click="closeAddModal" class="text-white/40 hover:text-white transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
</button>
</div>
<div class="p-6 overflow-y-auto">
<form @submit.prevent="saveSetting" class="space-y-4">
<form @submit.prevent="saveNewSetting" class="space-y-4">
<div class="space-y-2">
<label for="keyName" class="block text-xs font-medium text-art-muted uppercase tracking-wider">键名</label>
<input
type="text"
id="keyName"
v-model="form.keyName"
:disabled="editingSetting"
v-model="newForm.keyName"
required
class="admin-input font-mono disabled:opacity-50 disabled:cursor-not-allowed"
class="admin-input font-mono"
placeholder="例如: site_title"
>
</div>
@@ -74,7 +111,7 @@
<input
type="text"
id="value"
v-model="form.value"
v-model="newForm.value"
required
class="admin-input"
placeholder="配置项的值"
@@ -85,7 +122,7 @@
<label for="description" class="block text-xs font-medium text-art-muted uppercase tracking-wider">描述</label>
<textarea
id="description"
v-model="form.description"
v-model="newForm.description"
rows="3"
class="admin-input resize-none"
placeholder="该配置项的用途说明"
@@ -93,7 +130,7 @@
</div>
<div class="pt-4 flex justify-end gap-3">
<button type="button" @click="closeModal" class="admin-btn-secondary">取消</button>
<button type="button" @click="closeAddModal" class="admin-btn-secondary">取消</button>
<button type="submit" class="admin-btn-primary">保存</button>
</div>
</form>
@@ -110,11 +147,10 @@ import { useToast } from '../../composables/useToast'
const toast = useToast()
const settings = ref<Setting[]>([])
const showModal = ref(false)
const editingSetting = ref(false)
const showAddModal = ref(false)
const isSaving = ref(false)
const form = ref({
id: 0,
const newForm = ref({
keyName: '',
value: '',
description: ''
@@ -129,35 +165,44 @@ const fetchSettings = async () => {
}
}
const editSetting = (setting: Setting) => {
editingSetting.value = true
form.value = {
id: setting.id,
keyName: setting.keyName,
value: setting.value,
description: setting.description
const saveAllSettings = async () => {
isSaving.value = true
try {
// 批量更新所有配置项
const updatePromises = settings.value.map(setting =>
updateSetting({
id: setting.id,
keyName: setting.keyName,
value: setting.value,
description: setting.description
})
)
await Promise.all(updatePromises)
toast.showToast('所有配置保存成功', 'success')
// 重新获取配置以确保数据同步
await fetchSettings()
} catch (error) {
console.error('Error saving settings:', error)
toast.showToast('保存配置失败', 'error')
} finally {
isSaving.value = false
}
showModal.value = true
}
const saveSetting = async () => {
const saveNewSetting = async () => {
try {
if (editingSetting.value) {
await updateSetting(form.value)
toast.showToast('配置更新成功', 'success')
} else {
await createSetting({
keyName: form.value.keyName,
value: form.value.value,
description: form.value.description
})
toast.showToast('配置创建成功', 'success')
}
closeModal()
await createSetting({
keyName: newForm.value.keyName,
value: newForm.value.value,
description: newForm.value.description
})
toast.showToast('配置创建成功', 'success')
closeAddModal()
fetchSettings()
} catch (error) {
console.error('Error saving setting:', error)
toast.showToast(editingSetting.value ? '更新配置失败' : '创建配置失败', 'error')
console.error('Error creating setting:', error)
toast.showToast('创建配置失败', 'error')
}
}
@@ -174,11 +219,9 @@ const deleteSetting = async (keyName: string) => {
}
}
const closeModal = () => {
showModal.value = false
editingSetting.value = false
form.value = {
id: 0,
const closeAddModal = () => {
showAddModal.value = false
newForm.value = {
keyName: '',
value: '',
description: ''