Files
hertz_django/hertz_demo/templates/captcha_demo.html
2025-11-11 17:21:59 +08:00

499 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">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hertz验证码演示 - Hertz Server Django</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
color: #333;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 2rem;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.header {
text-align: center;
color: white;
margin-bottom: 2rem;
}
.header h1 {
font-size: 2.5rem;
margin-bottom: 0.5rem;
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
}
.header p {
font-size: 1.1rem;
opacity: 0.9;
}
.demo-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
margin-bottom: 2rem;
}
.demo-card {
background: white;
border-radius: 10px;
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
overflow: hidden;
}
.demo-header {
background: #667eea;
color: white;
padding: 1rem;
text-align: center;
}
.demo-header h3 {
font-size: 1.3rem;
margin-bottom: 0.5rem;
}
.demo-content {
padding: 1.5rem;
}
@media (max-width: 768px) {
.demo-grid {
grid-template-columns: 1fr;
}
.header h1 {
font-size: 2rem;
}
body {
padding: 1rem;
}
}
.form-group {
margin-bottom: 1.5rem;
}
.form-group label {
display: block;
margin-bottom: 0.5rem;
font-weight: 600;
color: #333;
}
.form-group input {
width: 100%;
padding: 0.8rem;
border: 2px solid #e1e5e9;
border-radius: 8px;
font-size: 1rem;
transition: border-color 0.3s ease;
}
.form-group input:focus {
outline: none;
border-color: #667eea;
}
.captcha-container {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 1rem;
}
.captcha-image {
border: 2px solid #e1e5e9;
border-radius: 8px;
cursor: pointer;
transition: border-color 0.3s ease;
}
.captcha-image:hover {
border-color: #667eea;
}
.btn {
padding: 0.8rem 1.5rem;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 1rem;
font-weight: 500;
transition: background 0.3s ease;
}
.btn-primary {
background: #667eea;
color: white;
}
.btn-primary:hover {
background: #5a6fd8;
}
.btn-success {
background: #4CAF50;
color: white;
}
.btn-success:hover {
background: #45a049;
}
.btn:disabled {
background: #ccc;
cursor: not-allowed;
}
.refresh-btn {
background: #667eea;
color: white;
border: none;
padding: 0.5rem 1rem;
border-radius: 5px;
cursor: pointer;
font-size: 0.9rem;
transition: background 0.3s ease;
}
.refresh-btn:hover {
background: #5a6fd8;
}
.submit-btn {
width: 100%;
background: #667eea;
color: white;
border: none;
padding: 1rem;
border-radius: 5px;
font-size: 1.1rem;
font-weight: 600;
cursor: pointer;
transition: background 0.3s ease;
}
.submit-btn:hover {
background: #5a6fd8;
}
.back-link {
text-align: center;
margin-top: 2rem;
}
.back-link a {
color: white;
text-decoration: none;
font-weight: 500;
font-size: 1.1rem;
}
.back-link a:hover {
text-decoration: underline;
}
.info-box {
background: #f8f9fa;
border-left: 4px solid #667eea;
padding: 1rem;
margin-bottom: 2rem;
border-radius: 0 8px 8px 0;
}
.info-box h3 {
color: #667eea;
margin-bottom: 0.5rem;
}
.info-box ul {
margin-left: 1.5rem;
color: #666;
}
.info-box li {
margin-bottom: 0.3rem;
}
.info-box code {
background: #e9ecef;
padding: 0.2rem 0.4rem;
border-radius: 4px;
font-family: 'Courier New', monospace;
font-size: 0.9rem;
}
.captcha-types {
background: #f8f9fa;
border-left: 4px solid #28a745;
padding: 1rem;
margin-bottom: 2rem;
border-radius: 0 8px 8px 0;
}
.type-buttons {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
margin-bottom: 0.5rem;
}
.type-btn {
background: #e9ecef;
color: #495057;
border: 2px solid #dee2e6;
padding: 0.5rem 1rem;
border-radius: 5px;
cursor: pointer;
font-size: 0.9rem;
transition: all 0.3s ease;
flex: 1;
min-width: 120px;
}
.type-btn:hover {
background: #dee2e6;
border-color: #adb5bd;
}
.type-btn.active {
background: #28a745;
color: white;
border-color: #28a745;
}
.demo-section {
background: #fff3cd;
border-left: 4px solid #ffc107;
padding: 1rem;
margin-bottom: 2rem;
border-radius: 0 8px 8px 0;
}
.demo-section h4 {
color: #856404;
margin-bottom: 0.5rem;
}
.demo-section p {
color: #856404;
margin-bottom: 0.3rem;
}
.success-message {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
padding: 1rem;
border-radius: 8px;
margin-bottom: 1rem;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🔐 Hertz验证码演示</h1>
<p>{{ demo_description }}</p>
</div>
<div class="demo-grid">
<!-- 验证码功能介绍 -->
<div class="demo-card">
<div class="demo-header">
<h3>🎯 Hertz验证码功能特性</h3>
<p>自定义验证码系统支持Redis缓存</p>
</div>
<div class="demo-content">
<div class="info-box">
<ul>
<li>🔤 随机字符验证码 - 生成随机字母数字组合</li>
<li>🎨 自定义样式配置 - 支持颜色、字体、噪声等设置</li>
<li>⚡ Ajax刷新功能 - 无需刷新页面</li>
<li>💾 Redis缓存 - 高性能数据存储</li>
<li>⏰ 超时自动失效 - 可配置过期时间</li>
<li>🔧 灵活配置 - 通过settings.py进行配置</li>
</ul>
</div>
<div class="captcha-types">
<h3 style="margin-bottom: 1rem; color: #667eea;">配置信息</h3>
<p style="color: #666; font-size: 0.9rem; margin-bottom: 0.5rem;">• 验证码长度: 可通过HERTZ_CAPTCHA_LENGTH配置</p>
<p style="color: #666; font-size: 0.9rem; margin-bottom: 0.5rem;">• 图片尺寸: 可通过HERTZ_CAPTCHA_WIDTH/HEIGHT配置</p>
<p style="color: #666; font-size: 0.9rem; margin-bottom: 0.5rem;">• 过期时间: 可通过HERTZ_CAPTCHA_TIMEOUT配置</p>
<p style="color: #666; font-size: 0.9rem;">• Redis前缀: 可通过HERTZ_CAPTCHA_REDIS_KEY_PREFIX配置</p>
</div>
</div>
</div>
<!-- 验证码测试 -->
<div class="demo-card">
<div class="demo-header">
<h3>🔒 Hertz验证码测试</h3>
<p>输入验证码进行功能测试</p>
</div>
<div class="demo-content">
{% if messages %}
{% for message in messages %}
<div class="success-message" style="{% if message.tags == 'error' %}background: #f8d7da; color: #721c24; border-color: #f5c6cb;{% endif %}">
{% if message.tags == 'success' %}✅{% elif message.tags == 'error' %}❌{% endif %} {{ message }}
</div>
{% endfor %}
{% endif %}
<div class="demo-section">
<h4>📋 Hertz验证码说明</h4>
<p>• 随机字符验证码:生成随机字母和数字组合</p>
<p>• 特点自定义样式支持噪声干扰Redis缓存存储</p>
<p>• 功能支持Ajax刷新自动过期失效</p>
</div>
<form method="post" id="captcha-form">
{% csrf_token %}
<div class="form-group">
<label for="captcha_input">验证码:</label>
<div class="captcha-container">
<img id="captcha-image" src="{{ initial_captcha.image_data }}"
alt="验证码" class="captcha-image" onclick="refreshCaptcha()"
style="cursor: pointer; border: 2px solid #e1e5e9; border-radius: 8px;">
<button type="button" class="refresh-btn" onclick="refreshCaptcha()">🔄 刷新</button>
</div>
<input type="text" id="captcha_input" name="captcha_input"
placeholder="请输入验证码" required
style="width: 100%; padding: 0.8rem; border: 2px solid #e1e5e9; border-radius: 8px; font-size: 1rem; margin-top: 0.5rem;">
<input type="hidden" id="captcha_id" name="captcha_id" value="{{ initial_captcha.captcha_id }}">
</div>
<button type="submit" class="submit-btn">验证提交</button>
</form>
<div style="margin-top: 1rem; padding: 1rem; background: #e7f3ff; border-radius: 8px; border-left: 4px solid #007bff;">
<h4 style="color: #007bff; margin-bottom: 0.5rem;">💡 使用提示</h4>
<p style="color: #004085; margin-bottom: 0.3rem;">• 点击验证码图片可以刷新</p>
<p style="color: #004085; margin-bottom: 0.3rem;">• 验证码不区分大小写</p>
<p style="color: #004085;">• 验证码有效期为5分钟</p>
</div>
</div>
</div>
</div>
<div class="back-link">
<a href="/" style="color: white; text-decoration: none; font-weight: 500; font-size: 1.1rem;">← 返回首页</a>
</div>
</div>
<script>
let currentCaptchaId = '{{ initial_captcha.captcha_id }}';
function refreshCaptcha() {
fetch(window.location.href, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value
},
body: JSON.stringify({
action: 'refresh',
captcha_id: currentCaptchaId
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
document.getElementById('captcha-image').src = data.data.image_data;
document.getElementById('captcha_id').value = data.data.captcha_id;
document.getElementById('captcha_input').value = '';
currentCaptchaId = data.data.captcha_id;
} else {
console.error('刷新验证码失败:', data.error);
alert('刷新验证码失败,请重试');
}
})
.catch(error => {
console.error('刷新验证码失败:', error);
alert('刷新验证码失败,请重试');
});
}
// 表单提交处理
const captchaForm = document.getElementById('captcha-form');
if (captchaForm) {
captchaForm.addEventListener('submit', function(e) {
e.preventDefault();
const captchaId = document.getElementById('captcha_id').value;
const userInput = document.getElementById('captcha_input').value;
if (!userInput.trim()) {
alert('请输入验证码');
return;
}
fetch(window.location.href, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value
},
body: JSON.stringify({
action: 'verify',
captcha_id: captchaId,
user_input: userInput
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
if (data.valid) {
alert('✅ ' + data.message);
document.getElementById('captcha_input').value = '';
refreshCaptcha();
} else {
alert('❌ ' + data.message);
document.getElementById('captcha_input').value = '';
refreshCaptcha();
}
} else {
alert('❌ 验证失败: ' + (data.error || '未知错误'));
refreshCaptcha();
}
})
.catch(error => {
console.error('提交失败:', error);
alert('❌ 提交失败,请重试');
refreshCaptcha();
});
});
}
// 回车键提交
document.getElementById('captcha_input').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
captchaForm.dispatchEvent(new Event('submit'));
}
});
</script>
</body>
</html>