2026-01-15 13:51:44 +08:00
|
|
|
|
<template>
|
2026-01-16 11:06:59 +08:00
|
|
|
|
<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>
|
2026-01-15 13:51:44 +08:00
|
|
|
|
</div>
|
2026-01-19 16:14:08 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- Tab切换 -->
|
|
|
|
|
|
<div class="mb-6 border-b border-white/10">
|
|
|
|
|
|
<div class="flex gap-4">
|
|
|
|
|
|
<button
|
|
|
|
|
|
@click="activeTab = 'settings'"
|
|
|
|
|
|
:class="[
|
|
|
|
|
|
'px-4 py-2 text-sm font-medium transition-colors border-b-2',
|
|
|
|
|
|
activeTab === 'settings'
|
|
|
|
|
|
? 'text-art-accent border-art-accent'
|
|
|
|
|
|
: 'text-art-muted border-transparent hover:text-white'
|
|
|
|
|
|
]"
|
|
|
|
|
|
>
|
|
|
|
|
|
基础配置
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button
|
|
|
|
|
|
@click="activeTab = 'oss'"
|
|
|
|
|
|
:class="[
|
|
|
|
|
|
'px-4 py-2 text-sm font-medium transition-colors border-b-2',
|
|
|
|
|
|
activeTab === 'oss'
|
|
|
|
|
|
? 'text-art-accent border-art-accent'
|
|
|
|
|
|
: 'text-art-muted border-transparent hover:text-white'
|
|
|
|
|
|
]"
|
|
|
|
|
|
>
|
|
|
|
|
|
OSS配置
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 基础配置Tab -->
|
|
|
|
|
|
<div v-if="activeTab === 'settings'">
|
2026-01-15 13:51:44 +08:00
|
|
|
|
|
2026-01-16 11:06:59 +08:00
|
|
|
|
<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 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>
|
|
|
|
|
|
</div>
|
2026-01-15 13:51:44 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Add/Edit Modal -->
|
2026-01-16 11:06:59 +08:00
|
|
|
|
<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>
|
|
|
|
|
|
|
|
|
|
|
|
<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">
|
|
|
|
|
|
<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>
|
2026-01-15 13:51:44 +08:00
|
|
|
|
</div>
|
2026-01-16 11:06:59 +08:00
|
|
|
|
|
|
|
|
|
|
<div class="p-6 overflow-y-auto">
|
|
|
|
|
|
<form @submit.prevent="saveSetting" 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>
|
2026-01-15 13:51:44 +08:00
|
|
|
|
<input
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
id="keyName"
|
|
|
|
|
|
v-model="form.keyName"
|
|
|
|
|
|
:disabled="editingSetting"
|
|
|
|
|
|
required
|
2026-01-16 11:06:59 +08:00
|
|
|
|
class="admin-input font-mono disabled:opacity-50 disabled:cursor-not-allowed"
|
|
|
|
|
|
placeholder="例如: site_title"
|
2026-01-15 13:51:44 +08:00
|
|
|
|
>
|
|
|
|
|
|
</div>
|
2026-01-16 11:06:59 +08:00
|
|
|
|
|
|
|
|
|
|
<div class="space-y-2">
|
|
|
|
|
|
<label for="value" class="block text-xs font-medium text-art-muted uppercase tracking-wider">值</label>
|
2026-01-15 13:51:44 +08:00
|
|
|
|
<input
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
id="value"
|
|
|
|
|
|
v-model="form.value"
|
|
|
|
|
|
required
|
2026-01-16 11:06:59 +08:00
|
|
|
|
class="admin-input"
|
|
|
|
|
|
placeholder="配置项的值"
|
2026-01-15 13:51:44 +08:00
|
|
|
|
>
|
|
|
|
|
|
</div>
|
2026-01-16 11:06:59 +08:00
|
|
|
|
|
|
|
|
|
|
<div class="space-y-2">
|
|
|
|
|
|
<label for="description" class="block text-xs font-medium text-art-muted uppercase tracking-wider">描述</label>
|
2026-01-15 13:51:44 +08:00
|
|
|
|
<textarea
|
|
|
|
|
|
id="description"
|
|
|
|
|
|
v-model="form.description"
|
|
|
|
|
|
rows="3"
|
2026-01-16 11:06:59 +08:00
|
|
|
|
class="admin-input resize-none"
|
|
|
|
|
|
placeholder="该配置项的用途说明"
|
2026-01-15 13:51:44 +08:00
|
|
|
|
></textarea>
|
|
|
|
|
|
</div>
|
2026-01-16 11:06:59 +08:00
|
|
|
|
|
|
|
|
|
|
<div class="pt-4 flex justify-end gap-3">
|
|
|
|
|
|
<button type="button" @click="closeModal" class="admin-btn-secondary">取消</button>
|
|
|
|
|
|
<button type="submit" class="admin-btn-primary">保存</button>
|
2026-01-15 13:51:44 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-01-19 16:14:08 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- OSS配置Tab -->
|
|
|
|
|
|
<div v-if="activeTab === 'oss'">
|
|
|
|
|
|
<div class="flex items-center justify-between mb-6">
|
|
|
|
|
|
<h2 class="text-xl font-medium text-white">OSS存储配置</h2>
|
|
|
|
|
|
<button @click="openOSSModal" class="admin-btn-primary">
|
|
|
|
|
|
+ 新增OSS配置
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="admin-card overflow-hidden">
|
|
|
|
|
|
<div class="overflow-x-auto">
|
|
|
|
|
|
<table class="admin-table">
|
|
|
|
|
|
<thead>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<th class="w-1/6">名称</th>
|
|
|
|
|
|
<th class="w-1/6">存储类型</th>
|
|
|
|
|
|
<th class="w-1/6">Bucket</th>
|
|
|
|
|
|
<th class="w-1/6">区域</th>
|
|
|
|
|
|
<th class="w-1/6">域名</th>
|
|
|
|
|
|
<th class="w-1/12">状态</th>
|
|
|
|
|
|
<th class="text-right w-32">操作</th>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</thead>
|
|
|
|
|
|
<tbody>
|
|
|
|
|
|
<tr v-for="config in ossConfigs" :key="config.id" class="group transition-colors duration-200">
|
|
|
|
|
|
<td class="font-medium text-white">{{ config.name }}</td>
|
|
|
|
|
|
<td class="text-art-muted">
|
|
|
|
|
|
<span class="px-2 py-1 text-xs rounded bg-white/5">
|
|
|
|
|
|
{{ getStorageTypeLabel(config.storageType) }}
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
<td class="text-art-muted text-sm">{{ config.bucket || '-' }}</td>
|
|
|
|
|
|
<td class="text-art-muted text-sm">{{ config.region || '-' }}</td>
|
|
|
|
|
|
<td class="text-art-muted text-sm max-w-xs truncate" :title="config.domain">{{ config.domain || '-' }}</td>
|
|
|
|
|
|
<td>
|
|
|
|
|
|
<span
|
|
|
|
|
|
:class="[
|
|
|
|
|
|
'px-2 py-1 text-xs rounded',
|
|
|
|
|
|
config.isActive === 1
|
|
|
|
|
|
? 'bg-green-500/20 text-green-400'
|
|
|
|
|
|
: 'bg-white/5 text-art-muted'
|
|
|
|
|
|
]"
|
|
|
|
|
|
>
|
|
|
|
|
|
{{ config.isActive === 1 ? '已启用' : '已停用' }}
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</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="editOSSConfig(config)" class="admin-btn-secondary py-1 px-3 text-xs">
|
|
|
|
|
|
编辑
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button @click="deleteOSSConfig(config.id)" class="admin-btn-danger py-1 px-3 text-xs">
|
|
|
|
|
|
删除
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div v-if="ossConfigs.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">暂无OSS配置</h3>
|
|
|
|
|
|
<p class="text-art-muted text-sm mb-4">点击上方按钮添加OSS配置</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- OSS配置编辑Modal -->
|
|
|
|
|
|
<div v-if="showOSSModal" 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="closeOSSModal"></div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="admin-card w-full max-w-2xl 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">{{ editingOSSConfig ? '编辑OSS配置' : '新增OSS配置' }}</h2>
|
|
|
|
|
|
<button @click="closeOSSModal" 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="saveOSSConfig" class="space-y-4">
|
|
|
|
|
|
<div class="space-y-2">
|
|
|
|
|
|
<label for="ossName" class="block text-xs font-medium text-art-muted uppercase tracking-wider">配置名称</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
id="ossName"
|
|
|
|
|
|
v-model="ossForm.name"
|
|
|
|
|
|
required
|
|
|
|
|
|
class="admin-input"
|
|
|
|
|
|
placeholder="例如: 腾讯云CDN"
|
|
|
|
|
|
>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="space-y-2">
|
|
|
|
|
|
<label for="storageType" class="block text-xs font-medium text-art-muted uppercase tracking-wider">存储类型</label>
|
|
|
|
|
|
<CustomSelect
|
|
|
|
|
|
v-model="ossForm.storageType"
|
|
|
|
|
|
:options="storageTypeOptions"
|
|
|
|
|
|
placeholder="选择存储类型"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="space-y-2">
|
|
|
|
|
|
<label for="accessKey" class="block text-xs font-medium text-art-muted uppercase tracking-wider">Access Key</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
id="accessKey"
|
|
|
|
|
|
v-model="ossForm.accessKey"
|
|
|
|
|
|
required
|
|
|
|
|
|
class="admin-input font-mono"
|
|
|
|
|
|
placeholder="访问密钥ID"
|
|
|
|
|
|
>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="space-y-2">
|
|
|
|
|
|
<label for="secretKey" class="block text-xs font-medium text-art-muted uppercase tracking-wider">Secret Key</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="password"
|
|
|
|
|
|
id="secretKey"
|
|
|
|
|
|
v-model="ossForm.secretKey"
|
|
|
|
|
|
required
|
|
|
|
|
|
class="admin-input font-mono"
|
|
|
|
|
|
placeholder="访问密钥Secret"
|
|
|
|
|
|
>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="grid grid-cols-2 gap-4">
|
|
|
|
|
|
<div class="space-y-2">
|
|
|
|
|
|
<label for="bucket" class="block text-xs font-medium text-art-muted uppercase tracking-wider">Bucket</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
id="bucket"
|
|
|
|
|
|
v-model="ossForm.bucket"
|
|
|
|
|
|
class="admin-input"
|
|
|
|
|
|
placeholder="存储桶名称"
|
|
|
|
|
|
>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="space-y-2">
|
|
|
|
|
|
<label for="region" class="block text-xs font-medium text-art-muted uppercase tracking-wider">区域</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
id="region"
|
|
|
|
|
|
v-model="ossForm.region"
|
|
|
|
|
|
class="admin-input"
|
|
|
|
|
|
placeholder="例如: ap-beijing"
|
|
|
|
|
|
>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="space-y-2">
|
|
|
|
|
|
<label for="domain" class="block text-xs font-medium text-art-muted uppercase tracking-wider">访问域名</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
id="domain"
|
|
|
|
|
|
v-model="ossForm.domain"
|
|
|
|
|
|
class="admin-input"
|
|
|
|
|
|
placeholder="例如: https://cdn.example.com"
|
|
|
|
|
|
>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="space-y-2">
|
|
|
|
|
|
<label class="flex items-center gap-2 cursor-pointer">
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="checkbox"
|
|
|
|
|
|
v-model="ossForm.isActive"
|
|
|
|
|
|
:true-value="1"
|
|
|
|
|
|
:false-value="0"
|
|
|
|
|
|
class="w-4 h-4 rounded border-white/20 bg-white/5 text-art-accent focus:ring-art-accent"
|
|
|
|
|
|
>
|
|
|
|
|
|
<span class="text-sm text-art-muted">启用此配置</span>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="pt-4 flex justify-end gap-3">
|
|
|
|
|
|
<button type="button" @click="closeOSSModal" class="admin-btn-secondary">取消</button>
|
|
|
|
|
|
<button type="submit" class="admin-btn-primary">保存</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-01-15 13:51:44 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
2026-01-19 16:14:08 +08:00
|
|
|
|
import { ref, onMounted, computed } from 'vue'
|
2026-01-15 13:51:44 +08:00
|
|
|
|
import { getSettings, createSetting, updateSetting, deleteSetting as deleteSettingApi, Setting } from '../../services/api'
|
2026-01-19 16:14:08 +08:00
|
|
|
|
import { getOSSConfigs, createOSSConfig, updateOSSConfig, deleteOSSConfig as deleteOSSConfigApi, OSSConfig } from '../../services/api'
|
2026-01-15 13:51:44 +08:00
|
|
|
|
import { useToast } from '../../composables/useToast'
|
2026-01-19 16:14:08 +08:00
|
|
|
|
import CustomSelect from '../../components/CustomSelect.vue'
|
2026-01-15 13:51:44 +08:00
|
|
|
|
|
|
|
|
|
|
const toast = useToast()
|
|
|
|
|
|
const settings = ref<Setting[]>([])
|
|
|
|
|
|
const showModal = ref(false)
|
|
|
|
|
|
const editingSetting = ref(false)
|
|
|
|
|
|
|
2026-01-19 16:14:08 +08:00
|
|
|
|
// Tab管理
|
|
|
|
|
|
const activeTab = ref<'settings' | 'oss'>('settings')
|
|
|
|
|
|
|
|
|
|
|
|
// OSS配置管理
|
|
|
|
|
|
const ossConfigs = ref<OSSConfig[]>([])
|
|
|
|
|
|
const showOSSModal = ref(false)
|
|
|
|
|
|
const editingOSSConfig = ref(false)
|
|
|
|
|
|
|
|
|
|
|
|
const ossForm = ref({
|
|
|
|
|
|
id: 0,
|
|
|
|
|
|
name: '',
|
|
|
|
|
|
storageType: '',
|
|
|
|
|
|
accessKey: '',
|
|
|
|
|
|
secretKey: '',
|
|
|
|
|
|
bucket: '',
|
|
|
|
|
|
region: '',
|
|
|
|
|
|
domain: '',
|
|
|
|
|
|
isActive: 0 as number
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 存储类型选项
|
|
|
|
|
|
const storageTypeOptions = [
|
|
|
|
|
|
{ value: 'local', label: '本地存储' },
|
|
|
|
|
|
{ value: 'qcloud', label: '腾讯云COS' },
|
|
|
|
|
|
{ value: 'aliyun', label: '阿里云OSS' },
|
|
|
|
|
|
{ value: 'qiniu', label: '七牛云' }
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
// 获取存储类型标签
|
|
|
|
|
|
const getStorageTypeLabel = (type: string): string => {
|
|
|
|
|
|
const option = storageTypeOptions.find(opt => opt.value === type)
|
|
|
|
|
|
return option ? option.label : type
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-15 13:51:44 +08:00
|
|
|
|
const form = ref({
|
|
|
|
|
|
id: 0,
|
|
|
|
|
|
keyName: '',
|
|
|
|
|
|
value: '',
|
|
|
|
|
|
description: ''
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const fetchSettings = async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
settings.value = await getSettings()
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('Error fetching settings:', error)
|
2026-01-16 11:06:59 +08:00
|
|
|
|
toast.showToast('获取系统配置失败', 'error')
|
2026-01-15 13:51:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const editSetting = (setting: Setting) => {
|
|
|
|
|
|
editingSetting.value = true
|
|
|
|
|
|
form.value = {
|
|
|
|
|
|
id: setting.id,
|
|
|
|
|
|
keyName: setting.keyName,
|
|
|
|
|
|
value: setting.value,
|
|
|
|
|
|
description: setting.description
|
|
|
|
|
|
}
|
|
|
|
|
|
showModal.value = true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const saveSetting = async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
if (editingSetting.value) {
|
|
|
|
|
|
await updateSetting(form.value)
|
2026-01-16 11:06:59 +08:00
|
|
|
|
toast.showToast('配置更新成功', 'success')
|
2026-01-15 13:51:44 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
await createSetting({
|
|
|
|
|
|
keyName: form.value.keyName,
|
|
|
|
|
|
value: form.value.value,
|
|
|
|
|
|
description: form.value.description
|
|
|
|
|
|
})
|
2026-01-16 11:06:59 +08:00
|
|
|
|
toast.showToast('配置创建成功', 'success')
|
2026-01-15 13:51:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
closeModal()
|
|
|
|
|
|
fetchSettings()
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('Error saving setting:', error)
|
2026-01-16 11:06:59 +08:00
|
|
|
|
toast.showToast(editingSetting.value ? '更新配置失败' : '创建配置失败', 'error')
|
2026-01-15 13:51:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const deleteSetting = async (keyName: string) => {
|
|
|
|
|
|
if (confirm(`确定要删除配置项 "${keyName}" 吗?`)) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
await deleteSettingApi(keyName)
|
2026-01-16 11:06:59 +08:00
|
|
|
|
toast.showToast('配置删除成功', 'success')
|
2026-01-15 13:51:44 +08:00
|
|
|
|
fetchSettings()
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('Error deleting setting:', error)
|
2026-01-16 11:06:59 +08:00
|
|
|
|
toast.showToast('删除配置失败', 'error')
|
2026-01-15 13:51:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const closeModal = () => {
|
|
|
|
|
|
showModal.value = false
|
|
|
|
|
|
editingSetting.value = false
|
|
|
|
|
|
form.value = {
|
|
|
|
|
|
id: 0,
|
|
|
|
|
|
keyName: '',
|
|
|
|
|
|
value: '',
|
|
|
|
|
|
description: ''
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-19 16:14:08 +08:00
|
|
|
|
// OSS配置相关函数
|
|
|
|
|
|
const fetchOSSConfigs = async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
ossConfigs.value = await getOSSConfigs()
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('Error fetching OSS configs:', error)
|
|
|
|
|
|
toast.showToast('获取OSS配置失败', 'error')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const openOSSModal = () => {
|
|
|
|
|
|
editingOSSConfig.value = false
|
|
|
|
|
|
ossForm.value = {
|
|
|
|
|
|
id: 0,
|
|
|
|
|
|
name: '',
|
|
|
|
|
|
storageType: '',
|
|
|
|
|
|
accessKey: '',
|
|
|
|
|
|
secretKey: '',
|
|
|
|
|
|
bucket: '',
|
|
|
|
|
|
region: '',
|
|
|
|
|
|
domain: '',
|
|
|
|
|
|
isActive: 0
|
|
|
|
|
|
}
|
|
|
|
|
|
showOSSModal.value = true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const editOSSConfig = (config: OSSConfig) => {
|
|
|
|
|
|
editingOSSConfig.value = true
|
|
|
|
|
|
ossForm.value = {
|
|
|
|
|
|
id: config.id,
|
|
|
|
|
|
name: config.name,
|
|
|
|
|
|
storageType: config.storageType,
|
|
|
|
|
|
accessKey: config.accessKey === '***' ? '' : config.accessKey, // 如果是加密值,清空让用户重新输入
|
|
|
|
|
|
secretKey: config.secretKey === '***' ? '' : config.secretKey,
|
|
|
|
|
|
bucket: config.bucket,
|
|
|
|
|
|
region: config.region,
|
|
|
|
|
|
domain: config.domain,
|
|
|
|
|
|
isActive: config.isActive
|
|
|
|
|
|
}
|
|
|
|
|
|
showOSSModal.value = true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const saveOSSConfig = async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
if (editingOSSConfig.value) {
|
|
|
|
|
|
// 更新时,如果密钥是空的,不发送密钥字段
|
|
|
|
|
|
const updateData: any = {
|
|
|
|
|
|
name: ossForm.value.name,
|
|
|
|
|
|
storageType: ossForm.value.storageType,
|
|
|
|
|
|
bucket: ossForm.value.bucket,
|
|
|
|
|
|
region: ossForm.value.region,
|
|
|
|
|
|
domain: ossForm.value.domain,
|
|
|
|
|
|
isActive: ossForm.value.isActive
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 只有用户输入了新密钥时才更新
|
|
|
|
|
|
if (ossForm.value.accessKey && ossForm.value.accessKey !== '***') {
|
|
|
|
|
|
updateData.accessKey = ossForm.value.accessKey
|
|
|
|
|
|
}
|
|
|
|
|
|
if (ossForm.value.secretKey && ossForm.value.secretKey !== '***') {
|
|
|
|
|
|
updateData.secretKey = ossForm.value.secretKey
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
await updateOSSConfig(ossForm.value.id, updateData)
|
|
|
|
|
|
toast.showToast('OSS配置更新成功', 'success')
|
|
|
|
|
|
} else {
|
|
|
|
|
|
await createOSSConfig({
|
|
|
|
|
|
name: ossForm.value.name,
|
|
|
|
|
|
storageType: ossForm.value.storageType,
|
|
|
|
|
|
accessKey: ossForm.value.accessKey,
|
|
|
|
|
|
secretKey: ossForm.value.secretKey,
|
|
|
|
|
|
bucket: ossForm.value.bucket,
|
|
|
|
|
|
region: ossForm.value.region,
|
|
|
|
|
|
domain: ossForm.value.domain,
|
|
|
|
|
|
isActive: ossForm.value.isActive,
|
|
|
|
|
|
createdAt: '',
|
|
|
|
|
|
updatedAt: ''
|
|
|
|
|
|
})
|
|
|
|
|
|
toast.showToast('OSS配置创建成功', 'success')
|
|
|
|
|
|
}
|
|
|
|
|
|
closeOSSModal()
|
|
|
|
|
|
fetchOSSConfigs()
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('Error saving OSS config:', error)
|
|
|
|
|
|
toast.showToast(editingOSSConfig.value ? '更新OSS配置失败' : '创建OSS配置失败', 'error')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const deleteOSSConfig = async (id: number) => {
|
|
|
|
|
|
if (confirm(`确定要删除这个OSS配置吗?`)) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
await deleteOSSConfigApi(id)
|
|
|
|
|
|
toast.showToast('OSS配置删除成功', 'success')
|
|
|
|
|
|
fetchOSSConfigs()
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('Error deleting OSS config:', error)
|
|
|
|
|
|
toast.showToast('删除OSS配置失败', 'error')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const closeOSSModal = () => {
|
|
|
|
|
|
showOSSModal.value = false
|
|
|
|
|
|
editingOSSConfig.value = false
|
|
|
|
|
|
ossForm.value = {
|
|
|
|
|
|
id: 0,
|
|
|
|
|
|
name: '',
|
|
|
|
|
|
storageType: '',
|
|
|
|
|
|
accessKey: '',
|
|
|
|
|
|
secretKey: '',
|
|
|
|
|
|
bucket: '',
|
|
|
|
|
|
region: '',
|
|
|
|
|
|
domain: '',
|
|
|
|
|
|
isActive: 0
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-15 13:51:44 +08:00
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
fetchSettings()
|
2026-01-19 16:14:08 +08:00
|
|
|
|
fetchOSSConfigs()
|
2026-01-15 13:51:44 +08:00
|
|
|
|
})
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
2026-01-16 11:06:59 +08:00
|
|
|
|
/* Scoped styles removed */
|
|
|
|
|
|
</style>
|