This commit is contained in:
Yvan
2026-08-17 15:52:59 +08:00
parent 083cc3a9ea
commit 10ccc005be
11 changed files with 884 additions and 110 deletions
+14
View File
@@ -27,6 +27,20 @@ export const setSystemConfig = (data) => {
})
}
// 对象存储配置以局部 payload 提交,避免连带覆盖其他尚未保存的表单项。
export const setStorageConfig = (storage) => {
return setSystemConfig({
config: {
admin: { storage }
}
})
}
// 邮件配置同样以局部 payload 提交,SMTP 密钥由后端写入集成配置表。
export const setEmailConfig = (email) => {
return setSystemConfig({ config: { email } })
}
// @Tags system
// @Summary 获取服务器运行状态
// @Security ApiKeyAuth
+1 -1
View File
@@ -1,7 +1,7 @@
<template>
<div>
<warning-bar
title="需要提前配置email配置文件,为防止不必要的垃圾邮件,在线体验功能不开放此功能体验。"
title="请先在系统设置的邮件设置中完成 SMTP 配置。为防止不必要的垃圾邮件,在线体验不开放此功能。"
/>
<div class="kra-form-box">
<el-form
+86 -5
View File
@@ -193,7 +193,9 @@
<el-form-item v-if="config.admin.storage.type === 'cloudflare-r2'" label="Account ID"><el-input v-model.trim="currentObjectStorage.account_id" /></el-form-item>
<el-form-item label="连接选项"><div class="flex gap-5"><el-switch v-model="currentObjectStorage.use_ssl" active-text="HTTPS" /><el-switch v-model="currentObjectStorage.force_path_style" active-text="Path Style" /></div></el-form-item>
</template>
<p class="md:col-span-2 text-sm text-gray-500">保存后点击“重载服务”,新的对象存储配置会立即生效。</p>
<div class="md:col-span-2 flex justify-end">
<el-button type="primary" :loading="storageSaving" @click="saveStorage">保存对象存储</el-button>
</div>
</el-form>
</el-tab-pane>
@@ -223,8 +225,11 @@
<el-switch v-model="config.email['is-loginauth']" active-text="LOGIN 认证" />
</div>
</el-form-item>
<el-form-item label="连通性测试">
<el-button :loading="testing" @click="testEmail">发送测试邮件</el-button>
<el-form-item label="配置操作" class="md:col-span-2">
<div class="flex gap-2">
<el-button type="primary" :loading="emailSaving" @click="saveEmail">保存邮件配置</el-button>
<el-button :loading="testing" @click="testEmail">保存并发送测试邮件</el-button>
</div>
</el-form-item>
</el-form>
</el-tab-pane>
@@ -235,7 +240,7 @@
<script setup>
import { computed, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getSystemConfig, reloadSystem, setSystemConfig } from '@/api/system'
import { getSystemConfig, reloadSystem, setEmailConfig, setStorageConfig, setSystemConfig } from '@/api/system'
import { emailTest } from '@/api/email'
import { CreateUUID } from '@/utils/format'
@@ -243,6 +248,8 @@
const activeKey = ref('basic')
const saving = ref(false)
const storageSaving = ref(false)
const emailSaving = ref(false)
const testing = ref(false)
const config = ref({
admin: {
@@ -256,7 +263,7 @@
storage: { type: 'local', qiniu: {}, aliyun_oss: {}, huawei_obs: {}, tencent_cos: {}, aws_s3: {}, cloudflare_r2: {}, minio: {} }
},
email: {
to: '', from: '', host: '', secret: '******', nickname: '', port: 465,
to: '', from: '', host: '', secret: '', nickname: '', port: 465,
'is-ssl': true, 'is-loginauth': false
},
data: {
@@ -352,6 +359,49 @@
config.value.admin.jwt.signingKey = CreateUUID()
}
const storageFieldLabels = {
endpoint: 'Endpoint', region: 'Region', bucket: 'Bucket',
access_key: 'Access Key', secret_key: 'Secret Key', account_id: 'Account ID'
}
const validateStorage = () => {
const storage = config.value.admin.storage
if (storage.type === 'local') return true
const target = storage.type === 'qiniu' ? storage.qiniu : currentObjectStorage.value
const required = {
qiniu: ['bucket', 'access_key', 'secret_key'],
'aliyun-oss': ['endpoint', 'bucket', 'access_key', 'secret_key'],
'huawei-obs': ['endpoint', 'bucket', 'access_key', 'secret_key'],
'tencent-cos': ['region', 'bucket', 'access_key', 'secret_key'],
'aws-s3': ['region', 'bucket', 'access_key', 'secret_key'],
'cloudflare-r2': ['bucket', 'access_key', 'secret_key'],
minio: ['endpoint', 'bucket', 'access_key', 'secret_key']
}[storage.type] || []
const missing = required.filter(key => !String(target?.[key] || '').trim())
if (storage.type === 'cloudflare-r2' && !String(target?.endpoint || target?.account_id || '').trim()) {
missing.push('account_id')
}
if (missing.length) {
ElMessage.warning(`请填写:${missing.map(key => storageFieldLabels[key]).join('、')}`)
return false
}
return true
}
const saveStorage = async () => {
if (!validateStorage()) return
storageSaving.value = true
try {
const res = await setStorageConfig(config.value.admin.storage)
if (res.code === 0) {
ElMessage.success('对象存储配置已保存并生效')
await initForm()
}
} finally {
storageSaving.value = false
}
}
const reload = async () => {
try {
await ElMessageBox.confirm('确定要重载服务配置吗?', '提示')
@@ -363,9 +413,40 @@
if (res.code === 0) ElMessage.success('配置已重载')
}
const validateEmail = () => {
const email = config.value.email
const fields = [
['to', '默认收件人'], ['from', '发件人'], ['host', 'SMTP 主机'], ['secret', 'SMTP 密钥']
]
const missing = fields.filter(([key]) => !String(email[key] || '').trim()).map(([, label]) => label)
if (!email.port) missing.push('SMTP 端口')
if (missing.length) {
ElMessage.warning(`请填写:${missing.join('、')}`)
return false
}
return true
}
const saveEmail = async () => {
if (!validateEmail()) return false
emailSaving.value = true
try {
const res = await setEmailConfig(config.value.email)
if (res.code !== 0) return false
ElMessage.success('邮件配置已保存并生效')
await initForm()
return true
} finally {
emailSaving.value = false
}
}
const testEmail = async () => {
if (!validateEmail()) return
testing.value = true
try {
const saved = await setEmailConfig(config.value.email)
if (saved.code !== 0) return
const res = await emailTest()
if (res.code === 0) {
ElMessage.success('测试邮件发送成功')