mirror of
https://github.com/ctwj/urldb.git
synced 2025-11-25 03:15:04 +08:00
update: 完善新后台
This commit is contained in:
@@ -376,10 +376,22 @@ const dataManagementItems = ref([
|
||||
// 系统配置菜单项
|
||||
const systemConfigItems = ref([
|
||||
{
|
||||
to: '/admin/system-config',
|
||||
label: '系统配置',
|
||||
icon: 'fas fa-cog',
|
||||
active: (route: any) => route.path.startsWith('/admin/system-config')
|
||||
to: '/admin/site-config',
|
||||
label: '站点配置',
|
||||
icon: 'fas fa-globe',
|
||||
active: (route: any) => route.path.startsWith('/admin/site-config')
|
||||
},
|
||||
{
|
||||
to: '/admin/feature-config',
|
||||
label: '功能配置',
|
||||
icon: 'fas fa-sliders-h',
|
||||
active: (route: any) => route.path.startsWith('/admin/feature-config')
|
||||
},
|
||||
{
|
||||
to: '/admin/dev-config',
|
||||
label: '开发配置',
|
||||
icon: 'fas fa-code',
|
||||
active: (route: any) => route.path.startsWith('/admin/dev-config')
|
||||
},
|
||||
{
|
||||
to: '/admin/users',
|
||||
@@ -416,7 +428,7 @@ const autoExpandCurrentGroup = () => {
|
||||
// 检查当前页面属于哪个分组并展开
|
||||
if (currentPath.startsWith('/admin/resources') || currentPath.startsWith('/admin/ready-resources') || currentPath.startsWith('/admin/tags') || currentPath.startsWith('/admin/categories') || currentPath.startsWith('/admin/accounts')) {
|
||||
expandedGroups.value.dataManagement = true
|
||||
} else if (currentPath.startsWith('/admin/system-config') || currentPath.startsWith('/admin/users')) {
|
||||
} else if (currentPath.startsWith('/admin/site-config') || currentPath.startsWith('/admin/feature-config') || currentPath.startsWith('/admin/dev-config') || currentPath.startsWith('/admin/users')) {
|
||||
expandedGroups.value.systemConfig = true
|
||||
} else if (currentPath.startsWith('/admin/hot-dramas')) {
|
||||
expandedGroups.value.operation = true
|
||||
@@ -438,7 +450,7 @@ watch(() => useRoute().path, (newPath) => {
|
||||
// 根据新路径展开对应分组
|
||||
if (newPath.startsWith('/admin/resources') || newPath.startsWith('/admin/ready-resources') || newPath.startsWith('/admin/tags') || newPath.startsWith('/admin/categories') || newPath.startsWith('/admin/accounts')) {
|
||||
expandedGroups.value.dataManagement = true
|
||||
} else if (newPath.startsWith('/admin/system-config') || newPath.startsWith('/admin/users')) {
|
||||
} else if (newPath.startsWith('/admin/site-config') || newPath.startsWith('/admin/feature-config') || newPath.startsWith('/admin/dev-config') || newPath.startsWith('/admin/users')) {
|
||||
expandedGroups.value.systemConfig = true
|
||||
} else if (newPath.startsWith('/admin/hot-dramas')) {
|
||||
expandedGroups.value.operation = true
|
||||
|
||||
286
web/pages/admin/dev-config.vue
Normal file
286
web/pages/admin/dev-config.vue
Normal file
@@ -0,0 +1,286 @@
|
||||
<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">管理API和开发相关配置</p>
|
||||
</div>
|
||||
<n-button type="primary" @click="saveConfig" :loading="saving">
|
||||
<template #icon>
|
||||
<i class="fas fa-save"></i>
|
||||
</template>
|
||||
保存配置
|
||||
</n-button>
|
||||
</div>
|
||||
|
||||
<!-- 配置表单 -->
|
||||
<n-card>
|
||||
<div class="space-y-6">
|
||||
<!-- API Token -->
|
||||
<div>
|
||||
<n-form-item label="公开API访问令牌" path="api_token">
|
||||
<div class="flex gap-2">
|
||||
<n-input
|
||||
v-model:value="configForm.api_token"
|
||||
type="password"
|
||||
placeholder="输入API Token,用于公开API访问认证"
|
||||
show-password-on="click"
|
||||
/>
|
||||
<n-button
|
||||
v-if="!configForm.api_token"
|
||||
type="primary"
|
||||
@click="generateApiToken"
|
||||
>
|
||||
生成
|
||||
</n-button>
|
||||
<template v-else>
|
||||
<n-button
|
||||
type="primary"
|
||||
@click="copyApiToken"
|
||||
>
|
||||
复制
|
||||
</n-button>
|
||||
<n-button
|
||||
type="warning"
|
||||
@click="regenerateApiToken"
|
||||
>
|
||||
重新生成
|
||||
</n-button>
|
||||
</template>
|
||||
</div>
|
||||
<template #help>
|
||||
API Token用于公开API的访问认证,请妥善保管
|
||||
</template>
|
||||
</n-form-item>
|
||||
</div>
|
||||
|
||||
<!-- API文档链接 -->
|
||||
<div class="p-4 bg-blue-50 dark:bg-blue-900/20 rounded-lg">
|
||||
<h3 class="text-lg font-medium text-blue-900 dark:text-blue-100 mb-2">
|
||||
API文档
|
||||
</h3>
|
||||
<p class="text-sm text-blue-700 dark:text-blue-300 mb-3">
|
||||
查看完整的API文档和使用说明
|
||||
</p>
|
||||
<n-button type="primary" @click="openApiDocs">
|
||||
<template #icon>
|
||||
<i class="fas fa-book"></i>
|
||||
</template>
|
||||
查看API文档
|
||||
</n-button>
|
||||
</div>
|
||||
</div>
|
||||
</n-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 设置页面布局
|
||||
definePageMeta({
|
||||
layout: 'admin',
|
||||
ssr: false
|
||||
})
|
||||
|
||||
const notification = useNotification()
|
||||
const saving = ref(false)
|
||||
|
||||
// 配置表单数据
|
||||
const configForm = ref({
|
||||
api_token: ''
|
||||
})
|
||||
|
||||
// 获取系统配置
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const { useSystemConfigApi } = await import('~/composables/useApi')
|
||||
const systemConfigApi = useSystemConfigApi()
|
||||
const response = await systemConfigApi.getSystemConfig()
|
||||
|
||||
if (response) {
|
||||
configForm.value = {
|
||||
api_token: response.api_token || ''
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取系统配置失败:', error)
|
||||
notification.error({
|
||||
content: '获取系统配置失败',
|
||||
duration: 3000
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 保存配置
|
||||
const saveConfig = async () => {
|
||||
try {
|
||||
saving.value = true
|
||||
|
||||
const { useSystemConfigApi } = await import('~/composables/useApi')
|
||||
const systemConfigApi = useSystemConfigApi()
|
||||
|
||||
await systemConfigApi.updateSystemConfig({
|
||||
api_token: configForm.value.api_token
|
||||
})
|
||||
|
||||
notification.success({
|
||||
content: '开发配置保存成功',
|
||||
duration: 3000
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('保存开发配置失败:', error)
|
||||
notification.error({
|
||||
content: '保存开发配置失败',
|
||||
duration: 3000
|
||||
})
|
||||
} finally {
|
||||
saving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 生成API Token
|
||||
const generateApiToken = async () => {
|
||||
try {
|
||||
const token = Math.random().toString(36).substring(2) + Date.now().toString(36)
|
||||
configForm.value.api_token = token
|
||||
|
||||
notification.success({
|
||||
content: 'API Token生成成功',
|
||||
duration: 3000
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('生成API Token失败:', error)
|
||||
notification.error({
|
||||
content: '生成API Token失败',
|
||||
duration: 3000
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 复制API Token
|
||||
const copyApiToken = async () => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(configForm.value.api_token)
|
||||
notification.success({
|
||||
content: 'API Token已复制到剪贴板',
|
||||
duration: 3000
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('复制API Token失败:', error)
|
||||
notification.error({
|
||||
content: '复制API Token失败',
|
||||
duration: 3000
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 重新生成API Token
|
||||
const regenerateApiToken = async () => {
|
||||
try {
|
||||
const token = Math.random().toString(36).substring(2) + Date.now().toString(36)
|
||||
configForm.value.api_token = token
|
||||
|
||||
notification.success({
|
||||
content: 'API Token重新生成成功',
|
||||
duration: 3000
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('重新生成API Token失败:', error)
|
||||
notification.error({
|
||||
content: '重新生成API Token失败',
|
||||
duration: 3000
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 打开API文档
|
||||
const openApiDocs = () => {
|
||||
window.open('/api-docs', '_blank')
|
||||
}
|
||||
|
||||
// 打开API测试工具
|
||||
const openApiTest = () => {
|
||||
window.open('/api-test', '_blank')
|
||||
}
|
||||
|
||||
// 导出配置
|
||||
const exportConfig = async () => {
|
||||
try {
|
||||
const configData = {
|
||||
api_token: configForm.value.api_token,
|
||||
export_time: new Date().toISOString()
|
||||
}
|
||||
|
||||
const blob = new Blob([JSON.stringify(configData, null, 2)], { type: 'application/json' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = `dev-config-${new Date().toISOString().split('T')[0]}.json`
|
||||
document.body.appendChild(a)
|
||||
a.click()
|
||||
document.body.removeChild(a)
|
||||
URL.revokeObjectURL(url)
|
||||
|
||||
notification.success({
|
||||
content: '配置导出成功',
|
||||
duration: 3000
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('导出配置失败:', error)
|
||||
notification.error({
|
||||
content: '导出配置失败',
|
||||
duration: 3000
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 导入配置
|
||||
const importConfig = () => {
|
||||
const input = document.createElement('input')
|
||||
input.type = 'file'
|
||||
input.accept = '.json'
|
||||
input.onchange = async (e) => {
|
||||
const file = (e.target as HTMLInputElement).files?.[0]
|
||||
if (file) {
|
||||
try {
|
||||
const text = await file.text()
|
||||
const configData = JSON.parse(text)
|
||||
|
||||
if (configData.api_token) {
|
||||
configForm.value.api_token = configData.api_token
|
||||
notification.success({
|
||||
content: '配置导入成功',
|
||||
duration: 3000
|
||||
})
|
||||
} else {
|
||||
notification.error({
|
||||
content: '配置文件格式错误',
|
||||
duration: 3000
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('导入配置失败:', error)
|
||||
notification.error({
|
||||
content: '导入配置失败',
|
||||
duration: 3000
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
input.click()
|
||||
}
|
||||
|
||||
// 页面加载时获取配置
|
||||
onMounted(() => {
|
||||
fetchConfig()
|
||||
})
|
||||
|
||||
// 设置页面标题
|
||||
useHead({
|
||||
title: '开发配置 - 老九网盘资源数据库'
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 自定义样式 */
|
||||
</style>
|
||||
199
web/pages/admin/feature-config.vue
Normal file
199
web/pages/admin/feature-config.vue
Normal file
@@ -0,0 +1,199 @@
|
||||
<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>
|
||||
<div class="space-y-6">
|
||||
<!-- 自动处理 -->
|
||||
<div class="flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-700 rounded-lg">
|
||||
<div class="flex-1">
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-white">
|
||||
待处理资源自动处理
|
||||
</h3>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400 mt-1">
|
||||
开启后,系统将自动处理待处理的资源,无需手动操作
|
||||
</p>
|
||||
</div>
|
||||
<div class="ml-4">
|
||||
<n-switch v-model:value="configForm.auto_process_enabled" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 自动处理间隔 -->
|
||||
<div v-if="configForm.auto_process_enabled" class="ml-6">
|
||||
<n-form-item label="自动处理间隔 (分钟)" path="auto_process_interval">
|
||||
<n-input
|
||||
v-model:value="configForm.auto_process_interval"
|
||||
type="text"
|
||||
placeholder="30"
|
||||
/>
|
||||
<template #help>
|
||||
建议设置 5-60 分钟,避免过于频繁的处理
|
||||
</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="flex-1">
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-white">
|
||||
自动转存
|
||||
</h3>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400 mt-1">
|
||||
开启后,系统将自动转存资源到其他网盘平台
|
||||
</p>
|
||||
</div>
|
||||
<div class="ml-4">
|
||||
<n-switch v-model:value="configForm.auto_transfer_enabled" />
|
||||
</div>
|
||||
</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="flex-1">
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-white">
|
||||
自动拉取热播剧
|
||||
</h3>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400 mt-1">
|
||||
开启后,系统将自动从豆瓣获取热播剧信息
|
||||
</p>
|
||||
</div>
|
||||
<div class="ml-4">
|
||||
<n-switch v-model:value="configForm.hot_drama_auto_fetch" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</n-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 设置页面布局
|
||||
definePageMeta({
|
||||
layout: 'admin',
|
||||
ssr: false
|
||||
})
|
||||
|
||||
const notification = useNotification()
|
||||
const saving = ref(false)
|
||||
|
||||
// 配置表单数据
|
||||
const configForm = ref({
|
||||
auto_process_enabled: false,
|
||||
auto_process_interval: 30,
|
||||
auto_transfer_enabled: false,
|
||||
auto_transfer_limit_days: 30,
|
||||
auto_transfer_min_space: 500,
|
||||
hot_drama_auto_fetch: false
|
||||
})
|
||||
|
||||
// 获取系统配置
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const { useSystemConfigApi } = await import('~/composables/useApi')
|
||||
const systemConfigApi = useSystemConfigApi()
|
||||
const response = await systemConfigApi.getSystemConfig()
|
||||
|
||||
if (response) {
|
||||
configForm.value = {
|
||||
auto_process_enabled: response.auto_process_ready_resources || false,
|
||||
auto_process_interval: response.auto_process_interval || 30,
|
||||
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,
|
||||
hot_drama_auto_fetch: response.auto_fetch_hot_drama_enabled || false
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取系统配置失败:', error)
|
||||
notification.error({
|
||||
content: '获取系统配置失败',
|
||||
duration: 3000
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 保存配置
|
||||
const saveConfig = async () => {
|
||||
try {
|
||||
saving.value = true
|
||||
|
||||
const { useSystemConfigApi } = await import('~/composables/useApi')
|
||||
const systemConfigApi = useSystemConfigApi()
|
||||
|
||||
await systemConfigApi.updateSystemConfig({
|
||||
auto_process_ready_resources: configForm.value.auto_process_enabled,
|
||||
auto_process_interval: configForm.value.auto_process_interval,
|
||||
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_fetch_hot_drama_enabled: configForm.value.hot_drama_auto_fetch
|
||||
})
|
||||
|
||||
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>
|
||||
193
web/pages/admin/site-config.vue
Normal file
193
web/pages/admin/site-config.vue
Normal file
@@ -0,0 +1,193 @@
|
||||
<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>
|
||||
<n-form
|
||||
ref="formRef"
|
||||
:model="configForm"
|
||||
:rules="rules"
|
||||
label-placement="left"
|
||||
label-width="auto"
|
||||
require-mark-placement="right-hanging"
|
||||
>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<!-- 网站标题 -->
|
||||
<n-form-item label="网站标题" path="site_title">
|
||||
<n-input
|
||||
v-model:value="configForm.site_title"
|
||||
placeholder="请输入网站标题"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<!-- 网站描述 -->
|
||||
<n-form-item label="网站描述" path="site_description">
|
||||
<n-input
|
||||
v-model:value="configForm.site_description"
|
||||
placeholder="请输入网站描述"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<!-- 关键词 -->
|
||||
<n-form-item label="关键词" path="keywords">
|
||||
<n-input
|
||||
v-model:value="configForm.keywords"
|
||||
placeholder="请输入关键词,用逗号分隔"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<!-- 版权信息 -->
|
||||
<n-form-item label="版权信息" path="copyright">
|
||||
<n-input
|
||||
v-model:value="configForm.copyright"
|
||||
placeholder="请输入版权信息"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<!-- 维护模式 -->
|
||||
<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="forbidden_words" class="md:col-span-2">
|
||||
<n-input
|
||||
v-model:value="configForm.forbidden_words"
|
||||
placeholder="请输入违禁词,用逗号分隔"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
/>
|
||||
<template #help>
|
||||
包含这些词汇的资源将被过滤
|
||||
</template>
|
||||
</n-form-item>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 设置页面布局
|
||||
definePageMeta({
|
||||
layout: 'admin',
|
||||
ssr: false
|
||||
})
|
||||
|
||||
const notification = useNotification()
|
||||
const formRef = ref()
|
||||
const saving = ref(false)
|
||||
|
||||
// 配置表单数据
|
||||
const configForm = ref({
|
||||
site_title: '',
|
||||
site_description: '',
|
||||
keywords: '',
|
||||
copyright: '',
|
||||
maintenance_mode: false,
|
||||
forbidden_words: ''
|
||||
})
|
||||
|
||||
// 表单验证规则
|
||||
const rules = {
|
||||
site_title: {
|
||||
required: true,
|
||||
message: '请输入网站标题',
|
||||
trigger: 'blur'
|
||||
},
|
||||
site_description: {
|
||||
required: true,
|
||||
message: '请输入网站描述',
|
||||
trigger: 'blur'
|
||||
}
|
||||
}
|
||||
|
||||
// 获取系统配置
|
||||
const fetchConfig = async () => {
|
||||
try {
|
||||
const { useSystemConfigApi } = await import('~/composables/useApi')
|
||||
const systemConfigApi = useSystemConfigApi()
|
||||
const response = await systemConfigApi.getSystemConfig()
|
||||
|
||||
if (response) {
|
||||
configForm.value = {
|
||||
site_title: response.site_title || '',
|
||||
site_description: response.site_description || '',
|
||||
keywords: response.keywords || '',
|
||||
copyright: response.copyright || '',
|
||||
maintenance_mode: response.maintenance_mode || false,
|
||||
forbidden_words: response.forbidden_words || ''
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取系统配置失败:', error)
|
||||
notification.error({
|
||||
content: '获取系统配置失败',
|
||||
duration: 3000
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 保存配置
|
||||
const saveConfig = async () => {
|
||||
try {
|
||||
await formRef.value?.validate()
|
||||
saving.value = true
|
||||
|
||||
const { useSystemConfigApi } = await import('~/composables/useApi')
|
||||
const systemConfigApi = useSystemConfigApi()
|
||||
|
||||
await systemConfigApi.updateSystemConfig({
|
||||
site_title: configForm.value.site_title,
|
||||
site_description: configForm.value.site_description,
|
||||
keywords: configForm.value.keywords,
|
||||
copyright: configForm.value.copyright,
|
||||
maintenance_mode: configForm.value.maintenance_mode,
|
||||
forbidden_words: configForm.value.forbidden_words
|
||||
})
|
||||
|
||||
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>
|
||||
@@ -1,399 +0,0 @@
|
||||
<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>
|
||||
<n-tabs type="line" animated>
|
||||
<!-- 站点配置 -->
|
||||
<n-tab-pane name="站点配置" tab="站点配置">
|
||||
<n-form
|
||||
ref="formRef"
|
||||
:model="configForm"
|
||||
:rules="rules"
|
||||
label-placement="left"
|
||||
label-width="auto"
|
||||
require-mark-placement="right-hanging"
|
||||
>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<!-- 网站标题 -->
|
||||
<n-form-item label="网站标题" path="site_title">
|
||||
<n-input
|
||||
v-model:value="configForm.site_title"
|
||||
placeholder="请输入网站标题"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<!-- 网站描述 -->
|
||||
<n-form-item label="网站描述" path="site_description">
|
||||
<n-input
|
||||
v-model:value="configForm.site_description"
|
||||
placeholder="请输入网站描述"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<!-- 关键词 -->
|
||||
<n-form-item label="关键词" path="keywords">
|
||||
<n-input
|
||||
v-model:value="configForm.keywords"
|
||||
placeholder="请输入关键词,用逗号分隔"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<!-- 版权信息 -->
|
||||
<n-form-item label="版权信息" path="copyright">
|
||||
<n-input
|
||||
v-model:value="configForm.copyright"
|
||||
placeholder="请输入版权信息"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<!-- 维护模式 -->
|
||||
<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="forbidden_words" class="md:col-span-2">
|
||||
<n-input
|
||||
v-model:value="configForm.forbidden_words"
|
||||
placeholder="请输入违禁词,用逗号分隔"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
/>
|
||||
<template #help>
|
||||
包含这些词汇的资源将被过滤
|
||||
</template>
|
||||
</n-form-item>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-tab-pane>
|
||||
|
||||
<!-- 功能配置 -->
|
||||
<n-tab-pane name="功能配置" tab="功能配置">
|
||||
<div class="space-y-6">
|
||||
<!-- 自动处理 -->
|
||||
<div class="flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-700 rounded-lg">
|
||||
<div class="flex-1">
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-white">
|
||||
待处理资源自动处理
|
||||
</h3>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400 mt-1">
|
||||
开启后,系统将自动处理待处理的资源,无需手动操作
|
||||
</p>
|
||||
</div>
|
||||
<div class="ml-4">
|
||||
<n-switch v-model:value="configForm.auto_process_enabled" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 自动处理间隔 -->
|
||||
<div v-if="configForm.auto_process_enabled" class="ml-6">
|
||||
<n-form-item label="自动处理间隔 (分钟)" path="auto_process_interval">
|
||||
<n-input
|
||||
v-model:value="configForm.auto_process_interval"
|
||||
type="text"
|
||||
placeholder="30"
|
||||
/>
|
||||
<template #help>
|
||||
建议设置 5-60 分钟,避免过于频繁的处理
|
||||
</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="flex-1">
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-white">
|
||||
自动转存
|
||||
</h3>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400 mt-1">
|
||||
开启后,系统将自动转存资源到其他网盘平台
|
||||
</p>
|
||||
</div>
|
||||
<div class="ml-4">
|
||||
<n-switch v-model:value="configForm.auto_transfer_enabled" />
|
||||
</div>
|
||||
</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="flex-1">
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-white">
|
||||
自动拉取热播剧
|
||||
</h3>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400 mt-1">
|
||||
开启后,系统将自动从豆瓣获取热播剧信息
|
||||
</p>
|
||||
</div>
|
||||
<div class="ml-4">
|
||||
<n-switch v-model:value="configForm.hot_drama_auto_fetch" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</n-tab-pane>
|
||||
|
||||
<!-- API配置 -->
|
||||
<n-tab-pane name="API配置" tab="API配置">
|
||||
<div class="space-y-6">
|
||||
<!-- API Token -->
|
||||
<div>
|
||||
<n-form-item label="公开API访问令牌" path="api_token">
|
||||
<div class="flex gap-2">
|
||||
<n-input
|
||||
v-model:value="configForm.api_token"
|
||||
type="password"
|
||||
placeholder="输入API Token,用于公开API访问认证"
|
||||
show-password-on="click"
|
||||
/>
|
||||
<n-button
|
||||
v-if="!configForm.api_token"
|
||||
type="primary"
|
||||
@click="generateApiToken"
|
||||
>
|
||||
生成
|
||||
</n-button>
|
||||
<template v-else>
|
||||
<n-button
|
||||
type="primary"
|
||||
@click="copyApiToken"
|
||||
>
|
||||
复制
|
||||
</n-button>
|
||||
<n-button
|
||||
type="default"
|
||||
@click="generateApiToken"
|
||||
>
|
||||
重新生成
|
||||
</n-button>
|
||||
</template>
|
||||
</div>
|
||||
<template #help>
|
||||
用于公开API的访问认证,建议使用随机字符串
|
||||
</template>
|
||||
</n-form-item>
|
||||
</div>
|
||||
|
||||
<!-- API使用说明 -->
|
||||
<n-card>
|
||||
<template #header>
|
||||
<span class="text-lg font-semibold">API使用说明</span>
|
||||
</template>
|
||||
<div class="space-y-2 text-sm">
|
||||
<p><strong>批量添加资源:</strong> POST /api/public/resources/batch-add</p>
|
||||
<p><strong>资源搜索:</strong> GET /api/public/resources/search</p>
|
||||
<p><strong>热门剧:</strong> GET /api/public/hot-dramas</p>
|
||||
</div>
|
||||
</n-card>
|
||||
</div>
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
</n-card>
|
||||
|
||||
<!-- 系统状态 -->
|
||||
<n-card>
|
||||
<template #header>
|
||||
<span class="text-lg font-semibold">系统状态</span>
|
||||
</template>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<div class="p-4 bg-green-50 dark:bg-green-900/20 rounded-lg">
|
||||
<div class="flex items-center">
|
||||
<i class="fas fa-server text-green-600 text-xl mr-3"></i>
|
||||
<div>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">系统状态</p>
|
||||
<p class="text-lg font-semibold text-green-600">正常运行</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-4 bg-blue-50 dark:bg-blue-900/20 rounded-lg">
|
||||
<div class="flex items-center">
|
||||
<i class="fas fa-database text-blue-600 text-xl mr-3"></i>
|
||||
<div>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">数据库</p>
|
||||
<p class="text-lg font-semibold text-blue-600">连接正常</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-4 bg-yellow-50 dark:bg-yellow-900/20 rounded-lg">
|
||||
<div class="flex items-center">
|
||||
<i class="fas fa-clock text-yellow-600 text-xl mr-3"></i>
|
||||
<div>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">自动处理</p>
|
||||
<p class="text-lg font-semibold text-yellow-600">
|
||||
{{ configForm.auto_process_enabled ? '已启用' : '已禁用' }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-4 bg-purple-50 dark:bg-purple-900/20 rounded-lg">
|
||||
<div class="flex items-center">
|
||||
<i class="fas fa-exchange-alt text-purple-600 text-xl mr-3"></i>
|
||||
<div>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">自动转存</p>
|
||||
<p class="text-lg font-semibold text-purple-600">
|
||||
{{ configForm.auto_transfer_enabled ? '已启用' : '已禁用' }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</n-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
definePageMeta({
|
||||
layout: 'admin' as any
|
||||
})
|
||||
|
||||
// 获取运行时配置
|
||||
const config = useRuntimeConfig()
|
||||
|
||||
// 使用API
|
||||
const { useSystemConfigApi } = await import('~/composables/useApi')
|
||||
const systemConfigApi = useSystemConfigApi()
|
||||
|
||||
// 响应式数据
|
||||
const saving = ref(false)
|
||||
const formRef = ref()
|
||||
|
||||
// 配置表单
|
||||
const configForm = ref({
|
||||
site_title: '',
|
||||
site_description: '',
|
||||
keywords: '',
|
||||
copyright: '',
|
||||
maintenance_mode: false,
|
||||
api_token: '',
|
||||
auto_process_enabled: false,
|
||||
auto_process_interval: '30',
|
||||
auto_transfer_enabled: false,
|
||||
auto_transfer_limit_days: '30',
|
||||
auto_transfer_min_space: '500',
|
||||
forbidden_words: '',
|
||||
hot_drama_auto_fetch: false
|
||||
})
|
||||
|
||||
// 表单验证规则
|
||||
const rules = {
|
||||
site_title: {
|
||||
required: true,
|
||||
message: '请输入网站标题',
|
||||
trigger: 'blur'
|
||||
}
|
||||
}
|
||||
|
||||
// 获取配置
|
||||
const { data: configData, refresh: refreshConfig } = await useAsyncData(
|
||||
'systemConfig',
|
||||
() => systemConfigApi.getSystemConfig()
|
||||
)
|
||||
|
||||
// 监听配置数据变化
|
||||
watch(configData, (newData) => {
|
||||
if (newData && (newData as any)?.data) {
|
||||
configForm.value = {
|
||||
...configForm.value,
|
||||
...(newData as any).data
|
||||
}
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
// 保存配置
|
||||
const saveConfig = async () => {
|
||||
try {
|
||||
saving.value = true
|
||||
await systemConfigApi.updateSystemConfig(configForm.value)
|
||||
useNotification().success({
|
||||
content: '配置保存成功',
|
||||
duration: 3000
|
||||
})
|
||||
await refreshConfig()
|
||||
} catch (error: any) {
|
||||
useNotification().error({
|
||||
content: error.message || '保存配置失败',
|
||||
duration: 5000
|
||||
})
|
||||
} finally {
|
||||
saving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 生成API Token
|
||||
const generateApiToken = () => {
|
||||
const token = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15)
|
||||
configForm.value.api_token = token
|
||||
useNotification().success({
|
||||
content: 'API Token已生成',
|
||||
duration: 3000
|
||||
})
|
||||
}
|
||||
|
||||
// 复制API Token
|
||||
const copyApiToken = async () => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(configForm.value.api_token)
|
||||
useNotification().success({
|
||||
content: 'API Token已复制到剪贴板',
|
||||
duration: 3000
|
||||
})
|
||||
} catch (error) {
|
||||
useNotification().error({
|
||||
content: '复制失败',
|
||||
duration: 3000
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 确保Font Awesome图标正确显示 */
|
||||
.fas {
|
||||
font-family: 'Font Awesome 6 Free';
|
||||
font-weight: 900;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user