安静养小树edit icon

Fork(复制)
下载
嵌入
BUG反馈
index.html
style.css
index.js
现在支持上传本地图片了!
index.html
            
            <!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>静音育林 - 教室自律系统</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        :root {
            --main-green: #2ecc71;
            --dark-green: #27ae60;
            --bg-color: #f5fbf7;
            --warning-red: #e74c3c;
            --dark-red: #c0392b;
            --panel-bg: #ffffff;
            --text-color: #333333;
            --border-color: #e0e0e0;
        }

        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }

        body {
            font-family: '微软雅黑', sans-serif;
            background: var(--bg-color);
            color: var(--text-color);
            min-height: 100vh;
            display: flex;
            flex-direction: column;
            padding: 20px;
        }

        .header {
            text-align: center;
            padding: 20px;
            background: var(--panel-bg);
            border-radius: 15px;
            box-shadow: 0 4px 6px rgba(0,0,0,0.1);
            margin-bottom: 20px;
        }

        .header h1 {
            font-size: 1.8rem;
            margin-bottom: 10px;
            color: var(--dark-green);
        }

        .header p {
            font-size: 1rem;
            color: #666;
        }

        .main-container {
            display: flex;
            gap: 20px;
            flex: 1;
        }

        /* 左侧功能区 */
        .control-panel {
            background: var(--panel-bg);
            padding: 20px;
            border-radius: 15px;
            box-shadow: 0 4px 6px rgba(0,0,0,0.1);
            width: 200px;
            display: flex;
            flex-direction: column;
            gap: 10px;
        }

        .btn {
            padding: 12px 15px;
            background: var(--main-green);
            color: white;
            border: none;
            border-radius: 8px;
            cursor: pointer;
            font-size: 0.9rem;
            transition: 0.3s;
            display: flex;
            align-items: center;
            gap: 8px;
            justify-content: center;
        }

        .btn:hover {
            background: var(--dark-green);
        }

        .btn.secondary {
            background: #3498db;
        }

        .btn.secondary:hover {
            background: #2980b9;
        }

        .btn.warning {
            background: var(--warning-red);
        }

        .btn.warning:hover {
            background: var(--dark-red);
        }

        /* 中间状态区 */
        .status-panel {
            background: var(--panel-bg);
            padding: 20px;
            border-radius: 15px;
            box-shadow: 0 4px 6px rgba(0,0,0,0.1);
            flex: 0.7;
            display: flex;
            flex-direction: column;
        }

        .status-grid {
            display: grid;
            grid-template-columns: 1fr;
            gap: 15px;
            margin-bottom: 20px;
        }

        .status-item {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .status-label {
            font-weight: bold;
            display: flex;
            align-items: center;
            gap: 8px;
        }

        .status-value {
            font-size: 1.2rem;
            font-weight: bold;
            color: var(--dark-green);
        }

        .status-value.warning {
            color: var(--warning-red);
        }

        .progress-container {
            margin: 10px 0;
        }

        .progress-bar {
            height: 20px;
            background: #eee;
            border-radius: 10px;
            overflow: hidden;
        }

        .progress {
            height: 100%;
            background: var(--main-green);
            width: 0;
            transition: width 0.5s;
        }

        .progress.warning {
            background: var(--warning-red);
        }

        /* 小树苗生长区 */
        .saplings-area {
            background: #f9f9f9;
            padding: 15px;
            border-radius: 10px;
            min-height:100px;
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
            align-content: flex-start;
            flex: 1;
        }

        /* 右侧森林区 */
        .forest-panel {
            background: var(--panel-bg);
            padding: 20px;
            border-radius: 15px;
            box-shadow: 0 4px 6px rgba(0,0,0,0.1);
            flex: 1;
            display: flex;
            flex-direction: column;
            overflow: hidden; /* 新增:防止内容溢出 */
        }

        .panel-title {
            margin-bottom: 15px;
            text-align: center;
            color: var(--dark-green);
            font-size: 1.3rem;
        }

        .forest {
            flex: 1;
            display: flex;
            flex-wrap: wrap;
            gap: 15px;
            align-content: flex-start;
            justify-content:flex-start; /* 关键修改:从左对齐(原为center) */
            padding: 10px;
            overflow-y: auto;
        }

        .tree {
            display: inline-block;
            transition: transform 0.3s;
        }
           /* 小树苗单独样式 */
         .sapling {
         font-size: 30px;  /* 小树苗大小 */
         }

           /* 大树单独样式 */
          .mature-tree {
          font-size: 50px;  /* 大树大小 */
         }
        /* 弹窗样式 */
        .modal-overlay {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: rgba(0,0,0,0.5);
            z-index: 100;
            justify-content: center;
            align-items: center;
        }
            .fa-trophy {
            color: gold;  /* 金色奖杯 */
            text-shadow: 0 0 2px rgba(0,0,0,0.3); /* 轻微阴影 */
        }
        .modal-content {
            background: var(--panel-bg);
            padding: 20px;
            border-radius: 15px;
            box-shadow: 0 4px 20px rgba(0,0,0,0.2);
            width: 90%;
            max-width: 500px;
            max-height: 80vh;
            overflow-y: auto;
        }

        /* 响应式设计 */
        @media (max-width: 992px) {
            .main-container {
                flex-direction: column;
            }
            .control-panel {
                width: 100%;
            }
        }
       /* ========= 新增屏蔽模式样式 ========= */
       .shield-overlay {
        display: none;
        position: fixed;
        top: 120px;                  /* 与页面边距一致 */
        left: 240px;
        right: 20px;
        bottom: 20px;
        background: #f8f8f8;
        z-index: 999;
        justify-content: center;
        align-items: center;
        border-radius: 20px;        /* 圆角匹配整体风格 */
        box-shadow: 0 0 20px rgba(0,0,0,0.2);
        margin: 0;
    }
* 响应式调整 */
@media (max-width: 992px) {
    .shield-overlay {
        left: 20px; /* 移动端恢复全屏 */
        top: 180px; /* 留出顶部空间 */
    }
}
    .shield-timer {
        font-size: 3rem;
        background: var(--main-green);
        color: white;
        width: 200px;
        height: 200px;
        border-radius: 50%;
        display: flex;
        justify-content: center;
        align-items: center;
        box-shadow: 0 0 20px rgba(0,0,0,0.3);
    }
    </style>
</head>
<body>
    <div class="header">
        <h1>🌱嘘!小树正在安静生长🌱</h1>
        <p>保持安静环境,培育属于班级的静谧森林</p>
    </div>

    <div class="main-container">
        <!-- 左侧功能按钮区 -->
        <div class="control-panel">
            <button class="btn" id="settingsBtn">
                <i class="fas fa-cog"></i> 参数设置
            </button>
            <button class="btn" id="startBtn">
                <i class="fas fa-play"></i> 开始生长
            </button>
            <button class="btn warning" id="pauseBtn" disabled>
                <i class="fas fa-pause"></i> 暂停培育
            </button>
            <button class="btn secondary" id="restartBtn">
                <i class="fas fa-redo"></i> 重新开始
            </button>
            <button class="btn" id="fullscreenBtn">
                <i class="fas fa-expand"></i> 全          屏
            </button>
            <button class="btn secondary" id="historyBtn">
                <i class="fas fa-trophy"></i> 历史成就
            </button>
             <button class="btn secondary" id="shieldBtn">
                <i class="fas fa-eye-slash"></i> 屏蔽模式
            </button>
        </div>

        <!-- 中间状态和小树苗区 -->
        <div class="status-panel">
            <div class="status-grid">
                <div class="status-item">
                    <span class="status-label">
                        <i class="fas fa-volume-up" ></i> 当前分贝
                    </span>
                    <span class="status-value" id="currentDB">-- dB</span>
                </div>
                
                <div class="status-item">
                    <span class="status-label">
                        <i class="far fa-clock"></i> 安静时间
                    </span>
                    <span class="status-value" id="quietTime">0秒</span>
                </div>
                
                <div class="status-item">
                    <span class="status-label">
                        <i class="fas fa-seedling" style="color: var(--main-green)"></i> 树苗数量
                    </span>
                    <span class="status-value" id="saplingCount">0</span>
                </div>
            </div>
            
            <div class="progress-container">
                <div class="progress-bar">
                    <div class="progress" id="progress"></div>
                </div>
            </div>
            
            <div class="status-item" style="margin: 10px 0;">
                <span class="status-label">
                    <i class="fas fa-info-circle"></i> 生长进度
                </span>
                <span class="status-value" id="statusText">准备就绪</span>
            </div>
            
            <h3 class="panel-title">小树苗生长区</h3>
            <div class="saplings-area" id="saplingsArea"></div>
        </div>

        <!-- 右侧森林展示区 -->
        <div class="forest-panel">
            <h3 class="panel-title">班级静谧森林</h3>
            <div class="forest" id="forest"></div>
        </div>
    </div>

    <!-- 设置面板 -->
    <div class="modal-overlay" id="settingsModal">
        <div class="modal-content">
            <h3>参数设置</h3>
            
            <div class="settings-item" style="margin: 15px 0;">
                <label for="volumeThreshold">音量阈值 (dB) <span style="color:#666">(0-100)</span></label>
                <input type="range" id="volumeThreshold" min="0" max="100" value="20" style="width:100%">
                <div style="text-align:center" id="volumeThresholdValue">20</div>
            </div>
            
            <div class="settings-item" style="margin: 15px 0;">
                <label for="timeThreshold">计时时间 (秒) <span style="color:#666">(10-300)</span></label>
                <input type="range" id="timeThreshold" min="10" max="300" value="30" style="width:100%">
                <div style="text-align:center" id="timeThresholdValue">30</div>
            </div>
            
            <div class="settings-item" style="margin: 15px 0;">
                <label>
                    <input type="checkbox" id="resetProgress" checked> 重置进度(清零所有树苗和大树)
                </label>
            </div>
            
            <div class="settings-item" style="margin: 15px 0;">
                <label for="punishVolumeThreshold">惩罚音量 (dB)</label>
                <input type="range" id="punishVolumeThreshold" min="50" max="100" value="60" style="width:100%">
                <div style="text-align:center" id="punishVolumeThresholdValue">60</div>
            </div>
            
            <div class="settings-item" style="margin: 15px 0;">
                <label for="punishTimeThreshold">持续时间 (秒)</label>
                <input type="range" id="punishTimeThreshold" min="10" max="120" value="20" style="width:100%">
                <div style="text-align:center" id="punishTimeThresholdValue">10</div>
            </div>
            
            <div style="margin-top: 20px; display: flex;justify-content: flex-end; gap: 30px;">
                <button class="btn secondary" id="cancelSettings">
                    <i class="fas fa-times"></i> 取消
                </button>
                <button class="btn" id="saveSettings">
                    <i class="fas fa-save"></i> 保存
                </button>
            </div>
        </div>
    </div>

    <!-- 历史记录面板 -->
    <div class="modal-overlay" id="historyModal">
        <div class="modal-content">
            <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:20px;">
                <h3>培育历史记录</h3>
                <button id="closeHistory" style="background:none; border:none; font-size:1.5rem; cursor:pointer;">
                    <i class="fas fa-times"></i>
                </button>
            </div>
            <div id="historyList">
                <!-- 历史记录将在这里动态生成 -->
            </div>
        </div>
       
    </div>
<div class="shield-overlay" id="shieldOverlay">
           <div class="shield-timer" id="shieldTimer">00:00:00</div>
       </div>
    <script>
        document.addEventListener('DOMContentLoaded', function() {
            // 可选的树种emoji
            const TREE_TYPES = ['🌲', '🌳', '🌴', '🌻', '🌾', '🌵', '🎄', '🎋'];
            
            // 系统状态变量
            let isMonitoring = false;
            let audioContext = null;
            let analyser = null;
            let microphone = null;
            let quietStartTime = null;
            let noisyStartTime = null;
            let saplingCount = 0;
            let treeCount = 0;
            let detectionInterval = null;
            let requiredQuietTime = 30;
            let punishVolumeThreshold = 60;
            let punishTimeThreshold = 10;
            let treeTypes = [];
            let historyRecords = JSON.parse(localStorage.getItem('forestHistory')) || [];
            let currentSessionStart = null;
            let totalQuietTime = 0;
            let lastQuietCheckTime = null;
                 // ========= 新增屏蔽模式变量 =========
                let isShieldMode = false;
                let shieldStartTime = null;
                let shieldInterval = null;
               const shieldBtn = document.getElementById('shieldBtn');
                const shieldOverlay = document.getElementById('shieldOverlay');
                const shieldTimer = document.getElementById('shieldTimer');
            // DOM元素
            const startBtn = document.getElementById('startBtn');
            const pauseBtn = document.getElementById('pauseBtn');
            const restartBtn = document.getElementById('restartBtn');
            const fullscreenBtn = document.getElementById('fullscreenBtn');
            const settingsBtn = document.getElementById('settingsBtn');
            const historyBtn = document.getElementById('historyBtn');
            const currentDB = document.getElementById('currentDB');
            const quietTime = document.getElementById('quietTime');
            const saplingDisplay = document.getElementById('saplingCount');
            const statusText = document.getElementById('statusText');
            const progress = document.getElementById('progress');
            const forest = document.getElementById('forest');
            const saplingsArea = document.getElementById('saplingsArea');
            
            // 弹窗相关
            const settingsModal = document.getElementById('settingsModal');
            const historyModal = document.getElementById('historyModal');
            const closeHistory = document.getElementById('closeHistory');
            const historyList = document.getElementById('historyList');
            
            // 设置相关元素
            const volumeThreshold = document.getElementById('volumeThreshold');
            const volumeThresholdValue = document.getElementById('volumeThresholdValue');
            const timeThreshold = document.getElementById('timeThreshold');
            const timeThresholdValue = document.getElementById('timeThresholdValue');
            const punishVolumeThresholdInput = document.getElementById('punishVolumeThreshold');
            const punishVolumeThresholdValue = document.getElementById('punishVolumeThresholdValue');
            const punishTimeThresholdInput = document.getElementById('punishTimeThreshold');
            const punishTimeThresholdValue = document.getElementById('punishTimeThresholdValue');
            const resetProgress = document.getElementById('resetProgress');
            const saveSettings = document.getElementById('saveSettings');
            const cancelSettings = document.getElementById('cancelSettings');

            // 初始化
            loadSettingsFromLocal(); // 加载保存的设置
            renderHistory();
            updateButtonStates();

            // 获取随机树种
            function getRandomTree() {
                return TREE_TYPES[Math.floor(Math.random() * TREE_TYPES.length)];
            }

            // 更新按钮状态
            function updateButtonStates() {
                startBtn.disabled = isMonitoring;
                pauseBtn.disabled = !isMonitoring;
            }

            // 开始培育
            startBtn.addEventListener('click', startMonitoring);
            
            // 暂停培育
            pauseBtn.addEventListener('click', stopMonitoring);
            // ========= 新增按钮监听 =========
            shieldBtn.addEventListener('click', toggleShieldMode);
            // 重新开始
            restartBtn.addEventListener('click', function() {
                if (confirm('确定要重新开始吗?这将重置所有进度。')) {
                    resetSystem();
                }
            });
            
            // 全屏模式
            fullscreenBtn.addEventListener('click', toggleFullscreen);
            
            // 设置按钮
            settingsBtn.addEventListener('click', function() {
                settingsModal.style.display = 'flex';
            });
            
            // 历史记录按钮
            historyBtn.addEventListener('click', function() {
                renderHistory();
                historyModal.style.display = 'flex';
            });
            
            // 关闭历史记录
            closeHistory.addEventListener('click', function() {
                historyModal.style.display = 'none';
            });

            // 音量阈值调整
            volumeThreshold.addEventListener('input', function(e) {
                volumeThresholdValue.textContent = e.target.value;
            });

            // 计时时间调整
            timeThreshold.addEventListener('input', function(e) {
                timeThresholdValue.textContent = e.target.value;
            });

            // 惩罚音量阈值调整
            punishVolumeThresholdInput.addEventListener('input', function(e) {
                punishVolumeThresholdValue.textContent = e.target.value;
            });

            // 惩罚计时时间调整
            punishTimeThresholdInput.addEventListener('input', function(e) {
                punishTimeThresholdValue.textContent = e.target.value;
            });

            // 保存设置
            saveSettings.addEventListener('click', saveSettingsHandler);

            // 取消设置
            cancelSettings.addEventListener('click', function() {
                settingsModal.style.display = 'none';
            });

            // 开始监测
            async function startMonitoring() {
                if (!isMonitoring) {
                    try {
                        const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
                        audioContext = new (window.AudioContext || window.webkitAudioContext)();
                        analyser = audioContext.createAnalyser();
                        microphone = audioContext.createMediaStreamSource(stream);
                        microphone.connect(analyser);
                        analyser.fftSize = 2048;
                        
                        isMonitoring = true;
                        currentSessionStart = new Date();
                        totalQuietTime = 0;
                        lastQuietCheckTime = null;
                        updateButtonStates();
                        startDetection();
                    } catch (error) {
                        alert('需要允许麦克风权限才能使用本功能');
                        console.error('麦克风访问错误:', error);
                        stopMonitoring();
                    }
                }
            }

            // 停止监测
            function stopMonitoring() {
                if (isMonitoring) {
                    clearInterval(detectionInterval);
                    if (microphone) {
                        microphone.disconnect();
                    }
                    if (audioContext) {
                        audioContext.close();
                        audioContext = null;
                    }
                    isMonitoring = false;
                    updateButtonStates();
                    
                    if (totalQuietTime > 0) {
                        addHistoryRecord();
                    }
                }
            }

            // 开始检测
            function startDetection() {
                detectionInterval = setInterval(function() {
                    const bufferLength = analyser.frequencyBinCount;
                    const dataArray = new Uint8Array(bufferLength);
                    analyser.getByteFrequencyData(dataArray);
                    
                    let sum = 0;
                    for (let i = 0; i < bufferLength; i++) {
                        sum += dataArray[i];
                    }
                    const average = sum / bufferLength;
                    const db = 20 * Math.log10(average / 255 * 1000);
                    const displayDB = Math.max(Math.round(db), 0);
                    currentDB.textContent = `${displayDB} dB`;

                    const rewardThreshold = parseInt(volumeThreshold.value);
                    const punishThreshold = parseInt(punishVolumeThresholdInput.value);
                    
                    if (displayDB >= punishThreshold) {
                        currentDB.classList.add('warning');
                        progress.classList.add('warning');
                        statusText.classList.add('warning');
                        statusText.textContent = '环境嘈杂,请保持安静';
                        
                        if (!noisyStartTime) {
                            noisyStartTime = Date.now();
                            progress.style.width = '0%';
                        }
                        
                        const noisyElapsed = Math.floor((Date.now() - noisyStartTime) / 1000);
                        const progressWidth = Math.min((noisyElapsed / punishTimeThreshold) * 100, 100);
                        progress.style.width = `${progressWidth}%`;
                        
                        if (noisyElapsed >= punishTimeThreshold) {
                            removeSapling();
                            noisyStartTime = Date.now();
                            progress.style.width = '0%';
                        }
                        
                        quietStartTime = null;
                        lastQuietCheckTime = null;
                    } 
                    else if (displayDB < rewardThreshold) {
                        currentDB.classList.remove('warning');
                        progress.classList.remove('warning');
                        statusText.classList.remove('warning');
                        statusText.textContent = '环境达标,正在培育';
                        
                        const now = Date.now();
                        
                        if (!quietStartTime) {
                            quietStartTime = now;
                            progress.style.width = '0%';
                        }
                        
                        if (lastQuietCheckTime) {
                            totalQuietTime += (now - lastQuietCheckTime) / 1000;
                        }
                        lastQuietCheckTime = now;
                        
                        const quietElapsed = Math.floor((now - quietStartTime) / 1000);
                        quietTime.textContent = `${Math.floor(totalQuietTime)}秒`;
                        
                        const progressWidth = Math.min((quietElapsed / requiredQuietTime) * 100, 100);
                        progress.style.width = `${progressWidth}%`;

                        if (quietElapsed >= requiredQuietTime) {
                            addSapling();
                            quietStartTime = now;
                            progress.style.width = '0%';
                        }
                        
                        noisyStartTime = null;
                    } 
                    else {
                        currentDB.classList.remove('warning');
                        progress.classList.remove('warning');
                        statusText.classList.remove('warning');
                        statusText.textContent = '环境一般,请保持安静';
                        
                        quietStartTime = null;
                        noisyStartTime = null;
                        lastQuietCheckTime = null;
                        progress.style.width = '0%';
                    }
                }, 500);
            }

            // 添加小树苗
            function addSapling() {
                saplingCount++;
                saplingDisplay.textContent = `${saplingCount}/10`;
                
                const saplingIcon = document.createElement('span');
                saplingIcon.textContent = '🌱';
                saplingIcon.className = 'tree sapling';
                saplingsArea.appendChild(saplingIcon);
                
                if (saplingCount >= 10) {
                    saplingsArea.innerHTML = '';
                    const newTreeType = getRandomTree();
                    treeTypes.push(newTreeType);
                    treeCount++;
                    saplingCount = 0;
                    saplingDisplay.textContent = '0/10';
                    renderForest();
                }
            }

            // 移除小树苗
            function removeSapling() {
                if (saplingCount > 0) {
                    saplingCount--;
                    saplingDisplay.textContent = `${saplingCount}/10`;
                    const saplings = saplingsArea.querySelectorAll('.tree');
                    if (saplings.length > 0) {
                        saplingsArea.removeChild(saplings[saplings.length-1]);
                    }
                } else if (treeCount > 0) {
                    treeCount--;
                    treeTypes.pop();
                    saplingCount = 9;
                    saplingDisplay.textContent = '9/10';
                    renderForest();
                    
                    for (let i = 0; i < 9; i++) {
                        const saplingIcon = document.createElement('span');
                        saplingIcon.textContent = '🌱';
                        saplingIcon.className = 'tree';
                        saplingsArea.appendChild(saplingIcon);
                    }
                }
            }

            // 渲染森林
            function renderForest() {
                forest.innerHTML = '';
                
               // 渲染所有大树
              treeTypes.forEach(treeType => {
             const treeIcon = document.createElement('span');
             treeIcon.textContent = treeType;
             treeIcon.className = 'tree mature-tree';  // 添加大树类
             forest.appendChild(treeIcon);
            });

            // 渲染当前的小树苗
           for (let i = 0; i < saplingCount; i++) {
            const saplingIcon = document.createElement('span');
            saplingIcon.textContent = '🌱';
            saplingIcon.className = 'tree sapling';  // 添加小树苗类
            forest.appendChild(saplingIcon);
             }
            }

            // 重置系统
            function resetSystem() {
                stopMonitoring();
                saplingCount = 0;
                treeCount = 0;
                treeTypes = [];
                saplingDisplay.textContent = saplingCount;
                quietTime.textContent = '0秒';
                currentDB.textContent = '-- dB';
                statusText.textContent = '准备就绪';
                progress.style.width = '0%';
                forest.innerHTML = '';
                saplingsArea.innerHTML = '';
                currentSessionStart = null;
                totalQuietTime = 0;
                lastQuietCheckTime = null;
            }

            // 保存设置
            function saveSettingsHandler() {
                requiredQuietTime = parseInt(timeThreshold.value);
                punishVolumeThreshold = parseInt(punishVolumeThresholdInput.value);
                punishTimeThreshold = parseInt(punishTimeThresholdInput.value);
                
                if (resetProgress.checked) {
                    resetSystem();
                }
                
                settingsModal.style.display = 'none';
            }
                // ========= 新增屏蔽模式函数 =========
        function toggleShieldMode() {
            isShieldMode = !isShieldMode;
            
            if (isShieldMode) {
               // 进入屏蔽模式
                shieldOverlay.style.display = 'flex';
            shieldBtn.innerHTML = '<i class="fas fa-eye"></i> 显示森林';
        
            // 立即显示当前时间并开始计时
            updateShieldTimer();
            clearInterval(shieldInterval);
            shieldInterval = setInterval(updateShieldTimer, 1000);
            } else {
                // 退出屏蔽模式
                shieldOverlay.style.display = 'none';
            shieldBtn.innerHTML = '<i class="fas fa-eye-slash"></i> 屏蔽模式';
            clearInterval(shieldInterval);
            }
        }

        function updateShieldTimer() {
                const now = new Date();
            const hours = String(now.getHours()).padStart(2, '0');
            const minutes = String(now.getMinutes()).padStart(2, '0');
            const seconds = String(now.getSeconds()).padStart(2, '0');
            shieldTimer.textContent = `${hours}:${minutes}:${seconds}`;
        }

            // 切换全屏
            function toggleFullscreen() {
                if (!document.fullscreenElement) {
                    document.documentElement.requestFullscreen().catch(err => {
                        alert(`全屏错误: ${err.message}`);
                    });
                    document.body.classList.add('fullscreen');
                    fullscreenBtn.innerHTML = '<i class="fas fa-compress"></i> 退出全屏';
                } else {
                    if (document.exitFullscreen) {
                        document.exitFullscreen();
                        document.body.classList.remove('fullscreen');
                        fullscreenBtn.innerHTML = '<i class="fas fa-expand"></i> 全屏';
                    }
                }
            }
             // 保存设置到本地存储
function saveSettingsToLocal() {
    const settings = {
        volumeThreshold: volumeThreshold.value,
        timeThreshold: timeThreshold.value,
        punishVolumeThreshold: punishVolumeThresholdInput.value,
        punishTimeThreshold: punishTimeThresholdInput.value
    };
    localStorage.setItem('forestSettings', JSON.stringify(settings));
}

// 从本地存储加载设置
function loadSettingsFromLocal() {
    const savedSettings = localStorage.getItem('forestSettings');
    if (savedSettings) {
        const settings = JSON.parse(savedSettings);
        
        // 更新滑块和显示值
        volumeThreshold.value = settings.volumeThreshold;
        volumeThresholdValue.textContent = settings.volumeThreshold;
        
        timeThreshold.value = settings.timeThreshold;
        timeThresholdValue.textContent = settings.timeThreshold;
        
        punishVolumeThresholdInput.value = settings.punishVolumeThreshold;
        punishVolumeThresholdValue.textContent = settings.punishVolumeThreshold;
        
        punishTimeThresholdInput.value = settings.punishTimeThreshold;
        punishTimeThresholdValue.textContent = settings.punishTimeThreshold;
        
        // 更新全局变量
        requiredQuietTime = parseInt(settings.timeThreshold);
        punishVolumeThreshold = parseInt(settings.punishVolumeThreshold);
        punishTimeThreshold = parseInt(settings.punishTimeThreshold);
    }
}

// 修改保存设置的函数
function saveSettingsHandler() {
    requiredQuietTime = parseInt(timeThreshold.value);
    punishVolumeThreshold = parseInt(punishVolumeThresholdInput.value);
    punishTimeThreshold = parseInt(punishTimeThresholdInput.value);
    
    saveSettingsToLocal(); // 保存到本地存储
    
    if (resetProgress.checked) {
        resetSystem();
    }
    
    settingsModal.style.display = 'none';
}
            // 添加历史记录
            function addHistoryRecord() {
                const record = {
                    date: currentSessionStart,
                    quietTime: Math.floor(totalQuietTime),
                    saplingCount: saplingCount,
                    treeCount: treeCount
                };
                historyRecords.unshift(record);
                localStorage.setItem('forestHistory', JSON.stringify(historyRecords));
            }

            // 删除历史记录
            function deleteHistoryRecord(index) {
                historyRecords.splice(index, 1);
                localStorage.setItem('forestHistory', JSON.stringify(historyRecords));
                renderHistory();
            }

            // 渲染历史记录
            function renderHistory() {
                historyList.innerHTML = '';
                
                if (historyRecords.length === 0) {
                    historyList.innerHTML = '<p style="text-align: center; color: #666;">暂无历史记录</p>';
                    return;
                }
                
                historyRecords.forEach((record, index) => {
                    const item = document.createElement('div');
                    item.style.display = 'flex';
                    item.style.justifyContent = 'space-between';
                    item.style.alignItems = 'center';
                    item.style.padding = '10px';
                    item.style.marginBottom = '10px';
                    item.style.background = '#f9f9f9';
                    item.style.borderRadius = '8px';
                    
                    const dateStr = new Date(record.date).toLocaleString();
                    saplingDisplay.textContent = '0/10';
                    item.innerHTML = `
                        <div style="display:flex; gap:15px; flex-wrap:wrap;">
                            <span><i class="far fa-calendar-alt"></i> ${dateStr}</span>
                            <span><i class="far fa-clock"></i> ${record.quietTime}秒</span>
                            <span><i class="fas fa-seedling"></i> ${record.saplingCount}</span>
                            <span><i class="fas fa-tree"></i> ${record.treeCount}</span>
                        </div>
                        <div>
                            <button onclick="deleteHistoryRecord(${index})" style="background:var(--warning-red); color:white; border:none; border-radius:5px; padding:5px 10px; cursor:pointer;">
                                <i class="fas fa-trash"></i>
                            </button>
                        </div>
                    `;
                    
                    historyList.appendChild(item);
                });
            }

            // 使deleteHistoryRecord在全局可用
            window.deleteHistoryRecord = deleteHistoryRecord;

            // 监听全屏变化
            document.addEventListener('fullscreenchange', function() {
                if (!document.fullscreenElement) {
                    document.body.classList.remove('fullscreen');
                    fullscreenBtn.innerHTML = '<i class="fas fa-expand"></i> 全屏';
                }
            });

            // 点击模态框外部关闭
            window.addEventListener('click', function(event) {
                if (event.target === settingsModal) {
                    settingsModal.style.display = 'none';
                }
                if (event.target === historyModal) {
                    historyModal.style.display = 'none';
                }
            });
        });
    </script>
</body>
</html>
        
编辑器加载中
预览
控制台