2025-11-11 21:39:12 +08:00
|
|
|
|
{% extends "base.html" %}
|
|
|
|
|
|
|
|
|
|
|
|
{% block title %}系统设置 - 软件授权管理系统{% endblock %}
|
|
|
|
|
|
|
|
|
|
|
|
{% block page_title %}系统设置{% endblock %}
|
|
|
|
|
|
|
|
|
|
|
|
{% block content %}
|
|
|
|
|
|
<div class="row">
|
|
|
|
|
|
<div class="col-lg-8">
|
|
|
|
|
|
<div class="card shadow mb-4">
|
|
|
|
|
|
<div class="card-header">
|
|
|
|
|
|
<h6 class="mb-0">基本设置</h6>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="card-body">
|
|
|
|
|
|
<form id="basic-settings-form">
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="site_name" class="form-label">系统名称</label>
|
|
|
|
|
|
<input type="text" class="form-control" id="site_name" name="site_name" value="{{ config.SITE_NAME or '软件授权管理系统' }}">
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="admin_email" class="form-label">管理员邮箱</label>
|
|
|
|
|
|
<input type="email" class="form-control" id="admin_email" name="admin_email" value="{{ config.ADMIN_EMAIL or '' }}">
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2025-11-16 19:06:49 +08:00
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="frontend_domain" class="form-label">前端域名</label>
|
|
|
|
|
|
<input type="text" class="form-control" id="frontend_domain" name="frontend_domain"
|
|
|
|
|
|
value="{{ config.FRONTEND_DOMAIN or '' }}">
|
|
|
|
|
|
<div class="form-text">前端API请求使用的域名,留空则使用当前访问域名</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2025-11-11 21:39:12 +08:00
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="max_failed_attempts" class="form-label">最大失败尝试次数</label>
|
|
|
|
|
|
<input type="number" class="form-control" id="max_failed_attempts" name="max_failed_attempts"
|
|
|
|
|
|
value="{{ config.MAX_FAILED_ATTEMPTS or 5 }}" min="1" max="20">
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="lockout_minutes" class="form-label">锁定时间(分钟)</label>
|
|
|
|
|
|
<input type="number" class="form-control" id="lockout_minutes" name="lockout_minutes"
|
|
|
|
|
|
value="{{ config.LOCKOUT_MINUTES or 10 }}" min="1" max="1440">
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="max_unbind_times" class="form-label">最大解绑次数</label>
|
|
|
|
|
|
<input type="number" class="form-control" id="max_unbind_times" name="max_unbind_times"
|
|
|
|
|
|
value="{{ config.MAX_UNBIND_TIMES or 3 }}" min="0" max="100">
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="auth_secret_key" class="form-label">授权验证密钥</label>
|
|
|
|
|
|
<input type="text" class="form-control" id="auth_secret_key" name="auth_secret_key"
|
|
|
|
|
|
value="{{ config.AUTH_SECRET_KEY or 'auth-validator-secret-key' }}">
|
|
|
|
|
|
<div class="form-text">用于授权验证的密钥,请妥善保管</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<button type="submit" class="btn btn-primary" id="save-basic-btn">
|
|
|
|
|
|
<i class="fas fa-save me-2"></i>
|
|
|
|
|
|
<span id="save-basic-text">保存设置</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2025-11-22 16:48:45 +08:00
|
|
|
|
<!-- 新增的安全配置 -->
|
|
|
|
|
|
<div class="card shadow mb-4">
|
|
|
|
|
|
<div class="card-header">
|
|
|
|
|
|
<h6 class="mb-0">安全配置</h6>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="card-body">
|
|
|
|
|
|
<form id="security-settings-form">
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="secret_key" class="form-label">应用密钥</label>
|
|
|
|
|
|
<div class="input-group">
|
|
|
|
|
|
<input type="password" class="form-control" id="secret_key" name="secret_key"
|
|
|
|
|
|
placeholder="••••••••">
|
|
|
|
|
|
<button class="btn btn-outline-secondary" type="button" id="generate-secret-key">
|
|
|
|
|
|
生成新密钥
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="form-text">Flask应用密钥,用于会话和CSRF保护</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="session_cookie_secure" class="form-label">会话Cookie安全</label>
|
|
|
|
|
|
<select class="form-select" id="session_cookie_secure" name="session_cookie_secure">
|
|
|
|
|
|
<option value="True" {{ 'selected' if config.SESSION_COOKIE_SECURE else '' }}>启用</option>
|
|
|
|
|
|
<option value="False" {{ 'selected' if not config.SESSION_COOKIE_SECURE else '' }}>禁用</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
<div class="form-text">在HTTPS环境下启用以增强安全性</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="session_cookie_httponly" class="form-label">会话Cookie HttpOnly</label>
|
|
|
|
|
|
<select class="form-select" id="session_cookie_httponly" name="session_cookie_httponly">
|
|
|
|
|
|
<option value="True" {{ 'selected' if config.SESSION_COOKIE_HTTPONLY else '' }}>启用</option>
|
|
|
|
|
|
<option value="False" {{ 'selected' if not config.SESSION_COOKIE_HTTPONLY else '' }}>禁用</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
<div class="form-text">防止客户端脚本访问Cookie</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="session_cookie_samesite" class="form-label">会话Cookie SameSite</label>
|
|
|
|
|
|
<select class="form-select" id="session_cookie_samesite" name="session_cookie_samesite">
|
|
|
|
|
|
<option value="Lax" {{ 'selected' if config.SESSION_COOKIE_SAMESITE == 'Lax' else '' }}>Lax</option>
|
|
|
|
|
|
<option value="Strict" {{ 'selected' if config.SESSION_COOKIE_SAMESITE == 'Strict' else '' }}>Strict</option>
|
|
|
|
|
|
<option value="None" {{ 'selected' if config.SESSION_COOKIE_SAMESITE == 'None' else '' }}>None</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
<div class="form-text">控制Cookie在跨站请求中的发送</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<button type="submit" class="btn btn-primary" id="save-security-btn">
|
|
|
|
|
|
<i class="fas fa-save me-2"></i>
|
|
|
|
|
|
<span id="save-security-text">保存设置</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2025-11-11 21:39:12 +08:00
|
|
|
|
<div class="card shadow mb-4">
|
|
|
|
|
|
<div class="card-header">
|
|
|
|
|
|
<h6 class="mb-0">卡密设置</h6>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="card-body">
|
|
|
|
|
|
<form id="license-settings-form">
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="license_key_length" class="form-label">卡密长度</label>
|
|
|
|
|
|
<input type="number" class="form-control" id="license_key_length" name="license_key_length"
|
|
|
|
|
|
value="{{ config.LICENSE_KEY_LENGTH or 32 }}" min="16" max="128">
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="license_key_prefix" class="form-label">卡密前缀</label>
|
|
|
|
|
|
<input type="text" class="form-control" id="license_key_prefix" name="license_key_prefix"
|
|
|
|
|
|
value="{{ config.LICENSE_KEY_PREFIX or '' }}" maxlength="10">
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="trial_prefix" class="form-label">试用卡密前缀</label>
|
|
|
|
|
|
<input type="text" class="form-control" id="trial_prefix" name="trial_prefix"
|
|
|
|
|
|
value="{{ config.TRIAL_PREFIX or 'TRIAL_' }}" maxlength="10">
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="offline_cache_days" class="form-label">离线缓存天数</label>
|
|
|
|
|
|
<input type="number" class="form-control" id="offline_cache_days" name="offline_cache_days"
|
|
|
|
|
|
value="{{ config.OFFLINE_CACHE_DAYS or 7 }}" min="1" max="365">
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<button type="submit" class="btn btn-primary" id="save-license-btn">
|
|
|
|
|
|
<i class="fas fa-save me-2"></i>
|
|
|
|
|
|
<span id="save-license-text">保存设置</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="card shadow mb-4">
|
|
|
|
|
|
<div class="card-header">
|
|
|
|
|
|
<h6 class="mb-0">API设置</h6>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="card-body">
|
|
|
|
|
|
<form id="api-settings-form">
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="api_version" class="form-label">API版本</label>
|
|
|
|
|
|
<input type="text" class="form-control" id="api_version" name="api_version"
|
|
|
|
|
|
value="{{ config.API_VERSION or 'v1' }}">
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="items_per_page" class="form-label">每页显示条目数</label>
|
|
|
|
|
|
<input type="number" class="form-control" id="items_per_page" name="items_per_page"
|
|
|
|
|
|
value="{{ config.ITEMS_PER_PAGE or 20 }}" min="5" max="100">
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<button type="submit" class="btn btn-primary" id="save-api-btn">
|
|
|
|
|
|
<i class="fas fa-save me-2"></i>
|
|
|
|
|
|
<span id="save-api-text">保存设置</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="card shadow mb-4">
|
|
|
|
|
|
<div class="card-header">
|
|
|
|
|
|
<h6 class="mb-0">文件上传设置</h6>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="card-body">
|
|
|
|
|
|
<form id="upload-settings-form">
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="max_content_length" class="form-label">最大上传文件大小 (MB)</label>
|
|
|
|
|
|
<input type="number" class="form-control" id="max_content_length" name="max_content_length"
|
|
|
|
|
|
value="{{ (config.MAX_CONTENT_LENGTH / 1024 / 1024) | int or 500 }}" min="1" max="1000">
|
|
|
|
|
|
<div class="form-text">当前设置: {{ config.MAX_CONTENT_LENGTH / 1024 / 1024 }} MB</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="upload_folder" class="form-label">上传文件夹</label>
|
|
|
|
|
|
<input type="text" class="form-control" id="upload_folder" name="upload_folder"
|
|
|
|
|
|
value="{{ config.UPLOAD_FOLDER or 'static/uploads' }}">
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<button type="submit" class="btn btn-primary" id="save-upload-btn">
|
|
|
|
|
|
<i class="fas fa-save me-2"></i>
|
|
|
|
|
|
<span id="save-upload-text">保存设置</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="card shadow mb-4">
|
|
|
|
|
|
<div class="card-header">
|
|
|
|
|
|
<h6 class="mb-0">会话设置</h6>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="card-body">
|
|
|
|
|
|
<form id="session-settings-form">
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="session_lifetime_hours" class="form-label">会话有效期(小时)</label>
|
|
|
|
|
|
<input type="number" class="form-control" id="session_lifetime_hours" name="session_lifetime_hours"
|
|
|
|
|
|
value="{{ (config.PERMANENT_SESSION_LIFETIME.seconds / 3600) | int or 24 }}" min="1" max="720">
|
|
|
|
|
|
<div class="form-text">当前设置: {{ config.PERMANENT_SESSION_LIFETIME.days * 24 + config.PERMANENT_SESSION_LIFETIME.seconds / 3600 }} 小时</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<button type="submit" class="btn btn-primary" id="save-session-btn">
|
|
|
|
|
|
<i class="fas fa-save me-2"></i>
|
|
|
|
|
|
<span id="save-session-text">保存设置</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2025-11-22 16:48:45 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 新增的记住我设置 -->
|
|
|
|
|
|
<div class="card shadow mb-4">
|
|
|
|
|
|
<div class="card-header">
|
|
|
|
|
|
<h6 class="mb-0">记住我设置</h6>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="card-body">
|
|
|
|
|
|
<form id="remember-settings-form">
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="remember_cookie_duration" class="form-label">记住我持续时间(天)</label>
|
|
|
|
|
|
<input type="number" class="form-control" id="remember_cookie_duration" name="remember_cookie_duration"
|
|
|
|
|
|
value="{{ (config.REMEMBER_COOKIE_DURATION.days) | int or 30 }}" min="1" max="365">
|
|
|
|
|
|
<div class="form-text">记住我功能的持续时间</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="remember_cookie_secure" class="form-label">记住我Cookie安全</label>
|
|
|
|
|
|
<select class="form-select" id="remember_cookie_secure" name="remember_cookie_secure">
|
|
|
|
|
|
<option value="True" {{ 'selected' if config.REMEMBER_COOKIE_SECURE else '' }}>启用</option>
|
|
|
|
|
|
<option value="False" {{ 'selected' if not config.REMEMBER_COOKIE_SECURE else '' }}>禁用</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
<div class="form-text">在HTTPS环境下启用以增强安全性</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="remember_cookie_httponly" class="form-label">记住我Cookie HttpOnly</label>
|
|
|
|
|
|
<select class="form-select" id="remember_cookie_httponly" name="remember_cookie_httponly">
|
|
|
|
|
|
<option value="True" {{ 'selected' if config.REMEMBER_COOKIE_HTTPONLY else '' }}>启用</option>
|
|
|
|
|
|
<option value="False" {{ 'selected' if not config.REMEMBER_COOKIE_HTTPONLY else '' }}>禁用</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
<div class="form-text">防止客户端脚本访问Cookie</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="remember_cookie_samesite" class="form-label">记住我Cookie SameSite</label>
|
|
|
|
|
|
<select class="form-select" id="remember_cookie_samesite" name="remember_cookie_samesite">
|
|
|
|
|
|
<option value="Lax" {{ 'selected' if config.REMEMBER_COOKIE_SAMESITE == 'Lax' else '' }}>Lax</option>
|
|
|
|
|
|
<option value="Strict" {{ 'selected' if config.REMEMBER_COOKIE_SAMESITE == 'Strict' else '' }}>Strict</option>
|
|
|
|
|
|
<option value="None" {{ 'selected' if config.REMEMBER_COOKIE_SAMESITE == 'None' else '' }}>None</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
<div class="form-text">控制Cookie在跨站请求中的发送</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<button type="submit" class="btn btn-primary" id="save-remember-btn">
|
|
|
|
|
|
<i class="fas fa-save me-2"></i>
|
|
|
|
|
|
<span id="save-remember-text">保存设置</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 新增的日志配置 -->
|
|
|
|
|
|
<div class="card shadow mb-4">
|
|
|
|
|
|
<div class="card-header">
|
|
|
|
|
|
<h6 class="mb-0">日志配置</h6>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="card-body">
|
|
|
|
|
|
<form id="log-settings-form">
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="log_level" class="form-label">日志级别</label>
|
|
|
|
|
|
<select class="form-select" id="log_level" name="log_level">
|
|
|
|
|
|
<option value="DEBUG" {{ 'selected' if config.LOG_LEVEL == 'DEBUG' else '' }}>DEBUG</option>
|
|
|
|
|
|
<option value="INFO" {{ 'selected' if config.LOG_LEVEL == 'INFO' else '' }}>INFO</option>
|
|
|
|
|
|
<option value="WARNING" {{ 'selected' if config.LOG_LEVEL == 'WARNING' else '' }}>WARNING</option>
|
|
|
|
|
|
<option value="ERROR" {{ 'selected' if config.LOG_LEVEL == 'ERROR' else '' }}>ERROR</option>
|
|
|
|
|
|
<option value="CRITICAL" {{ 'selected' if config.LOG_LEVEL == 'CRITICAL' else '' }}>CRITICAL</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
<div class="form-text">设置日志记录的详细程度</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<button type="submit" class="btn btn-primary" id="save-log-btn">
|
|
|
|
|
|
<i class="fas fa-save me-2"></i>
|
|
|
|
|
|
<span id="save-log-text">保存设置</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2025-11-11 21:39:12 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="col-lg-4">
|
|
|
|
|
|
<div class="card shadow mb-4">
|
|
|
|
|
|
<div class="card-header">
|
|
|
|
|
|
<h6 class="mb-0">系统信息</h6>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="card-body">
|
|
|
|
|
|
<dl class="row">
|
|
|
|
|
|
<dt class="col-sm-6">系统版本:</dt>
|
|
|
|
|
|
<dd class="col-sm-6">{{ system_version or 'v1.0.0' }}</dd>
|
|
|
|
|
|
|
|
|
|
|
|
<dt class="col-sm-6">Python版本:</dt>
|
|
|
|
|
|
<dd class="col-sm-6">{{ python_version or 'Unknown' }}</dd>
|
|
|
|
|
|
|
|
|
|
|
|
<dt class="col-sm-6">Flask版本:</dt>
|
|
|
|
|
|
<dd class="col-sm-6">{{ flask_version or 'Unknown' }}</dd>
|
|
|
|
|
|
|
|
|
|
|
|
<dt class="col-sm-6">数据库:</dt>
|
|
|
|
|
|
<dd class="col-sm-6">{{ database_type or 'Unknown' }}</dd>
|
|
|
|
|
|
|
|
|
|
|
|
<dt class="col-sm-6">运行时间:</dt>
|
|
|
|
|
|
<dd class="col-sm-6">{{ uptime or 'Unknown' }}</dd>
|
|
|
|
|
|
|
|
|
|
|
|
<dt class="col-sm-6">API版本:</dt>
|
|
|
|
|
|
<dd class="col-sm-6">{{ config.API_VERSION or 'v1' }}</dd>
|
|
|
|
|
|
|
|
|
|
|
|
<dt class="col-sm-6">上传限制:</dt>
|
|
|
|
|
|
<dd class="col-sm-6">{{ config.MAX_CONTENT_LENGTH / 1024 / 1024 }} MB</dd>
|
|
|
|
|
|
</dl>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="card shadow">
|
|
|
|
|
|
<div class="card-header">
|
|
|
|
|
|
<h6 class="mb-0">操作</h6>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="card-body">
|
|
|
|
|
|
<div class="d-grid gap-2">
|
|
|
|
|
|
<button type="button" class="btn btn-outline-primary" data-bs-toggle="modal" data-bs-target="#backupModal">
|
|
|
|
|
|
<i class="fas fa-database me-2"></i>
|
|
|
|
|
|
数据备份
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button type="button" class="btn btn-outline-warning" data-bs-toggle="modal" data-bs-target="#clearCacheModal">
|
|
|
|
|
|
<i class="fas fa-broom me-2"></i>
|
|
|
|
|
|
清理缓存
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button type="button" class="btn btn-outline-danger" data-bs-toggle="modal" data-bs-target="#resetModal">
|
|
|
|
|
|
<i class="fas fa-exclamation-triangle me-2"></i>
|
|
|
|
|
|
重置系统
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 数据备份模态框 -->
|
|
|
|
|
|
<div class="modal fade" id="backupModal" tabindex="-1">
|
|
|
|
|
|
<div class="modal-dialog">
|
|
|
|
|
|
<div class="modal-content">
|
|
|
|
|
|
<div class="modal-header">
|
|
|
|
|
|
<h5 class="modal-title">数据备份</h5>
|
|
|
|
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="modal-body">
|
|
|
|
|
|
<p>确定要创建数据备份吗?</p>
|
|
|
|
|
|
<div class="form-check">
|
|
|
|
|
|
<input class="form-check-input" type="checkbox" id="include_logs" checked>
|
|
|
|
|
|
<label class="form-check-label" for="include_logs">
|
|
|
|
|
|
包含日志文件
|
|
|
|
|
|
</label>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="modal-footer">
|
|
|
|
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
|
|
|
|
|
|
<button type="button" class="btn btn-primary" id="backup-btn">开始备份</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 清理缓存模态框 -->
|
|
|
|
|
|
<div class="modal fade" id="clearCacheModal" tabindex="-1">
|
|
|
|
|
|
<div class="modal-dialog">
|
|
|
|
|
|
<div class="modal-content">
|
|
|
|
|
|
<div class="modal-header">
|
|
|
|
|
|
<h5 class="modal-title">清理缓存</h5>
|
|
|
|
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="modal-body">
|
|
|
|
|
|
<p>确定要清理系统缓存吗?这将清除所有临时文件和缓存数据。</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="modal-footer">
|
|
|
|
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
|
|
|
|
|
|
<button type="button" class="btn btn-warning" id="clear-cache-btn">确认清理</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 重置系统模态框 -->
|
|
|
|
|
|
<div class="modal fade" id="resetModal" tabindex="-1">
|
|
|
|
|
|
<div class="modal-dialog">
|
|
|
|
|
|
<div class="modal-content">
|
|
|
|
|
|
<div class="modal-header">
|
|
|
|
|
|
<h5 class="modal-title">重置系统</h5>
|
|
|
|
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="modal-body">
|
|
|
|
|
|
<div class="alert alert-danger">
|
|
|
|
|
|
<strong>警告!</strong> 此操作将删除所有数据并重置系统到初始状态,无法恢复。
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<p>请输入"RESET"确认操作:</p>
|
|
|
|
|
|
<input type="text" class="form-control" id="reset-confirm" placeholder="输入RESET确认">
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="modal-footer">
|
|
|
|
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
|
|
|
|
|
|
<button type="button" class="btn btn-danger" id="reset-btn" disabled>确认重置</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
{% endblock %}
|
|
|
|
|
|
|
|
|
|
|
|
{% block extra_js %}
|
|
|
|
|
|
<script>
|
|
|
|
|
|
// 页面加载完成后初始化
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
|
|
initEventListeners();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化事件监听器
|
|
|
|
|
|
function initEventListeners() {
|
|
|
|
|
|
// 基本设置表单
|
|
|
|
|
|
document.getElementById('basic-settings-form').addEventListener('submit', function(e) {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
saveBasicSettings();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-11-22 16:48:45 +08:00
|
|
|
|
// 安全设置表单
|
|
|
|
|
|
document.getElementById('security-settings-form').addEventListener('submit', function(e) {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
saveSecuritySettings();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 生成密钥按钮
|
|
|
|
|
|
document.getElementById('generate-secret-key').addEventListener('click', function() {
|
|
|
|
|
|
generateSecretKey();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-11-11 21:39:12 +08:00
|
|
|
|
// 卡密设置表单
|
|
|
|
|
|
document.getElementById('license-settings-form').addEventListener('submit', function(e) {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
saveLicenseSettings();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// API设置表单
|
|
|
|
|
|
document.getElementById('api-settings-form').addEventListener('submit', function(e) {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
saveApiSettings();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 文件上传设置表单
|
|
|
|
|
|
document.getElementById('upload-settings-form').addEventListener('submit', function(e) {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
saveUploadSettings();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 会话设置表单
|
|
|
|
|
|
document.getElementById('session-settings-form').addEventListener('submit', function(e) {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
saveSessionSettings();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-11-22 16:48:45 +08:00
|
|
|
|
// 记住我设置表单
|
|
|
|
|
|
document.getElementById('remember-settings-form').addEventListener('submit', function(e) {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
saveRememberSettings();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 日志设置表单
|
|
|
|
|
|
document.getElementById('log-settings-form').addEventListener('submit', function(e) {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
saveLogSettings();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-11-11 21:39:12 +08:00
|
|
|
|
// 重置确认输入
|
|
|
|
|
|
document.getElementById('reset-confirm').addEventListener('input', function() {
|
|
|
|
|
|
const resetBtn = document.getElementById('reset-btn');
|
|
|
|
|
|
resetBtn.disabled = this.value !== 'RESET';
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 重置按钮
|
|
|
|
|
|
document.getElementById('reset-btn').addEventListener('click', function() {
|
|
|
|
|
|
resetSystem();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 清理缓存按钮
|
|
|
|
|
|
document.getElementById('clear-cache-btn').addEventListener('click', function() {
|
|
|
|
|
|
clearCache();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 备份按钮
|
|
|
|
|
|
document.getElementById('backup-btn').addEventListener('click', function() {
|
|
|
|
|
|
backupData();
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-22 16:48:45 +08:00
|
|
|
|
// 生成安全密钥
|
|
|
|
|
|
function generateSecretKey() {
|
|
|
|
|
|
// 生成一个随机的32字符密钥
|
|
|
|
|
|
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+-=[]{}|;:,.<>?';
|
|
|
|
|
|
let key = '';
|
|
|
|
|
|
for (let i = 0; i < 32; i++) {
|
|
|
|
|
|
key += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
|
|
|
|
}
|
|
|
|
|
|
document.getElementById('secret_key').value = key;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-11 21:39:12 +08:00
|
|
|
|
// 保存基本设置
|
|
|
|
|
|
function saveBasicSettings() {
|
|
|
|
|
|
const saveBtn = document.getElementById('save-basic-btn');
|
|
|
|
|
|
const saveText = document.getElementById('save-basic-text');
|
|
|
|
|
|
|
|
|
|
|
|
// 显示加载状态
|
|
|
|
|
|
saveBtn.disabled = true;
|
|
|
|
|
|
saveText.textContent = '保存中...';
|
|
|
|
|
|
|
|
|
|
|
|
// 收集表单数据
|
|
|
|
|
|
const formData = {
|
|
|
|
|
|
site_name: document.getElementById('site_name').value,
|
|
|
|
|
|
admin_email: document.getElementById('admin_email').value,
|
2025-11-16 19:06:49 +08:00
|
|
|
|
frontend_domain: document.getElementById('frontend_domain').value,
|
2025-11-11 21:39:12 +08:00
|
|
|
|
max_failed_attempts: parseInt(document.getElementById('max_failed_attempts').value),
|
|
|
|
|
|
lockout_minutes: parseInt(document.getElementById('lockout_minutes').value),
|
|
|
|
|
|
max_unbind_times: parseInt(document.getElementById('max_unbind_times').value),
|
|
|
|
|
|
auth_secret_key: document.getElementById('auth_secret_key').value
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 发送请求保存设置
|
2025-11-22 16:48:45 +08:00
|
|
|
|
const saveUrl = '/api/v1/settings';
|
|
|
|
|
|
|
|
|
|
|
|
apiRequest(saveUrl, {
|
2025-11-11 21:39:12 +08:00
|
|
|
|
method: 'POST',
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
|
|
},
|
|
|
|
|
|
body: JSON.stringify(formData)
|
|
|
|
|
|
})
|
|
|
|
|
|
.then(response => response.json())
|
|
|
|
|
|
.then(data => {
|
|
|
|
|
|
if (data.success) {
|
|
|
|
|
|
showNotification('基本设置保存成功', 'success');
|
|
|
|
|
|
// 更新页面标题(如果修改了系统名称)
|
|
|
|
|
|
if (formData.site_name) {
|
|
|
|
|
|
document.title = formData.site_name + ' - 软件授权管理系统';
|
|
|
|
|
|
// 更新页面标题元素
|
|
|
|
|
|
const pageTitle = document.querySelector('h1.h2');
|
|
|
|
|
|
if (pageTitle) {
|
|
|
|
|
|
pageTitle.textContent = formData.site_name;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
showNotification('保存失败: ' + data.message, 'error');
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(error => {
|
|
|
|
|
|
console.error('Error:', error);
|
|
|
|
|
|
showNotification('保存失败,请查看控制台了解详情', 'error');
|
|
|
|
|
|
})
|
|
|
|
|
|
.finally(() => {
|
|
|
|
|
|
saveBtn.disabled = false;
|
|
|
|
|
|
saveText.textContent = '保存设置';
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-22 16:48:45 +08:00
|
|
|
|
// 保存安全设置
|
|
|
|
|
|
function saveSecuritySettings() {
|
|
|
|
|
|
const saveBtn = document.getElementById('save-security-btn');
|
|
|
|
|
|
const saveText = document.getElementById('save-security-text');
|
|
|
|
|
|
|
|
|
|
|
|
// 显示加载状态
|
|
|
|
|
|
saveBtn.disabled = true;
|
|
|
|
|
|
saveText.textContent = '保存中...';
|
|
|
|
|
|
|
|
|
|
|
|
// 收集表单数据
|
|
|
|
|
|
const formData = {
|
|
|
|
|
|
secret_key: document.getElementById('secret_key').value,
|
|
|
|
|
|
session_cookie_secure: document.getElementById('session_cookie_secure').value === 'True',
|
|
|
|
|
|
session_cookie_httponly: document.getElementById('session_cookie_httponly').value === 'True',
|
|
|
|
|
|
session_cookie_samesite: document.getElementById('session_cookie_samesite').value
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 如果密钥为空,则不发送
|
|
|
|
|
|
if (!formData.secret_key) {
|
|
|
|
|
|
delete formData.secret_key;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 发送请求保存设置
|
|
|
|
|
|
apiRequest('/api/v1/settings', {
|
|
|
|
|
|
method: 'POST',
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
|
|
},
|
|
|
|
|
|
body: JSON.stringify(formData)
|
|
|
|
|
|
})
|
|
|
|
|
|
.then(response => response.json())
|
|
|
|
|
|
.then(data => {
|
|
|
|
|
|
if (data.success) {
|
|
|
|
|
|
showNotification('安全设置保存成功', 'success');
|
|
|
|
|
|
// 清空密钥输入框
|
|
|
|
|
|
document.getElementById('secret_key').value = '';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
showNotification('保存失败: ' + data.message, 'error');
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(error => {
|
|
|
|
|
|
console.error('Error:', error);
|
|
|
|
|
|
showNotification('保存失败,请查看控制台了解详情', 'error');
|
|
|
|
|
|
})
|
|
|
|
|
|
.finally(() => {
|
|
|
|
|
|
saveBtn.disabled = false;
|
|
|
|
|
|
saveText.textContent = '保存设置';
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-11 21:39:12 +08:00
|
|
|
|
// 保存卡密设置
|
|
|
|
|
|
function saveLicenseSettings() {
|
|
|
|
|
|
const saveBtn = document.getElementById('save-license-btn');
|
|
|
|
|
|
const saveText = document.getElementById('save-license-text');
|
|
|
|
|
|
|
|
|
|
|
|
// 显示加载状态
|
|
|
|
|
|
saveBtn.disabled = true;
|
|
|
|
|
|
saveText.textContent = '保存中...';
|
|
|
|
|
|
|
|
|
|
|
|
// 收集表单数据
|
|
|
|
|
|
const formData = {
|
|
|
|
|
|
license_key_length: parseInt(document.getElementById('license_key_length').value),
|
|
|
|
|
|
license_key_prefix: document.getElementById('license_key_prefix').value,
|
|
|
|
|
|
trial_prefix: document.getElementById('trial_prefix').value,
|
|
|
|
|
|
offline_cache_days: parseInt(document.getElementById('offline_cache_days').value)
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 发送请求保存设置
|
2025-11-22 16:48:45 +08:00
|
|
|
|
apiRequest('/api/v1/settings', {
|
2025-11-11 21:39:12 +08:00
|
|
|
|
method: 'POST',
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
|
|
},
|
|
|
|
|
|
body: JSON.stringify(formData)
|
|
|
|
|
|
})
|
|
|
|
|
|
.then(response => response.json())
|
|
|
|
|
|
.then(data => {
|
|
|
|
|
|
if (data.success) {
|
|
|
|
|
|
showNotification('卡密设置保存成功', 'success');
|
|
|
|
|
|
} else {
|
|
|
|
|
|
showNotification('保存失败: ' + data.message, 'error');
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(error => {
|
|
|
|
|
|
console.error('Error:', error);
|
|
|
|
|
|
showNotification('保存失败,请查看控制台了解详情', 'error');
|
|
|
|
|
|
})
|
|
|
|
|
|
.finally(() => {
|
|
|
|
|
|
saveBtn.disabled = false;
|
|
|
|
|
|
saveText.textContent = '保存设置';
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 保存API设置
|
|
|
|
|
|
function saveApiSettings() {
|
|
|
|
|
|
const saveBtn = document.getElementById('save-api-btn');
|
|
|
|
|
|
const saveText = document.getElementById('save-api-text');
|
|
|
|
|
|
|
|
|
|
|
|
// 显示加载状态
|
|
|
|
|
|
saveBtn.disabled = true;
|
|
|
|
|
|
saveText.textContent = '保存中...';
|
|
|
|
|
|
|
|
|
|
|
|
// 收集表单数据
|
|
|
|
|
|
const formData = {
|
|
|
|
|
|
api_version: document.getElementById('api_version').value,
|
|
|
|
|
|
items_per_page: parseInt(document.getElementById('items_per_page').value)
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 发送请求保存设置
|
2025-11-22 16:48:45 +08:00
|
|
|
|
apiRequest('/api/v1/settings', {
|
2025-11-11 21:39:12 +08:00
|
|
|
|
method: 'POST',
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
|
|
},
|
|
|
|
|
|
body: JSON.stringify(formData)
|
|
|
|
|
|
})
|
|
|
|
|
|
.then(response => response.json())
|
|
|
|
|
|
.then(data => {
|
|
|
|
|
|
if (data.success) {
|
|
|
|
|
|
showNotification('API设置保存成功', 'success');
|
|
|
|
|
|
} else {
|
|
|
|
|
|
showNotification('保存失败: ' + data.message, 'error');
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(error => {
|
|
|
|
|
|
console.error('Error:', error);
|
|
|
|
|
|
showNotification('保存失败,请查看控制台了解详情', 'error');
|
|
|
|
|
|
})
|
|
|
|
|
|
.finally(() => {
|
|
|
|
|
|
saveBtn.disabled = false;
|
|
|
|
|
|
saveText.textContent = '保存设置';
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 保存文件上传设置
|
|
|
|
|
|
function saveUploadSettings() {
|
|
|
|
|
|
const saveBtn = document.getElementById('save-upload-btn');
|
|
|
|
|
|
const saveText = document.getElementById('save-upload-text');
|
|
|
|
|
|
|
|
|
|
|
|
// 显示加载状态
|
|
|
|
|
|
saveBtn.disabled = true;
|
|
|
|
|
|
saveText.textContent = '保存中...';
|
|
|
|
|
|
|
|
|
|
|
|
// 收集表单数据
|
|
|
|
|
|
const formData = {
|
|
|
|
|
|
max_content_length: parseInt(document.getElementById('max_content_length').value),
|
|
|
|
|
|
upload_folder: document.getElementById('upload_folder').value
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 发送请求保存设置
|
2025-11-22 16:48:45 +08:00
|
|
|
|
const saveUrl = '/api/v1/settings';
|
|
|
|
|
|
|
|
|
|
|
|
apiRequest(saveUrl, {
|
2025-11-11 21:39:12 +08:00
|
|
|
|
method: 'POST',
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
|
|
},
|
|
|
|
|
|
body: JSON.stringify(formData)
|
|
|
|
|
|
})
|
|
|
|
|
|
.then(response => response.json())
|
|
|
|
|
|
.then(data => {
|
|
|
|
|
|
if (data.success) {
|
|
|
|
|
|
showNotification('文件上传设置保存成功', 'success');
|
|
|
|
|
|
// 更新显示的上传限制信息
|
|
|
|
|
|
const maxContentLength = formData.max_content_length;
|
|
|
|
|
|
const uploadInfoElements = document.querySelectorAll('div.form-text');
|
|
|
|
|
|
uploadInfoElements.forEach(element => {
|
|
|
|
|
|
if (element.textContent.includes('当前设置:')) {
|
|
|
|
|
|
element.textContent = `当前设置: ${maxContentLength} MB`;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
showNotification('保存失败: ' + data.message, 'error');
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(error => {
|
|
|
|
|
|
console.error('Error:', error);
|
|
|
|
|
|
showNotification('保存失败,请查看控制台了解详情', 'error');
|
|
|
|
|
|
})
|
|
|
|
|
|
.finally(() => {
|
|
|
|
|
|
saveBtn.disabled = false;
|
|
|
|
|
|
saveText.textContent = '保存设置';
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 保存会话设置
|
|
|
|
|
|
function saveSessionSettings() {
|
|
|
|
|
|
const saveBtn = document.getElementById('save-session-btn');
|
|
|
|
|
|
const saveText = document.getElementById('save-session-text');
|
|
|
|
|
|
|
|
|
|
|
|
// 显示加载状态
|
|
|
|
|
|
saveBtn.disabled = true;
|
|
|
|
|
|
saveText.textContent = '保存中...';
|
|
|
|
|
|
|
|
|
|
|
|
// 收集表单数据
|
|
|
|
|
|
const formData = {
|
|
|
|
|
|
session_lifetime_hours: parseInt(document.getElementById('session_lifetime_hours').value)
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 发送请求保存设置
|
2025-11-22 16:48:45 +08:00
|
|
|
|
const saveUrl = '/api/v1/settings';
|
|
|
|
|
|
|
|
|
|
|
|
apiRequest(saveUrl, {
|
2025-11-11 21:39:12 +08:00
|
|
|
|
method: 'POST',
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
|
|
},
|
|
|
|
|
|
body: JSON.stringify(formData)
|
|
|
|
|
|
})
|
|
|
|
|
|
.then(response => response.json())
|
|
|
|
|
|
.then(data => {
|
|
|
|
|
|
if (data.success) {
|
|
|
|
|
|
showNotification('会话设置保存成功', 'success');
|
|
|
|
|
|
// 更新显示的会话时间信息
|
|
|
|
|
|
const sessionHours = formData.session_lifetime_hours;
|
|
|
|
|
|
const sessionInfoElements = document.querySelectorAll('div.form-text');
|
|
|
|
|
|
sessionInfoElements.forEach(element => {
|
|
|
|
|
|
if (element.textContent.includes('当前设置:')) {
|
|
|
|
|
|
element.textContent = `当前设置: ${sessionHours} 小时`;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
showNotification('保存失败: ' + data.message, 'error');
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(error => {
|
|
|
|
|
|
console.error('Error:', error);
|
|
|
|
|
|
showNotification('保存失败,请查看控制台了解详情', 'error');
|
|
|
|
|
|
})
|
|
|
|
|
|
.finally(() => {
|
|
|
|
|
|
saveBtn.disabled = false;
|
|
|
|
|
|
saveText.textContent = '保存设置';
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-22 16:48:45 +08:00
|
|
|
|
// 保存记住我设置
|
|
|
|
|
|
function saveRememberSettings() {
|
|
|
|
|
|
const saveBtn = document.getElementById('save-remember-btn');
|
|
|
|
|
|
const saveText = document.getElementById('save-remember-text');
|
|
|
|
|
|
|
|
|
|
|
|
// 显示加载状态
|
|
|
|
|
|
saveBtn.disabled = true;
|
|
|
|
|
|
saveText.textContent = '保存中...';
|
|
|
|
|
|
|
|
|
|
|
|
// 收集表单数据
|
|
|
|
|
|
const formData = {
|
|
|
|
|
|
remember_cookie_duration: parseInt(document.getElementById('remember_cookie_duration').value),
|
|
|
|
|
|
remember_cookie_secure: document.getElementById('remember_cookie_secure').value === 'True',
|
|
|
|
|
|
remember_cookie_httponly: document.getElementById('remember_cookie_httponly').value === 'True',
|
|
|
|
|
|
remember_cookie_samesite: document.getElementById('remember_cookie_samesite').value
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 发送请求保存设置
|
|
|
|
|
|
const saveUrl = '/api/v1/settings';
|
|
|
|
|
|
|
|
|
|
|
|
apiRequest(saveUrl, {
|
|
|
|
|
|
method: 'POST',
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
|
|
},
|
|
|
|
|
|
body: JSON.stringify(formData)
|
|
|
|
|
|
})
|
|
|
|
|
|
.then(response => response.json())
|
|
|
|
|
|
.then(data => {
|
|
|
|
|
|
if (data.success) {
|
|
|
|
|
|
showNotification('记住我设置保存成功', 'success');
|
|
|
|
|
|
} else {
|
|
|
|
|
|
showNotification('保存失败: ' + data.message, 'error');
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(error => {
|
|
|
|
|
|
console.error('Error:', error);
|
|
|
|
|
|
showNotification('保存失败,请查看控制台了解详情', 'error');
|
|
|
|
|
|
})
|
|
|
|
|
|
.finally(() => {
|
|
|
|
|
|
saveBtn.disabled = false;
|
|
|
|
|
|
saveText.textContent = '保存设置';
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 保存日志设置
|
|
|
|
|
|
function saveLogSettings() {
|
|
|
|
|
|
const saveBtn = document.getElementById('save-log-btn');
|
|
|
|
|
|
const saveText = document.getElementById('save-log-text');
|
|
|
|
|
|
|
|
|
|
|
|
// 显示加载状态
|
|
|
|
|
|
saveBtn.disabled = true;
|
|
|
|
|
|
saveText.textContent = '保存中...';
|
|
|
|
|
|
|
|
|
|
|
|
// 收集表单数据
|
|
|
|
|
|
const formData = {
|
|
|
|
|
|
log_level: document.getElementById('log_level').value
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 发送请求保存设置
|
|
|
|
|
|
const saveUrl = '/api/v1/settings';
|
|
|
|
|
|
|
|
|
|
|
|
apiRequest(saveUrl, {
|
|
|
|
|
|
method: 'POST',
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
|
|
},
|
|
|
|
|
|
body: JSON.stringify(formData)
|
|
|
|
|
|
})
|
|
|
|
|
|
.then(response => response.json())
|
|
|
|
|
|
.then(data => {
|
|
|
|
|
|
if (data.success) {
|
|
|
|
|
|
showNotification('日志设置保存成功', 'success');
|
|
|
|
|
|
} else {
|
|
|
|
|
|
showNotification('保存失败: ' + data.message, 'error');
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(error => {
|
|
|
|
|
|
console.error('Error:', error);
|
|
|
|
|
|
showNotification('保存失败,请查看控制台了解详情', 'error');
|
|
|
|
|
|
})
|
|
|
|
|
|
.finally(() => {
|
|
|
|
|
|
saveBtn.disabled = false;
|
|
|
|
|
|
saveText.textContent = '保存设置';
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-11 21:39:12 +08:00
|
|
|
|
// 重置系统
|
|
|
|
|
|
function resetSystem() {
|
|
|
|
|
|
if (confirm('确定要重置系统吗?此操作无法恢复!')) {
|
|
|
|
|
|
showNotification('系统重置功能开发中...', 'info');
|
|
|
|
|
|
// 关闭模态框
|
|
|
|
|
|
const modal = bootstrap.Modal.getInstance(document.getElementById('resetModal'));
|
|
|
|
|
|
modal.hide();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 清理缓存
|
|
|
|
|
|
function clearCache() {
|
|
|
|
|
|
showNotification('正在清理缓存...', 'info');
|
|
|
|
|
|
// 关闭模态框
|
|
|
|
|
|
const modal = bootstrap.Modal.getInstance(document.getElementById('clearCacheModal'));
|
|
|
|
|
|
modal.hide();
|
|
|
|
|
|
|
|
|
|
|
|
// 模拟清理过程
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
showNotification('缓存清理完成', 'success');
|
|
|
|
|
|
}, 2000);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 数据备份
|
|
|
|
|
|
function backupData() {
|
|
|
|
|
|
showNotification('正在创建数据备份...', 'info');
|
|
|
|
|
|
// 关闭模态框
|
|
|
|
|
|
const modal = bootstrap.Modal.getInstance(document.getElementById('backupModal'));
|
|
|
|
|
|
modal.hide();
|
|
|
|
|
|
|
|
|
|
|
|
// 模拟备份过程
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
showNotification('数据备份创建成功', 'success');
|
|
|
|
|
|
}, 3000);
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
{% endblock %}
|