Files
pdf-translate-web/templates/admin/settings.html
coder aa8526035b feat: 系统配置增加网站基础配置
- 网站名称设置
- 底部信息设置(支持HTML)
- 最大上传文件大小设置(MB)
- 缓存有效期设置(天)
- 默认源语言/目标语言设置
- 翻译缓存开关
- 访客翻译开关
- 邮件通知开关
- 新增 get_site_config() 函数供其他模块使用
2026-04-16 18:36:21 +08:00

255 lines
16 KiB
HTML
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.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>系统配置 - 后台管理</title>
<link rel="icon" href="/static/img/favicon.svg" type="image/svg+xml">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css" rel="stylesheet">
<style>
body { background-color: #f5f5f5; }
.sidebar { position: fixed; top: 0; left: 0; height: 100vh; width: 250px; background: #343a40; padding-top: 60px; }
.sidebar .nav-link { color: #adb5bd; padding: 12px 20px; }
.sidebar .nav-link:hover, .sidebar .nav-link.active { color: #fff; background: rgba(255,255,255,0.1); }
.main-content { margin-left: 250px; padding: 20px; }
.config-card { border-radius: 10px; transition: all 0.3s; }
.config-card:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
</style>
</head>
<body>
<nav class="sidebar">
<div class="position-absolute top-0 w-100 p-3 border-bottom border-secondary">
<h5 class="text-white mb-0"><i class="bi bi-gear-fill"></i> 后台管理</h5>
</div>
<ul class="nav flex-column">
<li class="nav-item"><a class="nav-link" href="{{ url_for('admin.dashboard') }}"><i class="bi bi-speedometer2"></i> 数据概览</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('admin.users') }}"><i class="bi bi-people"></i> 用户管理</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('admin.translations') }}"><i class="bi bi-file-text"></i> 翻译记录</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('admin.cache_list') }}"><i class="bi bi-database"></i> 缓存管理</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('admin.packages') }}"><i class="bi bi-box-seam"></i> 数据包套餐</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('admin.stats') }}"><i class="bi bi-bar-chart"></i> 统计报表</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('admin.logs') }}"><i class="bi bi-list-check"></i> 操作日志</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('admin.llm_config') }}"><i class="bi bi-cpu"></i> 大模型配置</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('admin.user_types') }}"><i class="bi bi-person-badge"></i> 用户类型</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('admin.membership_plans') }}"><i class="bi bi-credit-card"></i> 会员套餐</a></li>
<li class="nav-item"><a class="nav-link active" href="{{ url_for('admin.settings') }}"><i class="bi bi-sliders"></i> 系统配置</a></li>
</ul>
<div class="position-absolute bottom-0 w-100 p-3 border-top border-secondary">
<a href="/" class="btn btn-outline-light btn-sm w-100"><i class="bi bi-house"></i> 返回前台</a>
</div>
</nav>
<main class="main-content">
<h4 class="mb-4"><i class="bi bi-sliders"></i> 系统配置</h4>
<!-- 网站基础配置 -->
<div class="card mb-4">
<div class="card-header">
<h6 class="mb-0"><i class="bi bi-building"></i> 网站基础配置</h6>
</div>
<div class="card-body">
<form id="siteConfigForm">
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">网站名称</label>
<input type="text" class="form-control" name="site_name" value="{{ site_config.site_name }}" placeholder="PDF翻译助手">
<small class="text-muted">显示在页面标题和Logo处</small>
</div>
<div class="mb-3">
<label class="form-label">底部信息</label>
<textarea class="form-control" name="site_footer" rows="2" placeholder="© 2026 PDF翻译助手">{{ site_config.site_footer }}</textarea>
<small class="text-muted">显示在页面底部支持HTML</small>
</div>
<div class="mb-3">
<label class="form-label">默认源语言</label>
<select class="form-select" name="default_source_lang">
<option value="en" {% if site_config.default_source_lang == 'en' %}selected{% endif %}>英语 (en)</option>
<option value="ja" {% if site_config.default_source_lang == 'ja' %}selected{% endif %}>日语 (ja)</option>
<option value="ko" {% if site_config.default_source_lang == 'ko' %}selected{% endif %}>韩语 (ko)</option>
<option value="fr" {% if site_config.default_source_lang == 'fr' %}selected{% endif %}>法语 (fr)</option>
<option value="de" {% if site_config.default_source_lang == 'de' %}selected{% endif %}>德语 (de)</option>
<option value="es" {% if site_config.default_source_lang == 'es' %}selected{% endif %}>西班牙语 (es)</option>
<option value="ru" {% if site_config.default_source_lang == 'ru' %}selected{% endif %}>俄语 (ru)</option>
<option value="pt" {% if site_config.default_source_lang == 'pt' %}selected{% endif %}>葡萄牙语 (pt)</option>
<option value="zh" {% if site_config.default_source_lang == 'zh' %}selected{% endif %}>中文 (zh)</option>
</select>
</div>
<div class="mb-3">
<label class="form-label">默认目标语言</label>
<select class="form-select" name="default_target_lang">
<option value="zh" {% if site_config.default_target_lang == 'zh' %}selected{% endif %}>中文 (zh)</option>
<option value="en" {% if site_config.default_target_lang == 'en' %}selected{% endif %}>英语 (en)</option>
<option value="ja" {% if site_config.default_target_lang == 'ja' %}selected{% endif %}>日语 (ja)</option>
<option value="ko" {% if site_config.default_target_lang == 'ko' %}selected{% endif %}>韩语 (ko)</option>
</select>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">最大上传文件大小 (MB)</label>
<input type="number" class="form-control" name="max_file_size" value="{{ site_config.max_file_size }}" min="1" max="500">
<small class="text-muted">用户上传PDF文件的最大大小限制</small>
</div>
<div class="mb-3">
<label class="form-label">缓存有效期 (天)</label>
<input type="number" class="form-control" name="cache_expire_days" value="{{ site_config.cache_expire_days }}" min="1" max="365">
<small class="text-muted">翻译结果缓存的保留天数</small>
</div>
<div class="mb-3">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="enable_cache" id="enable_cache" {% if site_config.enable_cache %}checked{% endif %}>
<label class="form-check-label" for="enable_cache">启用翻译缓存</label>
</div>
<small class="text-muted">相同文件翻译时直接返回缓存结果</small>
</div>
<div class="mb-3">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="enable_guest" id="enable_guest" {% if site_config.enable_guest %}checked{% endif %}>
<label class="form-check-label" for="enable_guest">允许访客翻译</label>
</div>
<small class="text-muted">未登录用户可以使用翻译服务</small>
</div>
<div class="mb-3">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="enable_email_notify" id="enable_email_notify" {% if site_config.enable_email_notify %}checked{% endif %}>
<label class="form-check-label" for="enable_email_notify">邮件通知</label>
</div>
<small class="text-muted">翻译完成后发送邮件通知用户</small>
</div>
</div>
</div>
<button type="submit" class="btn btn-primary"><i class="bi bi-check-lg"></i> 保存配置</button>
</form>
<div id="saveResult" class="mt-3" style="display:none;"></div>
</div>
</div>
<!-- 其他配置入口 -->
<div class="row mb-4">
<div class="col-md-6">
<div class="card config-card h-100">
<div class="card-header">
<h6 class="mb-0"><i class="bi bi-person-badge"></i> 用户类型配置</h6>
</div>
<div class="card-body">
<p class="text-muted">配置不同用户类型的权限限制,包括翻译次数、页数限制、功能权限等。</p>
<a href="{{ url_for('admin.user_types') }}" class="btn btn-outline-primary">
<i class="bi bi-gear"></i> 管理用户类型
</a>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card config-card h-100">
<div class="card-header">
<h6 class="mb-0"><i class="bi bi-credit-card"></i> 会员套餐配置</h6>
</div>
<div class="card-body">
<p class="text-muted">配置会员套餐的价格、周期、描述等,用户购买后可升级用户类型。</p>
<a href="{{ url_for('admin.membership_plans') }}" class="btn btn-outline-primary">
<i class="bi bi-credit-card"></i> 管理会员套餐
</a>
</div>
</div>
</div>
</div>
<div class="row mb-4">
<div class="col-md-6">
<div class="card config-card h-100">
<div class="card-header">
<h6 class="mb-0"><i class="bi bi-cpu"></i> 大模型配置</h6>
</div>
<div class="card-body">
<p class="text-muted">配置翻译使用的LLM大模型API地址、模型名称等参数。</p>
<p><strong>当前模型:</strong> {{ llm_config.get('model', '未设置') }}</p>
<a href="{{ url_for('admin.llm_config') }}" class="btn btn-outline-primary">
<i class="bi bi-cpu"></i> 配置大模型
</a>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card config-card h-100">
<div class="card-header">
<h6 class="mb-0"><i class="bi bi-box-seam"></i> 数据包套餐</h6>
</div>
<div class="card-body">
<p class="text-muted">管理数据包套餐,用户可以购买额外的翻译次数。</p>
<a href="{{ url_for('admin.packages') }}" class="btn btn-outline-primary">
<i class="bi bi-box-seam"></i> 管理数据包
</a>
</div>
</div>
</div>
</div>
<!-- 系统信息 -->
<div class="card">
<div class="card-header"><h6 class="mb-0"><i class="bi bi-info-circle"></i> 系统信息</h6></div>
<div class="card-body">
<div class="row">
<div class="col-md-4">
<p><strong>应用名称:</strong> {{ site_config.site_name }}</p>
<p><strong>版本:</strong> 2.3.1</p>
<p><strong>框架:</strong> Flask + SQLAlchemy</p>
</div>
<div class="col-md-4">
<p><strong>最大文件:</strong> {{ site_config.max_file_size }}MB</p>
<p><strong>缓存有效期:</strong> {{ site_config.cache_expire_days }}天</p>
<p><strong>数据库:</strong> SQLite</p>
</div>
<div class="col-md-4">
<p><strong>API地址:</strong> {{ llm_config.get('api_base', '未设置') }}</p>
<p><strong>超时时间:</strong> {{ llm_config.get('timeout', 180) }}秒</p>
</div>
</div>
</div>
</div>
</main>
<script>
document.getElementById('siteConfigForm').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
const data = {};
formData.forEach((value, key) => {
if (key === 'max_file_size' || key === 'cache_expire_days') {
data[key] = parseInt(value) || 0;
} else if (key === 'enable_cache' || key === 'enable_guest' || key === 'enable_email_notify') {
data[key] = document.getElementById(key).checked;
} else {
data[key] = value;
}
});
fetch('/admin/settings/site', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(data)
})
.then(r => r.json())
.then(res => {
const div = document.getElementById('saveResult');
div.style.display = 'block';
if (res.success) {
div.innerHTML = '<div class="alert alert-success"><i class="bi bi-check-circle"></i> 配置已保存!</div>';
setTimeout(() => div.style.display = 'none', 2000);
} else {
div.innerHTML = '<div class="alert alert-danger"><i class="bi bi-x-circle"></i> 保存失败: ' + (res.error || '未知错误') + '</div>';
}
})
.catch(err => {
const div = document.getElementById('saveResult');
div.style.display = 'block';
div.innerHTML = '<div class="alert alert-danger">请求失败: ' + err + '</div>';
});
});
</script>
</body>
</html>