smart-home/smart-home-app/static/captive-portal.html
2026-02-26 09:16:34 +08:00

361 lines
11 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>ESP32 萤火虫设备配置</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.container {
background: white;
border-radius: 20px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
padding: 40px;
max-width: 500px;
width: 100%;
}
.header {
text-align: center;
margin-bottom: 30px;
}
.logo {
font-size: 48px;
margin-bottom: 10px;
}
.title {
font-size: 24px;
font-weight: bold;
color: #333;
margin-bottom: 8px;
}
.subtitle {
color: #666;
font-size: 14px;
}
.form-group {
margin-bottom: 20px;
}
.form-label {
display: block;
font-weight: 500;
color: #333;
margin-bottom: 8px;
}
.form-input {
width: 100%;
padding: 12px 16px;
border: 2px solid #e1e5e9;
border-radius: 10px;
font-size: 16px;
transition: border-color 0.3s;
}
.form-input:focus {
outline: none;
border-color: #667eea;
}
.btn-primary {
width: 100%;
padding: 14px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 10px;
font-size: 16px;
font-weight: 500;
cursor: pointer;
transition: transform 0.2s;
}
.btn-primary:hover {
transform: translateY(-2px);
}
.btn-primary:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
}
.status {
margin-top: 20px;
padding: 12px;
border-radius: 8px;
text-align: center;
font-weight: 500;
}
.status.success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.status.error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.status.loading {
background: #d1ecf1;
color: #0c5460;
border: 1px solid #bee5eb;
}
.wifi-list {
max-height: 200px;
overflow-y: auto;
border: 1px solid #e1e5e9;
border-radius: 8px;
margin-bottom: 15px;
}
.wifi-item {
padding: 12px 16px;
border-bottom: 1px solid #f0f0f0;
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
}
.wifi-item:last-child {
border-bottom: none;
}
.wifi-item:hover {
background: #f8f9fa;
}
.wifi-item.selected {
background: #e3f2fd;
color: #1976d2;
}
.wifi-signal {
font-size: 12px;
color: #666;
}
.scan-btn {
width: 100%;
padding: 10px;
background: #f8f9fa;
border: 1px solid #e1e5e9;
border-radius: 8px;
cursor: pointer;
margin-bottom: 15px;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<div class="logo">🔥</div>
<div class="title">萤火虫设备配置</div>
<div class="subtitle">请配置您的WiFi网络连接</div>
</div>
<form id="configForm">
<div class="form-group">
<label class="form-label">扫描WiFi网络</label>
<button type="button" class="scan-btn" onclick="scanWifi()">🔍 扫描附近的WiFi网络</button>
<div id="wifiList" class="wifi-list" style="display: none;"></div>
</div>
<div class="form-group">
<label class="form-label" for="ssid">WiFi名称 (SSID)</label>
<input type="text" id="ssid" class="form-input" placeholder="请输入WiFi名称" required>
</div>
<div class="form-group">
<label class="form-label" for="password">WiFi密码</label>
<input type="password" id="password" class="form-input" placeholder="请输入WiFi密码" required>
</div>
<button type="submit" class="btn-primary" id="submitBtn">
📡 配置设备
</button>
</form>
<div id="status" class="status" style="display: none;"></div>
</div>
<script>
let selectedWifi = '';
// 扫描WiFi网络
async function scanWifi() {
const wifiList = document.getElementById('wifiList');
const scanBtn = document.querySelector('.scan-btn');
scanBtn.textContent = '🔄 扫描中...';
scanBtn.disabled = true;
try {
// 模拟WiFi扫描结果
const mockWifiList = [
{ ssid: 'MyHome_WiFi', rssi: -45, security: 'WPA2' },
{ ssid: 'Office_Network', rssi: -60, security: 'WPA2' },
{ ssid: 'Guest_WiFi', rssi: -75, security: 'Open' },
{ ssid: 'Neighbor_5G', rssi: -80, security: 'WPA3' }
];
// 实际应该调用ESP32的WiFi扫描API
// const response = await fetch('/api/wifi/scan');
// const wifiList = await response.json();
displayWifiList(mockWifiList);
} catch (error) {
showStatus('WiFi扫描失败: ' + error.message, 'error');
}
scanBtn.textContent = '🔍 重新扫描';
scanBtn.disabled = false;
}
// 显示WiFi列表
function displayWifiList(networks) {
const wifiList = document.getElementById('wifiList');
wifiList.innerHTML = '';
networks.forEach(network => {
const item = document.createElement('div');
item.className = 'wifi-item';
item.onclick = () => selectWifi(network.ssid, item);
const signalStrength = getSignalStrength(network.rssi);
item.innerHTML = `
<div>
<strong>${network.ssid}</strong>
<div class="wifi-signal">${network.security}${signalStrength}</div>
</div>
<div>${getSignalIcon(network.rssi)}</div>
`;
wifiList.appendChild(item);
});
wifiList.style.display = 'block';
}
// 选择WiFi
function selectWifi(ssid, element) {
selectedWifi = ssid;
document.getElementById('ssid').value = ssid;
// 移除其他选中状态
document.querySelectorAll('.wifi-item').forEach(item => {
item.classList.remove('selected');
});
// 添加选中状态
element.classList.add('selected');
}
// 获取信号强度描述
function getSignalStrength(rssi) {
if (rssi > -50) return '信号强';
if (rssi > -70) return '信号中等';
return '信号弱';
}
// 获取信号图标
function getSignalIcon(rssi) {
if (rssi > -50) return '📶';
if (rssi > -70) return '📶';
return '📶';
}
// 显示状态消息
function showStatus(message, type) {
const status = document.getElementById('status');
status.textContent = message;
status.className = `status ${type}`;
status.style.display = 'block';
}
// 表单提交
document.getElementById('configForm').addEventListener('submit', async function(e) {
e.preventDefault();
const ssid = document.getElementById('ssid').value;
const password = document.getElementById('password').value;
const submitBtn = document.getElementById('submitBtn');
if (!ssid || !password) {
showStatus('请填写完整的WiFi信息', 'error');
return;
}
submitBtn.disabled = true;
submitBtn.textContent = '⏳ 配置中...';
showStatus('正在配置WiFi连接请稍候...', 'loading');
try {
const response = await fetch('/api/wifi', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
ssid: ssid,
password: password
})
});
const result = await response.json();
if (result.success) {
showStatus('✅ 配置成功设备将重新连接到您的WiFi网络。请在手机上连接到相同的WiFi然后打开萤火虫APP继续使用。', 'success');
// 3秒后自动关闭页面
setTimeout(() => {
window.close();
}, 3000);
} else {
showStatus('❌ 配置失败: ' + (result.message || '未知错误'), 'error');
}
} catch (error) {
showStatus('❌ 配置失败: ' + error.message, 'error');
}
submitBtn.disabled = false;
submitBtn.textContent = '📡 配置设备';
});
// 页面加载完成后自动扫描WiFi
window.addEventListener('load', function() {
setTimeout(scanWifi, 1000);
});
</script>
</body>
</html>