初始化鸿蒙应用展示平台项目 - 前后端分离架构

This commit is contained in:
Nvex
2025-10-25 11:45:17 +08:00
commit c0f81dbbe2
92 changed files with 40210 additions and 0 deletions

520
templates/site_settings.html Executable file
View File

@@ -0,0 +1,520 @@
{% extends "base.html" %}
{% block content %}
{% include 'admin_nav.html' %}
<div class="admin-container">
<div class="admin-content">
<div class="settings-layout">
<!-- 左侧导航 -->
<div class="settings-nav">
<div class="nav-item active" data-target="basic">
<i class="fas fa-cog"></i>
<span>基础设置</span>
</div>
<div class="nav-item" data-target="groups">
<i class="fas fa-users"></i>
<span>群组设置</span>
</div>
<div class="nav-item" data-target="watermark">
<i class="fas fa-image"></i>
<span>水印设置</span>
</div>
</div>
<!-- 右侧内容区 -->
<div class="settings-content">
<!-- 基础设置 -->
<div class="settings-section active" id="basic-section">
<div class="section-header">
<h2>基础设置</h2>
<p class="section-desc">设置站点的基本信息和通知内容</p>
</div>
<form onsubmit="submitSettings(event, 'basic')" class="admin-form">
<div class="form-group">
<label for="site-notice">站点通知</label>
<textarea id="site-notice" name="site_notice" rows="3" required>{{ settings.site_notice }}</textarea>
</div>
<div class="form-group">
<label for="feedback-link">反馈链接</label>
<input type="url" id="feedback-link" name="feedback_link" value="{{ settings.feedback_link }}" required>
</div>
<div class="form-group">
<label for="discord-link">Discord 频道链接</label>
<input type="url" id="discord-link" name="discord_link" value="{{ settings.discord_link }}">
</div>
<div class="form-group">
<label for="icp-number">网站备案号</label>
<input type="text" id="icp-number" name="icp_number"
value="{{ settings.icp_number }}"
placeholder="例如京ICP备XXXXXXXX号">
</div>
<div class="form-group">
<label for="grayscale-enabled">网页黑白效果</label>
<div class="switch-wrapper">
<label class="switch">
<input type="checkbox" id="grayscale-enabled" name="grayscale_enabled"
{% if settings.grayscale_enabled == '1' %}checked{% endif %}>
<span class="slider round"></span>
</label>
<span class="switch-label">启用网页黑白效果(用于特殊纪念日)</span>
</div>
</div>
<button type="submit" class="btn-primary">
<i class="fas fa-save"></i> 保存设置
</button>
</form>
</div>
<!-- 群组设置 -->
<div class="settings-section" id="groups-section">
<div class="section-header">
<h2>群组设置</h2>
<p class="section-desc">管理QQ群和微信群的相关配置</p>
</div>
<form onsubmit="submitSettings(event, 'groups')" class="admin-form">
<div class="settings-grid">
<!-- QQ群设置 -->
<div class="setting-card">
<div class="card-header">
<i class="fab fa-qq"></i>
<h3>QQ群设置</h3>
</div>
<div class="card-body">
<div class="form-group">
<label>按钮文字</label>
<input type="text" name="qq_group_text" value="{{ settings.qq_group_text }}" class="form-control">
</div>
<div class="form-group">
<label>群号</label>
<input type="text" name="qq_group_number" value="{{ settings.qq_group_number }}" class="form-control">
</div>
<div class="form-group">
<label>加群链接</label>
<input type="text" name="qq_group_link" value="{{ settings.qq_group_link }}" class="form-control">
</div>
<div class="form-group">
<label>群二维码</label>
<input type="file" name="qq_group_qrcode" accept="image/*" class="form-control">
{% if settings.qq_group_qrcode %}
<div class="preview-image">
<img src="{{ settings.qq_group_qrcode }}" alt="QQ群二维码">
</div>
{% endif %}
</div>
</div>
</div>
<!-- 微信群设置 -->
<div class="setting-card">
<div class="card-header">
<i class="fab fa-weixin"></i>
<h3>微信群设置</h3>
</div>
<div class="card-body">
<div class="form-group">
<label>按钮文字</label>
<input type="text" name="wechat_group_text" value="{{ settings.wechat_group_text }}" class="form-control">
</div>
<div class="form-group">
<label>群二维码</label>
<input type="file" name="wechat_group_qrcode" accept="image/*" class="form-control">
{% if settings.wechat_group_qrcode %}
<div class="preview-image">
<img src="{{ settings.wechat_group_qrcode }}" alt="微信群二维码">
</div>
{% endif %}
</div>
</div>
</div>
</div>
<button type="submit" class="btn-primary">
<i class="fas fa-save"></i> 保存设置
</button>
</form>
</div>
<!-- 水印设置 -->
<div class="settings-section" id="watermark-section">
<div class="section-header">
<h2>水印设置</h2>
<p class="section-desc">设置应用图标的水印文本</p>
</div>
<form onsubmit="submitSettings(event, 'watermark')" class="admin-form">
<div class="form-group">
<label for="watermark-text-1">水印文本 1</label>
<input type="text" id="watermark-text-1" name="watermark_text_1"
value="{{ settings.watermark_text_1 }}"
placeholder="输入第一个水印文本">
</div>
<div class="form-group">
<label for="watermark-text-2">水印文本 2</label>
<input type="text" id="watermark-text-2" name="watermark_text_2"
value="{{ settings.watermark_text_2 }}"
placeholder="输入第二个水印文本">
</div>
<button type="submit" class="btn-primary">
<i class="fas fa-save"></i> 保存设置
</button>
</form>
</div>
</div>
</div>
</div>
</div>
<style>
/* 主布局 */
.settings-layout {
display: flex;
gap: 15px;
padding: 15px;
min-height: calc(100vh - 60px);
}
/* 左侧导航 */
.settings-nav {
width: 180px;
background: white;
border-radius: 8px;
padding: 10px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.nav-item {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 12px;
border-radius: 6px;
cursor: pointer;
transition: all 0.3s ease;
}
.nav-item i {
font-size: 16px;
width: 20px;
text-align: center;
}
.nav-item.active {
background: #007AFF;
color: white;
}
.nav-item:not(.active):hover {
background: #f5f5f7;
}
/* 右侧内容区 */
.settings-content {
flex: 1;
background: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.settings-section {
display: none;
}
.settings-section.active {
display: block;
}
.section-header {
margin-bottom: 30px;
}
.section-header h2 {
margin: 0;
font-size: 24px;
color: #333;
}
.section-desc {
margin: 8px 0 0 0;
color: #666;
font-size: 14px;
}
/* 表单样式 */
.settings-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
margin-bottom: 20px;
}
.setting-card {
background: #f5f5f7;
border-radius: 12px;
padding: 20px;
}
.card-header {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 20px;
}
.card-header i {
font-size: 20px;
}
.card-header h3 {
margin: 0;
font-size: 18px;
}
.form-group {
margin-bottom: 20px;
}
.form-control {
width: 100%;
padding: 10px;
border: 1px solid #d2d2d7;
border-radius: 8px;
font-size: 14px;
transition: all 0.3s ease;
}
.form-control:focus {
border-color: #007AFF;
box-shadow: 0 0 0 2px rgba(0,122,255,0.1);
outline: none;
}
textarea.form-control {
min-height: 100px;
resize: vertical;
}
.preview-image {
margin-top: 10px;
}
.preview-image img {
max-width: 200px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
/* 按钮样式 */
.btn-primary {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 10px 20px;
background: #007AFF;
color: white;
border: none;
border-radius: 8px;
font-size: 14px;
cursor: pointer;
transition: all 0.3s ease;
}
.btn-primary:hover {
background: #0066CC;
transform: translateY(-1px);
}
/* 暗色模式 */
[data-theme="dark"] .settings-nav,
[data-theme="dark"] .settings-content {
background: #1c1c1e;
}
[data-theme="dark"] .setting-card {
background: #2c2c2e;
}
[data-theme="dark"] .section-header h2 {
color: #fff;
}
[data-theme="dark"] .section-desc {
color: #999;
}
[data-theme="dark"] .form-control {
background: #2c2c2e;
border-color: #3a3a3c;
color: #fff;
}
[data-theme="dark"] .nav-item:not(.active):hover {
background: #2c2c2e;
}
/* 响应式布局 */
@media (max-width: 768px) {
.settings-layout {
flex-direction: column;
}
.settings-nav {
width: 100%;
}
.settings-grid {
grid-template-columns: 1fr;
}
}
/* 开关样式 */
.switch-wrapper {
display: flex;
align-items: center;
gap: 10px;
}
.switch {
position: relative;
display: inline-block;
width: 50px;
height: 24px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
transition: .4s;
border-radius: 24px;
}
.slider:before {
position: absolute;
content: "";
height: 18px;
width: 18px;
left: 3px;
bottom: 3px;
background-color: white;
transition: .4s;
border-radius: 50%;
}
input:checked + .slider {
background-color: #007AFF;
}
input:checked + .slider:before {
transform: translateX(26px);
}
.switch-label {
font-size: 14px;
color: #666;
}
/* 暗色模式适配 */
[data-theme="dark"] .switch-label {
color: #999;
}
</style>
<script>
// 标签页切换
document.querySelectorAll('.nav-item').forEach(item => {
item.addEventListener('click', () => {
// 更新导航项状态
document.querySelectorAll('.nav-item').forEach(nav => {
nav.classList.remove('active');
});
item.classList.add('active');
// 更新内容区域
const target = item.dataset.target;
document.querySelectorAll('.settings-section').forEach(section => {
section.classList.remove('active');
});
document.getElementById(`${target}-section`).classList.add('active');
});
});
// 表单提交
function submitSettings(event, type) {
event.preventDefault();
const form = event.target;
const formData = new FormData(form);
formData.append('type', type);
fetch('/admin/update_site_settings', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
showNotification(`${type}设置已更新`, 'success');
setTimeout(() => location.reload(), 1000);
} else {
showNotification(data.error || '更新失败', 'error');
}
})
.catch(error => {
console.error('Error:', error);
showNotification('更新失败,请重试', 'error');
});
}
// 通知提示
function showNotification(message, type = 'success') {
const notification = document.createElement('div');
notification.className = `notification ${type}`;
notification.textContent = message;
Object.assign(notification.style, {
position: 'fixed',
bottom: '20px',
right: '20px',
padding: '10px 20px',
borderRadius: '8px',
backgroundColor: type === 'success' ? '#4CAF50' : '#f44336',
color: 'white',
zIndex: '1000',
opacity: '0',
transform: 'translateY(20px)',
transition: 'all 0.3s ease'
});
document.body.appendChild(notification);
notification.offsetHeight;
notification.style.opacity = '1';
notification.style.transform = 'translateY(0)';
setTimeout(() => {
notification.style.opacity = '0';
notification.style.transform = 'translateY(20px)';
setTimeout(() => notification.remove(), 300);
}, 3000);
}
</script>
{% endblock %}