| <!DOCTYPE html>
|
| <html lang="zh">
|
| <head>
|
| <meta charset="UTF-8">
|
| <meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| <title>API密钥管理系统 - 登录</title>
|
|
|
| <script src="https://cdn.tailwindcss.com"></script>
|
| <script>
|
|
|
| tailwind.config = {
|
| theme: {
|
| extend: {
|
| colors: {
|
| primary: {
|
| 50: '#f0f9ff', 100: '#e0f2fe', 200: '#bae6fd',
|
| 300: '#7dd3fc', 400: '#38bdf8', 500: '#0ea5e9',
|
| 600: '#0284c7', 700: '#0369a1', 800: '#075985',
|
| 900: '#0c4a6e', 950: '#082f49',
|
| },
|
| },
|
| animation: {
|
| 'fade-in': 'fadeIn 0.3s ease-in-out',
|
| 'slide-down': 'slideDown 0.3s ease-in-out',
|
| 'slide-up': 'slideUp 0.3s ease-in-out',
|
| },
|
| keyframes: {
|
| fadeIn: {
|
| '0%': { opacity: '0' },
|
| '100%': { opacity: '1' },
|
| },
|
| slideDown: {
|
| '0%': { maxHeight: '0', opacity: '0', transform: 'translateY(-10px)' },
|
| '100%': { maxHeight: '1000px', opacity: '1', transform: 'translateY(0)' }
|
| },
|
| slideUp: {
|
| '0%': { maxHeight: '1000px', opacity: '1', transform: 'translateY(0)' },
|
| '100%': { maxHeight: '0', opacity: '0', transform: 'translateY(-10px)' }
|
| },
|
| },
|
| },
|
| },
|
| }
|
| </script>
|
| <script defer src="https://unpkg.com/alpinejs@3.14.8/dist/cdn.min.js"></script>
|
| <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
| <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
| <link rel="icon" href="{{ url_for('static', filename='img/favicon.ico') }}">
|
| </head>
|
| <body class="bg-gray-50 text-gray-900 min-h-screen">
|
|
|
| <header class="bg-white shadow animate-fade-in">
|
| <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 flex justify-between items-center">
|
| <h1 class="text-2xl font-bold text-primary-700">API密钥管理系统</h1>
|
| </div>
|
| </header>
|
|
|
|
|
| <main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8 mt-4">
|
| <div class="flex justify-center items-center min-h-[70vh]">
|
| <div class="max-w-md w-full animate-fade-in">
|
| <div class="bg-white rounded-lg shadow-lg overflow-hidden border border-gray-100">
|
|
|
| <div class="h-1.5 bg-gradient-to-r from-primary-400 via-primary-500 to-primary-600"></div>
|
|
|
| <div class="px-8 py-8">
|
|
|
| <div class="text-center mb-8">
|
| <div class="inline-flex items-center justify-center h-16 w-16 rounded-full bg-primary-100 mb-4">
|
| <svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8 text-primary-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z" />
|
| </svg>
|
| </div>
|
| <h2 class="text-xl font-semibold text-gray-900 mb-2">欢迎使用</h2>
|
| <p class="text-gray-600 text-sm">请输入密码继续访问系统</p>
|
| </div>
|
|
|
|
|
| <form method="POST" action="{{ url_for('web.login') }}" class="space-y-6">
|
| <div>
|
| <label for="password" class="block text-sm font-medium text-gray-700 mb-1">密码</label>
|
| <div class="relative">
|
|
|
| <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
| <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor">
|
| <path fill-rule="evenodd" d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z" clip-rule="evenodd" />
|
| </svg>
|
| </div>
|
| <input
|
| type="password"
|
| id="password"
|
| name="password"
|
| required
|
| class="block w-full pl-10 pr-4 py-2.5 border border-gray-300 rounded-md shadow-sm focus:ring-2 focus:ring-primary-500 focus:border-primary-500 transition-colors"
|
| placeholder="请输入访问密码"
|
| autofocus
|
| >
|
| </div>
|
| </div>
|
|
|
|
|
| {% if error %}
|
| <div class="bg-red-50 border-l-4 border-red-400 p-4 rounded animate-fade-in">
|
| <div class="flex">
|
| <div class="flex-shrink-0">
|
| <svg class="h-5 w-5 text-red-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
| <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd" />
|
| </svg>
|
| </div>
|
| <div class="ml-3">
|
| <p class="text-sm text-red-700">{{ error }}</p>
|
| </div>
|
| </div>
|
| </div>
|
| {% endif %}
|
|
|
|
|
| <button
|
| type="submit"
|
| class="w-full flex justify-center items-center py-2.5 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-gradient-to-r from-primary-500 to-primary-600 hover:from-primary-600 hover:to-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 transition-all duration-200"
|
| >
|
| <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1" />
|
| </svg>
|
| 登录
|
| </button>
|
| </form>
|
| </div>
|
| </div>
|
| </div>
|
| </div>
|
| </main>
|
|
|
| <script>
|
|
|
| document.addEventListener('DOMContentLoaded', () => {
|
| document.getElementById('password').focus();
|
| });
|
| </script>
|
| </body>
|
| </html>
|
|
|