Files
pk10/App/Views/Admin/settings.php
T

388 lines
19 KiB
PHP
Executable File
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.
<h1 class="text-2xl font-bold text-gray-800 mb-6 flex items-center">
<i class="fas fa-cog text-primary mr-3"></i>
系统设置
</h1>
<!-- 设置表单 -->
<form id="settingsForm" class="space-y-6">
<!-- Logo设置 -->
<div class="bg-white rounded-xl shadow-md p-6 mb-6">
<h3 class="text-lg font-semibold text-gray-800 mb-4 flex items-center">
<i class="fas fa-image text-primary mr-2"></i>
Logo设置
</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- Logo -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">网站Logo</label>
<div class="flex items-center gap-4">
<div class="flex-shrink-0">
<img id="site_logo_preview" src="<?= htmlspecialchars($settings['site_logo'] ?? '') ?>"
alt="Logo预览"
class="w-32 h-32 object-contain border border-gray-200 rounded-lg bg-gray-50 p-2"
style="<?= empty($settings['site_logo'] ?? '') ? 'display:none;' : '' ?>">
</div>
<div class="flex-1">
<input type="file" id="site_logo_file" name="site_logo_file" accept="image/jpeg,image/png,image/gif,image/webp"
class="hidden" onchange="handleLogoUpload(this, 'site_logo')">
<button type="button" onclick="document.getElementById('site_logo_file').click()"
class="w-full px-4 py-2 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors">
<i class="fas fa-upload mr-2"></i>选择图片
</button>
<input type="hidden" id="site_logo" name="site_logo" value="<?= htmlspecialchars($settings['site_logo'] ?? '') ?>">
<p class="text-xs text-gray-500 mt-2">建议尺寸:200x60px,支持JPG/PNG/GIF/WEBP,前端统一使用此Logo</p>
</div>
</div>
</div>
<!-- Favicon -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">网站图标 (Favicon)</label>
<div class="flex items-center gap-4">
<div class="flex-shrink-0">
<img id="site_favicon_preview" src="<?= htmlspecialchars($settings['site_favicon'] ?? '') ?>"
alt="Favicon预览"
class="w-16 h-16 object-contain border border-gray-200 rounded-lg bg-gray-50 p-2"
style="<?= empty($settings['site_favicon'] ?? '') ? 'display:none;' : '' ?>">
</div>
<div class="flex-1">
<input type="file" id="site_favicon_file" name="site_favicon_file" accept="image/x-icon,image/vnd.microsoft.icon,image/png"
class="hidden" onchange="handleLogoUpload(this, 'site_favicon')">
<button type="button" onclick="document.getElementById('site_favicon_file').click()"
class="w-full px-4 py-2 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors">
<i class="fas fa-upload mr-2"></i>选择图标
</button>
<input type="hidden" id="site_favicon" name="site_favicon" value="<?= htmlspecialchars($settings['site_favicon'] ?? '') ?>">
<p class="text-xs text-gray-500 mt-2">建议尺寸:32x32px,支持ICO/PNG格式</p>
</div>
</div>
</div>
</div>
</div>
<!-- 网站基本信息 -->
<div class="bg-white rounded-xl shadow-md p-6 mb-6">
<h3 class="text-lg font-semibold text-gray-800 mb-4 flex items-center">
<i class="fas fa-info-circle text-primary mr-2"></i>
网站基本信息
</h3>
<div class="space-y-4">
<div>
<label for="site_title" class="block text-sm font-medium text-gray-700 mb-1">网站标题</label>
<input type="text" id="site_title" name="site_title"
value="<?= htmlspecialchars($settings['site_title'] ?? '') ?>"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary transition-colors"
placeholder="请输入网站标题">
</div>
<div>
<label for="site_description" class="block text-sm font-medium text-gray-700 mb-1">网站描述</label>
<textarea id="site_description" name="site_description" rows="3"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary transition-colors resize-none"
placeholder="请输入网站描述"><?= htmlspecialchars($settings['site_description'] ?? '') ?></textarea>
<p class="text-xs text-gray-500 mt-1">用于SEO优化,建议控制在150字以内</p>
</div>
<div>
<label for="site_keywords" class="block text-sm font-medium text-gray-700 mb-1">网站关键词</label>
<input type="text" id="site_keywords" name="site_keywords"
value="<?= htmlspecialchars($settings['site_keywords'] ?? '') ?>"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary transition-colors"
placeholder="请输入关键词,用逗号分隔">
<p class="text-xs text-gray-500 mt-1">多个关键词用逗号分隔</p>
</div>
<div>
<label for="site_copyright" class="block text-sm font-medium text-gray-700 mb-1">版权信息</label>
<input type="text" id="site_copyright" name="site_copyright"
value="<?= htmlspecialchars($settings['site_copyright'] ?? '') ?>"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary transition-colors"
placeholder="请输入版权信息">
</div>
</div>
</div>
<!-- 操作按钮 -->
<div class="flex justify-end gap-3 pt-4">
<button type="button" onclick="resetSettings()"
class="px-6 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50 transition-colors">
<i class="fas fa-undo mr-2"></i>重置
</button>
<button type="button" id="saveSettingsBtn"
class="px-6 py-2 bg-primary hover:bg-primary/90 text-white rounded-lg shadow hover:shadow-md transition-all duration-200">
<i class="fas fa-save mr-2"></i>保存设置
</button>
</div>
<!-- SMTP 邮件配置 -->
<div class="bg-white rounded-xl shadow-md p-6 mb-6">
<h3 class="text-lg font-semibold text-gray-800 mb-4 flex items-center">
<i class="fas fa-envelope text-primary mr-2"></i>
SMTP 邮件配置
</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">SMTP 服务器</label>
<input type="text" id="smtp_host" name="smtp_host" value="<?= htmlspecialchars($settings['smtp_host'] ?? '') ?>"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary transition-colors"
placeholder="如 smtp.gmail.com">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">端口</label>
<input type="number" id="smtp_port" name="smtp_port" value="<?= htmlspecialchars($settings['smtp_port'] ?? '465') ?>"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary transition-colors"
placeholder="465">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">加密方式</label>
<select id="smtp_encryption" name="smtp_encryption"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary transition-colors">
<option value="ssl" <?= ($settings['smtp_encryption'] ?? 'ssl') === 'ssl' ? 'selected' : '' ?>>SSL (端口465)</option>
<option value="tls" <?= ($settings['smtp_encryption'] ?? '') === 'tls' ? 'selected' : '' ?>>TLS (端口587)</option>
<option value="none" <?= ($settings['smtp_encryption'] ?? '') === 'none' ? 'selected' : '' ?>>无加密 (端口25)</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">SMTP 用户名</label>
<input type="text" id="smtp_user" name="smtp_user" value="<?= htmlspecialchars($settings['smtp_user'] ?? '') ?>"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary transition-colors"
placeholder="your@email.com">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">SMTP 密码</label>
<input type="password" id="smtp_pass" name="smtp_pass" value="<?= htmlspecialchars($settings['smtp_pass'] ?? '') ?>"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary transition-colors"
placeholder="密码或应用专用密码">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">发件人地址</label>
<input type="text" id="smtp_from" name="smtp_from" value="<?= htmlspecialchars($settings['smtp_from'] ?? '') ?>"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary transition-colors"
placeholder="noreply@yourdomain.com(留空则用SMTP用户名)">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">发件人名称</label>
<input type="text" id="smtp_from_name" name="smtp_from_name" value="<?= htmlspecialchars($settings['smtp_from_name'] ?? 'PK10') ?>"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary transition-colors"
placeholder="PK10">
</div>
<div class="flex items-end">
<button type="button" onclick="testSmtp()"
class="w-full px-4 py-2 bg-green-600 hover:bg-green-700 text-white rounded-lg transition-colors">
<i class="fas fa-paper-plane mr-2"></i>发送测试邮件
</button>
</div>
</div>
<p class="text-xs text-gray-500 mt-3">
<i class="fas fa-info-circle mr-1"></i>
常用配置:Gmail(smtp.gmail.com:465/SSL)、Outlook(smtp-mail.outlook.com:587/TLS)、QQ邮箱(smtp.qq.com:465/SSL)、163邮箱(smtp.163.com:465/SSL)
</p>
</div>
</form>
<script>
function testSmtp(){
const email=prompt('输入接收测试邮件的邮箱地址:');
if(!email)return;
// 先保存当前配置再测试
const data={};
document.querySelectorAll('#settingsForm [name^="smtp_"]').forEach(el=>{data[el.name]=el.value;});
fetch('/admin/settings/save',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(data)})
.then(()=>fetch('/admin/settings/smtp-test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({email})}))
.then(r=>r.json())
.then(d=>{showMessage(d.message,d.success?'success':'error');})
.catch(()=>{showMessage('测试失败','error');});
}
</script>
<script>
// Logo上传处理
function handleLogoUpload(input, logoType) {
const file = input.files[0];
if (!file) return;
// 验证文件大小(5MB
if (file.size > 5 * 1024 * 1024) {
alert('文件大小不能超过5MB');
input.value = '';
return;
}
// 验证文件类型
const allowedTypes = logoType === 'site_favicon'
? ['image/x-icon', 'image/vnd.microsoft.icon', 'image/png']
: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
if (!allowedTypes.includes(file.type)) {
alert('不支持的文件类型');
input.value = '';
return;
}
// 预览图片
const reader = new FileReader();
reader.onload = function(e) {
const previewId = logoType + '_preview';
const previewImg = document.getElementById(previewId);
if (previewImg) {
previewImg.src = e.target.result;
previewImg.style.display = '';
}
};
reader.readAsDataURL(file);
// 立即上传
uploadLogo(file, logoType);
}
// 上传Logo到服务器
function uploadLogo(file, logoType) {
const formData = new FormData();
formData.append(logoType + '_file', file);
formData.append('logo_type', logoType);
// 显示上传中状态
const saveBtn = document.getElementById('saveSettingsBtn');
const originalText = saveBtn.innerHTML;
saveBtn.disabled = true;
saveBtn.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i>上传中...';
fetch('/admin/settings/save', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.status === 'success') {
// 更新隐藏字段的值
const hiddenInput = document.getElementById(logoType);
const previewImg = document.getElementById(logoType + '_preview');
if (data.data && data.data[logoType]) {
if (hiddenInput) hiddenInput.value = data.data[logoType];
if (previewImg) {
previewImg.src = data.data[logoType];
previewImg.style.display = '';
}
}
// 显示成功提示
showMessage('Logo上传成功', 'success');
} else {
alert('上传失败: ' + (data.message || '未知错误'));
}
})
.catch(error => {
console.error('Upload error:', error);
alert('上传失败,请稍后重试');
})
.finally(() => {
saveBtn.disabled = false;
saveBtn.innerHTML = originalText;
});
}
// 保存设置
document.getElementById('saveSettingsBtn').addEventListener('click', function() {
const form = document.getElementById('settingsForm');
const formData = new FormData(form);
// 将FormData转换为JSON对象
const data = {};
for (let [key, value] of formData.entries()) {
// 跳过文件输入
if (key.endsWith('_file')) continue;
data[key] = value;
}
// 发送保存请求
const saveBtn = this;
const originalText = saveBtn.innerHTML;
saveBtn.disabled = true;
saveBtn.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i>保存中...';
fetch('/admin/settings/save', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => {
if (data.status === 'success') {
showMessage('设置保存成功', 'success');
// 如果有返回的数据,更新页面
if (data.data) {
updateSettingsPreview(data.data);
}
} else {
showMessage('保存失败: ' + (data.message || '未知错误'), 'error');
}
})
.catch(error => {
console.error('Save error:', error);
showMessage('保存失败,请稍后重试', 'error');
})
.finally(() => {
saveBtn.disabled = false;
saveBtn.innerHTML = originalText;
});
});
// 重置设置
function resetSettings() {
if (confirm('确定要重置所有设置吗?')) {
location.reload();
}
}
// 更新预览
function updateSettingsPreview(settings) {
const logoPreview = document.getElementById('site_logo_preview');
if (logoPreview) {
if (settings.site_logo) {
logoPreview.src = settings.site_logo;
logoPreview.style.display = '';
} else {
logoPreview.src = '';
logoPreview.style.display = 'none';
}
}
const faviconPreview = document.getElementById('site_favicon_preview');
if (faviconPreview) {
if (settings.site_favicon) {
faviconPreview.src = settings.site_favicon;
faviconPreview.style.display = '';
} else {
faviconPreview.src = '';
faviconPreview.style.display = 'none';
}
}
}
// 显示消息提示
function showMessage(message, type = 'success') {
// 创建提示元素
const messageEl = document.createElement('div');
messageEl.className = `fixed top-4 right-4 px-6 py-3 rounded-lg shadow-lg z-50 ${
type === 'success' ? 'bg-green-500 text-white' : 'bg-red-500 text-white'
}`;
messageEl.innerHTML = `
<div class="flex items-center">
<i class="fas ${type === 'success' ? 'fa-check-circle' : 'fa-exclamation-circle'} mr-2"></i>
<span>${message}</span>
</div>
`;
document.body.appendChild(messageEl);
// 3秒后自动移除
setTimeout(() => {
messageEl.remove();
}, 3000);
}
// 页面加载时获取设置
document.addEventListener('DOMContentLoaded', function() {
// 设置已经在页面加载时通过PHP变量传递,无需额外请求
});
</script>