// 用户点名JavaScript - 支持服务器和本地双模式 // 状态管理 let currentList = null; let stream = null; // DOM元素 const inputSection = document.getElementById('inputSection'); const rollCallSection = document.getElementById('rollCallSection'); const enterForm = document.getElementById('enterForm'); const codeInput = document.getElementById('codeInput'); const scanQRBtn = document.getElementById('scanQRBtn'); const completedCount = document.getElementById('completedCount'); const totalCount = document.getElementById('totalCount'); const progressFill = document.getElementById('progressFill'); const memberListDisplay = document.getElementById('memberListDisplay'); const video = document.getElementById('video'); const canvas = document.getElementById('canvas'); const startCameraBtn = document.getElementById('startCameraBtn'); const captureBtn = document.getElementById('captureBtn'); const stopCameraBtn = document.getElementById('stopCameraBtn'); const capturedPhoto = document.getElementById('capturedPhoto'); const photoPreview = document.getElementById('photoPreview'); const confirmPhotoBtn = document.getElementById('confirmPhotoBtn'); const retakeBtn = document.getElementById('retakeBtn'); const manualSelect = document.getElementById('manualSelect'); const manualRollCallBtn = document.getElementById('manualRollCallBtn'); // 初始化 document.addEventListener('DOMContentLoaded', () => { // 显示运行模式 const modeText = dataStorage.isServerMode ? '服务器模式' : '本地模式'; const modeIndicator = document.getElementById('modeIndicator'); if (modeIndicator) { modeIndicator.textContent = `当前运行模式: ${modeText}`; if (!dataStorage.isServerMode) { modeIndicator.textContent += ' (数据保存在浏览器本地)'; } } console.log(`点名系统运行在: ${modeText}`); // 检查URL参数 const urlParams = new URLSearchParams(window.location.search); const codeFromUrl = urlParams.get('code'); if (codeFromUrl) { codeInput.value = codeFromUrl; enterRollCall(codeFromUrl); } }); // 进入点名 enterForm.addEventListener('submit', (e) => { e.preventDefault(); const code = codeInput.value.trim(); enterRollCall(code); }); async function enterRollCall(code) { try { currentList = await dataStorage.getList(code); inputSection.style.display = 'none'; rollCallSection.style.display = 'block'; updateProgress(); renderMemberList(); populateManualSelect(); } catch (error) { alert('进入点名失败:' + error.message); } } // 扫描二维码(简化版) scanQRBtn.addEventListener('click', () => { alert('扫码功能需要集成摄像头扫码库,当前版本请手动输入编号'); }); // 更新进度 function updateProgress() { if (!currentList) return; const completed = currentList.members.filter(m => m.completed).length; const total = currentList.members.length; const percentage = total > 0 ? (completed / total * 100) : 0; completedCount.textContent = completed; totalCount.textContent = total; progressFill.style.width = percentage + '%'; progressFill.textContent = Math.round(percentage) + '%'; } // 渲染成员列表 function renderMemberList() { if (!currentList) return; memberListDisplay.innerHTML = currentList.members.map((member, index) => `
${member.name} ${member.completed ? '已点名' : '未点名'}
`).join(''); } // 填充手动选择下拉框 function populateManualSelect() { if (!currentList) return; const uncompletedMembers = currentList.members.filter(m => !m.completed); manualSelect.innerHTML = '' + uncompletedMembers.map(member => ``).join(''); } // 开启摄像头 startCameraBtn.addEventListener('click', async () => { try { stream = await navigator.mediaDevices.getUserMedia({ video: true }); video.srcObject = stream; video.style.display = 'block'; startCameraBtn.style.display = 'none'; captureBtn.style.display = 'inline-block'; stopCameraBtn.style.display = 'inline-block'; } catch (err) { alert('无法访问摄像头,请检查权限设置'); console.error(err); } }); // 拍照 captureBtn.addEventListener('click', () => { const context = canvas.getContext('2d'); context.drawImage(video, 0, 0, canvas.width, canvas.height); const dataURL = canvas.toDataURL('image/jpeg'); photoPreview.src = dataURL; capturedPhoto.style.display = 'block'; video.style.display = 'none'; captureBtn.style.display = 'none'; }); // 关闭摄像头 stopCameraBtn.addEventListener('click', () => { if (stream) { stream.getTracks().forEach(track => track.stop()); stream = null; } video.style.display = 'block'; capturedPhoto.style.display = 'none'; startCameraBtn.style.display = 'inline-block'; captureBtn.style.display = 'none'; stopCameraBtn.style.display = 'none'; }); // 确认照片 confirmPhotoBtn.addEventListener('click', () => { // 模拟人脸识别 const recognizedName = simulateFaceRecognition(); if (recognizedName) { markAsCompleted(recognizedName); alert(`识别成功:${recognizedName}`); } else { alert('未能识别,请手动选择姓名'); } // 重置拍照区域 capturedPhoto.style.display = 'none'; video.style.display = 'block'; captureBtn.style.display = 'inline-block'; }); // 重新拍摄 retakeBtn.addEventListener('click', () => { capturedPhoto.style.display = 'none'; video.style.display = 'block'; captureBtn.style.display = 'inline-block'; }); // 模拟人脸识别 function simulateFaceRecognition() { // 随机返回一个未点名的成员(模拟识别) const uncompletedMembers = currentList.members.filter(m => !m.completed); if (uncompletedMembers.length === 0) return null; const randomIndex = Math.floor(Math.random() * uncompletedMembers.length); return uncompletedMembers[randomIndex].name; } // 手动点名 manualRollCallBtn.addEventListener('click', () => { const selectedName = manualSelect.value; if (!selectedName) { alert('请选择姓名'); return; } markAsCompleted(selectedName); }); // 标记为已完成 async function markAsCompleted(name) { try { await dataStorage.rollCall(currentList.code, name); // 更新本地数据 const member = currentList.members.find(m => m.name === name); if (member) { member.completed = true; member.timestamp = new Date().toLocaleString(); } // 更新UI updateProgress(); renderMemberList(); populateManualSelect(); // 检查是否全部完成 const allCompleted = currentList.members.every(m => m.completed); if (allCompleted) { alert('点名完成!所有成员已点名'); } } catch (error) { alert('点名失败:' + error.message); } }