/* ═══════════════════════════════════════════════════ 个人资料库 — 主脚本 ═══════════════════════════════════════════════════ */ document.addEventListener('DOMContentLoaded', () => { // ── 侧边栏折叠/展开 ────────────────────────────────────────────────────── const sidebar = document.getElementById('sidebar'); const toggleBtn = document.getElementById('sidebarToggle'); const overlay = document.createElement('div'); overlay.className = 'sidebar-overlay'; document.body.appendChild(overlay); if (toggleBtn && sidebar) { const isMobile = () => window.innerWidth <= 768; const STORAGE_KEY = 'sidebar_collapsed'; // 恢复桌面端折叠状态 if (!isMobile() && localStorage.getItem(STORAGE_KEY) === 'true') { sidebar.classList.add('collapsed'); } toggleBtn.addEventListener('click', () => { if (isMobile()) { sidebar.classList.toggle('mobile-open'); overlay.classList.toggle('active'); } else { sidebar.classList.toggle('collapsed'); localStorage.setItem(STORAGE_KEY, sidebar.classList.contains('collapsed') ? 'true' : 'false'); } }); overlay.addEventListener('click', () => { sidebar.classList.remove('mobile-open'); overlay.classList.remove('active'); }); window.addEventListener('resize', () => { if (!isMobile()) { sidebar.classList.remove('mobile-open'); overlay.classList.remove('active'); } }); } // ── 深色/浅色主题切换 ────────────────────────────────────────────────────── const themeToggle = document.getElementById('themeToggle'); const themeIcon = document.getElementById('themeIcon'); const html = document.documentElement; const THEME_KEY = 'theme'; function applyTheme(theme) { html.setAttribute('data-bs-theme', theme); if (themeIcon) { themeIcon.className = theme === 'dark' ? 'bi bi-moon-fill' : 'bi bi-sun-fill'; } localStorage.setItem(THEME_KEY, theme); } // 初始化主题 const savedTheme = localStorage.getItem(THEME_KEY) || (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'); applyTheme(savedTheme); if (themeToggle) { themeToggle.addEventListener('click', () => { applyTheme(html.getAttribute('data-bs-theme') === 'dark' ? 'light' : 'dark'); }); } // ── 自动关闭 Flash 消息 ─────────────────────────────────────────────────── document.querySelectorAll('.alert.alert-success, .alert.alert-info').forEach(el => { setTimeout(() => { const bsAlert = bootstrap.Alert.getOrCreateInstance(el); if (bsAlert) bsAlert.close(); }, 4000); }); // ── 表单提交防重复点击 ──────────────────────────────────────────────────── document.querySelectorAll('form').forEach(form => { form.addEventListener('submit', () => { const btn = form.querySelector('[type="submit"]'); if (btn && !btn.dataset.noDisable) { setTimeout(() => { btn.disabled = true; }, 0); } }); }); // ── 密码强度指示(注册/修改密码页面)──────────────────────────────────── const pwdInputs = document.querySelectorAll('input[type="password"][id$="Pwd"],' + 'input[type="password"][id$="Password"]'); pwdInputs.forEach(input => { const meter = document.createElement('div'); meter.className = 'password-strength mt-1'; meter.innerHTML = '
'; input.parentElement.appendChild(meter); input.addEventListener('input', () => { const val = input.value; let strength = 0; if (val.length >= 8) strength++; if (/[A-Z]/.test(val)) strength++; if (/[0-9]/.test(val)) strength++; if (/[^A-Za-z0-9]/.test(val)) strength++; const colors = ['#ef4444','#f97316','#eab308','#22c55e']; const bars = meter.querySelectorAll('.flex-fill'); bars.forEach((bar, i) => { bar.style.background = i < strength ? colors[strength - 1] : '#e5e7eb'; }); }); }); // ── 工具提示初始化 ──────────────────────────────────────────────────────── document.querySelectorAll('[title]').forEach(el => { new bootstrap.Tooltip(el, { trigger: 'hover', placement: 'top' }); }); });