iFileProxyAdmin/src/views/ConfigView.vue
2024-12-02 21:39:41 +08:00

393 lines
No EOL
9.5 KiB
Vue

<template>
<div class="config-view">
<el-card class="config-card">
<template #header>
<div class="card-header">
<span class="title">系统配置</span>
<el-button type="primary" @click="handleRefresh" class="refresh-btn">
<el-icon><Refresh /></el-icon>刷新配置
</el-button>
</div>
</template>
<el-tabs type="border-card">
<el-tab-pane label="下载配置">
<el-descriptions :column="isMobile ? 1 : 2" border>
<el-descriptions-item label="临时文件位置">
{{ config.Download.savePath }}
</el-descriptions-item>
<el-descriptions-item label="下载线程数">
{{ config.Download.threadNum }}
</el-descriptions-item>
<el-descriptions-item label="最大文件大小">
{{ formatFileSize(config.Download.maxAllowedFileSize) }}
<el-tooltip
content="仅针对新添加的任务 若是已经添加任务的文件则不受限制"
placement="top">
<el-icon class="ml-2"><InfoFilled /></el-icon>
</el-tooltip>
</el-descriptions-item>
<el-descriptions-item label="最大并行任务">
{{ config.Download.maxParallelTasks }}
</el-descriptions-item>
<el-descriptions-item label="最大队列长度">
{{ config.Download.maxQueueLength }}
</el-descriptions-item>
<el-descriptions-item label="缓存生命周期">
{{ formatDuration(config.Download.cacheLifetime) }}
</el-descriptions-item>
<el-descriptions-item label="Aria2c路径">
{{ config.Download.aria2cPath }}
</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<el-tab-pane label="安全配置">
<el-descriptions :column="1" border>
<el-descriptions-item label="禁止代理的主机">
<el-tag
v-for="host in config.Security.blockedHost"
:key="host"
class="mx-1"
type="danger">
{{ host }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="禁止代理的文件">
<el-tag
v-for="file in config.Security.blockedFileName"
:key="file"
class="mx-1"
type="danger">
{{ file }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="IP黑名单">
<el-tag
v-for="ip in config.Security.blockedClientIP"
:key="ip"
class="mx-1"
type="danger">
{{ ip }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="IP每日请求限制">
{{ config.Security.dailyRequestLimitPerIP }} /
</el-descriptions-item>
<el-descriptions-item label="统计请求的路径">
<el-tag
v-for="route in config.Security.routesToTrack"
:key="route"
class="mx-1"
type="info">
{{ route }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="允许不同IP下载">
<el-tag :type="config.Security.allowDifferentIPsForDownload ? 'success' : 'danger'">
{{ config.Security.allowDifferentIPsForDownload ? '是' : '否' }}
</el-tag>
</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<el-tab-pane label="数据库配置">
<el-descriptions :column="isMobile ? 1 : 2" border>
<el-descriptions-item label="数据库主机">
{{ config.Database.Common.Host }}
</el-descriptions-item>
<el-descriptions-item label="端口">
{{ config.Database.Common.Port }}
</el-descriptions-item>
<el-descriptions-item label="用户名">
{{ config.Database.Common.User }}
</el-descriptions-item>
<el-descriptions-item label="密码">
********
</el-descriptions-item>
<el-descriptions-item label="连接池最大连接数">
{{ config.Database.MaxConnectionPoolSize }}
</el-descriptions-item>
<el-descriptions-item label="数据库" :span="isMobile ? 1 : 2">
<div class="database-tags">
<el-tag
v-for="db in config.Database.Databases"
:key="db.DatabaseName"
class="database-tag">
{{ db.DatabaseName }}
<el-tooltip
v-if="db.Description"
:content="db.Description"
placement="top">
<el-icon class="ml-2"><InfoFilled /></el-icon>
</el-tooltip>
</el-tag>
</div>
</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
</el-tabs>
</el-card>
</div>
</template>
<script setup>
import { ref, computed, onMounted, onUnmounted } from 'vue'
import { ElMessage } from 'element-plus'
import { Refresh, InfoFilled } from '@element-plus/icons-vue'
import { TaskAPI } from '../api/task'
const config = ref({
Download: {
savePath: '',
threadNum: 0,
maxAllowedFileSize: 0,
maxParallelTasks: 0,
maxQueueLength: 0,
aria2cPath: '',
cacheLifetime: 0
},
Security: {
blockedHost: [],
blockedFileName: [],
blockedClientIP: [],
routesToTrack: [],
dailyRequestLimitPerIP: 0,
allowDifferentIPsForDownload: false
},
Database: {
Common: {
Host: '',
Port: 0,
User: '',
Password: '********'
},
Databases: []
}
})
const formatFileSize = (bytes) => {
if (!bytes) return '0 B'
const units = ['B', 'KB', 'MB', 'GB', 'TB']
let i = 0
while (bytes >= 1024 && i < units.length - 1) {
bytes /= 1024
i++
}
return `${bytes.toFixed(2)} ${units[i]}`
}
const formatDuration = (seconds) => {
if (seconds < 60) return `${seconds}`
if (seconds < 3600) return `${Math.floor(seconds / 60)}分钟`
return `${Math.floor(seconds / 3600)}小时${Math.floor((seconds % 3600) / 60)}分钟`
}
const fetchConfig = async () => {
try {
const response = await TaskAPI.getSystemConfig()
if (response.retcode === 0) {
config.value = response.data
}
} catch (error) {
console.error('获取系统配置失败:', error)
}
}
const handleRefresh = async () => {
try {
await fetchConfig()
ElMessage.success('配置已刷新')
} catch (error) {
ElMessage.error('刷新配置失败')
}
}
// 添加移动端检测
const isMobile = computed(() => {
return window.innerWidth <= 768
})
// 监听窗口大小变化
onMounted(() => {
window.addEventListener('resize', () => {
isMobile.value = window.innerWidth <= 768
})
})
onUnmounted(() => {
window.removeEventListener('resize', () => {
isMobile.value = window.innerWidth <= 768
})
})
onMounted(() => {
fetchConfig()
})
</script>
<style scoped>
.config-view {
padding: 20px;
}
.config-card {
background: #fff;
border-radius: 4px;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.title {
font-size: 16px;
font-weight: 500;
}
:deep(.el-descriptions__label) {
width: 140px;
font-weight: 500;
}
.mx-1 {
margin: 0 4px;
}
.ml-2 {
margin-left: 4px;
}
:deep(.el-tabs__content) {
padding: 20px;
}
:deep(.el-tag) {
margin: 4px;
}
.database-tags {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.database-tag {
display: inline-flex;
align-items: center;
gap: 4px;
}
/* 移动端样式 */
@media screen and (max-width: 768px) {
.config-view {
padding: 10px;
}
.card-header {
flex-direction: column;
gap: 12px;
}
.title {
font-size: 14px;
}
.refresh-btn {
width: 100%;
}
:deep(.el-descriptions) {
margin-top: 12px;
}
:deep(.el-descriptions__label) {
width: 100px;
min-width: 100px;
font-size: 12px;
}
:deep(.el-descriptions__content) {
font-size: 12px;
word-break: break-all;
}
:deep(.el-descriptions__cell) {
padding: 12px !important;
}
:deep(.el-tag) {
font-size: 11px;
padding: 0 4px;
}
.database-tags {
gap: 6px;
}
.database-tag {
font-size: 11px;
padding: 0 6px;
}
:deep(.el-tabs__item) {
font-size: 13px;
padding: 0 12px;
}
:deep(.el-tabs__content) {
padding: 12px;
}
:deep(.el-descriptions__cell) {
padding: 12px !important;
}
:deep(.el-descriptions__label) {
width: 90px;
min-width: 90px;
font-size: 12px;
padding-right: 12px;
}
:deep(.el-descriptions__content) {
font-size: 12px;
word-break: break-all;
}
}
/* 平板端样式 */
@media screen and (min-width: 769px) and (max-width: 1024px) {
.config-view {
padding: 15px;
}
:deep(.el-descriptions__label) {
width: 120px;
}
.database-tags {
gap: 8px;
}
:deep(.el-descriptions__label) {
width: 110px;
}
}
/* 优化标签显示 */
:deep(.el-tag) {
white-space: nowrap;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
}
/* 优化按钮图标对齐 */
:deep(.el-button .el-icon) {
margin-right: 4px;
vertical-align: middle;
}
</style>