refactor: 自动转存功能重构

This commit is contained in:
ctwj
2025-08-09 08:33:32 +08:00
parent a041a6f01d
commit 32e7240287
9 changed files with 486 additions and 1318 deletions

View File

@@ -31,19 +31,15 @@
## 🔔 温馨提示 ## 🔔 温馨提示
📌 **本项目仅供技术交流与学习使用**,自身不存储或提供任何资源文件及下载链接。 - [文档说明](https://ecn5khs4t956.feishu.cn/wiki/PsnDwtxghiP0mLkTiruczKtxnwd?from=from_copylink)
- [服务器要求](https://ecn5khs4t956.feishu.cn/wiki/W8YBww1Mmiu4Cdkp5W4c8pFNnMf?from=from_copylink)
📌 **请勿将本项目用于任何违法用途**,否则后果自负。 - [QQ机器人](https://github.com/ctwj/astrbot_plugin_urldb)
📌 如有任何问题或建议,欢迎交流探讨! 😊
> **免责声明**:本项目由 Trae AI 辅助编写。由于时间有限,仅在空闲时维护。如遇使用问题,请优先自行排查,感谢理解!
--- ---
## 📸 项目截图 ## 📸 项目截图
[文档说明](https://ecn5khs4t956.feishu.cn/wiki/PsnDwtxghiP0mLkTiruczKtxnwd?from=from_copylink) [服务器要求](https://ecn5khs4t956.feishu.cn/wiki/W8YBww1Mmiu4Cdkp5W4c8pFNnMf?from=from_copylink)
### 🏠 首页 ### 🏠 首页
![首页](https://raw.githubusercontent.com/ctwj/urldb/refs/heads/main/github/index.webp) ![首页](https://raw.githubusercontent.com/ctwj/urldb/refs/heads/main/github/index.webp)

View File

@@ -61,12 +61,6 @@ func (h *SystemConfigHandler) UpdateConfig(c *gin.Context) {
return return
} }
// 验证自动转存配置
if req.AutoTransferLimitDays > 0 && (req.AutoTransferLimitDays < 0 || req.AutoTransferLimitDays > 365) {
ErrorResponse(c, "自动转存限制天数必须在0-365之间", http.StatusBadRequest)
return
}
if req.AutoTransferMinSpace > 0 && (req.AutoTransferMinSpace < 100 || req.AutoTransferMinSpace > 1024) { if req.AutoTransferMinSpace > 0 && (req.AutoTransferMinSpace < 100 || req.AutoTransferMinSpace > 1024) {
ErrorResponse(c, "最小存储空间必须在100-1024GB之间", http.StatusBadRequest) ErrorResponse(c, "最小存储空间必须在100-1024GB之间", http.StatusBadRequest)
return return

18
main.go
View File

@@ -111,15 +111,15 @@ func main() {
utils.Info("系统配置中自动拉取热播剧功能已禁用,跳过启动定时任务") utils.Info("系统配置中自动拉取热播剧功能已禁用,跳过启动定时任务")
} }
autoTransferEnabled, err := repoManager.SystemConfigRepository.GetConfigBool(entity.ConfigKeyAutoTransferEnabled) // autoTransferEnabled, err := repoManager.SystemConfigRepository.GetConfigBool(entity.ConfigKeyAutoTransferEnabled)
if err != nil { // if err != nil {
utils.Error("获取自动转存配置失败: %v", err) // utils.Error("获取自动转存配置失败: %v", err)
} else if autoTransferEnabled { // } else if autoTransferEnabled {
scheduler.StartAutoTransferScheduler() // scheduler.StartAutoTransferScheduler()
utils.Info("已启动自动转存任务") // utils.Info("已启动自动转存任务")
} else { // } else {
utils.Info("系统配置中自动转存功能已禁用,跳过启动定时任务") // utils.Info("系统配置中自动转存功能已禁用,跳过启动定时任务")
} // }
// 创建Gin实例 // 创建Gin实例
r := gin.Default() r := gin.Default()

View File

@@ -33,6 +33,10 @@ func NewAutoTransferScheduler(base *BaseScheduler) *AutoTransferScheduler {
// Start 启动自动转存定时任务 // Start 启动自动转存定时任务
func (a *AutoTransferScheduler) Start() { func (a *AutoTransferScheduler) Start() {
// 自动转存已经放弃,不再自动缓存
return
if a.autoTransferRunning { if a.autoTransferRunning {
utils.Info("自动转存定时任务已在运行中") utils.Info("自动转存定时任务已在运行中")
return return

File diff suppressed because it is too large Load Diff

View File

@@ -452,10 +452,10 @@ const operationItems = ref([
active: (route: any) => route.path.startsWith('/admin/data-push') active: (route: any) => route.path.startsWith('/admin/data-push')
}, },
{ {
to: '/admin/bot', to: '/admin/auto-reply',
label: '机器人', label: '自动回复',
icon: 'fas fa-robot', icon: 'fas fa-comments',
active: (route: any) => route.path.startsWith('/admin/bot') active: (route: any) => route.path.startsWith('/admin/auto-reply')
}, },
{ {
to: '/admin/seo', to: '/admin/seo',
@@ -490,7 +490,7 @@ const autoExpandCurrentGroup = () => {
expandedGroups.value.dataManagement = true expandedGroups.value.dataManagement = true
} else if (currentPath.startsWith('/admin/site-config') || currentPath.startsWith('/admin/feature-config') || currentPath.startsWith('/admin/dev-config') || currentPath.startsWith('/admin/users') || currentPath.startsWith('/admin/version')) { } else if (currentPath.startsWith('/admin/site-config') || currentPath.startsWith('/admin/feature-config') || currentPath.startsWith('/admin/dev-config') || currentPath.startsWith('/admin/users') || currentPath.startsWith('/admin/version')) {
expandedGroups.value.systemConfig = true expandedGroups.value.systemConfig = true
} else if (currentPath.startsWith('/admin/data-transfer') || currentPath.startsWith('/admin/seo') || currentPath.startsWith('/admin/data-push') || currentPath.startsWith('/admin/bot')) { } else if (currentPath.startsWith('/admin/data-transfer') || currentPath.startsWith('/admin/seo') || currentPath.startsWith('/admin/data-push') || currentPath.startsWith('/admin/auto-reply')) {
expandedGroups.value.operation = true expandedGroups.value.operation = true
} else if (currentPath.startsWith('/admin/search-stats') || currentPath.startsWith('/admin/third-party-stats')) { } else if (currentPath.startsWith('/admin/search-stats') || currentPath.startsWith('/admin/third-party-stats')) {
expandedGroups.value.statistics = true expandedGroups.value.statistics = true
@@ -512,7 +512,7 @@ watch(() => useRoute().path, (newPath) => {
expandedGroups.value.dataManagement = true expandedGroups.value.dataManagement = true
} else if (newPath.startsWith('/admin/site-config') || newPath.startsWith('/admin/feature-config') || newPath.startsWith('/admin/dev-config') || newPath.startsWith('/admin/users') || newPath.startsWith('/admin/version')) { } else if (newPath.startsWith('/admin/site-config') || newPath.startsWith('/admin/feature-config') || newPath.startsWith('/admin/dev-config') || newPath.startsWith('/admin/users') || newPath.startsWith('/admin/version')) {
expandedGroups.value.systemConfig = true expandedGroups.value.systemConfig = true
} else if (newPath.startsWith('/admin/data-transfer') || newPath.startsWith('/admin/seo') || newPath.startsWith('/admin/data-push') || newPath.startsWith('/admin/bot')) { } else if (newPath.startsWith('/admin/data-transfer') || newPath.startsWith('/admin/seo') || newPath.startsWith('/admin/data-push') || newPath.startsWith('/admin/auto-reply')) {
expandedGroups.value.operation = true expandedGroups.value.operation = true
} else if (newPath.startsWith('/admin/search-stats') || newPath.startsWith('/admin/third-party-stats')) { } else if (newPath.startsWith('/admin/search-stats') || newPath.startsWith('/admin/third-party-stats')) {
expandedGroups.value.statistics = true expandedGroups.value.statistics = true

View File

@@ -0,0 +1,201 @@
<template>
<div class="space-y-6">
<!-- 页面标题 -->
<div class="flex items-center justify-between">
<div>
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">自动回复</h1>
<p class="text-gray-600 dark:text-gray-400">管理各平台的自动回复配置</p>
</div>
<n-button type="primary" @click="saveConfig" :loading="saving">
<template #icon>
<i class="fas fa-save"></i>
</template>
保存配置
</n-button>
</div>
<!-- 配置表单 -->
<n-card>
<!-- 顶部Tabs -->
<n-tabs
v-model:value="activeTab"
type="line"
animated
class="mb-6"
>
<n-tab-pane name="qq" tab="QQ机器人">
<n-form
ref="formRef"
:model="configForm"
:rules="rules"
label-placement="left"
label-width="auto"
require-mark-placement="right-hanging"
>
<div class="space-y-6">
<!-- QQ机器人配置占位符 -->
<div class="space-y-2">
<div class="flex items-center space-x-2">
<label class="text-base font-semibold text-gray-800 dark:text-gray-200">QQ机器人开关</label>
<span class="text-xs text-gray-500 dark:text-gray-400">开启QQ机器人自动回复功能</span>
</div>
<n-switch v-model:value="configForm.qq_bot_enabled" />
</div>
<!-- 占位符内容 -->
<div class="p-8 text-center text-gray-500 dark:text-gray-400">
<i class="fas fa-cog text-4xl mb-4"></i>
<p class="text-lg font-medium mb-2">QQ机器人配置</p>
<p class="text-sm">QQ机器人自动回复功能配置区域</p>
<p class="text-xs mt-2">具体配置项待开发...</p>
</div>
</div>
</n-form>
</n-tab-pane>
<n-tab-pane name="wechat" tab="微信公众号">
<n-form
ref="formRef"
:model="configForm"
:rules="rules"
label-placement="left"
label-width="auto"
require-mark-placement="right-hanging"
>
<div class="space-y-6">
<!-- 微信公众号配置占位符 -->
<div class="space-y-2">
<div class="flex items-center space-x-2">
<label class="text-base font-semibold text-gray-800 dark:text-gray-200">微信公众号开关</label>
<span class="text-xs text-gray-500 dark:text-gray-400">开启微信公众号自动回复功能</span>
</div>
<n-switch v-model:value="configForm.wechat_mp_enabled" />
</div>
<!-- 占位符内容 -->
<div class="p-8 text-center text-gray-500 dark:text-gray-400">
<i class="fas fa-comment-dots text-4xl mb-4"></i>
<p class="text-lg font-medium mb-2">微信公众号配置</p>
<p class="text-sm">微信公众号自动回复功能配置区域</p>
<p class="text-xs mt-2">具体配置项待开发...</p>
</div>
</div>
</n-form>
</n-tab-pane>
<n-tab-pane name="wechat_open" tab="微信对话开放平台">
<n-form
ref="formRef"
:model="configForm"
:rules="rules"
label-placement="left"
label-width="auto"
require-mark-placement="right-hanging"
>
<div class="space-y-6">
<!-- 微信对话开放平台配置占位符 -->
<div class="space-y-2">
<div class="flex items-center space-x-2">
<label class="text-base font-semibold text-gray-800 dark:text-gray-200">微信对话开放平台开关</label>
<span class="text-xs text-gray-500 dark:text-gray-400">开启微信对话开放平台自动回复功能</span>
</div>
<n-switch v-model:value="configForm.wechat_open_enabled" />
</div>
<!-- 占位符内容 -->
<div class="p-8 text-center text-gray-500 dark:text-gray-400">
<i class="fas fa-comments text-4xl mb-4"></i>
<p class="text-lg font-medium mb-2">微信对话开放平台配置</p>
<p class="text-sm">微信对话开放平台自动回复功能配置区域</p>
<p class="text-xs mt-2">具体配置项待开发...</p>
</div>
</div>
</n-form>
</n-tab-pane>
</n-tabs>
</n-card>
</div>
</template>
<script setup lang="ts">
// 设置页面布局
definePageMeta({
layout: 'admin',
ssr: false
})
const notification = useNotification()
const formRef = ref()
const saving = ref(false)
const activeTab = ref('qq')
// 配置表单数据
const configForm = ref({
qq_bot_enabled: false,
wechat_mp_enabled: false,
wechat_open_enabled: false
})
// 表单验证规则
const rules = {
// 暂时为空,后续添加验证规则
}
// 获取配置
const fetchConfig = async () => {
try {
// 暂时使用模拟数据
configForm.value = {
qq_bot_enabled: false,
wechat_mp_enabled: false,
wechat_open_enabled: false
}
} catch (error) {
console.error('获取自动回复配置失败:', error)
notification.error({
content: '获取自动回复配置失败',
duration: 3000
})
}
}
// 保存配置
const saveConfig = async () => {
try {
saving.value = true
// 暂时使用模拟保存
await new Promise(resolve => setTimeout(resolve, 1000))
notification.success({
content: '自动回复配置保存成功',
duration: 3000
})
} catch (error) {
console.error('保存自动回复配置失败:', error)
notification.error({
content: '保存自动回复配置失败',
duration: 3000
})
} finally {
saving.value = false
}
}
// 页面加载时获取配置
onMounted(() => {
fetchConfig()
})
// 设置页面标题
useHead({
title: '自动回复 - 老九网盘资源数据库'
})
</script>
<style scoped>
/* 自定义样式 */
</style>

View File

@@ -16,91 +16,141 @@
<!-- 配置表单 --> <!-- 配置表单 -->
<n-card> <n-card>
<div class="space-y-6"> <!-- 顶部Tabs -->
<!-- 自动处理 --> <n-tabs
<div class="flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-700 rounded-lg"> v-model:value="activeTab"
<div class="flex-1"> type="line"
<h3 class="text-lg font-medium text-gray-900 dark:text-white"> animated
待处理资源自动处理 class="mb-6"
</h3> >
<p class="text-sm text-gray-600 dark:text-gray-400 mt-1"> <n-tab-pane name="resource" tab="资源处理">
开启后系统将自动处理待处理的资源无需手动操作
</p> <n-form
</div> ref="formRef"
<div class="ml-4"> :model="configForm"
<n-switch v-model:value="configForm.auto_process_enabled" /> :rules="rules"
</div> label-placement="left"
</div> label-width="auto"
require-mark-placement="right-hanging"
>
<div class="space-y-6">
<!-- 自动处理 -->
<div class="space-y-2">
<div class="flex items-center space-x-2">
<label class="text-base font-semibold text-gray-800 dark:text-gray-200">待处理资源自动处理</label>
<span class="text-xs text-gray-500 dark:text-gray-400">开启后系统将自动处理待处理的资源无需手动操作</span>
</div>
<n-switch v-model:value="configForm.auto_process_enabled" />
</div>
<!-- 自动处理间隔 --> <!-- 自动处理间隔 -->
<div v-if="configForm.auto_process_enabled" class="ml-6"> <div class="space-y-2">
<n-form-item label="自动处理间隔 (分钟)" path="auto_process_interval"> <div class="flex items-center space-x-2">
<n-input <label class="text-base font-semibold text-gray-800 dark:text-gray-200">自动处理间隔 (分钟)</label>
v-model:value="configForm.auto_process_interval" <span class="text-xs text-gray-500 dark:text-gray-400">建议设置 5-60 分钟避免过于频繁的处理</span>
type="text" </div>
placeholder="30" <n-input
/> v-model:value="configForm.auto_process_interval"
<template #help> type="text"
建议设置 5-60 分钟避免过于频繁的处理 placeholder="30"
</template> :disabled="!configForm.auto_process_enabled"
</n-form-item> />
</div> </div>
</div>
</n-form>
</n-tab-pane>
<!-- 自动转存 --> <n-tab-pane name="transfer" tab="转存配置">
<div class="flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-700 rounded-lg">
<div class="flex-1"> <n-form
<h3 class="text-lg font-medium text-gray-900 dark:text-white"> ref="formRef"
自动转存 :model="configForm"
</h3> :rules="rules"
<p class="text-sm text-gray-600 dark:text-gray-400 mt-1"> label-placement="left"
开启后系统将自动转存资源到其他网盘平台 label-width="auto"
</p> require-mark-placement="right-hanging"
</div> >
<div class="ml-4"> <div class="space-y-6">
<n-switch v-model:value="configForm.auto_transfer_enabled" /> <!-- 自动转存 -->
</div> <div class="space-y-2">
</div> <div class="flex items-center space-x-2">
<label class="text-base font-semibold text-gray-800 dark:text-gray-200">自动转存</label>
<span class="text-xs text-gray-500 dark:text-gray-400">开启后访问夸克资源将自动转存并提供转存后分享链接</span>
</div>
<n-switch v-model:value="configForm.auto_transfer_enabled" />
</div>
<!-- 自动转存配置 -->
<div v-if="configForm.auto_transfer_enabled" class="ml-6 space-y-4">
<n-form-item label="自动转存限制n天内资源" path="auto_transfer_limit_days">
<n-input
v-model:value="configForm.auto_transfer_limit_days"
type="text"
placeholder="30"
/>
<template #help>
只转存指定天数内的资源0表示不限制时间
</template>
</n-form-item>
<n-form-item label="最小存储空间GB" path="auto_transfer_min_space">
<n-input
v-model:value="configForm.auto_transfer_min_space"
type="text"
placeholder="500"
/>
<template #help>
当网盘剩余空间小于此值时停止自动转存100-1024GB
</template>
</n-form-item>
</div>
<!-- 热播剧自动获取 --> <!-- 最小存储空间 -->
<div class="flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-700 rounded-lg"> <div class="space-y-2">
<div class="flex-1"> <div class="flex items-center space-x-2">
<h3 class="text-lg font-medium text-gray-900 dark:text-white"> <label class="text-base font-semibold text-gray-800 dark:text-gray-200">最小存储空间GB</label>
自动拉取热播剧 <span class="text-xs text-gray-500 dark:text-gray-400">当网盘剩余空间小于此值时停止自动转存100-1024GB</span>
</h3> </div>
<p class="text-sm text-gray-600 dark:text-gray-400 mt-1"> <n-input
开启后系统将自动从豆瓣获取热播剧信息 v-model:value="configForm.auto_transfer_min_space"
</p> type="text"
</div> placeholder="500"
<div class="ml-4"> :disabled="!configForm.auto_transfer_enabled"
<n-switch v-model:value="configForm.hot_drama_auto_fetch" /> />
</div> </div>
</div>
</div> <!-- 广告关键词 -->
<div class="space-y-2">
<div class="flex items-center space-x-2">
<label class="text-base font-semibold text-gray-800 dark:text-gray-200">广告关键词</label>
<span class="text-xs text-gray-500 dark:text-gray-400">设置广告关键词转存时如果文件名包含广告关键词则文件被删除</span>
</div>
<n-input
v-model:value="configForm.ad_keywords"
type="text"
placeholder="电影,电视剧,综艺"
:disabled="!configForm.auto_transfer_enabled"
/>
</div>
<!-- 自动插入广告 -->
<div class="space-y-2">
<div class="flex items-center space-x-2">
<label class="text-base font-semibold text-gray-800 dark:text-gray-200">自动插入广告</label>
<span class="text-xs text-gray-500 dark:text-gray-400">在分享链接中的广告内容会在转存时自动插入到转存文件夹</span>
</div>
<n-input
v-model:value="configForm.auto_insert_ad"
type="textarea"
placeholder="请输入广告内容..."
:rows="3"
:disabled="!configForm.auto_transfer_enabled"
/>
</div>
</div>
</n-form>
</n-tab-pane>
<n-tab-pane name="drama" tab="热播剧">
<n-form
ref="formRef"
:model="configForm"
:rules="rules"
label-placement="left"
label-width="auto"
require-mark-placement="right-hanging"
>
<div class="space-y-6">
<!-- 热播剧自动获取 -->
<div class="space-y-2">
<div class="flex items-center space-x-2">
<label class="text-base font-semibold text-gray-800 dark:text-gray-200">自动拉取热播剧</label>
<span class="text-xs text-gray-500 dark:text-gray-400">开启后系统将自动从豆瓣获取热播剧信息</span>
</div>
<n-switch v-model:value="configForm.hot_drama_auto_fetch" />
</div>
</div>
</n-form>
</n-tab-pane>
</n-tabs>
</n-card> </n-card>
</div> </div>
</template> </template>
@@ -114,14 +164,16 @@ definePageMeta({
const notification = useNotification() const notification = useNotification()
const saving = ref(false) const saving = ref(false)
const activeTab = ref('resource')
// 配置表单数据 // 配置表单数据
const configForm = ref({ const configForm = ref({
auto_process_enabled: false, auto_process_enabled: false,
auto_process_interval: 30, auto_process_interval: 30,
auto_transfer_enabled: false, auto_transfer_enabled: false,
auto_transfer_limit_days: 30,
auto_transfer_min_space: 500, auto_transfer_min_space: 500,
ad_keywords: '',
auto_insert_ad: '',
hot_drama_auto_fetch: false hot_drama_auto_fetch: false
}) })
@@ -137,8 +189,9 @@ const fetchConfig = async () => {
auto_process_enabled: response.auto_process_ready_resources || false, auto_process_enabled: response.auto_process_ready_resources || false,
auto_process_interval: response.auto_process_interval || 30, auto_process_interval: response.auto_process_interval || 30,
auto_transfer_enabled: response.auto_transfer_enabled || false, auto_transfer_enabled: response.auto_transfer_enabled || false,
auto_transfer_limit_days: response.auto_transfer_limit_days || 30,
auto_transfer_min_space: response.auto_transfer_min_space || 500, auto_transfer_min_space: response.auto_transfer_min_space || 500,
ad_keywords: response.ad_keywords || '',
auto_insert_ad: response.auto_insert_ad || '',
hot_drama_auto_fetch: response.auto_fetch_hot_drama_enabled || false hot_drama_auto_fetch: response.auto_fetch_hot_drama_enabled || false
} }
} }
@@ -163,8 +216,9 @@ const saveConfig = async () => {
auto_process_ready_resources: configForm.value.auto_process_enabled, auto_process_ready_resources: configForm.value.auto_process_enabled,
auto_process_interval: configForm.value.auto_process_interval, auto_process_interval: configForm.value.auto_process_interval,
auto_transfer_enabled: configForm.value.auto_transfer_enabled, auto_transfer_enabled: configForm.value.auto_transfer_enabled,
auto_transfer_limit_days: configForm.value.auto_transfer_limit_days,
auto_transfer_min_space: configForm.value.auto_transfer_min_space, auto_transfer_min_space: configForm.value.auto_transfer_min_space,
ad_keywords: configForm.value.ad_keywords,
auto_insert_ad: configForm.value.auto_insert_ad,
auto_fetch_hot_drama_enabled: configForm.value.hot_drama_auto_fetch auto_fetch_hot_drama_enabled: configForm.value.hot_drama_auto_fetch
}) })

View File

@@ -14,79 +14,125 @@
</n-button> </n-button>
</div> </div>
<!-- 配置表单 --> <!-- 配置表单 -->
<n-card> <n-card>
<n-form <!-- 顶部Tabs -->
ref="formRef" <n-tabs
:model="configForm" v-model:value="activeTab"
:rules="rules" type="line"
label-placement="left" animated
label-width="auto" class="mb-6"
require-mark-placement="right-hanging"
> >
<div class="grid grid-cols-1 md:grid-cols-2 gap-6"> <n-tab-pane name="basic" tab="基本信息">
<!-- 网站标题 -->
<n-form-item label="网站标题" path="site_title"> <n-form
<n-input ref="formRef"
v-model:value="configForm.site_title" :model="configForm"
placeholder="请输入网站标题" :rules="rules"
/> label-placement="left"
</n-form-item> label-width="auto"
require-mark-placement="right-hanging"
>
<div class="space-y-6">
<!-- 网站标题 -->
<div class="space-y-2">
<div class="flex items-center space-x-2">
<label class="text-base font-semibold text-gray-800 dark:text-gray-200">网站标题</label>
<span class="text-xs text-gray-500 dark:text-gray-400">网站的主要标识显示在浏览器标签页和搜索结果中</span>
</div>
<n-input
v-model:value="configForm.site_title"
placeholder="请输入网站标题"
/>
</div>
<!-- 网站描述 --> <!-- 网站描述 -->
<n-form-item label="网站描述" path="site_description"> <div class="space-y-2">
<n-input <div class="flex items-center space-x-2">
v-model:value="configForm.site_description" <label class="text-base font-semibold text-gray-800 dark:text-gray-200">网站描述</label>
placeholder="请输入网站描述" <span class="text-xs text-gray-500 dark:text-gray-400">网站的简要介绍用于SEO和社交媒体分享</span>
/> </div>
</n-form-item> <n-input
v-model:value="configForm.site_description"
placeholder="请输入网站描述"
/>
</div>
<!-- 关键词 --> <!-- 关键词 -->
<n-form-item label="关键词" path="keywords"> <div class="space-y-2">
<n-input <div class="flex items-center space-x-2">
v-model:value="configForm.keywords" <label class="text-base font-semibold text-gray-800 dark:text-gray-200">关键词</label>
placeholder="请输入关键词用逗号分隔" <span class="text-xs text-gray-500 dark:text-gray-400">用于SEO优化多个关键词用逗号分隔</span>
/> </div>
</n-form-item> <n-input
v-model:value="configForm.keywords"
placeholder="请输入关键词,用逗号分隔"
/>
</div>
<!-- 版权信息 --> <!-- 版权信息 -->
<n-form-item label="版权信息" path="copyright"> <div class="space-y-2">
<n-input <div class="flex items-center space-x-2">
v-model:value="configForm.copyright" <label class="text-base font-semibold text-gray-800 dark:text-gray-200">版权信息</label>
placeholder="请输入版权信息" <span class="text-xs text-gray-500 dark:text-gray-400">网站底部的版权声明信息</span>
/> </div>
</n-form-item> <n-input
v-model:value="configForm.copyright"
placeholder="请输入版权信息"
/>
</div>
</div>
</n-form>
</n-tab-pane>
<!-- 维护模式 -->
<n-form-item label="维护模式" path="maintenance_mode">
<n-switch v-model:value="configForm.maintenance_mode" />
<template #help>
开启后网站将显示维护页面
</template>
</n-form-item>
<!-- 开启注册 -->
<n-form-item label="开启注册" path="enable_register">
<n-switch v-model:value="configForm.enable_register" />
<template #help>
开启后用户才能注册新账号关闭后注册页面将显示"当前系统已关闭注册功能"
</template>
</n-form-item>
<!-- 违禁词 --> <n-tab-pane name="security" tab="安全设置">
<n-form-item label="违禁词" path="forbidden_words" class="md:col-span-2">
<n-input <n-form
v-model:value="configForm.forbidden_words" ref="formRef"
placeholder="请输入违禁词,用逗号分隔" :model="configForm"
type="textarea" :rules="rules"
:rows="4" label-placement="left"
/> label-width="auto"
<template #help> require-mark-placement="right-hanging"
包含这些词汇的资源将被过滤 >
</template> <div class="space-y-6">
</n-form-item> <!-- 维护模式 -->
</div> <div class="space-y-2">
</n-form> <div class="flex items-center space-x-2">
<label class="text-base font-semibold text-gray-800 dark:text-gray-200">维护模式</label>
<span class="text-xs text-gray-500 dark:text-gray-400">开启后网站将显示维护页面暂停用户访问</span>
</div>
<n-switch v-model:value="configForm.maintenance_mode" />
</div>
<!-- 违禁词 -->
<div class="space-y-2">
<div class="flex items-center space-x-2">
<label class="text-base font-semibold text-gray-800 dark:text-gray-200">违禁词</label>
<span class="text-xs text-gray-500 dark:text-gray-400">包含这些词汇的资源将被过滤多个词汇用逗号分隔</span>
</div>
<n-input
v-model:value="configForm.forbidden_words"
placeholder="请输入违禁词,用逗号分隔"
type="textarea"
:rows="4"
/>
</div>
<!-- 开启注册 -->
<div class="space-y-2">
<div class="flex items-center space-x-2">
<label class="text-base font-semibold text-gray-800 dark:text-gray-200">开启注册</label>
<span class="text-xs text-gray-500 dark:text-gray-400">开启后用户才能注册新账号关闭后注册页面将显示"当前系统已关闭注册功能"</span>
</div>
<n-switch v-model:value="configForm.enable_register" />
</div>
</div>
</n-form>
</n-tab-pane>
</n-tabs>
</n-card> </n-card>
</div> </div>
</template> </template>
@@ -101,6 +147,7 @@ definePageMeta({
const notification = useNotification() const notification = useNotification()
const formRef = ref() const formRef = ref()
const saving = ref(false) const saving = ref(false)
const activeTab = ref('basic')
// 配置表单数据 // 配置表单数据
const configForm = ref<{ const configForm = ref<{
@@ -111,6 +158,8 @@ const configForm = ref<{
maintenance_mode: boolean maintenance_mode: boolean
enable_register: boolean enable_register: boolean
forbidden_words: string forbidden_words: string
enable_sitemap: boolean
sitemap_update_frequency: string
}>({ }>({
site_title: '', site_title: '',
site_description: '', site_description: '',
@@ -118,9 +167,13 @@ const configForm = ref<{
copyright: '', copyright: '',
maintenance_mode: false, maintenance_mode: false,
enable_register: false, // 新增:开启注册开关 enable_register: false, // 新增:开启注册开关
forbidden_words: '' forbidden_words: '',
enable_sitemap: false,
sitemap_update_frequency: 'daily'
}) })
// 表单验证规则 // 表单验证规则
const rules = { const rules = {
site_title: { site_title: {
@@ -150,7 +203,9 @@ const fetchConfig = async () => {
copyright: response.copyright || '', copyright: response.copyright || '',
maintenance_mode: response.maintenance_mode || false, maintenance_mode: response.maintenance_mode || false,
enable_register: response.enable_register || false, // 新增:获取开启注册开关 enable_register: response.enable_register || false, // 新增:获取开启注册开关
forbidden_words: response.forbidden_words || '' forbidden_words: response.forbidden_words || '',
enable_sitemap: response.enable_sitemap || false,
sitemap_update_frequency: response.sitemap_update_frequency || 'daily'
} }
} }
} catch (error) { } catch (error) {
@@ -178,7 +233,9 @@ const saveConfig = async () => {
copyright: configForm.value.copyright, copyright: configForm.value.copyright,
maintenance_mode: configForm.value.maintenance_mode, maintenance_mode: configForm.value.maintenance_mode,
enable_register: configForm.value.enable_register, // 新增:保存开启注册开关 enable_register: configForm.value.enable_register, // 新增:保存开启注册开关
forbidden_words: configForm.value.forbidden_words forbidden_words: configForm.value.forbidden_words,
enable_sitemap: configForm.value.enable_sitemap,
sitemap_update_frequency: configForm.value.sitemap_update_frequency
}) })
notification.success({ notification.success({