Initial commit: 投注游戏平台初始化

This commit is contained in:
li
2026-02-25 01:26:58 +08:00
commit 77ca2cc8b3
275 changed files with 237479 additions and 0 deletions
+388
View File
@@ -0,0 +1,388 @@
<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>