mirror of
https://github.com/yangjian102621/geekai.git
synced 2026-04-14 07:04:29 +08:00
插件配置已完成
This commit is contained in:
@@ -223,14 +223,19 @@ const items = [
|
||||
title: '存储配置',
|
||||
},
|
||||
{
|
||||
icon: 'log',
|
||||
index: '/admin/config/communication',
|
||||
title: '通信配置',
|
||||
icon: 'sms',
|
||||
index: '/admin/config/sms',
|
||||
title: '短信配置',
|
||||
},
|
||||
{
|
||||
icon: 'api-key',
|
||||
index: '/admin/config/api',
|
||||
title: 'API配置',
|
||||
icon: 'email',
|
||||
index: '/admin/config/smtp',
|
||||
title: '邮件配置',
|
||||
},
|
||||
{
|
||||
icon: 'plugin',
|
||||
index: '/admin/config/plugin',
|
||||
title: '插件配置',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
47
web/src/components/ui/Alert.vue
Normal file
47
web/src/components/ui/Alert.vue
Normal file
@@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<div class="rounded-md p-3 border-2 text-base mb-4 flex items-center" :class="typeClass">
|
||||
<div :class="textColor">
|
||||
<slot name="icon">
|
||||
<i class="iconfont !text-xl" :class="typeIcon"></i>
|
||||
</slot>
|
||||
</div>
|
||||
<div class="ml-3 text-sm leading-relaxed">
|
||||
<slot>{{ message }}</slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
type: {
|
||||
type: String,
|
||||
default: 'info',
|
||||
},
|
||||
})
|
||||
|
||||
const typeClass = computed(() => {
|
||||
return {
|
||||
info: 'bg-blue-100 text-blue-500 border-blue-500',
|
||||
success: 'bg-green-100 text-green-500 border-green-500',
|
||||
warning: 'bg-yellow-100 text-yellow-500 border-yellow-500',
|
||||
}[props.type]
|
||||
})
|
||||
const typeIcon = computed(() => {
|
||||
return {
|
||||
info: 'icon-info',
|
||||
success: 'icon-success',
|
||||
warning: 'icon-warning',
|
||||
}[props.type]
|
||||
})
|
||||
const textColor = computed(() => {
|
||||
return {
|
||||
info: 'text-blue-500',
|
||||
success: 'text-green-500',
|
||||
warning: 'text-yellow-500',
|
||||
}[props.type]
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
@@ -192,16 +192,22 @@ const routes = [
|
||||
component: () => import('@/views/admin/settings/StorageConfig.vue'),
|
||||
},
|
||||
{
|
||||
path: '/admin/config/communication',
|
||||
name: 'admin-config-communication',
|
||||
meta: { title: '通信配置' },
|
||||
component: () => import('@/views/admin/settings/CommunicationConfig.vue'),
|
||||
path: '/admin/config/sms',
|
||||
name: 'admin-config-sms',
|
||||
meta: { title: '短信配置' },
|
||||
component: () => import('@/views/admin/settings/SmsConfig.vue'),
|
||||
},
|
||||
{
|
||||
path: '/admin/config/api',
|
||||
name: 'admin-config-api',
|
||||
meta: { title: 'API配置' },
|
||||
component: () => import('@/views/admin/settings/ApiConfig.vue'),
|
||||
path: '/admin/config/smtp',
|
||||
name: 'admin-config-smtp',
|
||||
meta: { title: '邮件配置' },
|
||||
component: () => import('@/views/admin/settings/SmtpConfig.vue'),
|
||||
},
|
||||
{
|
||||
path: '/admin/config/plugin',
|
||||
name: 'admin-config-plugin',
|
||||
meta: { title: '插件配置' },
|
||||
component: () => import('@/views/admin/settings/PluginConfig.vue'),
|
||||
},
|
||||
{
|
||||
path: '/admin/config/markmap',
|
||||
|
||||
@@ -5,8 +5,32 @@
|
||||
// * @Author yangjian102621@163.com
|
||||
// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
import axios from 'axios'
|
||||
import { getAdminToken, getUserToken, removeAdminToken, removeUserToken } from '@/store/session'
|
||||
import axios from 'axios'
|
||||
|
||||
// Blob 数据读取和解析的辅助函数
|
||||
export async function parseBlobResponse(blob) {
|
||||
try {
|
||||
// 检查 Blob 的类型
|
||||
if (blob.type && blob.type.includes('application/json')) {
|
||||
// 如果是 JSON 类型,直接解析
|
||||
const text = await blob.text()
|
||||
return JSON.parse(text)
|
||||
} else {
|
||||
// 如果不是 JSON 类型,尝试解析为文本
|
||||
const text = await blob.text()
|
||||
try {
|
||||
return JSON.parse(text)
|
||||
} catch (e) {
|
||||
// 如果解析 JSON 失败,返回文本内容
|
||||
return { message: text, rawData: text }
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('解析 Blob 响应失败:', error)
|
||||
return { message: '解析响应数据失败', error: error.message }
|
||||
}
|
||||
}
|
||||
|
||||
axios.defaults.timeout = 180000
|
||||
// axios.defaults.baseURL = process.env.VUE_APP_API_HOST
|
||||
@@ -29,7 +53,7 @@ axios.interceptors.response.use(
|
||||
(response) => {
|
||||
return response
|
||||
},
|
||||
(error) => {
|
||||
async (error) => {
|
||||
if (error.response.status === 401) {
|
||||
if (error.response.request.responseURL.indexOf('/api/admin') !== -1) {
|
||||
removeAdminToken()
|
||||
@@ -39,8 +63,14 @@ axios.interceptors.response.use(
|
||||
error.response.data.message = '请先登录'
|
||||
return Promise.reject(error.response.data)
|
||||
}
|
||||
|
||||
if (error.response.status === 400) {
|
||||
return Promise.reject(new Error(error.response.data.message))
|
||||
let errorMessage = error.response.data.message
|
||||
if (!errorMessage) {
|
||||
const parsedData = await parseBlobResponse(error.response.data)
|
||||
errorMessage = parsedData.message
|
||||
}
|
||||
return Promise.reject(new Error(errorMessage))
|
||||
} else {
|
||||
return Promise.reject(error)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<template>
|
||||
<div class="reset-pass"></div>
|
||||
<div class="flex-center loginPage">
|
||||
<div class="left">
|
||||
<div class="login-box">
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
<template>
|
||||
<div class="form" v-loading="loading">
|
||||
<el-tabs v-model="active">
|
||||
<el-tab-pane label="SMTP 邮件" name="smtp">
|
||||
<el-form :model="smtp" label-width="140px">
|
||||
<el-form-item label="启用TLS"><el-switch v-model="smtp.use_tls" /></el-form-item>
|
||||
<el-form-item label="SMTP服务器"><el-input v-model="smtp.host" /></el-form-item>
|
||||
<el-form-item label="端口"><el-input-number v-model="smtp.port" :min="1" /></el-form-item>
|
||||
<el-form-item label="应用名称"><el-input v-model="smtp.app_name" /></el-form-item>
|
||||
<el-form-item label="发件人地址"><el-input v-model="smtp.from" /></el-form-item>
|
||||
<el-form-item label="发件人密码"
|
||||
><el-input v-model="smtp.password" type="password"
|
||||
/></el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="save('smtp')">保存</el-button>
|
||||
<el-button @click="test('smtp')">测试</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="短信服务" name="sms">
|
||||
<el-form :model="sms" label-width="140px">
|
||||
<el-form-item label="服务商">
|
||||
<el-select v-model="sms.Active" style="width: 200px">
|
||||
<el-option label="阿里云" value="Ali" />
|
||||
<el-option label="短信宝" value="Bao" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<template v-if="sms.Active === 'Ali'">
|
||||
<el-form-item label="AccessKey"><el-input v-model="sms.Ali.AccessKey" /></el-form-item>
|
||||
<el-form-item label="AccessSecret"
|
||||
><el-input v-model="sms.Ali.AccessSecret"
|
||||
/></el-form-item>
|
||||
<el-form-item label="签名"><el-input v-model="sms.Ali.Sign" /></el-form-item>
|
||||
<el-form-item label="模板ID"><el-input v-model="sms.Ali.CodeTempId" /></el-form-item>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-form-item label="用户名"><el-input v-model="sms.Bao.Username" /></el-form-item>
|
||||
<el-form-item label="密码"
|
||||
><el-input v-model="sms.Bao.Password" type="password"
|
||||
/></el-form-item>
|
||||
<el-form-item label="签名"><el-input v-model="sms.Bao.Sign" /></el-form-item>
|
||||
<el-form-item label="模板"
|
||||
><el-input v-model="sms.Bao.CodeTemplate" type="textarea" :rows="2"
|
||||
/></el-form-item>
|
||||
</template>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="save('sms')">保存</el-button>
|
||||
<el-button @click="test('sms')">测试</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { httpGet, httpPost } from '@/utils/http'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
const loading = ref(true)
|
||||
const active = ref('smtp')
|
||||
const smtp = ref({ use_tls: false, host: '', port: 25, app_name: '', from: '', password: '' })
|
||||
const sms = ref({
|
||||
Active: 'Ali',
|
||||
Ali: { AccessKey: '', AccessSecret: '', Sign: '', CodeTempId: '' },
|
||||
Bao: { Username: '', Password: '', Sign: '', CodeTemplate: '' },
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
Promise.all([httpGet('/api/admin/config/get?key=smtp'), httpGet('/api/admin/config/get?key=sms')])
|
||||
.then(([s1, s2]) => {
|
||||
const smtpData = s1?.data || {}
|
||||
smtp.value = { ...smtp.value, ...smtpData }
|
||||
|
||||
const smsData = s2?.data || {}
|
||||
sms.value = {
|
||||
...sms.value,
|
||||
...smsData,
|
||||
Ali: { ...sms.value.Ali, ...(smsData.Ali || smsData.ali || {}) },
|
||||
Bao: { ...sms.value.Bao, ...(smsData.Bao || smsData.bao || {}) },
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => (loading.value = false))
|
||||
})
|
||||
|
||||
const save = (key) => {
|
||||
if (key === 'smtp') {
|
||||
httpPost('/api/admin/config/update/smtp', smtp.value)
|
||||
.then(() => ElMessage.success('保存成功'))
|
||||
.catch((e) => ElMessage.error(e.message))
|
||||
} else if (key === 'sms') {
|
||||
httpPost('/api/admin/config/update/sms', sms.value)
|
||||
.then(() => ElMessage.success('保存成功'))
|
||||
.catch((e) => ElMessage.error(e.message))
|
||||
}
|
||||
}
|
||||
|
||||
const test = (key) => {
|
||||
ElMessage.info('请在对应服务侧进行验证')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.form {
|
||||
padding: 10px 20px 40px 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -8,14 +8,14 @@
|
||||
<span class="ms-2">支付宝</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="rounded-md bg-blue-100 p-3 text-gray-500 border-blue-500 border-2 text-base">
|
||||
<Alert type="info">
|
||||
如果你不知道怎么获取这些配置信息,请参考文档:
|
||||
<a
|
||||
href="https://docs.geekai.me/plus/config/payment.html#%E6%94%AF%E4%BB%98%E5%AE%9D%E9%85%8D%E7%BD%AE"
|
||||
target="_blank"
|
||||
>支付宝配置</a
|
||||
>。
|
||||
</div>
|
||||
</Alert>
|
||||
|
||||
<el-form :model="alipay" class="mt-4" label-position="top">
|
||||
<el-form-item label="商户ID"><el-input v-model="alipay.app_id" /></el-form-item>
|
||||
@@ -52,14 +52,14 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="rounded-md bg-blue-100 p-3 text-gray-500 border-blue-500 border-2 text-base">
|
||||
<Alert type="info">
|
||||
如果你不知道怎么获取这些配置信息,请参考文档:
|
||||
<a
|
||||
href="https://docs.geekai.me/plus/config/payment.html#%E5%BE%AE%E4%BF%A1%E6%94%AF%E4%BB%98%E9%85%8D%E7%BD%AE"
|
||||
target="_blank"
|
||||
>微信支付配置</a
|
||||
>。
|
||||
</div>
|
||||
</Alert>
|
||||
|
||||
<el-form :model="wxpay" class="mt-4" label-position="top">
|
||||
<el-form-item label="AppID"><el-input v-model="wxpay.app_id" /></el-form-item>
|
||||
@@ -89,14 +89,14 @@
|
||||
<span class="ms-2">易支付</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="rounded-md bg-blue-100 p-3 text-gray-500 border-blue-500 border-2 text-base">
|
||||
<Alert type="info">
|
||||
如果你不知道怎么获取这些配置信息,请参考文档:
|
||||
<a
|
||||
href="https://docs.geekai.me/plus/config/payment.html#%E6%98%93%E6%94%AF%E4%BB%98%E5%BC%80%E9%80%9A"
|
||||
target="_blank"
|
||||
>易支付配置</a
|
||||
>。
|
||||
</div>
|
||||
</Alert>
|
||||
|
||||
<el-form :model="epay" class="mt-4" label-position="top">
|
||||
<el-form-item label="商户ID"><el-input v-model="epay.app_id" /></el-form-item>
|
||||
@@ -114,6 +114,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Alert from '@/components/ui/Alert.vue'
|
||||
import { httpGet, httpPost } from '@/utils/http'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
159
web/src/views/admin/settings/PluginConfig.vue
Normal file
159
web/src/views/admin/settings/PluginConfig.vue
Normal file
@@ -0,0 +1,159 @@
|
||||
<template>
|
||||
<div class="settings container p-5">
|
||||
<el-tabs v-model="activeTab" type="border-card">
|
||||
<el-tab-pane name="captcha">
|
||||
<template #label>
|
||||
<div class="flex items-center">
|
||||
<i class="iconfont icon-yanzm"></i>
|
||||
<span class="ml-2">行为验证码</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<Alert type="info">
|
||||
行为验证码服务,开启后用户登录的时候需要进行行为验证,可以有效防止恶意登录。<br />
|
||||
请联系作者获取令牌填入下面输入框开通验证服务。
|
||||
</Alert>
|
||||
|
||||
<el-form :model="captchaConfig" label-position="top">
|
||||
<el-form-item label="服务令牌">
|
||||
<el-input v-model="captchaConfig.api_key" placeholder="请输入服务令牌" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="验证码类型">
|
||||
<el-radio-group v-model="captchaConfig.type" size="large">
|
||||
<el-radio value="dot" border>点选验证码</el-radio>
|
||||
<el-radio value="slide" border>滑动验证码</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="启用验证码">
|
||||
<el-switch size="large" v-model="captchaConfig.enabled" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<div class="flex justify-center mt-6">
|
||||
<el-button type="primary" @click="saveCaptchaConfig" :loading="loading"
|
||||
>提交保存</el-button
|
||||
>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane name="wxlogin">
|
||||
<template #label>
|
||||
<div class="flex items-center">
|
||||
<i class="iconfont icon-wechat"></i>
|
||||
<span class="ml-2">微信登录</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<Alert type="info">
|
||||
微信登录服务,开启后用户可以使用微信扫码登录。<br />
|
||||
请联系作者获取令牌填入下面输入框开通验证服务。
|
||||
</Alert>
|
||||
|
||||
<el-form :model="wxLoginConfig" label-position="top">
|
||||
<el-form-item label="服务令牌">
|
||||
<el-input v-model="wxLoginConfig.api_key" placeholder="请输入服务令牌" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="登录成功回调URL">
|
||||
<el-input v-model="wxLoginConfig.notify_url" placeholder="请输入回调URL" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="启用微信登录">
|
||||
<el-switch size="large" v-model="wxLoginConfig.enabled" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<div class="flex justify-center mt-6">
|
||||
<el-button type="primary" @click="saveWxloginConfig" :loading="loading"
|
||||
>提交保存</el-button
|
||||
>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Alert from '@/components/ui/Alert.vue'
|
||||
import { httpGet, httpPost } from '@/utils/http.js'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
const activeTab = ref('captcha')
|
||||
const loading = ref(false)
|
||||
|
||||
// 行为验证码配置
|
||||
const captchaConfig = ref({
|
||||
api_key: '',
|
||||
type: 'slide',
|
||||
enabled: false,
|
||||
})
|
||||
|
||||
// 微信登录配置
|
||||
const wxLoginConfig = ref({
|
||||
api_key: '',
|
||||
notify_url: '',
|
||||
enabled: false,
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
fetchCaptchaConfig()
|
||||
fetchWxloginConfig()
|
||||
})
|
||||
|
||||
const fetchCaptchaConfig = async () => {
|
||||
try {
|
||||
const res = await httpGet('/api/admin/config/get?key=captcha')
|
||||
captchaConfig.value = Object.assign(captchaConfig.value, res.data)
|
||||
} catch (e) {
|
||||
// 使用默认值
|
||||
}
|
||||
}
|
||||
|
||||
const fetchWxloginConfig = async () => {
|
||||
try {
|
||||
const res = await httpGet('/api/admin/config/get?key=wx_login')
|
||||
wxLoginConfig.value = Object.assign(wxLoginConfig.value, res.data)
|
||||
wxLoginConfig.value.notify_url =
|
||||
wxLoginConfig.value.notify_url || window.location.origin + '/api/user/login/callback'
|
||||
} catch (e) {
|
||||
// 使用默认值
|
||||
}
|
||||
}
|
||||
|
||||
// 保存行为验证码配置
|
||||
const saveCaptchaConfig = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
await httpPost('/api/admin/config/update/captcha', captchaConfig.value)
|
||||
ElMessage.success('保存成功')
|
||||
} catch (e) {
|
||||
ElMessage.error('保存失败:' + (e.message || '未知错误'))
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 保存微信登录配置
|
||||
const saveWxloginConfig = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
await httpPost('/api/admin/config/update/wx_login', wxLoginConfig.value)
|
||||
ElMessage.success('保存成功')
|
||||
} catch (e) {
|
||||
ElMessage.error('保存失败:' + (e.message || '未知错误'))
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.settings {
|
||||
.el-form-item__label {
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
143
web/src/views/admin/settings/SmsConfig.vue
Normal file
143
web/src/views/admin/settings/SmsConfig.vue
Normal file
@@ -0,0 +1,143 @@
|
||||
<template>
|
||||
<div class="settings container p-5">
|
||||
<el-tabs v-model="activeTab" type="border-card">
|
||||
<el-tab-pane label="阿里云短信" name="aliyun">
|
||||
<template #label>
|
||||
<div class="flex items-center">
|
||||
<i class="iconfont icon-aliyun"></i>
|
||||
<span class="ml-2">阿里云短信</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<Alert type="info">
|
||||
如果你不知道怎么获取这些配置信息,请参考文档:
|
||||
<a
|
||||
href="https://docs.geekai.me/plus/config/sms.html#%E9%98%BF%E9%87%8C%E4%BA%91"
|
||||
target="_blank"
|
||||
>阿里云短信配置</a
|
||||
>。
|
||||
</Alert>
|
||||
|
||||
<el-form :model="configs.aliyun" label-position="top">
|
||||
<el-form-item label="AccessKey">
|
||||
<el-input v-model="configs.aliyun.access_key" placeholder="请输入AccessKey" />
|
||||
</el-form-item>
|
||||
<el-form-item label="AccessSecret">
|
||||
<el-input v-model="configs.aliyun.access_secret" placeholder="请输入AccessSecret" />
|
||||
</el-form-item>
|
||||
<el-form-item label="短信签名">
|
||||
<el-input v-model="configs.aliyun.sign" placeholder="请输入短信签名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="验证码模板ID">
|
||||
<el-input v-model="configs.aliyun.code_temp_id" placeholder="请输入验证码模板ID" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="短信宝" name="bao">
|
||||
<template #label>
|
||||
<div class="flex items-center">
|
||||
<i class="iconfont icon-sms"></i>
|
||||
<span class="ml-2">短信宝</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<Alert type="info">
|
||||
如果你不知道怎么获取这些配置信息,请参考文档:
|
||||
<a
|
||||
href="https://docs.geekai.me/plus/config/sms.html#%E7%9F%AD%E4%BF%A1%E5%AE%9D"
|
||||
target="_blank"
|
||||
>短信宝配置</a
|
||||
>。
|
||||
</Alert>
|
||||
|
||||
<el-form :model="configs.bao" label-position="top">
|
||||
<el-form-item label="用户名">
|
||||
<el-input v-model="configs.bao.username" placeholder="请输入用户名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="密码">
|
||||
<el-input v-model="configs.bao.password" placeholder="请输入密码" />
|
||||
</el-form-item>
|
||||
<el-form-item label="短信签名">
|
||||
<el-input v-model="configs.bao.sign" placeholder="请输入短信签名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="验证码模板">
|
||||
<el-input v-model="configs.bao.code_template" placeholder="请输入验证码模板" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<div class="mt-3">
|
||||
<label class="form-label mr-2">默认使用</label>
|
||||
<el-radio-group v-model="configs.active" size="large">
|
||||
<el-radio value="aliyun" border>阿里云</el-radio>
|
||||
<el-radio value="bao" border>短信宝</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center mt-6">
|
||||
<el-button type="primary" @click="saveSmsConfig" :loading="loading">提交保存</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Alert from '@/components/ui/Alert.vue'
|
||||
import { httpGet, httpPost } from '@/utils/http'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
const loading = ref(false)
|
||||
const activeTab = ref('aliyun')
|
||||
const configs = ref({
|
||||
active: 'aliyun',
|
||||
aliyun: {
|
||||
access_key: '',
|
||||
access_secret: '',
|
||||
sign: '',
|
||||
code_temp_id: '',
|
||||
},
|
||||
bao: {
|
||||
username: '',
|
||||
password: '',
|
||||
sign: '',
|
||||
code_template: '',
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const res = await httpGet('/api/admin/config/get?key=sms')
|
||||
configs.value = Object.assign(configs.value, res.data)
|
||||
} catch (e) {
|
||||
// 使用默认值
|
||||
}
|
||||
})
|
||||
|
||||
const saveSmsConfig = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
await httpPost('/api/admin/config/update/sms', configs.value)
|
||||
ElMessage.success('保存成功')
|
||||
} catch (e) {
|
||||
ElMessage.error('保存失败:' + (e.message || '未知错误'))
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.settings {
|
||||
a {
|
||||
color: #409eff;
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
.el-form-item__label {
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
140
web/src/views/admin/settings/SmtpConfig.vue
Normal file
140
web/src/views/admin/settings/SmtpConfig.vue
Normal file
@@ -0,0 +1,140 @@
|
||||
<template>
|
||||
<div class="settings container p-5">
|
||||
<el-tabs v-model="activeTab" type="border-card">
|
||||
<el-tab-pane label="邮件服务设置" name="smtp">
|
||||
<Alert type="info">
|
||||
如果你不知道怎么获取这些配置信息,请参考文档:
|
||||
<a
|
||||
href="https://docs.geekai.me/plus/config/sms.html#%E9%82%AE%E4%BB%B6%E6%9C%8D%E5%8A%A1%E9%85%8D%E7%BD%AE"
|
||||
target="_blank"
|
||||
>邮件服务配置</a
|
||||
>。
|
||||
</Alert>
|
||||
|
||||
<el-form :model="smtpConfig" label-position="top">
|
||||
<el-form-item>
|
||||
<label class="form-label"
|
||||
>邮件服务器地址
|
||||
<el-tooltip placement="top">
|
||||
<template #content>
|
||||
推荐使用网易邮箱,<br />
|
||||
国外邮箱推荐使用 Google 邮箱
|
||||
</template>
|
||||
<i class="iconfont icon-info"></i>
|
||||
</el-tooltip>
|
||||
</label>
|
||||
<el-input
|
||||
v-model="smtpConfig.host"
|
||||
placeholder="请输入邮件服务器地址,推荐使用网易邮箱"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<label class="form-label"
|
||||
>邮件服务器端口
|
||||
<el-tooltip placement="top">
|
||||
<template #content> 线上推荐使用465端口,<br />本地测试推荐使用25端口 </template>
|
||||
<i class="iconfont icon-info"></i>
|
||||
</el-tooltip>
|
||||
</label>
|
||||
<el-input v-model="smtpConfig.port" type="number" placeholder="请输入端口号" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="是否使用TLS"
|
||||
><el-switch v-model="smtpConfig.use_tls"
|
||||
/></el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<label class="form-label"
|
||||
>应用名称
|
||||
<el-tooltip placement="top">
|
||||
<template #content> 应用名称会显示在邮件的抬头 </template>
|
||||
<i class="iconfont icon-info"></i>
|
||||
</el-tooltip>
|
||||
</label>
|
||||
<el-input v-model="smtpConfig.app_name" placeholder="请输入应用名称" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<label class="form-label">发件人邮箱地址</label>
|
||||
<el-input v-model="smtpConfig.from" type="email" placeholder="请输入发件人邮箱地址" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<label class="form-label"
|
||||
>发件人邮箱密码
|
||||
<el-tooltip placement="top">
|
||||
<template #content> 如果使用授权码,请输入授权码 </template>
|
||||
<i class="iconfont icon-info"></i>
|
||||
</el-tooltip>
|
||||
</label>
|
||||
<el-input
|
||||
v-model="smtpConfig.password"
|
||||
type="password"
|
||||
placeholder="请输入邮箱密码或授权码"
|
||||
show-password
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<div class="flex justify-center mt-6">
|
||||
<el-button type="primary" @click="saveConfig" :loading="loading">提交保存</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Alert from '@/components/ui/Alert.vue'
|
||||
import { httpGet, httpPost } from '@/utils/http'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
const loading = ref(false)
|
||||
const activeTab = ref('smtp')
|
||||
const smtpConfig = ref({
|
||||
use_tls: false,
|
||||
host: 'smtp.163.com',
|
||||
port: 465,
|
||||
app_name: 'GeekAI',
|
||||
from: '',
|
||||
password: '',
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const res = await httpGet('/api/admin/config/get?key=smtp')
|
||||
smtpConfig.value = Object.assign(smtpConfig.value, res.data || {})
|
||||
} catch (e) {
|
||||
// 使用默认值
|
||||
}
|
||||
})
|
||||
|
||||
// 保存配置
|
||||
const saveConfig = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
await httpPost('/api/admin/config/update/smtp', smtpConfig.value)
|
||||
ElMessage.success('保存成功')
|
||||
} catch (e) {
|
||||
ElMessage.error('保存失败:' + (e.message || '未知错误'))
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.settings {
|
||||
a {
|
||||
color: #409eff;
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
.el-form-item__label {
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -59,14 +59,39 @@
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="七牛云" name="qiniu">
|
||||
<div class="rounded-md bg-blue-100 p-3 text-gray-500 border-blue-500 border-2 text-base">
|
||||
如果你不知道怎么获取这些配置信息,请参考文档:
|
||||
<a
|
||||
href="https://docs.geekai.me/plus/config/oss.html#%E4%B8%83%E7%89%9B%E4%BA%91-oss-%E9%85%8D%E7%BD%AE"
|
||||
target="_blank"
|
||||
>七牛云配置</a
|
||||
>。
|
||||
</div>
|
||||
<el-form :model="qiniu" class="mt-4" label-position="top">
|
||||
<el-form-item label="Zone"><el-input v-model="qiniu.zone" /></el-form-item>
|
||||
<el-form-item label="Zone">
|
||||
<template #label>
|
||||
<label
|
||||
>区域(Zone)
|
||||
<el-tooltip
|
||||
placement="right"
|
||||
content="华南:z2,华东:z0,华北:z1,北美:na0,新加坡:as0"
|
||||
>
|
||||
<i class="iconfont icon-info"></i>
|
||||
</el-tooltip>
|
||||
</label>
|
||||
</template>
|
||||
<el-input
|
||||
v-model="qiniu.zone"
|
||||
placeholder="华南:z2,华东:z0,华北:z1,北美:na0,新加坡:as0"
|
||||
/></el-form-item>
|
||||
<el-form-item label="AccessKey"><el-input v-model="qiniu.access_key" /></el-form-item>
|
||||
<el-form-item label="AccessSecret"
|
||||
><el-input v-model="qiniu.access_secret"
|
||||
/></el-form-item>
|
||||
<el-form-item label="Bucket"><el-input v-model="qiniu.bucket" /></el-form-item>
|
||||
<el-form-item label="Domain"><el-input v-model="qiniu.domain" /></el-form-item>
|
||||
<el-form-item label="Domain"
|
||||
><el-input v-model="qiniu.domain" placeholder="请输入七牛云Bucket绑定的域名"
|
||||
/></el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
|
||||
@@ -95,7 +120,6 @@
|
||||
|
||||
<div class="flex justify-center mt-6">
|
||||
<el-button type="primary" @click="save" :loading="loading">提交保存</el-button>
|
||||
<el-button class="ml-3" @click="test">连接测试</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -161,14 +185,16 @@ const save = () => {
|
||||
.then(() => ElMessage.success('保存成功'))
|
||||
.catch((e) => ElMessage.error(e.message))
|
||||
}
|
||||
|
||||
const test = () => {
|
||||
ElMessage.info('请在对象存储端验证配置')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.settings {
|
||||
a {
|
||||
color: #409eff;
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
.el-form-item__label {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user