Files
nl_cms-view/src/views/admin/Settings.vue
2025-07-31 10:00:19 +08:00

428 lines
17 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="space-y-6">
<!-- 页面标题 -->
<div>
<h1 class="text-2xl font-bold text-gray-900">系统设置</h1>
<p class="text-gray-600 mt-1">配置系统参数和功能选项</p>
</div>
<!-- 设置选项卡 -->
<div class="bg-white rounded-lg shadow-sm border border-gray-200">
<nav class="flex border-b border-gray-200">
<button
v-for="tab in tabs"
:key="tab.key"
@click="activeTab = tab.key"
:class="[
'px-6 py-4 text-sm font-medium border-b-2 transition-colors',
activeTab === tab.key
? 'border-blue-500 text-blue-600'
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
]"
>
{{ tab.name }}
</button>
</nav>
<div class="p-6">
<!-- 基础设置 -->
<div v-if="activeTab === 'basic'" class="space-y-6">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">网站名称</label>
<input
v-model="settings.siteName"
type="text"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">网站标语</label>
<input
v-model="settings.siteSlogan"
type="text"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
<div class="md:col-span-2">
<label class="block text-sm font-medium text-gray-700 mb-2">网站描述</label>
<textarea
v-model="settings.siteDescription"
rows="3"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
></textarea>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">联系邮箱</label>
<input
v-model="settings.contactEmail"
type="email"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">备案号</label>
<input
v-model="settings.icp"
type="text"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
</div>
</div>
<!-- 安全设置 -->
<div v-if="activeTab === 'security'" class="space-y-6">
<div class="space-y-4">
<div class="flex items-center justify-between p-4 bg-gray-50 rounded-lg">
<div>
<h4 class="text-sm font-medium text-gray-900">启用两步验证</h4>
<p class="text-sm text-gray-500">为管理员账户启用两步验证以提高安全性</p>
</div>
<label class="relative inline-flex items-center cursor-pointer">
<input
v-model="settings.twoFactorAuth"
type="checkbox"
class="sr-only peer"
/>
<div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div>
</label>
</div>
<div class="flex items-center justify-between p-4 bg-gray-50 rounded-lg">
<div>
<h4 class="text-sm font-medium text-gray-900">登录验证码</h4>
<p class="text-sm text-gray-500">登录时需要输入图形验证码</p>
</div>
<label class="relative inline-flex items-center cursor-pointer">
<input
v-model="settings.loginCaptcha"
type="checkbox"
class="sr-only peer"
/>
<div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div>
</label>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">密码最小长度</label>
<select
v-model="settings.minPasswordLength"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
>
<option value="6">6</option>
<option value="8">8</option>
<option value="10">10</option>
<option value="12">12</option>
</select>
</div>
</div>
</div>
<!-- 邮件设置 -->
<div v-if="activeTab === 'email'" class="space-y-6">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">SMTP服务器</label>
<input
v-model="settings.smtpHost"
type="text"
placeholder="smtp.example.com"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">SMTP端口</label>
<input
v-model="settings.smtpPort"
type="number"
placeholder="587"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">发件人邮箱</label>
<input
v-model="settings.fromEmail"
type="email"
placeholder="noreply@example.com"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">发件人名称</label>
<input
v-model="settings.fromName"
type="text"
placeholder="系统管理员"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">用户名</label>
<input
v-model="settings.smtpUsername"
type="text"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">密码</label>
<input
v-model="settings.smtpPassword"
type="password"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
</div>
</div>
<!-- 存储设置 -->
<div v-if="activeTab === 'storage'" class="space-y-6">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">存储类型</label>
<select
v-model="settings.storageType"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
>
<option value="local">本地存储</option>
<option value="oss">阿里云OSS</option>
<option value="cos">腾讯云COS</option>
<option value="qiniu">七牛云</option>
</select>
</div>
<div v-if="settings.storageType !== 'local'" class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Access Key</label>
<input
v-model="settings.accessKey"
type="text"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Secret Key</label>
<input
v-model="settings.secretKey"
type="password"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">存储桶名称</label>
<input
v-model="settings.bucket"
type="text"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">访问域名</label>
<input
v-model="settings.domain"
type="text"
placeholder="https://example.com"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">最大文件大小MB</label>
<input
v-model="settings.maxFileSize"
type="number"
min="1"
max="100"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">允许的文件类型</label>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mt-2">
<label v-for="type in fileTypes" :key="type.value" class="flex items-center">
<input
v-model="settings.allowedFileTypes"
:value="type.value"
type="checkbox"
class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"
/>
<span class="ml-2 text-sm text-gray-700">{{ type.label }}</span>
</label>
</div>
</div>
</div>
</div>
<!-- 系统信息 -->
<div v-if="activeTab === 'system'" class="space-y-6">
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div class="bg-gray-50 p-4 rounded-lg">
<h4 class="text-sm font-medium text-gray-900 mb-2">系统版本</h4>
<p class="text-lg font-semibold text-blue-600">v1.0.0</p>
</div>
<div class="bg-gray-50 p-4 rounded-lg">
<h4 class="text-sm font-medium text-gray-900 mb-2">数据库大小</h4>
<p class="text-lg font-semibold text-purple-600">45.2 MB</p>
</div>
<div class="bg-gray-50 p-4 rounded-lg">
<h4 class="text-sm font-medium text-gray-900 mb-2">存储空间</h4>
<p class="text-lg font-semibold text-green-600">2.1 GB</p>
</div>
</div>
<div class="bg-yellow-50 border border-yellow-200 rounded-lg p-4">
<div class="flex">
<div class="flex-shrink-0">
<WarningIcon class="h-5 w-5 text-yellow-400" />
</div>
<div class="ml-3">
<h3 class="text-sm font-medium text-yellow-800">系统维护建议</h3>
<div class="mt-2 text-sm text-yellow-700">
<p>建议定期清理系统缓存和日志文件以保持系统性能</p>
</div>
<div class="mt-4 flex space-x-3">
<button
@click="clearCache"
class="bg-yellow-100 hover:bg-yellow-200 text-yellow-800 px-3 py-1 rounded text-sm"
>
清理缓存
</button>
<button
@click="clearLogs"
class="bg-yellow-100 hover:bg-yellow-200 text-yellow-800 px-3 py-1 rounded text-sm"
>
清理日志
</button>
</div>
</div>
</div>
</div>
</div>
<!-- 保存按钮 -->
<div class="flex justify-end pt-6 border-t border-gray-200">
<button
@click="saveSettings"
class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded-lg"
>
保存设置
</button>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
// 图标组件
const WarningIcon = {
template: `<svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z"></path></svg>`
}
// 响应式数据
const activeTab = ref('basic')
const tabs = [
{ key: 'basic', name: '基础设置' },
{ key: 'security', name: '安全设置' },
{ key: 'email', name: '邮件设置' },
{ key: 'storage', name: '存储设置' },
{ key: 'system', name: '系统信息' }
]
const settings = ref({
// 基础设置
siteName: 'CMS管理系统',
siteSlogan: '高效、安全、易用的内容管理系统',
siteDescription: '这是一个基于Vue3和TailwindCSS构建的现代化内容管理系统提供完整的文章管理、用户管理和系统配置功能。',
contactEmail: 'admin@example.com',
icp: '京ICP备12345678号',
// 安全设置
twoFactorAuth: false,
loginCaptcha: true,
minPasswordLength: '8',
// 邮件设置
smtpHost: '',
smtpPort: 587,
fromEmail: 'noreply@example.com',
fromName: '系统管理员',
smtpUsername: '',
smtpPassword: '',
// 存储设置
storageType: 'local',
accessKey: '',
secretKey: '',
bucket: '',
domain: '',
maxFileSize: 10,
allowedFileTypes: ['jpg', 'png', 'gif', 'pdf', 'doc']
})
const fileTypes = [
{ value: 'jpg', label: 'JPG图片' },
{ value: 'png', label: 'PNG图片' },
{ value: 'gif', label: 'GIF图片' },
{ value: 'pdf', label: 'PDF文档' },
{ value: 'doc', label: 'Word文档' },
{ value: 'xls', label: 'Excel表格' },
{ value: 'zip', label: 'ZIP压缩包' },
{ value: 'mp4', label: 'MP4视频' }
]
// 保存设置
const saveSettings = () => {
console.log('保存设置:', settings.value)
// 这里应该调用API保存设置
alert('设置保存成功!')
}
// 清理缓存
const clearCache = () => {
if (confirm('确定要清理系统缓存吗?')) {
console.log('清理缓存')
// 这里应该调用API清理缓存
alert('缓存清理完成!')
}
}
// 清理日志
const clearLogs = () => {
if (confirm('确定要清理系统日志吗?此操作不可恢复!')) {
console.log('清理日志')
// 这里应该调用API清理日志
alert('日志清理完成!')
}
}
</script>
<style lang='scss' scoped>
/* 开关样式 */
.peer:checked ~ .peer-checked\:bg-blue-600 {
background-color: #2563eb;
}
/* 响应式优化 */
@media (max-width: 1024px) {
.grid-cols-1.md\:grid-cols-2 {
grid-template-columns: 1fr;
}
.grid-cols-1.md\:grid-cols-3 {
grid-template-columns: 1fr;
}
}
/* 标签页导航样式 */
nav ul li button {
transition: all 0.2s ease-in-out;
}
</style>