Files
gemini-balance/app/templates/auth.html
snaily 51bb71bdb5 ```git
feat: 添加密钥检查调度器并重构前端UI

主要变更:

- **调度器功能:**
    - 集成 APScheduler 实现定时任务,用于定期检查API密钥的有效性。
    - 在 `.env.example` 和 `app/config/config.py` 中添加了 `CHECK_INTERVAL_HOURS` 和 `TIMEZONE` 配置项。
    - 在应用生命周期 (`app/core/application.py`) 中添加了调度器的启动和停止逻辑。
    - 新增 `app/scheduler/` 目录及相关实现 (`key_checker.py`)。
    - 新增 `app/router/scheduler_routes.py` 用于调度器相关API (如果未来需要)。
    - 在 `requirements.txt` 中添加 `apscheduler` 依赖。

- **前端重构与改进:**
    - 引入 `app/templates/base.html` 作为基础模板,统一页面结构和样式引入。
    - 使用新的样式(推测为Tailwind CSS)重构了 `auth.html`, `config_editor.html`, `error_logs.html`, `keys_status.html` 页面,提升了UI一致性和响应式布局。
    - 删除了旧的CSS文件 (`auth.css`, `config_editor.css`, `error_logs.css`, `keys_status.css`)。
    - 更新了对应的 JavaScript 文件 (`config_editor.js`, `error_logs.js`, `keys_status.js`) 以适应新的HTML结构和交互。
    - 在 `keys_status.html` 页面增加了按失败次数过滤密钥、批量重置失败次数、确认模态框等功能。
    - 添加了新的 Logo 图片 (`logo.png`, `logo1.png`)。

- **其他:**
    - 更新了 `app/router/routes.py` 以包含新的路由。
    - 对 `app/service/key/key_manager.py` 和 `app/database/services.py` 进行了相关调整以支持新功能。
```
2025-04-11 03:16:51 +08:00

125 lines
4.9 KiB
HTML

{% extends "base.html" %}
{% block title %}验证页面 - Gemini Balance{% endblock %}
{% block head_extra_styles %}
<style>
/* auth.html specific styles */
.auth-glass-card { /* Renamed to avoid conflict if base.html has .glass-card */
background: rgba(255, 255, 255, 0.7);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
}
.auth-bg-gradient { /* Renamed to avoid conflict if base.html has .bg-gradient */
background: linear-gradient(135deg, #4F46E5 0%, #7C3AED 50%, #EC4899 100%);
}
/* .input-icon class removed, using direct Tailwind classes now */
/* Keep button ripple effect if needed, or remove if base provides similar */
.auth-button { /* Renamed to avoid conflict */
position: relative;
overflow: hidden;
}
.auth-button:after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
background: rgba(255, 255, 255, 0.2);
border-radius: 50%;
transform: translate(-50%, -50%);
transition: width 0.6s, height 0.6s;
}
.auth-button:active:after {
width: 300px;
height: 300px;
opacity: 0;
}
</style>
{% endblock %}
{% block content %}
<div class="auth-bg-gradient min-h-screen flex flex-col justify-center items-center p-4">
<div class="glass-card rounded-2xl shadow-2xl p-10 max-w-md w-full mx-auto transform transition duration-500 hover:-translate-y-1 hover:shadow-3xl animate-fade-in">
<div class="flex justify-center mb-8 animate-slide-down">
<div class="rounded-full bg-primary-100 p-4 text-primary-600">
<i class="fas fa-shield-alt text-4xl"></i>
</div>
</div>
<h2 class="text-3xl font-extrabold text-center text-transparent bg-clip-text bg-gradient-to-r from-primary-600 to-primary-700 mb-8 animate-slide-down">
<img src="/static/icons/logo.png" alt="Gemini Balance Logo" class="h-9 inline-block align-middle mr-2">
Gemini Balance
</h2>
<form id="auth-form" action="/auth" method="post" class="space-y-6 animate-slide-up">
<div class="relative">
<i class="fas fa-key absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-500"></i>
<input
type="password"
id="auth-token"
name="auth_token"
required
placeholder="请输入验证令牌"
class="w-full pl-10 pr-4 py-4 rounded-xl border border-gray-300 focus:border-primary-500 focus:ring focus:ring-primary-200 focus:ring-opacity-50 transition duration-300 bg-white bg-opacity-90 text-gray-700"
>
</div>
<button
type="submit"
class="w-full py-4 rounded-xl bg-gradient-to-r from-primary-600 to-primary-700 text-white font-semibold transition duration-300 transform hover:-translate-y-1 hover:shadow-lg"
>
登录
</button>
</form>
{% if error %}
<p class="mt-4 text-red-500 text-center font-medium p-3 bg-red-50 rounded-lg border border-red-200 animate-shake">
{{ error }}
</p>
{% endif %}
</div>
</div> <!-- Close auth-bg-gradient div -->
<!-- Notification placeholder for base.html's showNotification -->
<div id="notification" class="notification"></div>
{% endblock %}
{% block body_scripts %}
<script>
// auth.html specific JavaScript
document.addEventListener('DOMContentLoaded', function() {
const form = document.getElementById('auth-form');
if (form) {
form.addEventListener('submit', function(e) {
const token = document.getElementById('auth-token').value.trim();
if (!token) {
e.preventDefault();
// Use the base notification system
showNotification('请输入验证令牌', 'error');
}
});
}
// Apply renamed classes
document.querySelectorAll('button[type="submit"]').forEach(button => {
button.classList.add('auth-button');
});
const card = document.querySelector('.auth-glass-card'); // Find the renamed card
if (card) {
// If the base template also defines .glass-card, remove it first
// card.classList.remove('glass-card');
} else {
// If the card wasn't found by the new name, try the old name and rename
const oldCard = document.querySelector('.glass-card');
if (oldCard) {
oldCard.classList.remove('glass-card');
oldCard.classList.add('auth-glass-card');
}
}
});
</script>
{% endblock %}