You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Software_Architecture/distance-judgement/test_device_selector.html

392 lines
12 KiB

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>设备选择器测试</title>
<style>
body {
background: linear-gradient(135deg, #1e3c72, #2a5298);
color: white;
font-family: 'Microsoft YaHei', sans-serif;
margin: 0;
padding: 20px;
}
.container {
max-width: 500px;
margin: 0 auto;
padding: 20px;
}
.video-container {
background: rgba(0, 0, 0, 0.4);
border-radius: 15px;
margin: 20px 0;
overflow: hidden;
}
.video-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
background: rgba(0, 0, 0, 0.3);
border-radius: 8px 8px 0 0;
}
.device-select-btn {
background: #2196F3;
color: white;
border: none;
padding: 8px 12px;
border-radius: 4px;
font-size: 12px;
cursor: pointer;
}
.device-selector {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
}
.device-selector-content {
background: rgba(0, 20, 40, 0.95);
border: 2px solid #00aaff;
border-radius: 15px;
padding: 20px;
max-width: 90%;
max-height: 80%;
overflow-y: auto;
backdrop-filter: blur(10px);
}
.device-selector h3 {
margin: 0 0 15px 0;
color: #00aaff;
text-align: center;
}
.device-list {
margin: 15px 0;
}
.device-item {
background: rgba(255, 255, 255, 0.1);
border-radius: 8px;
padding: 15px;
margin: 10px 0;
cursor: pointer;
transition: all 0.3s ease;
border: 2px solid transparent;
}
.device-item:hover {
background: rgba(255, 255, 255, 0.2);
border-color: #00aaff;
}
.device-item.selected {
background: rgba(0, 170, 255, 0.3);
border-color: #00aaff;
}
.device-name {
font-weight: bold;
color: #00aaff;
margin-bottom: 5px;
}
.device-id {
font-size: 12px;
color: #ccc;
font-family: monospace;
}
.device-kind {
display: inline-block;
background: #4CAF50;
color: white;
padding: 2px 6px;
border-radius: 3px;
font-size: 10px;
margin-top: 5px;
}
.device-selector-buttons {
display: flex;
justify-content: space-between;
margin-top: 20px;
}
.btn {
padding: 10px 20px;
border: none;
border-radius: 8px;
cursor: pointer;
font-weight: bold;
margin: 0 5px;
}
.btn-primary {
background: #007bff;
color: white;
}
.btn-secondary {
background: #6c757d;
color: white;
}
.btn:disabled {
background: #666;
cursor: not-allowed;
}
.loading {
text-align: center;
color: #ccc;
padding: 20px;
}
.log {
background: rgba(0, 0, 0, 0.3);
border-radius: 8px;
padding: 10px;
margin: 20px 0;
max-height: 200px;
overflow-y: auto;
font-family: monospace;
font-size: 12px;
}
</style>
</head>
<body>
<div class="container">
<h1>🧪 设备选择器测试</h1>
<div class="video-container">
<div class="video-header">
<span>📹 视频设备</span>
<button class="device-select-btn" onclick="showDeviceSelector()">📷 选择设备</button>
</div>
<div id="videoPlaceholder" style="text-align: center; padding: 40px; color: #ccc;">
点击"选择设备"开始使用摄像头
</div>
</div>
<!-- 设备选择弹窗 -->
<div class="device-selector" id="deviceSelector" style="display: none;">
<div class="device-selector-content">
<h3>📷 选择视频设备</h3>
<!-- 本地设备列表 -->
<div>
<h4 style="color: #4CAF50; margin: 15px 0 10px 0;">📱 本地设备</h4>
<div class="device-list" id="localDeviceList">
<div class="loading">正在扫描本地设备...</div>
</div>
</div>
<div class="device-selector-buttons">
<button class="btn btn-secondary" onclick="hideDeviceSelector()">❌ 取消</button>
<button class="btn btn-primary" onclick="refreshDevices()">🔄 刷新设备</button>
<button class="btn" onclick="useSelectedDevice()" id="useDeviceBtn" disabled>✅ 使用选择的设备</button>
</div>
</div>
</div>
<div class="log" id="logPanel">
<div>系统初始化中...</div>
</div>
</div>
<script>
let availableDevices = [];
let selectedDeviceId = null;
let selectedDeviceInfo = null;
// 日志函数
function log(message, type = 'info') {
const logPanel = document.getElementById('logPanel');
const timestamp = new Date().toLocaleTimeString();
const entry = document.createElement('div');
entry.style.color = type === 'error' ? '#ff6b6b' : type === 'success' ? '#51cf66' : '#74c0fc';
entry.textContent = `${timestamp} - ${message}`;
logPanel.appendChild(entry);
logPanel.scrollTop = logPanel.scrollHeight;
}
// 扫描设备
async function scanDevices() {
log('正在扫描可用视频设备...', 'info');
try {
if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) {
throw new Error('浏览器不支持设备枚举功能');
}
const devices = await navigator.mediaDevices.enumerateDevices();
availableDevices = devices.filter(device => device.kind === 'videoinput');
log(`发现 ${availableDevices.length} 个视频设备`, 'success');
} catch (error) {
log(`设备扫描失败: ${error.message}`, 'error');
availableDevices = [];
}
}
// 显示设备选择器
async function showDeviceSelector() {
log('打开设备选择器', 'info');
const selector = document.getElementById('deviceSelector');
selector.style.display = 'flex';
await scanDevices();
updateDeviceList();
}
// 隐藏设备选择器
function hideDeviceSelector() {
document.getElementById('deviceSelector').style.display = 'none';
clearDeviceSelection();
}
// 刷新设备
async function refreshDevices() {
document.getElementById('localDeviceList').innerHTML = '<div class="loading">正在扫描设备...</div>';
await scanDevices();
updateDeviceList();
}
// 更新设备列表
function updateDeviceList() {
const localList = document.getElementById('localDeviceList');
if (availableDevices.length === 0) {
localList.innerHTML = '<div style="color: #ff6b6b; text-align: center; padding: 20px;">未发现本地摄像头设备<br><small>请确保已连接摄像头并允许浏览器访问</small></div>';
return;
}
localList.innerHTML = '';
availableDevices.forEach((device, index) => {
const deviceItem = document.createElement('div');
deviceItem.className = 'device-item';
deviceItem.onclick = () => selectDevice(device.deviceId, {
label: device.label || `摄像头 ${index + 1}`,
kind: device.kind,
isRemote: false
});
const deviceName = device.label || `摄像头 ${index + 1}`;
const isFrontCamera = deviceName.toLowerCase().includes('front') || deviceName.toLowerCase().includes('前');
const isBackCamera = deviceName.toLowerCase().includes('back') || deviceName.toLowerCase().includes('后');
let cameraIcon = '📷';
if (isFrontCamera) cameraIcon = '🤳';
else if (isBackCamera) cameraIcon = '📹';
deviceItem.innerHTML = `
<div class="device-name">${cameraIcon} ${deviceName}</div>
<div class="device-id">${device.deviceId}</div>
<div class="device-kind">本地设备</div>
`;
localList.appendChild(deviceItem);
});
}
// 选择设备
function selectDevice(deviceId, deviceInfo) {
// 清除之前的选择
document.querySelectorAll('.device-item').forEach(item => {
item.classList.remove('selected');
});
// 选择当前设备
event.currentTarget.classList.add('selected');
selectedDeviceId = deviceId;
selectedDeviceInfo = deviceInfo;
// 启用使用按钮
document.getElementById('useDeviceBtn').disabled = false;
log(`已选择设备: ${deviceInfo.label}`, 'info');
}
// 清除设备选择
function clearDeviceSelection() {
selectedDeviceId = null;
selectedDeviceInfo = null;
document.getElementById('useDeviceBtn').disabled = true;
document.querySelectorAll('.device-item').forEach(item => {
item.classList.remove('selected');
});
}
// 使用选择的设备
async function useSelectedDevice() {
if (!selectedDeviceId || !selectedDeviceInfo) {
log('请先选择一个设备', 'error');
return;
}
try {
log(`正在启动设备: ${selectedDeviceInfo.label}`, 'info');
const constraints = {
video: {
deviceId: { exact: selectedDeviceId },
width: { ideal: 640 },
height: { ideal: 480 }
},
audio: false
};
const stream = await navigator.mediaDevices.getUserMedia(constraints);
// 创建视频元素显示
const placeholder = document.getElementById('videoPlaceholder');
placeholder.innerHTML = `
<video autoplay muted playsinline style="width: 100%; height: auto;"></video>
<div style="font-size: 12px; color: #ccc; margin-top: 10px;">
正在使用: ${selectedDeviceInfo.label}
</div>
`;
const videoElement = placeholder.querySelector('video');
videoElement.srcObject = stream;
hideDeviceSelector();
log(`设备启动成功: ${selectedDeviceInfo.label}`, 'success');
} catch (error) {
let errorMsg = error.message;
if (error.name === 'NotAllowedError') {
errorMsg = '设备权限被拒绝,请允许访问摄像头';
} else if (error.name === 'NotFoundError') {
errorMsg = '设备未找到或已被占用';
}
log(`设备启动失败: ${errorMsg}`, 'error');
}
}
// 初始化
window.addEventListener('load', () => {
log('设备选择器测试页面已加载', 'success');
});
</script>
</body>
</html>