diff --git a/frontend/60sapi/实用功能/实时天气[目前有问题]/background.css b/frontend/60sapi/实用功能/实时天气[目前有问题]/background.css new file mode 100644 index 00000000..078de8fa --- /dev/null +++ b/frontend/60sapi/实用功能/实时天气[目前有问题]/background.css @@ -0,0 +1,202 @@ +/* 背景样式文件 - 独立管理背景相关CSS */ + +/* 主体背景 */ +body { + background: linear-gradient(135deg, #a8e6cf 0%, #dcedc8 50%, #f0f4c3 100%); + background-attachment: fixed; + background-size: cover; + position: relative; +} + +/* 背景装饰元素 */ +body::before { + content: ''; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-image: + radial-gradient(circle at 20% 80%, rgba(120, 219, 226, 0.1) 0%, transparent 50%), + radial-gradient(circle at 80% 20%, rgba(168, 230, 207, 0.1) 0%, transparent 50%), + radial-gradient(circle at 40% 40%, rgba(220, 237, 200, 0.1) 0%, transparent 50%); + pointer-events: none; + z-index: -1; +} + +/* 动态背景效果 */ +body::after { + content: ''; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: + linear-gradient(45deg, transparent 30%, rgba(255, 255, 255, 0.05) 50%, transparent 70%), + linear-gradient(-45deg, transparent 30%, rgba(168, 230, 207, 0.05) 50%, transparent 70%); + background-size: 200px 200px; + animation: backgroundMove 20s linear infinite; + pointer-events: none; + z-index: -1; +} + +/* 背景动画 */ +@keyframes backgroundMove { + 0% { + background-position: 0 0, 0 0; + } + 100% { + background-position: 200px 200px, -200px -200px; + } +} + +/* 容器背景 */ +.container { + background: rgba(255, 255, 255, 0.1); + backdrop-filter: blur(5px); + border-radius: 20px; + border: 1px solid rgba(255, 255, 255, 0.2); +} + +/* 卡片背景增强 */ +.weather-card { + background: rgba(255, 255, 255, 0.95); + backdrop-filter: blur(15px); + border: 1px solid rgba(168, 230, 207, 0.3); + box-shadow: + 0 10px 30px rgba(0, 0, 0, 0.1), + 0 1px 8px rgba(168, 230, 207, 0.2), + inset 0 1px 0 rgba(255, 255, 255, 0.8); +} + +/* 当前天气区域背景 */ +.current-weather { + background: linear-gradient(135deg, + rgba(168, 230, 207, 0.8) 0%, + rgba(220, 237, 200, 0.8) 50%, + rgba(240, 244, 195, 0.8) 100%); + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.3); + box-shadow: + 0 4px 15px rgba(39, 174, 96, 0.1), + inset 0 1px 0 rgba(255, 255, 255, 0.6); +} + +/* 详情项背景 */ +.detail-item { + background: linear-gradient(135deg, + rgba(168, 230, 207, 0.1) 0%, + rgba(255, 255, 255, 0.1) 100%); + backdrop-filter: blur(5px); + border: 1px solid rgba(168, 230, 207, 0.2); + box-shadow: 0 2px 8px rgba(39, 174, 96, 0.05); +} + +/* 生活指数项背景 */ +.index-item { + background: linear-gradient(135deg, + rgba(168, 230, 207, 0.05) 0%, + rgba(255, 255, 255, 0.1) 100%); + backdrop-filter: blur(5px); + border: 1px solid rgba(168, 230, 207, 0.15); + box-shadow: 0 2px 10px rgba(39, 174, 96, 0.05); +} + +.index-item:hover { + background: linear-gradient(135deg, + rgba(168, 230, 207, 0.1) 0%, + rgba(255, 255, 255, 0.15) 100%); + box-shadow: 0 5px 20px rgba(39, 174, 96, 0.1); +} + +/* 输入框背景 */ +#cityInput { + background: rgba(255, 255, 255, 0.9); + backdrop-filter: blur(10px); + border: 2px solid rgba(168, 230, 207, 0.6); + box-shadow: 0 2px 10px rgba(39, 174, 96, 0.1); +} + +#cityInput:focus { + background: rgba(255, 255, 255, 0.95); + box-shadow: + 0 0 15px rgba(39, 174, 96, 0.2), + 0 2px 10px rgba(39, 174, 96, 0.1); +} + +/* 按钮背景 */ +#searchBtn { + background: linear-gradient(135deg, + #27ae60 0%, + #2ecc71 50%, + #58d68d 100%); + box-shadow: + 0 4px 15px rgba(39, 174, 96, 0.3), + inset 0 1px 0 rgba(255, 255, 255, 0.2); +} + +#searchBtn:hover { + background: linear-gradient(135deg, + #229954 0%, + #27ae60 50%, + #52c370 100%); + box-shadow: + 0 6px 20px rgba(39, 174, 96, 0.4), + inset 0 1px 0 rgba(255, 255, 255, 0.3); +} + +/* 错误消息背景 */ +.error-message { + background: linear-gradient(135deg, + rgba(231, 76, 60, 0.1) 0%, + rgba(255, 255, 255, 0.1) 100%); + backdrop-filter: blur(10px); + border: 1px solid rgba(231, 76, 60, 0.2); + box-shadow: 0 4px 15px rgba(231, 76, 60, 0.1); +} + +/* 加载状态背景 */ +.loading { + background: rgba(255, 255, 255, 0.8); + backdrop-filter: blur(10px); + border-radius: 15px; + border: 1px solid rgba(168, 230, 207, 0.3); + box-shadow: 0 4px 15px rgba(39, 174, 96, 0.1); +} + +/* 移动端背景优化 */ +@media (max-width: 767px) { + body::after { + background-size: 100px 100px; + animation-duration: 15s; + } + + .container { + background: rgba(255, 255, 255, 0.05); + backdrop-filter: blur(3px); + } + + .weather-card { + backdrop-filter: blur(10px); + } +} + +/* 高性能设备背景增强 */ +@media (min-width: 1024px) { + body::before { + background-image: + radial-gradient(circle at 20% 80%, rgba(120, 219, 226, 0.15) 0%, transparent 50%), + radial-gradient(circle at 80% 20%, rgba(168, 230, 207, 0.15) 0%, transparent 50%), + radial-gradient(circle at 40% 40%, rgba(220, 237, 200, 0.15) 0%, transparent 50%), + radial-gradient(circle at 60% 70%, rgba(240, 244, 195, 0.1) 0%, transparent 50%); + } + + .weather-card { + backdrop-filter: blur(20px); + } + + .current-weather { + backdrop-filter: blur(15px); + } +} \ No newline at end of file diff --git a/frontend/60sapi/实用功能/实时天气[目前有问题]/index.html b/frontend/60sapi/实用功能/实时天气[目前有问题]/index.html new file mode 100644 index 00000000..5a632718 --- /dev/null +++ b/frontend/60sapi/实用功能/实时天气[目前有问题]/index.html @@ -0,0 +1,143 @@ + + + + + + 实时天气查询 + + + + +
+
+

实时天气

+ +
+ +
+
正在加载天气数据...
+ + + + +
+
+ + + + \ No newline at end of file diff --git a/frontend/60sapi/实用功能/实时天气[目前有问题]/script.js b/frontend/60sapi/实用功能/实时天气[目前有问题]/script.js new file mode 100644 index 00000000..bb339d26 --- /dev/null +++ b/frontend/60sapi/实用功能/实时天气[目前有问题]/script.js @@ -0,0 +1,354 @@ +// 天气应用主要功能 +class WeatherApp { + constructor() { + this.apiUrl = 'https://60s.api.shumengya.top/v2/weather'; + this.init(); + } + + init() { + this.bindEvents(); + this.loadWeather('北京'); // 默认加载北京天气 + } + + bindEvents() { + const searchBtn = document.getElementById('searchBtn'); + const cityInput = document.getElementById('cityInput'); + + // 搜索按钮点击事件 + searchBtn.addEventListener('click', () => { + const city = cityInput.value.trim(); + if (city) { + this.loadWeather(city); + } + }); + + // 输入框回车事件 + cityInput.addEventListener('keypress', (e) => { + if (e.key === 'Enter') { + const city = cityInput.value.trim(); + if (city) { + this.loadWeather(city); + } + } + }); + } + + async loadWeather(city) { + this.showLoading(); + + try { + const response = await fetch(`${this.apiUrl}?query=${encodeURIComponent(city)}`); + + if (!response.ok) { + throw new Error(`HTTP错误: ${response.status}`); + } + + const data = await response.json(); + console.log('完整API响应:', data); // 调试日志 + + if (data.code === 200 && data.data) { + this.displayWeather(data.data); + this.hideLoading(); + } else { + throw new Error(data.message || `API返回错误: code=${data.code}`); + } + } catch (error) { + console.error('获取天气数据失败:', error); + console.error('错误详情:', { + message: error.message, + stack: error.stack + }); + this.showError(error.message); + this.hideLoading(); + } + } + + showLoading() { + document.getElementById('loading').style.display = 'block'; + document.getElementById('weatherCard').style.display = 'none'; + document.getElementById('errorMessage').style.display = 'none'; + } + + hideLoading() { + document.getElementById('loading').style.display = 'none'; + } + + showError(message = '获取天气数据失败,请检查网络连接或稍后重试') { + const errorElement = document.getElementById('errorMessage'); + const errorText = errorElement.querySelector('p'); + + if (errorText) { + errorText.textContent = message; + } + + errorElement.style.display = 'block'; + document.getElementById('weatherCard').style.display = 'none'; + } + + displayWeather(data) { + console.log('API返回数据:', data); // 调试日志 + + // 根据实际API结构解构数据 + const location = data.location || {}; + const realtime = data.realtime || {}; + const air_quality = realtime.air_quality || {}; + const life_indices = realtime.life_indices || []; + + // 显示位置信息 + const locationName = location.formatted || location.city || location.name || '未知位置'; + document.getElementById('locationName').textContent = locationName; + + const updateTime = realtime.updated || '未知时间'; + document.getElementById('updateTime').textContent = `更新时间: ${updateTime}`; + + // 显示当前天气 + const temperature = realtime.temperature !== undefined ? realtime.temperature : '--'; + document.getElementById('temperature').textContent = `${temperature}°C`; + + const condition = realtime.weather || realtime.weather_desc || '未知'; + document.getElementById('weatherDesc').textContent = condition; + document.getElementById('weatherIcon').textContent = this.getWeatherIcon(condition); + + // 显示天气详情 + const feelsLike = realtime.temperature_feels_like !== undefined ? realtime.temperature_feels_like : temperature; + document.getElementById('feelsLike').textContent = `${feelsLike}°C`; + + const humidity = realtime.humidity !== undefined ? realtime.humidity : '--'; + document.getElementById('humidity').textContent = `${humidity}%`; + + const windDirection = realtime.wind_direction || '--'; + document.getElementById('windDirection').textContent = windDirection; + + const windPower = realtime.wind_power || realtime.wind_strength || '--'; + document.getElementById('windStrength').textContent = windPower; + + const pressure = realtime.pressure !== undefined ? realtime.pressure : '--'; + document.getElementById('pressure').textContent = `${pressure} hPa`; + + document.getElementById('visibility').textContent = '--'; // API中没有能见度数据 + + const aqi = air_quality.aqi !== undefined ? air_quality.aqi : '--'; + document.getElementById('aqi').textContent = `AQI ${aqi}`; + + const pm25 = air_quality.pm25 !== undefined ? air_quality.pm25 : '--'; + document.getElementById('pm25').textContent = `${pm25} μg/m³`; + + // 显示生活指数 + if (life_indices && life_indices.length > 0) { + this.displayLifeIndex(life_indices); + } else { + // 如果没有生活指数数据,重置显示 + this.resetLifeIndex(); + } + + // 显示天气卡片 + document.getElementById('weatherCard').style.display = 'block'; + } + + displayLifeIndex(lifeIndices) { + const indexMap = { + comfort: { level: 'comfortLevel', desc: 'comfortDesc' }, + clothes: { level: 'clothingLevel', desc: 'clothingDesc' }, + umbrella: { level: 'umbrellaLevel', desc: 'umbrellaDesc' }, + ultraviolet: { level: 'uvLevel', desc: 'uvDesc' }, + carwash: { level: 'carWashLevel', desc: 'carWashDesc' }, + tourism: { level: 'travelLevel', desc: 'travelDesc' }, + sports: { level: 'sportLevel', desc: 'sportDesc' } + }; + + // 重置所有指数显示 + this.resetLifeIndex(); + + // 根据新的API数据结构更新生活指数 + if (Array.isArray(lifeIndices)) { + lifeIndices.forEach(index => { + if (index && index.key && indexMap[index.key]) { + const { level, desc } = indexMap[index.key]; + const levelElement = document.getElementById(level); + const descElement = document.getElementById(desc); + + if (levelElement) levelElement.textContent = index.level || '--'; + if (descElement) descElement.textContent = index.description || '--'; + } + }); + } + } + + resetLifeIndex() { + const indexMap = { + comfort: { level: 'comfortLevel', desc: 'comfortDesc' }, + clothes: { level: 'clothingLevel', desc: 'clothingDesc' }, + umbrella: { level: 'umbrellaLevel', desc: 'umbrellaDesc' }, + ultraviolet: { level: 'uvLevel', desc: 'uvDesc' }, + carwash: { level: 'carWashLevel', desc: 'carWashDesc' }, + tourism: { level: 'travelLevel', desc: 'travelDesc' }, + sports: { level: 'sportLevel', desc: 'sportDesc' } + }; + + Object.values(indexMap).forEach(({ level, desc }) => { + const levelElement = document.getElementById(level); + const descElement = document.getElementById(desc); + + if (levelElement) levelElement.textContent = '--'; + if (descElement) descElement.textContent = '--'; + }); + } + + getWeatherIcon(weather) { + const iconMap = { + '晴': '☀️', + '多云': '⛅', + '阴': '☁️', + '小雨': '🌦️', + '中雨': '🌧️', + '大雨': '⛈️', + '雷阵雨': '⛈️', + '雪': '❄️', + '小雪': '🌨️', + '中雪': '❄️', + '大雪': '❄️', + '雾': '🌫️', + '霾': '😷', + '沙尘暴': '🌪️' + }; + + // 查找匹配的天气图标 + for (const [key, icon] of Object.entries(iconMap)) { + if (weather.includes(key)) { + return icon; + } + } + + // 默认图标 + return '🌤️'; + } + + // 获取空气质量等级颜色 + getAQIColor(aqi) { + if (aqi <= 50) return '#00e400'; + if (aqi <= 100) return '#ffff00'; + if (aqi <= 150) return '#ff7e00'; + if (aqi <= 200) return '#ff0000'; + if (aqi <= 300) return '#8f3f97'; + return '#7e0023'; + } + + // 格式化时间 + formatTime(timeString) { + try { + const date = new Date(timeString); + return date.toLocaleString('zh-CN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + hour: '2-digit', + minute: '2-digit' + }); + } catch (error) { + return timeString; + } + } +} + +// 页面加载完成后初始化应用 +document.addEventListener('DOMContentLoaded', () => { + new WeatherApp(); +}); + +// 添加一些实用的工具函数 +const utils = { + // 防抖函数 + debounce(func, wait) { + let timeout; + return function executedFunction(...args) { + const later = () => { + clearTimeout(timeout); + func(...args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; + }, + + // 节流函数 + throttle(func, limit) { + let inThrottle; + return function() { + const args = arguments; + const context = this; + if (!inThrottle) { + func.apply(context, args); + inThrottle = true; + setTimeout(() => inThrottle = false, limit); + } + }; + }, + + // 检查网络状态 + checkNetworkStatus() { + return navigator.onLine; + }, + + // 显示提示消息 + showToast(message, type = 'info') { + const toast = document.createElement('div'); + toast.className = `toast toast-${type}`; + toast.textContent = message; + toast.style.cssText = ` + position: fixed; + top: 20px; + right: 20px; + padding: 12px 20px; + background: ${type === 'error' ? '#e74c3c' : '#27ae60'}; + color: white; + border-radius: 8px; + z-index: 1000; + animation: slideIn 0.3s ease; + `; + + document.body.appendChild(toast); + + setTimeout(() => { + toast.style.animation = 'slideOut 0.3s ease'; + setTimeout(() => { + document.body.removeChild(toast); + }, 300); + }, 3000); + } +}; + +// 添加CSS动画 +const style = document.createElement('style'); +style.textContent = ` + @keyframes slideIn { + from { + transform: translateX(100%); + opacity: 0; + } + to { + transform: translateX(0); + opacity: 1; + } + } + + @keyframes slideOut { + from { + transform: translateX(0); + opacity: 1; + } + to { + transform: translateX(100%); + opacity: 0; + } + } +`; +document.head.appendChild(style); + +// 网络状态监听 +window.addEventListener('online', () => { + utils.showToast('网络连接已恢复', 'success'); +}); + +window.addEventListener('offline', () => { + utils.showToast('网络连接已断开', 'error'); +}); \ No newline at end of file diff --git a/frontend/60sapi/实用功能/实时天气[目前有问题]/styles.css b/frontend/60sapi/实用功能/实时天气[目前有问题]/styles.css new file mode 100644 index 00000000..88113f63 --- /dev/null +++ b/frontend/60sapi/实用功能/实时天气[目前有问题]/styles.css @@ -0,0 +1,442 @@ +/* 基础样式重置 */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Microsoft YaHei', 'PingFang SC', 'Helvetica Neue', Arial, sans-serif; + line-height: 1.6; + color: #2c3e50; + min-height: 100vh; +} + +.container { + max-width: 1200px; + margin: 0 auto; + padding: 20px; + min-height: 100vh; +} + +/* 头部样式 */ +.header { + text-align: center; + margin-bottom: 30px; +} + +.header h1 { + font-size: 2.5rem; + color: #27ae60; + margin-bottom: 20px; + font-weight: 300; + text-shadow: 0 2px 4px rgba(39, 174, 96, 0.1); +} + +.search-box { + display: flex; + justify-content: center; + gap: 10px; + margin-bottom: 20px; +} + +#cityInput { + padding: 12px 16px; + border: 2px solid #a8e6cf; + border-radius: 25px; + font-size: 16px; + outline: none; + background: rgba(255, 255, 255, 0.9); + transition: all 0.3s ease; + min-width: 200px; +} + +#cityInput:focus { + border-color: #27ae60; + box-shadow: 0 0 10px rgba(39, 174, 96, 0.2); +} + +#searchBtn { + padding: 12px 24px; + background: linear-gradient(135deg, #27ae60, #2ecc71); + color: white; + border: none; + border-radius: 25px; + font-size: 16px; + cursor: pointer; + transition: all 0.3s ease; + box-shadow: 0 4px 15px rgba(39, 174, 96, 0.3); +} + +#searchBtn:hover { + transform: translateY(-2px); + box-shadow: 0 6px 20px rgba(39, 174, 96, 0.4); +} + +#searchBtn:active { + transform: translateY(0); +} + +/* 主要内容区域 */ +.main-content { + display: flex; + justify-content: center; + align-items: flex-start; +} + +.loading { + text-align: center; + font-size: 18px; + color: #27ae60; + padding: 40px; +} + +.weather-card { + background: rgba(255, 255, 255, 0.95); + border-radius: 20px; + padding: 30px; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); + backdrop-filter: blur(10px); + border: 1px solid rgba(168, 230, 207, 0.3); + width: 100%; + max-width: 800px; +} + +/* 位置信息 */ +.location-info { + text-align: center; + margin-bottom: 30px; + padding-bottom: 20px; + border-bottom: 2px solid #a8e6cf; +} + +.location-info h2 { + font-size: 2rem; + color: #27ae60; + margin-bottom: 10px; +} + +.location-info p { + color: #7f8c8d; + font-size: 14px; +} + +/* 当前天气 */ +.current-weather { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 30px; + padding: 20px; + background: linear-gradient(135deg, #a8e6cf, #dcedc8); + border-radius: 15px; +} + +.temperature-section { + display: flex; + flex-direction: column; + align-items: flex-start; +} + +.temperature { + font-size: 3.5rem; + font-weight: 300; + color: #27ae60; + line-height: 1; +} + +.weather-desc { + font-size: 1.2rem; + color: #2c3e50; + margin-top: 5px; +} + +.weather-icon { + font-size: 4rem; + opacity: 0.8; +} + +/* 天气详情 */ +.weather-details { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); + gap: 15px; + margin-bottom: 30px; +} + +.detail-item { + display: flex; + justify-content: space-between; + align-items: center; + padding: 15px; + background: rgba(168, 230, 207, 0.1); + border-radius: 10px; + border-left: 4px solid #27ae60; +} + +.detail-item .label { + color: #7f8c8d; + font-size: 14px; +} + +.detail-item .value { + color: #2c3e50; + font-weight: 500; + font-size: 16px; +} + +/* 生活指数 */ +.life-index h3 { + color: #27ae60; + margin-bottom: 20px; + font-size: 1.5rem; + text-align: center; +} + +.index-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 20px; +} + +.index-item { + display: flex; + align-items: flex-start; + padding: 20px; + background: rgba(168, 230, 207, 0.05); + border-radius: 15px; + border: 1px solid rgba(168, 230, 207, 0.2); + transition: all 0.3s ease; +} + +.index-item:hover { + transform: translateY(-2px); + box-shadow: 0 5px 15px rgba(39, 174, 96, 0.1); +} + +.index-icon { + font-size: 2rem; + margin-right: 15px; + opacity: 0.8; +} + +.index-content { + flex: 1; +} + +.index-title { + font-weight: 500; + color: #2c3e50; + margin-bottom: 5px; +} + +.index-level { + color: #27ae60; + font-weight: 600; + margin-bottom: 5px; +} + +.index-desc { + color: #7f8c8d; + font-size: 14px; + line-height: 1.4; +} + +.error-message { + text-align: center; + padding: 40px; + color: #e74c3c; + background: rgba(231, 76, 60, 0.1); + border-radius: 15px; + border: 1px solid rgba(231, 76, 60, 0.2); +} + +/* 平板端适配 (768px - 1024px) */ +@media (min-width: 768px) and (max-width: 1024px) { + .container { + padding: 25px; + } + + .header h1 { + font-size: 2.8rem; + } + + .search-box { + max-width: 500px; + margin: 0 auto 20px; + } + + .weather-details { + grid-template-columns: repeat(2, 1fr); + } + + .index-grid { + grid-template-columns: repeat(2, 1fr); + } + + .current-weather { + padding: 25px; + } + + .temperature { + font-size: 4rem; + } +} + +/* 电脑端适配 (1024px+) */ +@media (min-width: 1024px) { + .container { + padding: 40px; + } + + .header h1 { + font-size: 3.2rem; + } + + .search-box { + max-width: 600px; + margin: 0 auto 30px; + } + + .weather-card { + padding: 40px; + } + + .weather-details { + grid-template-columns: repeat(4, 1fr); + } + + .index-grid { + grid-template-columns: repeat(3, 1fr); + } + + .current-weather { + padding: 30px; + } + + .temperature { + font-size: 4.5rem; + } + + .index-item { + padding: 25px; + } +} + +/* 手机端适配 (优先优化) */ +@media (max-width: 767px) { + .container { + padding: 15px; + } + + .header h1 { + font-size: 2rem; + margin-bottom: 15px; + } + + .search-box { + flex-direction: column; + align-items: center; + gap: 15px; + } + + #cityInput { + width: 100%; + max-width: 300px; + font-size: 16px; + } + + #searchBtn { + width: 100%; + max-width: 300px; + padding: 14px 24px; + } + + .weather-card { + padding: 20px; + margin: 0; + } + + .current-weather { + flex-direction: column; + text-align: center; + gap: 20px; + padding: 20px; + } + + .temperature { + font-size: 3rem; + } + + .weather-icon { + font-size: 3rem; + } + + .weather-details { + grid-template-columns: 1fr; + gap: 10px; + } + + .detail-item { + padding: 12px; + } + + .index-grid { + grid-template-columns: 1fr; + gap: 15px; + } + + .index-item { + padding: 15px; + } + + .index-icon { + font-size: 1.5rem; + margin-right: 10px; + } + + .life-index h3 { + font-size: 1.3rem; + margin-bottom: 15px; + } + + .location-info h2 { + font-size: 1.5rem; + } +} + +/* 超小屏幕适配 */ +@media (max-width: 480px) { + .container { + padding: 10px; + } + + .header h1 { + font-size: 1.8rem; + } + + .weather-card { + padding: 15px; + } + + .temperature { + font-size: 2.5rem; + } + + .current-weather { + padding: 15px; + } + + .detail-item { + padding: 10px; + font-size: 14px; + } + + .index-item { + padding: 12px; + } + + .index-desc { + font-size: 13px; + } +} \ No newline at end of file diff --git a/frontend/60sapi/实用功能/实时天气[目前有问题]/返回接口.json b/frontend/60sapi/实用功能/实时天气[目前有问题]/返回接口.json new file mode 100644 index 00000000..671a75a4 --- /dev/null +++ b/frontend/60sapi/实用功能/实时天气[目前有问题]/返回接口.json @@ -0,0 +1,68 @@ +{ + "code": 200, + "message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s,反馈群 595941841", + "data": { + "location": { + "province": "北京", + "city": "北京", + "town": "北京", + "formatted": "北京", + "location_id": "101010100", + "detail_url": "http://www.weather.com.cn/weather/101010100.shtml", + "is_province": true, + "is_city": false, + "is_town": false, + "area_code": "10", + "zip_code": "100000" + }, + "realtime": { + "weather": "晴转雷阵雨", + "weather_desc": "未知", + "weather_code": "d0", + "temperature": 999, + "temperature_feels_like": 75.6, + "humidity": 63, + "wind_direction": "南风", + "wind_strength": "3-4级转\u003C3级", + "wind_speed": "1km/h", + "pressure": 1006, + "visibility": "21km", + "aqi": 41, + "pm25": 41, + "rainfall": 0, + "rainfall_24h": 0, + "updated": "2025-09-08 08:00:00", + "updated_at": "20:30", + "life_index": { + "comfort": { + "level": "舒适", + "desc": "白天温度宜人,风力不大。" + }, + "clothing": { + "level": "舒适", + "desc": "建议穿长袖衬衫单裤等服装。" + }, + "umbrella": { + "level": "带伞", + "desc": "有降水,短时间出行不必带伞。" + }, + "uv": { + "level": "最弱", + "desc": "辐射弱,涂擦SPF8-12防晒护肤品。" + }, + "car_wash": { + "level": "不宜", + "desc": "有雨,雨水和泥水会弄脏爱车。" + }, + "travel": { + "level": "一般", + "desc": "可能有雷暴,外出请尽量避开降雨时段。" + }, + "sport": { + "level": "较不宜", + "desc": "有降水,推荐您在室内进行休闲运动。" + } + } + } + } +} \ No newline at end of file diff --git a/frontend/60sapi/实用功能/密码强度检测/css/style.css b/frontend/60sapi/实用功能/密码强度检测/css/style.css new file mode 100644 index 00000000..858e4bea --- /dev/null +++ b/frontend/60sapi/实用功能/密码强度检测/css/style.css @@ -0,0 +1,878 @@ +/* 基础样式重置 */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif; + line-height: 1.6; + color: #2c3e50; + min-height: 100vh; + overflow-x: hidden; +} + +/* 容器布局 */ +.container { + max-width: 1200px; + margin: 0 auto; + padding: 20px; + min-height: 100vh; + display: flex; + flex-direction: column; +} + +/* 头部样式 */ +.header { + text-align: center; + margin-bottom: 40px; + padding: 40px 20px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + border-radius: 20px; + box-shadow: 0 10px 30px rgba(102, 126, 234, 0.3); + color: white; +} + +.header h1 { + font-size: 2.8rem; + font-weight: 700; + margin-bottom: 15px; + text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); +} + +.subtitle { + font-size: 1.2rem; + opacity: 0.9; + font-weight: 400; +} + +/* 主内容区域 */ +.main-content { + flex: 1; + display: flex; + flex-direction: column; + gap: 30px; +} + +/* 输入容器 */ +.input-container { + background: #ffffff; + border-radius: 20px; + padding: 40px; + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1); + border: 1px solid #e8ecf4; +} + +.input-group { + margin-bottom: 30px; +} + +.input-label { + display: block; + font-size: 1.1rem; + font-weight: 600; + color: #2c3e50; + margin-bottom: 15px; +} + +.password-input-wrapper { + position: relative; + margin-bottom: 15px; +} + +.password-input { + width: 100%; + padding: 18px 60px 18px 20px; + border: 2px solid #e8ecf4; + border-radius: 12px; + font-size: 1.1rem; + font-family: 'Courier New', monospace; + background: #f8fafc; + transition: all 0.3s ease; + letter-spacing: 1px; +} + +.password-input:focus { + outline: none; + border-color: #667eea; + background: #ffffff; + box-shadow: 0 0 0 4px rgba(102, 126, 234, 0.1); +} + +.password-input::placeholder { + color: #94a3b8; + letter-spacing: normal; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; +} + +.toggle-visibility { + position: absolute; + right: 15px; + top: 50%; + transform: translateY(-50%); + background: none; + border: none; + cursor: pointer; + padding: 8px; + border-radius: 6px; + color: #64748b; + transition: all 0.3s ease; +} + +.toggle-visibility:hover { + background: #f1f5f9; + color: #475569; +} + +.input-hint { + display: flex; + align-items: center; + gap: 8px; + color: #64748b; + font-size: 0.9rem; +} + +.hint-icon { + font-size: 1rem; +} + +/* 检测按钮 */ +.check-btn { + width: 100%; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + border: none; + padding: 18px 32px; + border-radius: 12px; + font-size: 1.1rem; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; + box-shadow: 0 4px 20px rgba(102, 126, 234, 0.3); + display: flex; + align-items: center; + justify-content: center; + gap: 10px; + position: relative; + overflow: hidden; +} + +.check-btn:hover { + transform: translateY(-2px); + box-shadow: 0 6px 25px rgba(102, 126, 234, 0.4); +} + +.check-btn:active { + transform: translateY(0); +} + +.check-btn:disabled { + opacity: 0.7; + cursor: not-allowed; + transform: none; +} + +.btn-icon { + font-size: 1.2rem; +} + +/* 结果容器 */ +.result-container { + background: #ffffff; + border-radius: 20px; + padding: 40px; + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1); + border: 1px solid #e8ecf4; + animation: slideIn 0.5s ease-out; +} + +@keyframes slideIn { + from { + opacity: 0; + transform: translateY(30px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* 强度概览 */ +.strength-overview { + margin-bottom: 40px; + padding: 30px; + background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%); + border-radius: 16px; + border: 1px solid #e2e8f0; +} + +.strength-score { + display: flex; + align-items: center; + gap: 30px; + margin-bottom: 25px; +} + +.score-circle { + width: 120px; + height: 120px; + border-radius: 50%; + background: conic-gradient(from 0deg, #e2e8f0 0deg, #e2e8f0 360deg); + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + position: relative; + transition: all 0.5s ease; +} + +.score-circle::before { + content: ''; + position: absolute; + width: 90px; + height: 90px; + background: white; + border-radius: 50%; + z-index: 1; +} + +.score-value { + font-size: 2.5rem; + font-weight: 700; + color: #2c3e50; + z-index: 2; + position: relative; +} + +.score-label { + font-size: 0.9rem; + color: #64748b; + z-index: 2; + position: relative; +} + +.strength-info { + flex: 1; +} + +.strength-level { + font-size: 2rem; + font-weight: 700; + margin-bottom: 8px; + color: #2c3e50; +} + +.strength-description { + font-size: 1.1rem; + color: #64748b; + line-height: 1.5; +} + +.strength-bar { + margin-top: 20px; +} + +.bar-background { + width: 100%; + height: 12px; + background: #e2e8f0; + border-radius: 6px; + overflow: hidden; + margin-bottom: 10px; +} + +.bar-fill { + height: 100%; + background: linear-gradient(90deg, #ef4444, #f97316, #eab308, #22c55e); + border-radius: 6px; + width: 0%; + transition: width 0.8s ease; +} + +.bar-labels { + display: flex; + justify-content: space-between; + font-size: 0.85rem; + color: #64748b; +} + +/* 详细信息网格 */ +.details-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: 25px; + margin-bottom: 30px; +} + +.detail-card { + background: #f8fafc; + border-radius: 16px; + padding: 25px; + border: 1px solid #e2e8f0; + transition: all 0.3s ease; +} + +.detail-card:hover { + transform: translateY(-2px); + box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1); +} + +.card-header { + display: flex; + align-items: center; + gap: 12px; + margin-bottom: 20px; +} + +.card-icon { + font-size: 1.5rem; +} + +.card-header h3 { + font-size: 1.3rem; + font-weight: 600; + color: #2c3e50; +} + +.card-content { + display: flex; + flex-direction: column; + gap: 15px; +} + +.info-row { + display: flex; + justify-content: space-between; + align-items: center; + padding: 12px 0; + border-bottom: 1px solid #e2e8f0; +} + +.info-row:last-child { + border-bottom: none; +} + +.info-label { + font-weight: 500; + color: #64748b; +} + +.info-value { + font-weight: 600; + color: #2c3e50; +} + +/* 字符类型分析 */ +.character-types { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 12px; + margin-bottom: 20px; +} + +.char-type { + display: flex; + align-items: center; + gap: 8px; + padding: 10px 12px; + background: white; + border-radius: 8px; + border: 1px solid #e2e8f0; + font-size: 0.9rem; +} + +.char-type.has-type { + background: #dcfce7; + border-color: #bbf7d0; + color: #166534; +} + +.char-type.has-type .type-icon { + color: #22c55e; +} + +.type-icon { + font-size: 1rem; +} + +.character-issues { + display: flex; + flex-direction: column; + gap: 8px; +} + +.issue-item { + display: flex; + align-items: center; + gap: 8px; + padding: 8px 12px; + background: #fef2f2; + border: 1px solid #fecaca; + border-radius: 8px; + color: #dc2626; + font-size: 0.9rem; +} + +.issue-item.hidden { + display: none; +} + +.issue-icon { + font-size: 1rem; +} + +/* 建议和提示区域 */ +.recommendations-section { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); + gap: 25px; +} + +.recommendations-card, +.security-tips-card { + background: #f8fafc; + border-radius: 16px; + padding: 25px; + border: 1px solid #e2e8f0; +} + +.recommendations-list { + list-style: none; + display: flex; + flex-direction: column; + gap: 12px; +} + +.recommendations-list li { + display: flex; + align-items: flex-start; + gap: 10px; + padding: 12px 16px; + background: white; + border-radius: 10px; + border: 1px solid #e2e8f0; + color: #2c3e50; + line-height: 1.5; +} + +.recommendations-list li::before { + content: '💡'; + font-size: 1rem; + margin-top: 2px; + flex-shrink: 0; +} + +.tips-container { + display: flex; + flex-direction: column; + gap: 12px; +} + +.tip-item { + display: flex; + align-items: flex-start; + gap: 12px; + padding: 12px 16px; + background: white; + border-radius: 10px; + border: 1px solid #e2e8f0; + color: #2c3e50; + line-height: 1.5; +} + +.tip-icon { + font-size: 1rem; + margin-top: 2px; + flex-shrink: 0; +} + +/* 错误容器 */ +.error-container { + background: #ffffff; + border-radius: 20px; + padding: 50px 40px; + text-align: center; + box-shadow: 0 10px 40px rgba(239, 68, 68, 0.1); + border: 1px solid #fecaca; +} + +.error-icon { + font-size: 4rem; + margin-bottom: 20px; +} + +.error-container h3 { + color: #dc2626; + margin-bottom: 15px; + font-size: 1.5rem; + font-weight: 600; +} + +.error-container p { + color: #64748b; + margin-bottom: 25px; + font-size: 1.1rem; +} + +.retry-btn { + background: #dc2626; + color: white; + border: none; + padding: 14px 28px; + border-radius: 10px; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; + font-size: 1rem; +} + +.retry-btn:hover { + background: #b91c1c; + transform: translateY(-1px); +} + +/* 页脚 */ +.footer { + text-align: center; + padding: 40px 20px; + color: #64748b; + margin-top: 40px; +} + +.footer p { + margin-bottom: 8px; + font-size: 1rem; +} + +.footer-note { + font-size: 0.9rem; + opacity: 0.8; +} + +/* 提示框 */ +.toast { + position: fixed; + top: 20px; + right: 20px; + background: #22c55e; + color: white; + padding: 16px 24px; + border-radius: 10px; + box-shadow: 0 4px 20px rgba(34, 197, 94, 0.3); + z-index: 1000; + animation: toastSlide 0.3s ease-out; + font-weight: 500; +} + +@keyframes toastSlide { + from { + transform: translateX(100%); + opacity: 0; + } + to { + transform: translateX(0); + opacity: 1; + } +} + +/* 强度等级颜色 */ +.strength-weak { + color: #dc2626 !important; +} + +.strength-medium { + color: #f59e0b !important; +} + +.strength-strong { + color: #059669 !important; +} + +.strength-very-strong { + color: #047857 !important; +} + +/* 分数圆圈颜色 */ +.score-weak { + background: conic-gradient(from 0deg, #dc2626 0deg, #dc2626 var(--score-deg), #e2e8f0 var(--score-deg), #e2e8f0 360deg) !important; +} + +.score-medium { + background: conic-gradient(from 0deg, #f59e0b 0deg, #f59e0b var(--score-deg), #e2e8f0 var(--score-deg), #e2e8f0 360deg) !important; +} + +.score-strong { + background: conic-gradient(from 0deg, #059669 0deg, #059669 var(--score-deg), #e2e8f0 var(--score-deg), #e2e8f0 360deg) !important; +} + +.score-very-strong { + background: conic-gradient(from 0deg, #047857 0deg, #047857 var(--score-deg), #e2e8f0 var(--score-deg), #e2e8f0 360deg) !important; +} + +/* 平板端适配 (768px - 1024px) */ +@media (min-width: 768px) and (max-width: 1024px) { + .container { + max-width: 900px; + padding: 25px; + } + + .header h1 { + font-size: 2.4rem; + } + + .input-container, + .result-container { + padding: 30px; + } + + .details-grid { + grid-template-columns: 1fr; + } + + .recommendations-section { + grid-template-columns: 1fr; + } + + .strength-score { + flex-direction: column; + text-align: center; + gap: 20px; + } +} + +/* 手机端适配 (最大767px) */ +@media (max-width: 767px) { + .container { + padding: 15px; + max-width: 100%; + } + + .header { + padding: 25px 15px; + margin-bottom: 25px; + } + + .header h1 { + font-size: 2rem; + } + + .subtitle { + font-size: 1rem; + } + + .input-container, + .result-container { + padding: 25px; + border-radius: 15px; + } + + .main-content { + gap: 20px; + } + + .password-input { + padding: 16px 50px 16px 16px; + font-size: 1rem; + } + + .check-btn { + padding: 16px 28px; + font-size: 1rem; + } + + .strength-overview { + padding: 20px; + margin-bottom: 25px; + } + + .strength-score { + flex-direction: column; + text-align: center; + gap: 20px; + } + + .score-circle { + width: 100px; + height: 100px; + } + + .score-circle::before { + width: 75px; + height: 75px; + } + + .score-value { + font-size: 2rem; + } + + .strength-level { + font-size: 1.6rem; + } + + .details-grid { + grid-template-columns: 1fr; + gap: 20px; + } + + .detail-card { + padding: 20px; + } + + .character-types { + grid-template-columns: 1fr; + } + + .recommendations-section { + grid-template-columns: 1fr; + gap: 20px; + } + + .recommendations-card, + .security-tips-card { + padding: 20px; + } + + .toast { + right: 15px; + left: 15px; + top: 15px; + text-align: center; + } +} + +/* 小屏手机适配 (最大480px) */ +@media (max-width: 480px) { + .container { + padding: 10px; + } + + .header { + padding: 20px 10px; + margin-bottom: 20px; + } + + .header h1 { + font-size: 1.8rem; + } + + .input-container, + .result-container { + padding: 20px; + } + + .password-input { + padding: 14px 45px 14px 14px; + font-size: 0.95rem; + } + + .check-btn { + padding: 14px 24px; + } + + .detail-card { + padding: 15px; + } + + .card-header h3 { + font-size: 1.1rem; + } +} + +/* 触摸设备优化 */ +@media (hover: none) and (pointer: coarse) { + .check-btn, + .retry-btn, + .toggle-visibility { + min-height: 44px; + } + + .toggle-visibility { + padding: 12px; + } +} + +/* 高对比度模式支持 */ +@media (prefers-contrast: high) { + .input-container, + .result-container, + .detail-card { + border: 2px solid #2c3e50; + } + + .password-input { + border: 2px solid #2c3e50; + } +} + +/* 减少动画模式支持 */ +@media (prefers-reduced-motion: reduce) { + * { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } +} + +/* 深色模式支持 */ +@media (prefers-color-scheme: dark) { + body { + background: #0f172a; + color: #e2e8f0; + } + + .input-container, + .result-container, + .detail-card, + .recommendations-card, + .security-tips-card { + background: #1e293b; + border-color: #334155; + } + + .password-input { + background: #334155; + border-color: #475569; + color: #e2e8f0; + } + + .password-input:focus { + background: #1e293b; + border-color: #667eea; + } + + .strength-overview { + background: #1e293b; + border-color: #334155; + } + + .char-type, + .recommendations-list li, + .tip-item { + background: #334155; + border-color: #475569; + color: #e2e8f0; + } +} + +/* 打印样式 */ +@media print { + .header { + background: none !important; + color: black !important; + box-shadow: none !important; + } + + .check-btn, + .retry-btn, + .toggle-visibility, + .toast { + display: none !important; + } + + .input-container, + .result-container { + box-shadow: none !important; + border: 1px solid #ccc !important; + } +} \ No newline at end of file diff --git a/frontend/60sapi/实用功能/密码强度检测/index.html b/frontend/60sapi/实用功能/密码强度检测/index.html new file mode 100644 index 00000000..f9b0c70a --- /dev/null +++ b/frontend/60sapi/实用功能/密码强度检测/index.html @@ -0,0 +1,218 @@ + + + + + + + + 🔒 密码强度检测器 + + + + + + +
+
+

🔒 密码强度检测器

+

实时分析密码安全性,保护您的数字生活

+
+ +
+ +
+
+ +
+ + +
+
+ 💡 + 输入密码后将实时显示安全性分析结果 +
+
+ + +
+ + + + + + +
+ + +
+ + + + + + + \ No newline at end of file diff --git a/frontend/60sapi/实用功能/密码强度检测/js/script.js b/frontend/60sapi/实用功能/密码强度检测/js/script.js new file mode 100644 index 00000000..8861664a --- /dev/null +++ b/frontend/60sapi/实用功能/密码强度检测/js/script.js @@ -0,0 +1,516 @@ +/** + * 密码强度检测器 + * 提供密码强度分析和安全建议 + */ +class PasswordStrengthChecker { + constructor() { + this.apiUrl = 'https://60s.api.shumengya.top/v2/password/check'; + this.isChecking = false; + this.currentPassword = ''; + this.init(); + } + + /** + * 初始化应用 + */ + init() { + this.bindEvents(); + this.setupFormValidation(); + this.hideResultContainer(); + this.hideErrorContainer(); + console.log('密码强度检测器初始化完成'); + } + + /** + * 绑定事件监听器 + */ + bindEvents() { + // 密码输入框事件 + const passwordInput = document.getElementById('passwordInput'); + if (passwordInput) { + passwordInput.addEventListener('input', this.handlePasswordInput.bind(this)); + passwordInput.addEventListener('keypress', this.handleKeyPress.bind(this)); + } + + // 显示/隐藏密码按钮 + const toggleBtn = document.getElementById('toggleVisibility'); + if (toggleBtn) { + toggleBtn.addEventListener('click', this.togglePasswordVisibility.bind(this)); + } + + // 检测按钮 + const checkBtn = document.getElementById('checkBtn'); + if (checkBtn) { + checkBtn.addEventListener('click', this.handleCheckPassword.bind(this)); + } + + // 重试按钮 + const retryBtn = document.getElementById('retryBtn'); + if (retryBtn) { + retryBtn.addEventListener('click', this.handleRetry.bind(this)); + } + } + + /** + * 设置表单验证 + */ + setupFormValidation() { + const form = document.querySelector('.input-container'); + if (form) { + form.addEventListener('submit', (e) => { + e.preventDefault(); + this.handleCheckPassword(); + }); + } + } + + /** + * 处理密码输入 + */ + handlePasswordInput(event) { + const password = event.target.value; + this.currentPassword = password; + + // 更新按钮状态 + this.updateCheckButtonState(); + + // 如果密码为空,隐藏结果 + if (!password.trim()) { + this.hideResultContainer(); + this.hideErrorContainer(); + } + } + + /** + * 处理键盘事件 + */ + handleKeyPress(event) { + if (event.key === 'Enter' && !this.isChecking) { + event.preventDefault(); + this.handleCheckPassword(); + } + } + + /** + * 切换密码可见性 + */ + togglePasswordVisibility() { + const passwordInput = document.getElementById('passwordInput'); + const toggleBtn = document.getElementById('toggleVisibility'); + + if (passwordInput && toggleBtn) { + const isPassword = passwordInput.type === 'password'; + passwordInput.type = isPassword ? 'text' : 'password'; + toggleBtn.innerHTML = isPassword ? '🙈' : '👁️'; + toggleBtn.title = isPassword ? '隐藏密码' : '显示密码'; + } + } + + /** + * 更新检测按钮状态 + */ + updateCheckButtonState() { + const checkBtn = document.getElementById('checkBtn'); + const hasPassword = this.currentPassword.trim().length > 0; + + if (checkBtn) { + checkBtn.disabled = !hasPassword || this.isChecking; + + if (this.isChecking) { + checkBtn.innerHTML = '检测中...'; + } else if (hasPassword) { + checkBtn.innerHTML = '🔍检测密码强度'; + } else { + checkBtn.innerHTML = '🔍请输入密码'; + } + } + } + + /** + * 处理密码检测 + */ + async handleCheckPassword() { + const password = this.currentPassword.trim(); + + if (!password) { + this.showToast('请输入要检测的密码', 'error'); + return; + } + + if (this.isChecking) { + return; + } + + try { + this.setLoadingState(true); + this.hideErrorContainer(); + + const result = await this.checkPasswordStrength(password); + + if (result.code === 200 && result.data) { + this.displayResults(result.data); + this.showResultContainer(); + this.showToast('密码强度检测完成', 'success'); + } else { + throw new Error(result.message || '检测失败'); + } + } catch (error) { + console.error('密码检测错误:', error); + this.showError(error.message || '检测服务暂时不可用,请稍后重试'); + } finally { + this.setLoadingState(false); + } + } + + /** + * 调用API检测密码强度 + */ + async checkPasswordStrength(password) { + const url = new URL(this.apiUrl); + url.searchParams.append('password', password); + url.searchParams.append('encoding', 'utf-8'); + + const response = await fetch(url.toString(), { + method: 'GET', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + } + }); + + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + + return await response.json(); + } + + /** + * 显示检测结果 + */ + displayResults(data) { + this.updateStrengthOverview(data); + this.updateDetailedInfo(data); + this.updateRecommendations(data); + } + + /** + * 更新强度概览 + */ + updateStrengthOverview(data) { + // 更新分数圆圈 + const scoreCircle = document.getElementById('scoreCircle'); + const scoreValue = document.getElementById('scoreValue'); + const strengthLevel = document.getElementById('strengthLevel'); + const strengthDescription = document.getElementById('strengthDescription'); + const barFill = document.getElementById('strengthBar'); + + if (scoreValue) { + scoreValue.textContent = data.score || 0; + } + + if (strengthLevel) { + strengthLevel.textContent = this.getStrengthText(data.strength); + const strengthClass = this.getStrengthClass(data.strength); + strengthLevel.className = `strength-level strength-${strengthClass}`; + } + + if (strengthDescription) { + strengthDescription.textContent = this.getStrengthDescription(data.strength); + } + + // 更新分数圆圈 + if (scoreCircle) { + const percentage = (data.score / 100) * 360; + scoreCircle.style.setProperty('--score-deg', `${percentage}deg`); + // 将中文强度转换为CSS类名 + const strengthClass = this.getStrengthClass(data.strength); + scoreCircle.className = `score-circle score-${strengthClass}`; + } + + // 更新强度条 + if (barFill) { + setTimeout(() => { + barFill.style.width = `${data.score}%`; + }, 100); + } + } + + /** + * 更新详细信息 + */ + updateDetailedInfo(data) { + // 基本信息 + this.updateElement('passwordLength', data.length || 0); + this.updateElement('entropyValue', data.entropy ? data.entropy.toFixed(2) : '0.00'); + this.updateElement('crackTime', data.time_to_crack || '未知'); + + // 字符类型分析 + this.updateCharacterAnalysis(data.character_analysis || {}); + } + + /** + * 更新字符类型分析 + */ + updateCharacterAnalysis(analysis) { + const types = { + 'has_lowercase': { element: 'hasLowercase', label: '小写字母', icon: '🔤' }, + 'has_uppercase': { element: 'hasUppercase', label: '大写字母', icon: '🔠' }, + 'has_numbers': { element: 'hasNumbers', label: '数字', icon: '🔢' }, + 'has_symbols': { element: 'hasSymbols', label: '特殊符号', icon: '🔣' } + }; + + Object.keys(types).forEach(key => { + const element = document.getElementById(types[key].element); + if (element) { + const hasType = analysis[key] || false; + element.className = `char-type ${hasType ? 'has-type' : ''}`; + element.innerHTML = ` + ${hasType ? '✅' : '❌'} + ${types[key].label} + `; + } + }); + + // 更新字符种类数量 + this.updateElement('characterVariety', analysis.character_variety || 0); + + // 更新问题提示 + this.updateCharacterIssues(analysis); + } + + /** + * 更新字符问题提示 + */ + updateCharacterIssues(analysis) { + const issues = [ + { id: 'hasRepeated', condition: analysis.has_repeated, text: '包含重复字符' }, + { id: 'hasSequential', condition: analysis.has_sequential, text: '包含连续字符' } + ]; + + issues.forEach(issue => { + const element = document.getElementById(issue.id); + if (element) { + if (issue.condition) { + element.style.display = 'flex'; + element.innerHTML = ` + ⚠️ + ${issue.text} + `; + } else { + element.style.display = 'none'; + } + } + }); + } + + /** + * 更新建议和提示 + */ + updateRecommendations(data) { + // 更新建议列表 + const recommendationsList = document.getElementById('recommendationsList'); + if (recommendationsList && data.recommendations) { + recommendationsList.innerHTML = ''; + data.recommendations.forEach(recommendation => { + const li = document.createElement('li'); + li.textContent = recommendation; + recommendationsList.appendChild(li); + }); + } + + // 更新安全提示 + const tipsContainer = document.getElementById('securityTips'); + if (tipsContainer && data.security_tips) { + tipsContainer.innerHTML = ''; + data.security_tips.forEach((tip, index) => { + const tipElement = document.createElement('div'); + tipElement.className = 'tip-item'; + tipElement.innerHTML = ` + ${this.getTipIcon(index)} + ${tip} + `; + tipsContainer.appendChild(tipElement); + }); + } + } + + /** + * 获取提示图标 + */ + getTipIcon(index) { + const icons = ['🛡️', '🔐', '⚡', '🎯', '💡', '🔄']; + return icons[index % icons.length]; + } + + /** + * 获取强度文本 + */ + getStrengthText(strength) { + // API直接返回中文强度,无需映射 + return strength || '未知'; + } + + /** + * 获取强度CSS类名 + */ + getStrengthClass(strength) { + const classMap = { + '弱': 'weak', + '中等': 'medium', + '强': 'strong', + '非常强': 'very-strong' + }; + return classMap[strength] || 'unknown'; + } + + /** + * 获取强度描述 + */ + getStrengthDescription(strength) { + const descriptions = { + '弱': '密码强度较弱,建议增加复杂度', + '中等': '密码强度中等,可以进一步优化', + '强': '密码强度良好,安全性较高', + '非常强': '密码强度非常好,安全性很高' + }; + return descriptions[strength] || '无法评估密码强度'; + } + + /** + * 设置加载状态 + */ + setLoadingState(loading) { + this.isChecking = loading; + this.updateCheckButtonState(); + + const passwordInput = document.getElementById('passwordInput'); + if (passwordInput) { + passwordInput.disabled = loading; + } + } + + /** + * 显示结果容器 + */ + showResultContainer() { + const container = document.getElementById('resultContainer'); + if (container) { + container.style.display = 'block'; + container.scrollIntoView({ behavior: 'smooth', block: 'start' }); + } + } + + /** + * 隐藏结果容器 + */ + hideResultContainer() { + const container = document.getElementById('resultContainer'); + if (container) { + container.style.display = 'none'; + } + } + + /** + * 显示错误 + */ + showError(message) { + const errorContainer = document.getElementById('errorContainer'); + const errorMessage = document.getElementById('errorMessage'); + + if (errorContainer && errorMessage) { + errorMessage.textContent = message; + errorContainer.style.display = 'block'; + this.hideResultContainer(); + errorContainer.scrollIntoView({ behavior: 'smooth', block: 'start' }); + } + } + + /** + * 隐藏错误容器 + */ + hideErrorContainer() { + const container = document.getElementById('errorContainer'); + if (container) { + container.style.display = 'none'; + } + } + + /** + * 处理重试 + */ + handleRetry() { + this.hideErrorContainer(); + const passwordInput = document.getElementById('passwordInput'); + if (passwordInput) { + passwordInput.focus(); + } + } + + /** + * 更新元素内容 + */ + updateElement(id, content) { + const element = document.getElementById(id); + if (element) { + element.textContent = content; + } + } + + /** + * 显示提示消息 + */ + showToast(message, type = 'success') { + const toast = document.getElementById('toast'); + const toastMessage = document.getElementById('toastMessage'); + + if (toast && toastMessage) { + toastMessage.textContent = message; + toast.className = `toast toast-${type}`; + toast.style.display = 'block'; + + // 3秒后自动隐藏 + setTimeout(() => { + toast.style.display = 'none'; + }, 3000); + } + } +} + +// 页面加载完成后初始化 +document.addEventListener('DOMContentLoaded', () => { + try { + window.passwordChecker = new PasswordStrengthChecker(); + console.log('密码强度检测器已启动'); + } catch (error) { + console.error('初始化失败:', error); + } +}); + +// 页面可见性变化处理 +document.addEventListener('visibilitychange', () => { + if (document.visibilityState === 'visible' && window.passwordChecker) { + console.log('页面重新激活'); + } +}); + +// 全局错误处理 +window.addEventListener('error', (event) => { + console.error('全局错误:', event.error); + if (window.passwordChecker) { + window.passwordChecker.showToast('发生了意外错误,请刷新页面重试', 'error'); + } +}); + +// 网络状态监听 +window.addEventListener('online', () => { + if (window.passwordChecker) { + window.passwordChecker.showToast('网络连接已恢复', 'success'); + } +}); + +window.addEventListener('offline', () => { + if (window.passwordChecker) { + window.passwordChecker.showToast('网络连接已断开', 'error'); + } +}); \ No newline at end of file diff --git a/frontend/60sapi/实用功能/密码强度检测/返回接口.json b/frontend/60sapi/实用功能/密码强度检测/返回接口.json new file mode 100644 index 00000000..f9eba55a --- /dev/null +++ b/frontend/60sapi/实用功能/密码强度检测/返回接口.json @@ -0,0 +1,37 @@ +{ + "code": 200, + "message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s,反馈群 595941841", + "data": { + "password": "adasdasdasdadasd", + "length": 16, + "score": 68, + "strength": "中等", + "entropy": 75.21, + "time_to_crack": "数百万年", + "character_analysis": { + "has_lowercase": true, + "has_uppercase": false, + "has_numbers": false, + "has_symbols": false, + "has_repeated": false, + "has_sequential": true, + "character_variety": 26 + }, + "recommendations": [ + "建议包含大写字母", + "建议包含数字", + "建议包含特殊符号", + "避免使用连续序列字符" + ], + "security_tips": [ + "使用密码管理器生成和存储复杂密码", + "为不同账户使用不同的密码", + "定期更换重要账户的密码", + "启用双因素认证(2FA)增强安全性", + "避免在公共场合输入密码", + "不要将密码保存在浏览器中(除非使用可信的密码管理器)", + "避免使用个人信息作为密码", + "长密码比复杂密码更安全" + ] + } +} \ No newline at end of file diff --git a/frontend/60sapi/实用功能/生成要求模板.txt b/frontend/60sapi/实用功能/生成要求模板.txt deleted file mode 100755 index 91b7c04d..00000000 --- a/frontend/60sapi/实用功能/生成要求模板.txt +++ /dev/null @@ -1,8 +0,0 @@ -1.生成为静态网页,js,css,html分离出来,不要混合在一起放入html里,难以阅读 -2.网页要适配手机端,电脑端和平板端三个设备分别做不同的css格式,优先优化手机端用户体验 -3.网页默认风格以淡绿色清新风格为主,除非用户要求 -4.尽量不要引用外部css,js,实在要引用就使用中国国内的cdn,否则用户可能加载不出来 -5.返回接口.json储存了网页api返回的数据格式 -6.严格按照用户要求执行,不得随意添加什么注解,如“以下数据来自...” -7.接口集合.json保存了所有已知的后端API接口,一个访问不了尝试自动切换另一个 -8.在css中有关背景的css单独一个css文件,方便我直接迁移 diff --git a/frontend/60sapi/实用功能/身体健康分析/background.css b/frontend/60sapi/实用功能/身体健康分析/background.css new file mode 100644 index 00000000..9eb864ab --- /dev/null +++ b/frontend/60sapi/实用功能/身体健康分析/background.css @@ -0,0 +1,243 @@ +/* 背景样式文件 - 独立管理背景相关样式 */ + +/* 主体背景 */ +body { + background: linear-gradient(135deg, #e8f5e8 0%, #f0f8f0 25%, #e1f5e1 50%, #f5f9f5 75%, #e8f5e8 100%); + background-size: 400% 400%; + animation: gradientShift 15s ease infinite; + position: relative; + overflow-x: hidden; +} + +/* 背景动画 */ +@keyframes gradientShift { + 0% { + background-position: 0% 50%; + } + 50% { + background-position: 100% 50%; + } + 100% { + background-position: 0% 50%; + } +} + +/* 装饰性背景元素 */ +body::before { + content: ''; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-image: + radial-gradient(circle at 20% 80%, rgba(144, 238, 144, 0.1) 0%, transparent 50%), + radial-gradient(circle at 80% 20%, rgba(152, 251, 152, 0.1) 0%, transparent 50%), + radial-gradient(circle at 40% 40%, rgba(173, 255, 173, 0.08) 0%, transparent 50%); + pointer-events: none; + z-index: -2; +} + +/* 浮动装饰圆点 */ +body::after { + content: ''; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-image: + radial-gradient(2px 2px at 20px 30px, rgba(76, 175, 80, 0.3), transparent), + radial-gradient(2px 2px at 40px 70px, rgba(129, 199, 132, 0.3), transparent), + radial-gradient(1px 1px at 90px 40px, rgba(165, 214, 167, 0.3), transparent), + radial-gradient(1px 1px at 130px 80px, rgba(200, 230, 201, 0.3), transparent), + radial-gradient(2px 2px at 160px 30px, rgba(76, 175, 80, 0.2), transparent); + background-repeat: repeat; + background-size: 200px 100px; + animation: floatDots 20s linear infinite; + pointer-events: none; + z-index: -1; +} + +@keyframes floatDots { + 0% { + transform: translateY(0px); + } + 100% { + transform: translateY(-100px); + } +} + +/* 容器背景增强 */ +.container { + background: rgba(255, 255, 255, 0.02); + backdrop-filter: blur(10px); + border-radius: 20px; + position: relative; +} + +/* 表单区域背景 */ +.form-section { + background: rgba(255, 255, 255, 0.95); + backdrop-filter: blur(20px); + border: 1px solid rgba(144, 238, 144, 0.3); + position: relative; + overflow: hidden; +} + +.form-section::before { + content: ''; + position: absolute; + top: -50%; + left: -50%; + width: 200%; + height: 200%; + background: linear-gradient(45deg, transparent, rgba(144, 238, 144, 0.05), transparent); + animation: shimmer 3s ease-in-out infinite; + pointer-events: none; +} + +@keyframes shimmer { + 0% { + transform: translateX(-100%) translateY(-100%) rotate(45deg); + } + 50% { + transform: translateX(100%) translateY(100%) rotate(45deg); + } + 100% { + transform: translateX(-100%) translateY(-100%) rotate(45deg); + } +} + +/* 结果卡片背景 */ +.basic-info-card, +.bmi-card, +.weight-card, +.metabolism-card, +.body-fat-card, +.measurements-card, +.advice-card { + background: rgba(255, 255, 255, 0.95); + backdrop-filter: blur(15px); + border: 1px solid rgba(144, 238, 144, 0.2); + position: relative; + overflow: hidden; +} + +/* 卡片悬停背景效果 */ +.basic-info-card:hover, +.bmi-card:hover, +.weight-card:hover, +.metabolism-card:hover, +.body-fat-card:hover, +.measurements-card:hover, +.advice-card:hover { + background: rgba(255, 255, 255, 0.98); + border-color: rgba(76, 175, 80, 0.4); +} + +/* 免责声明卡片背景 */ +.disclaimer-card { + background: rgba(255, 243, 205, 0.95); + backdrop-filter: blur(15px); + border: 1px solid rgba(255, 234, 167, 0.5); +} + +/* 错误区域背景 */ +.error-content { + background: rgba(255, 255, 255, 0.95); + backdrop-filter: blur(20px); + border: 1px solid rgba(220, 53, 69, 0.2); +} + +/* 输入框背景 */ +.form-input, +.form-select { + background: rgba(248, 255, 248, 0.9); + backdrop-filter: blur(10px); +} + +.form-input:focus, +.form-select:focus { + background: rgba(255, 255, 255, 0.95); + backdrop-filter: blur(15px); +} + +/* 信息项背景 */ +.info-item { + background: rgba(248, 255, 248, 0.8); + backdrop-filter: blur(5px); +} + +/* BMI分类背景 */ +.bmi-category { + background: rgba(232, 245, 232, 0.9); + backdrop-filter: blur(10px); +} + +/* 健康建议列表项背景 */ +.health-tips li { + background: rgba(248, 255, 248, 0.8); + backdrop-filter: blur(5px); +} + +/* 按钮背景增强 */ +.submit-btn { + position: relative; + overflow: hidden; +} + +.submit-btn::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); + transition: left 0.5s; +} + +.submit-btn:hover::before { + left: 100%; +} + +/* 重置按钮背景 */ +.reset-btn { + background: rgba(232, 245, 232, 0.9); + backdrop-filter: blur(10px); +} + +.reset-btn:hover { + background: rgba(212, 237, 218, 0.95); +} + +/* 响应式背景调整 */ +@media (max-width: 767px) { + body::after { + background-size: 150px 75px; + animation-duration: 15s; + } + + .form-section::before { + animation-duration: 2s; + } +} + +@media (min-width: 768px) and (max-width: 1024px) { + body::after { + background-size: 180px 90px; + animation-duration: 18s; + } +} + +@media (min-width: 1024px) { + body::after { + background-size: 220px 110px; + animation-duration: 25s; + } + + .container { + background: rgba(255, 255, 255, 0.05); + } +} \ No newline at end of file diff --git a/frontend/60sapi/实用功能/身体健康分析/index.html b/frontend/60sapi/实用功能/身体健康分析/index.html new file mode 100644 index 00000000..d34d508c --- /dev/null +++ b/frontend/60sapi/实用功能/身体健康分析/index.html @@ -0,0 +1,115 @@ + + + + + + 身体健康分析 + + + + +
+
+

身体健康分析

+

通过身高、体重、年龄、性别多维度分析身体健康状态

+
+ +
+
+
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+
+ + + + +
+ + +
+ + + + \ No newline at end of file diff --git a/frontend/60sapi/实用功能/身体健康分析/script.js b/frontend/60sapi/实用功能/身体健康分析/script.js new file mode 100644 index 00000000..d0a440df --- /dev/null +++ b/frontend/60sapi/实用功能/身体健康分析/script.js @@ -0,0 +1,515 @@ +// 身体健康分析 JavaScript 功能 + +// DOM 元素获取 +const healthForm = document.getElementById('healthForm'); +const analyzeBtn = document.getElementById('analyzeBtn'); +const btnText = analyzeBtn.querySelector('.btn-text'); +const loadingSpinner = analyzeBtn.querySelector('.loading-spinner'); +const resultSection = document.getElementById('resultSection'); +const errorSection = document.getElementById('errorSection'); +const resetBtn = document.getElementById('resetBtn'); +const retryBtn = document.getElementById('retryBtn'); + +// API 配置 +const API_BASE_URL = 'https://60s.api.shumengya.top/v2/health'; + +// 表单验证规则 +const validationRules = { + height: { + min: 100, + max: 250, + message: '身高应在100-250cm之间' + }, + weight: { + min: 30, + max: 200, + message: '体重应在30-200kg之间' + }, + age: { + min: 1, + max: 120, + message: '年龄应在1-120岁之间' + } +}; + +// 初始化 +document.addEventListener('DOMContentLoaded', function() { + initializeEventListeners(); + setupFormValidation(); +}); + +// 事件监听器初始化 +function initializeEventListeners() { + healthForm.addEventListener('submit', handleFormSubmit); + resetBtn.addEventListener('click', resetForm); + retryBtn.addEventListener('click', retryAnalysis); + + // 输入框实时验证 + const inputs = healthForm.querySelectorAll('input, select'); + inputs.forEach(input => { + input.addEventListener('blur', validateField); + input.addEventListener('input', clearFieldError); + }); +} + +// 表单验证设置 +function setupFormValidation() { + const inputs = healthForm.querySelectorAll('input[type="number"]'); + inputs.forEach(input => { + input.addEventListener('input', function() { + // 移除非数字字符 + this.value = this.value.replace(/[^0-9.]/g, ''); + + // 防止多个小数点 + const parts = this.value.split('.'); + if (parts.length > 2) { + this.value = parts[0] + '.' + parts.slice(1).join(''); + } + }); + }); +} + +// 表单提交处理 +async function handleFormSubmit(event) { + event.preventDefault(); + + if (!validateForm()) { + return; + } + + const formData = getFormData(); + + try { + setLoadingState(true); + hideAllSections(); + + const result = await callHealthAPI(formData); + displayResults(result); + + } catch (error) { + console.error('分析失败:', error); + displayError(error.message || '分析失败,请稍后重试'); + } finally { + setLoadingState(false); + } +} + +// 获取表单数据 +function getFormData() { + return { + height: parseInt(document.getElementById('height').value), + weight: parseInt(document.getElementById('weight').value), + age: parseInt(document.getElementById('age').value), + gender: document.getElementById('gender').value + }; +} + +// 表单验证 +function validateForm() { + let isValid = true; + const inputs = healthForm.querySelectorAll('input, select'); + + inputs.forEach(input => { + if (!validateField({ target: input })) { + isValid = false; + } + }); + + return isValid; +} + +// 单个字段验证 +function validateField(event) { + const field = event.target; + const value = field.value.trim(); + const fieldName = field.name; + + // 清除之前的错误状态 + clearFieldError(event); + + // 必填验证 + if (!value) { + showFieldError(field, '此字段为必填项'); + return false; + } + + // 数值范围验证 + if (validationRules[fieldName]) { + const numValue = parseFloat(value); + const rule = validationRules[fieldName]; + + if (numValue < rule.min || numValue > rule.max) { + showFieldError(field, rule.message); + return false; + } + } + + return true; +} + +// 显示字段错误 +function showFieldError(field, message) { + field.classList.add('error'); + + // 移除已存在的错误消息 + const existingError = field.parentNode.querySelector('.error-message'); + if (existingError) { + existingError.remove(); + } + + // 添加错误消息 + const errorDiv = document.createElement('div'); + errorDiv.className = 'error-message'; + errorDiv.textContent = message; + errorDiv.style.color = '#dc3545'; + errorDiv.style.fontSize = '0.875rem'; + errorDiv.style.marginTop = '5px'; + + field.parentNode.appendChild(errorDiv); +} + +// 清除字段错误 +function clearFieldError(event) { + const field = event.target; + field.classList.remove('error'); + + const errorMessage = field.parentNode.querySelector('.error-message'); + if (errorMessage) { + errorMessage.remove(); + } +} + +// 调用健康分析API +async function callHealthAPI(data) { + const params = new URLSearchParams({ + height: data.height, + weight: data.weight, + age: data.age, + gender: data.gender + }); + + const response = await fetch(`${API_BASE_URL}?${params}`); + + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + + const result = await response.json(); + + if (result.code !== 200) { + throw new Error(result.message || '分析失败'); + } + + return result.data; +} + +// 显示分析结果 +function displayResults(data) { + // 基本信息 + displayBasicInfo(data.basic_info); + + // BMI 分析 + displayBMIInfo(data.bmi); + + // 体重评估 + displayWeightAssessment(data.weight_assessment); + + // 代谢分析 + displayMetabolism(data.metabolism); + + // 体脂分析 + displayBodyFat(data.body_fat); + + // 理想三围 + displayMeasurements(data.ideal_measurements); + + // 健康建议 + displayHealthAdvice(data.health_advice); + + // 免责声明 + displayDisclaimer(data.disclaimer); + + // 显示结果区域 + resultSection.style.display = 'block'; + resultSection.scrollIntoView({ behavior: 'smooth' }); +} + +// 显示基本信息 +function displayBasicInfo(basicInfo) { + const container = document.getElementById('basicInfo'); + container.innerHTML = ''; + + const infoItems = [ + { label: basicInfo.height_desc, value: basicInfo.height }, + { label: basicInfo.weight_desc, value: basicInfo.weight }, + { label: basicInfo.age_desc, value: basicInfo.age }, + { label: basicInfo.gender_desc, value: basicInfo.gender } + ]; + + infoItems.forEach(item => { + const itemDiv = createInfoItem(item.label, item.value); + container.appendChild(itemDiv); + }); +} + +// 显示BMI信息 +function displayBMIInfo(bmiData) { + const container = document.getElementById('bmiContent'); + container.innerHTML = ` +
${bmiData.value}
+
${bmiData.category}
+
+ ${createInfoItem(bmiData.evaluation_desc, bmiData.evaluation).outerHTML} + ${createInfoItem(bmiData.risk_desc, bmiData.risk).outerHTML} +
+ `; +} + +// 显示体重评估 +function displayWeightAssessment(weightData) { + const container = document.getElementById('weightContent'); + container.innerHTML = ''; + + const items = [ + { label: weightData.ideal_weight_range_desc, value: weightData.ideal_weight_range }, + { label: weightData.standard_weight_desc, value: weightData.standard_weight }, + { label: weightData.status_desc, value: weightData.status }, + { label: weightData.adjustment_desc, value: weightData.adjustment } + ]; + + const grid = document.createElement('div'); + grid.className = 'info-grid'; + + items.forEach(item => { + const itemDiv = createInfoItem(item.label, item.value); + grid.appendChild(itemDiv); + }); + + container.appendChild(grid); +} + +// 显示代谢分析 +function displayMetabolism(metabolismData) { + const container = document.getElementById('metabolismContent'); + container.innerHTML = ''; + + const items = [ + { label: metabolismData.bmr_desc, value: metabolismData.bmr }, + { label: metabolismData.tdee_desc, value: metabolismData.tdee }, + { label: metabolismData.recommended_calories_desc, value: metabolismData.recommended_calories }, + { label: metabolismData.weight_loss_calories_desc, value: metabolismData.weight_loss_calories }, + { label: metabolismData.weight_gain_calories_desc, value: metabolismData.weight_gain_calories } + ]; + + const grid = document.createElement('div'); + grid.className = 'info-grid'; + + items.forEach(item => { + const itemDiv = createInfoItem(item.label, item.value); + grid.appendChild(itemDiv); + }); + + container.appendChild(grid); +} + +// 显示体脂分析 +function displayBodyFat(bodyFatData) { + const container = document.getElementById('bodyFatContent'); + container.innerHTML = ''; + + const items = [ + { label: bodyFatData.percentage_desc, value: bodyFatData.percentage }, + { label: bodyFatData.category_desc, value: bodyFatData.category }, + { label: bodyFatData.fat_weight_desc, value: bodyFatData.fat_weight }, + { label: bodyFatData.lean_weight_desc, value: bodyFatData.lean_weight } + ]; + + const grid = document.createElement('div'); + grid.className = 'info-grid'; + + items.forEach(item => { + const itemDiv = createInfoItem(item.label, item.value); + grid.appendChild(itemDiv); + }); + + container.appendChild(grid); +} + +// 显示理想三围 +function displayMeasurements(measurementsData) { + const container = document.getElementById('measurementsContent'); + container.innerHTML = ''; + + const items = [ + { label: measurementsData.chest_desc, value: measurementsData.chest }, + { label: measurementsData.waist_desc, value: measurementsData.waist }, + { label: measurementsData.hip_desc, value: measurementsData.hip } + ]; + + const grid = document.createElement('div'); + grid.className = 'info-grid'; + + items.forEach(item => { + const itemDiv = createInfoItem(item.label, item.value); + grid.appendChild(itemDiv); + }); + + // 添加说明 + const note = document.createElement('p'); + note.style.marginTop = '15px'; + note.style.fontSize = '0.9rem'; + note.style.color = '#4a7c59'; + note.style.textAlign = 'center'; + note.textContent = measurementsData.note; + + container.appendChild(grid); + container.appendChild(note); +} + +// 显示健康建议 +function displayHealthAdvice(adviceData) { + const container = document.getElementById('adviceContent'); + container.innerHTML = ''; + + // 饮水量建议 + const waterDiv = createAdviceSection(adviceData.daily_water_intake_desc, adviceData.daily_water_intake); + container.appendChild(waterDiv); + + // 运动建议 + const exerciseDiv = createAdviceSection(adviceData.exercise_recommendation_desc, adviceData.exercise_recommendation); + container.appendChild(exerciseDiv); + + // 营养建议 + const nutritionDiv = createAdviceSection(adviceData.nutrition_advice_desc, adviceData.nutrition_advice); + container.appendChild(nutritionDiv); + + // 健康提示 + const tipsDiv = document.createElement('div'); + tipsDiv.innerHTML = ` +

${adviceData.health_tips_desc}

+ + `; + + const tipsList = tipsDiv.querySelector('.health-tips'); + adviceData.health_tips.forEach(tip => { + const li = document.createElement('li'); + li.textContent = tip; + tipsList.appendChild(li); + }); + + container.appendChild(tipsDiv); +} + +// 创建建议区块 +function createAdviceSection(title, content) { + const div = document.createElement('div'); + div.style.marginBottom = '20px'; + div.innerHTML = ` +

${title}

+

${content}

+ `; + return div; +} + +// 显示免责声明 +function displayDisclaimer(disclaimer) { + const container = document.getElementById('disclaimer'); + container.textContent = disclaimer; +} + +// 创建信息项 +function createInfoItem(label, value) { + const div = document.createElement('div'); + div.className = 'info-item'; + div.innerHTML = ` +
${label}
+
${value}
+ `; + return div; +} + +// 显示错误信息 +function displayError(message) { + const errorMessage = document.getElementById('errorMessage'); + errorMessage.textContent = message; + errorSection.style.display = 'block'; + errorSection.scrollIntoView({ behavior: 'smooth' }); +} + +// 设置加载状态 +function setLoadingState(isLoading) { + if (isLoading) { + analyzeBtn.disabled = true; + btnText.style.display = 'none'; + loadingSpinner.style.display = 'block'; + } else { + analyzeBtn.disabled = false; + btnText.style.display = 'block'; + loadingSpinner.style.display = 'none'; + } +} + +// 隐藏所有结果区域 +function hideAllSections() { + resultSection.style.display = 'none'; + errorSection.style.display = 'none'; +} + +// 重置表单 +function resetForm() { + healthForm.reset(); + hideAllSections(); + + // 清除所有错误状态 + const errorInputs = healthForm.querySelectorAll('.error'); + errorInputs.forEach(input => { + input.classList.remove('error'); + }); + + const errorMessages = healthForm.querySelectorAll('.error-message'); + errorMessages.forEach(msg => msg.remove()); + + // 滚动到表单顶部 + healthForm.scrollIntoView({ behavior: 'smooth' }); +} + +// 重试分析 +function retryAnalysis() { + hideAllSections(); + healthForm.scrollIntoView({ behavior: 'smooth' }); +} + +// 工具函数:防抖 +function debounce(func, wait) { + let timeout; + return function executedFunction(...args) { + const later = () => { + clearTimeout(timeout); + func(...args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; +} + +// 添加CSS样式到错误输入框 +const style = document.createElement('style'); +style.textContent = ` + .form-input.error, + .form-select.error { + border-color: #dc3545 !important; + box-shadow: 0 0 0 3px rgba(220, 53, 69, 0.1) !important; + } +`; +document.head.appendChild(style); + +// 页面可见性变化处理(用户切换标签页时暂停动画等) +document.addEventListener('visibilitychange', function() { + if (document.hidden) { + // 页面隐藏时的处理 + document.body.style.animationPlayState = 'paused'; + } else { + // 页面显示时的处理 + document.body.style.animationPlayState = 'running'; + } +}); \ No newline at end of file diff --git a/frontend/60sapi/实用功能/身体健康分析/styles.css b/frontend/60sapi/实用功能/身体健康分析/styles.css new file mode 100644 index 00000000..90fde65a --- /dev/null +++ b/frontend/60sapi/实用功能/身体健康分析/styles.css @@ -0,0 +1,697 @@ +/* 基础样式重置 */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif; + line-height: 1.6; + color: #2d5a3d; + min-height: 100vh; +} + +/* 容器布局 */ +.container { + max-width: 1200px; + margin: 0 auto; + padding: 20px; + min-height: 100vh; + display: flex; + flex-direction: column; +} + +/* 头部样式 */ +.header { + text-align: center; + margin-bottom: 30px; + padding: 20px 0; +} + +.title { + font-size: 2.5rem; + font-weight: 700; + color: #1a4d2e; + margin-bottom: 10px; + text-shadow: 0 2px 4px rgba(26, 77, 46, 0.1); +} + +.subtitle { + font-size: 1.1rem; + color: #4a7c59; + font-weight: 400; +} + +/* 主内容区域 */ +.main-content { + flex: 1; + display: flex; + flex-direction: column; + gap: 30px; +} + +/* 表单区域 */ +.form-section { + background: rgba(255, 255, 255, 0.95); + border-radius: 20px; + padding: 30px; + box-shadow: 0 8px 32px rgba(26, 77, 46, 0.1); + border: 1px solid rgba(144, 238, 144, 0.3); +} + +.health-form { + display: grid; + gap: 20px; +} + +.form-group { + display: flex; + flex-direction: column; + gap: 8px; +} + +.form-label { + font-weight: 600; + color: #2d5a3d; + font-size: 1rem; +} + +.form-input, +.form-select { + padding: 15px 20px; + border: 2px solid #a8e6a3; + border-radius: 12px; + font-size: 1rem; + background: #f8fff8; + color: #2d5a3d; + transition: all 0.3s ease; +} + +.form-input:focus, +.form-select:focus { + outline: none; + border-color: #4caf50; + box-shadow: 0 0 0 3px rgba(76, 175, 80, 0.1); + background: #ffffff; +} + +.form-input::placeholder { + color: #81c784; +} + +/* 提交按钮 */ +.submit-btn { + background: linear-gradient(135deg, #4caf50, #66bb6a); + color: white; + border: none; + padding: 18px 30px; + border-radius: 12px; + font-size: 1.1rem; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; + position: relative; + overflow: hidden; + margin-top: 10px; +} + +.submit-btn:hover { + background: linear-gradient(135deg, #45a049, #5cb85c); + transform: translateY(-2px); + box-shadow: 0 8px 25px rgba(76, 175, 80, 0.3); +} + +.submit-btn:active { + transform: translateY(0); +} + +.submit-btn:disabled { + background: #c8e6c9; + cursor: not-allowed; + transform: none; + box-shadow: none; +} + +/* 加载动画 */ +.loading-spinner { + width: 20px; + height: 20px; + border: 2px solid rgba(255, 255, 255, 0.3); + border-top: 2px solid white; + border-radius: 50%; + animation: spin 1s linear infinite; + margin: 0 auto; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +/* 结果区域 */ +.result-section { + animation: fadeInUp 0.6s ease-out; +} + +.result-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 25px; + flex-wrap: wrap; + gap: 15px; +} + +.result-title { + font-size: 2rem; + color: #1a4d2e; + font-weight: 700; +} + +.reset-btn { + background: #e8f5e8; + color: #2d5a3d; + border: 2px solid #a8e6a3; + padding: 10px 20px; + border-radius: 8px; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; +} + +.reset-btn:hover { + background: #d4edda; + border-color: #4caf50; +} + +/* 结果卡片 */ +.result-content { + display: grid; + gap: 20px; +} + +.basic-info-card, +.bmi-card, +.weight-card, +.metabolism-card, +.body-fat-card, +.measurements-card, +.advice-card, +.disclaimer-card { + background: rgba(255, 255, 255, 0.95); + border-radius: 16px; + padding: 25px; + box-shadow: 0 6px 20px rgba(26, 77, 46, 0.08); + border: 1px solid rgba(144, 238, 144, 0.2); + transition: transform 0.3s ease, box-shadow 0.3s ease; +} + +.basic-info-card:hover, +.bmi-card:hover, +.weight-card:hover, +.metabolism-card:hover, +.body-fat-card:hover, +.measurements-card:hover, +.advice-card:hover { + transform: translateY(-2px); + box-shadow: 0 8px 25px rgba(26, 77, 46, 0.12); +} + +.card-title { + font-size: 1.4rem; + color: #1a4d2e; + font-weight: 700; + margin-bottom: 15px; + border-bottom: 2px solid #e8f5e8; + padding-bottom: 10px; +} + +/* 信息网格 */ +.info-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 15px; +} + +.info-item { + background: #f8fff8; + padding: 15px; + border-radius: 10px; + border-left: 4px solid #4caf50; +} + +.info-label { + font-size: 0.9rem; + color: #4a7c59; + font-weight: 600; + margin-bottom: 5px; +} + +.info-value { + font-size: 1.2rem; + color: #2d5a3d; + font-weight: 700; +} + +/* BMI 特殊样式 */ +.bmi-value { + font-size: 2.5rem; + font-weight: 800; + color: #4caf50; + text-align: center; + margin: 15px 0; +} + +.bmi-category { + text-align: center; + font-size: 1.3rem; + font-weight: 600; + color: #2d5a3d; + background: #e8f5e8; + padding: 10px; + border-radius: 8px; + margin: 10px 0; +} + +/* 健康建议列表 */ +.health-tips { + list-style: none; + padding: 0; +} + +.health-tips li { + background: #f8fff8; + margin: 10px 0; + padding: 12px 15px; + border-radius: 8px; + border-left: 4px solid #81c784; + position: relative; +} + +.health-tips li::before { + content: "✓"; + color: #4caf50; + font-weight: bold; + margin-right: 10px; +} + +/* 免责声明 */ +.disclaimer { + background: #fff3cd; + border: 1px solid #ffeaa7; + color: #856404; + padding: 15px; + border-radius: 8px; + font-size: 0.95rem; + line-height: 1.5; + text-align: center; +} + +/* 错误区域 */ +.error-section { + text-align: center; + padding: 40px 20px; +} + +.error-content { + background: rgba(255, 255, 255, 0.95); + border-radius: 16px; + padding: 30px; + box-shadow: 0 6px 20px rgba(220, 53, 69, 0.1); + border: 1px solid rgba(220, 53, 69, 0.2); + max-width: 400px; + margin: 0 auto; +} + +.error-title { + color: #dc3545; + font-size: 1.5rem; + margin-bottom: 15px; +} + +.error-message { + color: #6c757d; + margin-bottom: 20px; +} + +.retry-btn { + background: #dc3545; + color: white; + border: none; + padding: 12px 24px; + border-radius: 8px; + font-weight: 600; + cursor: pointer; + transition: background 0.3s ease; +} + +.retry-btn:hover { + background: #c82333; +} + +/* 底部 */ +.footer { + text-align: center; + padding: 20px 0; + margin-top: 30px; + border-top: 1px solid rgba(144, 238, 144, 0.3); +} + +.footer-text { + color: #4a7c59; + font-size: 0.9rem; +} + +/* 动画效果 */ +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(30px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* 平板端适配 (768px - 1024px) */ +@media (min-width: 768px) and (max-width: 1024px) { + .container { + padding: 30px; + } + + .title { + font-size: 2.8rem; + } + + .form-section { + padding: 35px; + } + + .health-form { + grid-template-columns: repeat(2, 1fr); + gap: 25px; + } + + .form-group:last-child { + grid-column: 1 / -1; + } + + .result-content { + grid-template-columns: repeat(2, 1fr); + } + + .advice-card, + .disclaimer-card { + grid-column: 1 / -1; + } +} + +/* 电脑端适配 (1024px+) */ +@media (min-width: 1024px) { + .container { + padding: 40px; + max-width: 1400px; + } + + .title { + font-size: 3.2rem; + } + + .main-content { + flex-direction: row; + gap: 40px; + align-items: flex-start; + } + + .form-section { + flex: 0 0 380px; + position: sticky; + top: 20px; + max-height: calc(100vh - 40px); + overflow-y: auto; + } + + .result-section, + .error-section { + flex: 1; + min-width: 0; + } + + /* 桌面端结果区域重新设计 - 使用更清晰的布局 */ + .result-content { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 25px; + grid-auto-rows: min-content; + } + + /* 基本信息卡片 - 占满第一行 */ + .basic-info-card { + grid-column: 1 / -1; + } + + /* 第二行:BMI、体重评估、代谢分析 */ + .bmi-card, + .weight-card, + .metabolism-card { + grid-column: span 1; + } + + /* 第三行:体脂分析和理想三围 */ + .body-fat-card { + grid-column: span 2; + } + + .measurements-card { + grid-column: span 1; + } + + /* 第四行:健康建议 - 占满整行 */ + .advice-card { + grid-column: 1 / -1; + } + + /* 第五行:免责声明 - 占满整行 */ + .disclaimer-card { + grid-column: 1 / -1; + } + + /* 基本信息网格优化 */ + .basic-info-card .info-grid { + grid-template-columns: repeat(4, 1fr); + gap: 20px; + } + + /* BMI卡片特殊布局 */ + .bmi-card { + display: flex; + flex-direction: column; + min-height: 280px; + } + + .bmi-card .bmi-content { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; + } + + .bmi-value { + font-size: 3rem; + margin: 20px 0; + } + + /* 体重评估卡片布局优化 */ + .weight-card { + display: flex; + flex-direction: column; + min-height: 280px; + } + + .weight-card .weight-content { + flex: 1; + display: flex; + flex-direction: column; + justify-content: space-between; + } + + .weight-card .info-grid { + grid-template-columns: 1fr; + gap: 12px; + } + + /* 代谢分析卡片布局优化 */ + .metabolism-card { + display: flex; + flex-direction: column; + min-height: 280px; + } + + .metabolism-card .metabolism-content { + flex: 1; + display: flex; + flex-direction: column; + justify-content: space-between; + } + + .metabolism-card .info-grid { + grid-template-columns: 1fr; + gap: 12px; + } + + /* 体脂分析卡片网格优化 */ + .body-fat-card .info-grid { + grid-template-columns: repeat(2, 1fr); + gap: 15px; + } + + /* 理想三围卡片网格优化 */ + .measurements-card { + display: flex; + flex-direction: column; + min-height: 200px; + } + + .measurements-card .measurements-content { + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + } + + .measurements-card .info-grid { + grid-template-columns: 1fr; + gap: 15px; + } + + /* 健康建议卡片布局优化 */ + .advice-card { + padding: 30px; + } + + .advice-card .advice-content { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 25px; + margin-bottom: 25px; + } + + .advice-card .health-tips { + grid-column: 1 / -1; + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 15px; + list-style: none; + padding: 0; + } + + /* 表单区域优化 */ + .health-form { + display: grid; + gap: 25px; + } + + .form-group { + margin-bottom: 0; + } + + .submit-btn { + margin-top: 20px; + padding: 20px 30px; + font-size: 1.2rem; + } +} + +/* 手机端适配 (最高优先级) */ +@media (max-width: 767px) { + .container { + padding: 15px; + } + + .header { + margin-bottom: 20px; + padding: 15px 0; + } + + .title { + font-size: 2rem; + } + + .subtitle { + font-size: 1rem; + } + + .form-section { + padding: 20px; + border-radius: 16px; + } + + .form-input, + .form-select { + padding: 12px 16px; + font-size: 16px; /* 防止iOS缩放 */ + } + + .submit-btn { + padding: 16px 24px; + font-size: 1rem; + } + + .result-header { + flex-direction: column; + align-items: stretch; + gap: 15px; + } + + .result-title { + font-size: 1.6rem; + text-align: center; + } + + .reset-btn { + align-self: center; + padding: 12px 24px; + } + + .basic-info-card, + .bmi-card, + .weight-card, + .metabolism-card, + .body-fat-card, + .measurements-card, + .advice-card, + .disclaimer-card { + padding: 20px; + border-radius: 12px; + } + + .card-title { + font-size: 1.2rem; + } + + .info-grid { + grid-template-columns: 1fr; + gap: 12px; + } + + .bmi-value { + font-size: 2rem; + } + + .bmi-category { + font-size: 1.1rem; + } + + .health-tips li { + padding: 10px 12px; + font-size: 0.95rem; + } + + .error-content { + padding: 25px 20px; + } +} \ No newline at end of file diff --git a/frontend/60sapi/实用功能/身体健康分析/返回接口.json b/frontend/60sapi/实用功能/身体健康分析/返回接口.json new file mode 100644 index 00000000..455126d6 --- /dev/null +++ b/frontend/60sapi/实用功能/身体健康分析/返回接口.json @@ -0,0 +1,93 @@ +{ + "code": 200, + "message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s,反馈群 595941841", + "data": { + "basic_info": { + "height": "176cm", + "height_desc": "身高", + "weight": "60kg", + "weight_desc": "体重", + "gender": "男性", + "gender_desc": "性别", + "age": "24岁", + "age_desc": "年龄" + }, + "bmi": { + "value": 19.37, + "value_desc": "BMI 值", + "category": "正常体重", + "category_desc": "BMI 分类", + "evaluation": "体重正常,保持良好", + "evaluation_desc": "BMI 评价", + "risk": "健康风险较低", + "risk_desc": "健康风险" + }, + "weight_assessment": { + "ideal_weight_range": "57.3-74.3kg", + "ideal_weight_range_desc": "理想体重范围", + "standard_weight": "71kg", + "standard_weight_desc": "标准体重", + "status": "体重正常", + "status_desc": "体重状态", + "adjustment": "保持当前体重", + "adjustment_desc": "调整建议" + }, + "metabolism": { + "bmr": "1601 卡路里/天", + "bmr_desc": "基础代谢率", + "tdee": "2561 卡路里/天", + "tdee_desc": "每日总消耗", + "recommended_calories": "2561 卡路里/天", + "recommended_calories_desc": "推荐卡路里摄入", + "weight_loss_calories": "2061 卡路里/天", + "weight_loss_calories_desc": "减重卡路里", + "weight_gain_calories": "2861 卡路里/天", + "weight_gain_calories_desc": "增重卡路里" + }, + "body_surface_area": { + "value": "1.74m²", + "value_desc": "体表面积", + "formula": "Du Bois 公式", + "formula_desc": "计算公式" + }, + "body_fat": { + "percentage": "12.6%", + "percentage_desc": "体脂率", + "category": "正常", + "category_desc": "体脂分类", + "fat_weight": "7.6kg", + "fat_weight_desc": "脂肪重量", + "lean_weight": "52.4kg", + "lean_weight_desc": "瘦体重" + }, + "health_advice": { + "daily_water_intake": "2000ml (约 8 杯水),运动时需额外补充 500-1000ml", + "daily_water_intake_desc": "每日饮水量", + "exercise_recommendation": "继续保持运动习惯,有氧运动和力量训练相结合效果更佳。年轻人可选择多样化的运动方式,建议每周运动 3-5 次", + "exercise_recommendation_desc": "运动建议", + "nutrition_advice": "保持均衡饮食,三大营养素合理搭配,定时定量进餐。年轻人新陈代谢较快,可适当增加能量摄入,男性可适当增加蛋白质摄入", + "nutrition_advice_desc": "营养建议", + "health_tips": [ + "保持充足睡眠,成年人建议每天 7-9 小时", + "定期体检有助于早期发现健康问题", + "保持良好心态,适当释放压力", + "年轻人要注意作息规律,合理安排工作与休息", + "长时间用眼后适当休息,保护视力", + "培养兴趣爱好,保持积极的生活态度", + "多饮水,成年人每天 1500-2000ml 为宜" + ], + "health_tips_desc": "健康提示" + }, + "ideal_measurements": { + "chest": "84cm", + "chest_desc": "胸围", + "waist": "74cm", + "waist_desc": "腰围", + "hip": "83cm", + "hip_desc": "臀围", + "note": "男性理想三围参考标准", + "note_desc": "说明" + }, + "disclaimer": "结果基于通用公式和统计数据,仅供参考,不能替代专业医疗建议。如有健康问题,请咨询医生。" + } +} \ No newline at end of file diff --git a/frontend/60sapi/实用功能/配色方案/background.css b/frontend/60sapi/实用功能/配色方案/background.css new file mode 100644 index 00000000..13feaa42 --- /dev/null +++ b/frontend/60sapi/实用功能/配色方案/background.css @@ -0,0 +1,187 @@ +/* 背景样式文件 - 单独管理所有背景相关样式 */ + +/* 主体背景 */ +body { + background: linear-gradient(135deg, #f0fff4 0%, #e6fffa 50%, #f0fff4 100%); + background-attachment: fixed; + position: relative; +} + +/* 背景装饰元素 */ +body::before { + content: ''; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-image: + radial-gradient(circle at 20% 80%, rgba(104, 211, 145, 0.1) 0%, transparent 50%), + radial-gradient(circle at 80% 20%, rgba(72, 187, 120, 0.1) 0%, transparent 50%), + radial-gradient(circle at 40% 40%, rgba(56, 161, 105, 0.05) 0%, transparent 50%); + pointer-events: none; + z-index: -1; +} + +/* 容器背景 */ +.container { + background: rgba(255, 255, 255, 0.1); + backdrop-filter: blur(10px); + border-radius: 20px; + border: 1px solid rgba(255, 255, 255, 0.2); +} + +/* 输入区域背景 */ +.input-section { + background: rgba(255, 255, 255, 0.95); + backdrop-filter: blur(20px); + border: 1px solid rgba(104, 211, 145, 0.2); + position: relative; + overflow: hidden; +} + +.input-section::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 3px; + background: linear-gradient(90deg, #48bb78, #68d391, #9ae6b4); +} + +/* 配色方案卡片背景 */ +.palette { + background: rgba(255, 255, 255, 0.95); + backdrop-filter: blur(15px); + border: 1px solid rgba(104, 211, 145, 0.15); + position: relative; + overflow: hidden; +} + +.palette::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 2px; + background: linear-gradient(90deg, transparent, #68d391, transparent); + opacity: 0; + transition: opacity 0.3s ease; +} + +.palette:hover::before { + opacity: 1; +} + +/* 颜色信息背景 */ +.color-info { + background: rgba(255, 255, 255, 0.9); + backdrop-filter: blur(10px); + border: 1px solid rgba(104, 211, 145, 0.2); +} + +/* 颜色项背景 */ +.color-item { + background: rgba(255, 255, 255, 0.8); + backdrop-filter: blur(5px); + border: 1px solid rgba(104, 211, 145, 0.15); + position: relative; +} + +.color-item::after { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(45deg, transparent 48%, rgba(104, 211, 145, 0.05) 50%, transparent 52%); + opacity: 0; + transition: opacity 0.3s ease; + pointer-events: none; +} + +.color-item:hover::after { + opacity: 1; +} + +/* 颜色详情背景 */ +.color-detail { + background: rgba(104, 211, 145, 0.08); + border: 1px solid rgba(104, 211, 145, 0.1); + position: relative; +} + +.color-detail::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, transparent 100%); + pointer-events: none; +} + +/* 按钮背景 */ +.generate-btn { + background: linear-gradient(135deg, #48bb78 0%, #68d391 50%, #9ae6b4 100%); + position: relative; + overflow: hidden; +} + +.generate-btn::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); + transition: left 0.5s ease; +} + +.generate-btn:hover::before { + left: 100%; +} + +/* 加载动画背景 */ +.loading { + background: rgba(255, 255, 255, 0.9); + backdrop-filter: blur(10px); + border-radius: 12px; + border: 1px solid rgba(104, 211, 145, 0.2); +} + +/* 响应式背景调整 */ +@media (max-width: 768px) { + body { + background: linear-gradient(180deg, #f0fff4 0%, #e6fffa 100%); + } + + .container { + background: rgba(255, 255, 255, 0.05); + backdrop-filter: blur(5px); + } + + .input-section, + .palette, + .color-info { + backdrop-filter: blur(10px); + } +} + +@media (max-width: 480px) { + body::before { + background-image: + radial-gradient(circle at 50% 50%, rgba(104, 211, 145, 0.08) 0%, transparent 70%); + } + + .container { + background: transparent; + backdrop-filter: none; + border: none; + } +} \ No newline at end of file diff --git a/frontend/60sapi/实用功能/配色方案/index.html b/frontend/60sapi/实用功能/配色方案/index.html new file mode 100644 index 00000000..066b2764 --- /dev/null +++ b/frontend/60sapi/实用功能/配色方案/index.html @@ -0,0 +1,64 @@ + + + + + + 配色方案生成器 + + + + +
+
+

配色方案生成器

+

输入颜色值,获取专业的配色方案

+
+ +
+
+
+ +
+ + +
+
+ +
+ + +
+ + +
+ +
+ + + + +
+ +
+
+
+ + +
+ + + + \ No newline at end of file diff --git a/frontend/60sapi/实用功能/配色方案/script.js b/frontend/60sapi/实用功能/配色方案/script.js new file mode 100644 index 00000000..3bf8719f --- /dev/null +++ b/frontend/60sapi/实用功能/配色方案/script.js @@ -0,0 +1,315 @@ +// 配色方案生成器 JavaScript +class ColorPaletteGenerator { + constructor() { + this.apiUrl = 'https://60s.api.shumengya.top/v2/color/palette'; + this.init(); + } + + init() { + this.bindEvents(); + this.loadDefaultPalette(); + } + + bindEvents() { + const colorInput = document.getElementById('colorInput'); + const colorPicker = document.getElementById('colorPicker'); + const generateBtn = document.getElementById('generateBtn'); + const formatSelect = document.getElementById('formatSelect'); + + // 颜色输入框事件 + colorInput.addEventListener('input', (e) => { + const color = e.target.value; + if (this.isValidColor(color)) { + colorPicker.value = color; + } + }); + + // 颜色选择器事件 + colorPicker.addEventListener('change', (e) => { + colorInput.value = e.target.value; + }); + + // 生成按钮事件 + generateBtn.addEventListener('click', () => { + this.generatePalette(); + }); + + // 回车键生成 + colorInput.addEventListener('keypress', (e) => { + if (e.key === 'Enter') { + this.generatePalette(); + } + }); + + // 格式选择事件 + formatSelect.addEventListener('change', () => { + const currentColor = colorInput.value; + if (currentColor && this.isValidColor(currentColor)) { + this.generatePalette(); + } + }); + } + + // 验证颜色格式 + isValidColor(color) { + const hexRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/; + return hexRegex.test(color); + } + + // 显示加载状态 + showLoading() { + const loading = document.getElementById('loading'); + const colorInfo = document.getElementById('colorInfo'); + const palettesContainer = document.getElementById('palettesContainer'); + + loading.style.display = 'block'; + colorInfo.style.display = 'none'; + palettesContainer.innerHTML = ''; + } + + // 隐藏加载状态 + hideLoading() { + const loading = document.getElementById('loading'); + loading.style.display = 'none'; + } + + // 生成配色方案 + async generatePalette() { + const colorInput = document.getElementById('colorInput'); + const formatSelect = document.getElementById('formatSelect'); + const color = colorInput.value.trim(); + const format = formatSelect.value; + + if (!color) { + this.showError('请输入颜色值'); + return; + } + + if (!this.isValidColor(color)) { + this.showError('请输入有效的十六进制颜色值(如:#33AAFF)'); + return; + } + + this.showLoading(); + + try { + const url = new URL(this.apiUrl); + url.searchParams.append('color', color); + url.searchParams.append('encoding', format); + + const response = await fetch(url); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const data = await response.json(); + + if (data.code === 200) { + this.displayResults(data.data); + } else { + throw new Error(data.message || '获取配色方案失败'); + } + } catch (error) { + console.error('Error:', error); + this.showError('获取配色方案失败,请检查网络连接或稍后重试'); + } finally { + this.hideLoading(); + } + } + + // 显示错误信息 + showError(message) { + const palettesContainer = document.getElementById('palettesContainer'); + palettesContainer.innerHTML = ` +
+

❌ ${message}

+
+ `; + } + + // 显示结果 + displayResults(data) { + this.displayColorInfo(data.input); + this.displayPalettes(data.palettes); + } + + // 显示颜色信息 + displayColorInfo(inputData) { + const colorInfo = document.getElementById('colorInfo'); + const colorPreview = document.getElementById('colorPreview'); + const colorDetails = document.getElementById('colorDetails'); + + colorPreview.style.backgroundColor = inputData.hex; + + colorDetails.innerHTML = ` +
+ HEX + ${inputData.hex} +
+
+ RGB + rgb(${inputData.rgb.r}, ${inputData.rgb.g}, ${inputData.rgb.b}) +
+
+ HSL + hsl(${inputData.hsl.h}°, ${inputData.hsl.s}%, ${inputData.hsl.l}%) +
+
+ 色系 + ${inputData.name} +
+ `; + + colorInfo.style.display = 'block'; + } + + // 显示配色方案 + displayPalettes(palettes) { + const palettesContainer = document.getElementById('palettesContainer'); + + palettesContainer.innerHTML = palettes.map(palette => ` +
+
+

${palette.name}

+

${palette.description}

+
+
+ ${palette.colors.map(color => ` +
+
+
+
${color.name}
+
${color.hex}
+
${color.role} • ${color.theory}
+
+ `).join('')} +
+
+ `).join(''); + } + + // 加载默认配色方案 + async loadDefaultPalette() { + const colorInput = document.getElementById('colorInput'); + const defaultColor = colorInput.value; + + if (defaultColor && this.isValidColor(defaultColor)) { + await this.generatePalette(); + } + } +} + +// 复制到剪贴板功能 +function copyToClipboard(text) { + if (navigator.clipboard && window.isSecureContext) { + navigator.clipboard.writeText(text).then(() => { + showToast(`已复制 ${text} 到剪贴板`); + }).catch(err => { + console.error('复制失败:', err); + fallbackCopyTextToClipboard(text); + }); + } else { + fallbackCopyTextToClipboard(text); + } +} + +// 备用复制方法 +function fallbackCopyTextToClipboard(text) { + const textArea = document.createElement('textarea'); + textArea.value = text; + textArea.style.position = 'fixed'; + textArea.style.left = '-999999px'; + textArea.style.top = '-999999px'; + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + + try { + document.execCommand('copy'); + showToast(`已复制 ${text} 到剪贴板`); + } catch (err) { + console.error('复制失败:', err); + showToast('复制失败,请手动复制'); + } + + document.body.removeChild(textArea); +} + +// 显示提示信息 +function showToast(message) { + // 移除已存在的toast + const existingToast = document.querySelector('.toast'); + if (existingToast) { + existingToast.remove(); + } + + const toast = document.createElement('div'); + toast.className = 'toast'; + toast.textContent = message; + toast.style.cssText = ` + position: fixed; + top: 20px; + right: 20px; + background: rgba(45, 90, 39, 0.95); + color: white; + padding: 12px 20px; + border-radius: 8px; + font-size: 14px; + font-weight: 500; + z-index: 10000; + box-shadow: 0 4px 12px rgba(45, 90, 39, 0.3); + transform: translateX(100%); + transition: transform 0.3s ease; + backdrop-filter: blur(10px); + `; + + document.body.appendChild(toast); + + // 动画显示 + setTimeout(() => { + toast.style.transform = 'translateX(0)'; + }, 100); + + // 3秒后隐藏 + setTimeout(() => { + toast.style.transform = 'translateX(100%)'; + setTimeout(() => { + if (toast.parentNode) { + toast.parentNode.removeChild(toast); + } + }, 300); + }, 3000); +} + +// 页面加载完成后初始化 +document.addEventListener('DOMContentLoaded', () => { + new ColorPaletteGenerator(); +}); + +// 添加移动端优化 +if ('ontouchstart' in window) { + // 移动端触摸优化 + document.addEventListener('touchstart', function() {}, {passive: true}); + + // 防止双击缩放 + let lastTouchEnd = 0; + document.addEventListener('touchend', function (event) { + const now = (new Date()).getTime(); + if (now - lastTouchEnd <= 300) { + event.preventDefault(); + } + lastTouchEnd = now; + }, false); +} \ No newline at end of file diff --git a/frontend/60sapi/实用功能/配色方案/styles.css b/frontend/60sapi/实用功能/配色方案/styles.css new file mode 100644 index 00000000..68225012 --- /dev/null +++ b/frontend/60sapi/实用功能/配色方案/styles.css @@ -0,0 +1,422 @@ +/* 基础样式重置 */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif; + line-height: 1.6; + color: #2d3748; + min-height: 100vh; +} + +.container { + max-width: 1200px; + margin: 0 auto; + padding: 20px; + min-height: 100vh; + display: flex; + flex-direction: column; +} + +/* 头部样式 */ +.header { + text-align: center; + margin-bottom: 40px; + padding: 30px 0; +} + +.header h1 { + font-size: 2.5rem; + color: #2d5a27; + margin-bottom: 10px; + font-weight: 700; +} + +.subtitle { + font-size: 1.1rem; + color: #68d391; + font-weight: 400; +} + +/* 主内容区域 */ +.main-content { + flex: 1; + display: flex; + flex-direction: column; + gap: 30px; +} + +/* 输入区域 */ +.input-section { + background: rgba(255, 255, 255, 0.9); + padding: 30px; + border-radius: 16px; + box-shadow: 0 4px 20px rgba(45, 90, 39, 0.1); + border: 1px solid rgba(104, 211, 145, 0.2); +} + +.color-input-group { + margin-bottom: 20px; +} + +.color-input-group label, +.format-select label { + display: block; + margin-bottom: 8px; + font-weight: 600; + color: #2d5a27; + font-size: 0.95rem; +} + +.input-wrapper { + display: flex; + gap: 10px; + align-items: center; +} + +#colorInput { + flex: 1; + padding: 12px 16px; + border: 2px solid #e2e8f0; + border-radius: 8px; + font-size: 1rem; + transition: all 0.3s ease; + background: white; +} + +#colorInput:focus { + outline: none; + border-color: #68d391; + box-shadow: 0 0 0 3px rgba(104, 211, 145, 0.1); +} + +#colorPicker { + width: 50px; + height: 44px; + border: 2px solid #e2e8f0; + border-radius: 8px; + cursor: pointer; + background: none; +} + +.format-select { + margin-bottom: 25px; +} + +#formatSelect { + width: 100%; + padding: 12px 16px; + border: 2px solid #e2e8f0; + border-radius: 8px; + font-size: 1rem; + background: white; + cursor: pointer; + transition: all 0.3s ease; +} + +#formatSelect:focus { + outline: none; + border-color: #68d391; + box-shadow: 0 0 0 3px rgba(104, 211, 145, 0.1); +} + +.generate-btn { + width: 100%; + padding: 14px 24px; + background: linear-gradient(135deg, #48bb78, #68d391); + color: white; + border: none; + border-radius: 8px; + font-size: 1.1rem; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; + box-shadow: 0 4px 12px rgba(72, 187, 120, 0.3); +} + +.generate-btn:hover { + background: linear-gradient(135deg, #38a169, #48bb78); + transform: translateY(-2px); + box-shadow: 0 6px 20px rgba(72, 187, 120, 0.4); +} + +.generate-btn:active { + transform: translateY(0); +} + +/* 结果区域 */ +.result-section { + min-height: 200px; +} + +.loading { + text-align: center; + padding: 40px; +} + +.spinner { + width: 40px; + height: 40px; + border: 4px solid #e2e8f0; + border-top: 4px solid #68d391; + border-radius: 50%; + animation: spin 1s linear infinite; + margin: 0 auto 20px; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +.loading p { + color: #68d391; + font-weight: 500; +} + +/* 颜色信息 */ +.color-info { + background: rgba(255, 255, 255, 0.9); + padding: 25px; + border-radius: 12px; + margin-bottom: 25px; + box-shadow: 0 2px 10px rgba(45, 90, 39, 0.1); + border: 1px solid rgba(104, 211, 145, 0.2); +} + +.color-info h3 { + color: #2d5a27; + margin-bottom: 15px; + font-size: 1.3rem; +} + +.color-preview { + width: 100%; + height: 60px; + border-radius: 8px; + margin-bottom: 15px; + border: 2px solid rgba(104, 211, 145, 0.3); +} + +.color-details { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); + gap: 15px; +} + +.color-detail { + text-align: center; + padding: 10px; + background: rgba(104, 211, 145, 0.1); + border-radius: 6px; +} + +.color-detail strong { + display: block; + color: #2d5a27; + font-size: 0.9rem; + margin-bottom: 5px; +} + +.color-detail span { + color: #4a5568; + font-size: 0.95rem; +} + +/* 配色方案容器 */ +.palettes-container { + display: grid; + gap: 25px; +} + +.palette { + background: rgba(255, 255, 255, 0.9); + border-radius: 12px; + padding: 25px; + box-shadow: 0 4px 15px rgba(45, 90, 39, 0.1); + border: 1px solid rgba(104, 211, 145, 0.2); + transition: transform 0.3s ease, box-shadow 0.3s ease; +} + +.palette:hover { + transform: translateY(-3px); + box-shadow: 0 8px 25px rgba(45, 90, 39, 0.15); +} + +.palette-header { + margin-bottom: 20px; +} + +.palette-name { + font-size: 1.4rem; + color: #2d5a27; + margin-bottom: 8px; + font-weight: 600; +} + +.palette-description { + color: #68d391; + font-size: 0.95rem; + line-height: 1.5; +} + +.colors-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 15px; +} + +.color-item { + background: white; + border-radius: 8px; + padding: 15px; + border: 1px solid rgba(104, 211, 145, 0.2); + transition: all 0.3s ease; +} + +.color-item:hover { + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(45, 90, 39, 0.1); +} + +.color-swatch { + width: 100%; + height: 50px; + border-radius: 6px; + margin-bottom: 10px; + border: 1px solid rgba(0, 0, 0, 0.1); + cursor: pointer; + position: relative; + overflow: hidden; +} + +.color-swatch::after { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(45deg, transparent 45%, rgba(255,255,255,0.1) 50%, transparent 55%); + opacity: 0; + transition: opacity 0.3s ease; +} + +.color-swatch:hover::after { + opacity: 1; +} + +.color-name { + font-weight: 600; + color: #2d5a27; + margin-bottom: 5px; + font-size: 0.9rem; +} + +.color-hex { + font-family: 'Courier New', monospace; + color: #4a5568; + font-size: 0.85rem; + margin-bottom: 3px; +} + +.color-role { + font-size: 0.8rem; + color: #68d391; + font-style: italic; +} + +/* 底部 */ +.footer { + text-align: center; + padding: 30px 0; + margin-top: 40px; + color: #68d391; + font-size: 0.9rem; +} + +/* 平板端适配 */ +@media (max-width: 1024px) { + .container { + padding: 15px; + } + + .header h1 { + font-size: 2.2rem; + } + + .colors-grid { + grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); + } +} + +/* 手机端适配 */ +@media (max-width: 768px) { + .container { + padding: 10px; + } + + .header { + margin-bottom: 25px; + padding: 20px 0; + } + + .header h1 { + font-size: 1.8rem; + } + + .subtitle { + font-size: 1rem; + } + + .input-section { + padding: 20px; + } + + .input-wrapper { + flex-direction: column; + align-items: stretch; + } + + #colorPicker { + width: 100%; + height: 44px; + } + + .colors-grid { + grid-template-columns: 1fr; + } + + .color-details { + grid-template-columns: repeat(2, 1fr); + } + + .palette { + padding: 20px; + } + + .palette-name { + font-size: 1.2rem; + } +} + +@media (max-width: 480px) { + .header h1 { + font-size: 1.6rem; + } + + .input-section { + padding: 15px; + } + + .palette { + padding: 15px; + } + + .color-details { + grid-template-columns: 1fr; + } +} \ No newline at end of file diff --git a/frontend/60sapi/实用功能/配色方案/返回接口.json b/frontend/60sapi/实用功能/配色方案/返回接口.json new file mode 100644 index 00000000..6f353332 --- /dev/null +++ b/frontend/60sapi/实用功能/配色方案/返回接口.json @@ -0,0 +1,273 @@ +{ + "code": 200, + "message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s,反馈群 595941841", + "data": { + "input": { + "hex": "#DE4F99", + "rgb": { + "r": 222, + "g": 79, + "b": 153 + }, + "hsl": { + "h": 329, + "s": 68, + "l": 59 + }, + "name": "红色系" + }, + "palettes": [ + { + "name": "单色配色", + "description": "基于同一色相,通过调整明度和饱和度创建的和谐配色方案,适合营造统一、专业的视觉效果", + "colors": [ + { + "hex": "#DE4F99", + "name": "主色", + "role": "primary", + "theory": "基础色相" + }, + { + "hex": "#7C184C", + "name": "深色变体", + "role": "dark", + "theory": "降低明度" + }, + { + "hex": "#EEA5CB", + "name": "浅色变体", + "role": "light", + "theory": "提高明度" + }, + { + "hex": "#C96498", + "name": "柔和变体", + "role": "muted", + "theory": "降低饱和度" + }, + { + "hex": "#ED4099", + "name": "鲜艳变体", + "role": "vibrant", + "theory": "提高饱和度" + } + ] + }, + { + "name": "互补配色", + "description": "使用色轮上相对的颜色,创造强烈对比和视觉冲击力,适用于需要突出重点的设计", + "colors": [ + { + "hex": "#DE4F99", + "name": "主色", + "role": "primary", + "theory": "基础色相" + }, + { + "hex": "#4FDE94", + "name": "互补色", + "role": "complementary", + "theory": "色轮对面 +180°" + }, + { + "hex": "#F2BAD7", + "name": "主色浅调", + "role": "primary-light", + "theory": "主色提高明度" + }, + { + "hex": "#BAF2D5", + "name": "互补色浅调", + "role": "complementary-light", + "theory": "互补色提高明度" + } + ] + }, + { + "name": "邻近配色", + "description": "使用色轮上相邻的颜色,创造自然和谐的渐变效果,常见于自然景观中", + "colors": [ + { + "hex": "#DB4FDE", + "name": "邻近色1", + "role": "analogous-1", + "theory": "色相 -30°" + }, + { + "hex": "#DE4F99", + "name": "主色", + "role": "primary", + "theory": "基础色相" + }, + { + "hex": "#DE4F52", + "name": "邻近色2", + "role": "analogous-2", + "theory": "色相 +30°" + }, + { + "hex": "#DE944F", + "name": "邻近色3", + "role": "analogous-3", + "theory": "色相 +60°" + } + ] + }, + { + "name": "三角配色", + "description": "在色轮上形成等边三角形的三种颜色,提供丰富对比的同时保持和谐平衡", + "colors": [ + { + "hex": "#DE4F99", + "name": "主色", + "role": "primary", + "theory": "基础色相" + }, + { + "hex": "#99DE4F", + "name": "三角色1", + "role": "triadic-1", + "theory": "色相 +120°" + }, + { + "hex": "#4F99DE", + "name": "三角色2", + "role": "triadic-2", + "theory": "色相 +240°" + } + ] + }, + { + "name": "分裂互补配色", + "description": "使用互补色两侧的颜色,比纯互补配色更柔和,同时保持强烈的视觉对比", + "colors": [ + { + "hex": "#DE4F99", + "name": "主色", + "role": "primary", + "theory": "基础色相" + }, + { + "hex": "#52DE4F", + "name": "分裂互补色1", + "role": "split-comp-1", + "theory": "互补色 -30°" + }, + { + "hex": "#4FDEDB", + "name": "分裂互补色2", + "role": "split-comp-2", + "theory": "互补色 +30°" + } + ] + }, + { + "name": "四边形配色", + "description": "在色轮上形成正方形的四种颜色,提供最丰富的颜色变化,适合复杂的设计项目", + "colors": [ + { + "hex": "#DE4F99", + "name": "主色", + "role": "primary", + "theory": "基础色相" + }, + { + "hex": "#DEDB4F", + "name": "四边形色1", + "role": "square-1", + "theory": "色相 +90°" + }, + { + "hex": "#4FDE94", + "name": "四边形色2", + "role": "square-2", + "theory": "色相 +180°" + }, + { + "hex": "#4F52DE", + "name": "四边形色3", + "role": "square-3", + "theory": "色相 +270°" + } + ] + }, + { + "name": "Web 设计配色", + "description": "专为 Web 界面设计优化的配色方案,考虑了可访问性和用户体验", + "colors": [ + { + "hex": "#DE4F99", + "name": "品牌主色", + "role": "brand-primary", + "theory": "品牌识别色" + }, + { + "hex": "#982F65", + "name": "按钮悬停", + "role": "hover-state", + "theory": "主色加深变体" + }, + { + "hex": "#F6E9F0", + "name": "背景浅色", + "role": "background", + "theory": "高明度低饱和度" + }, + { + "hex": "#1BDE7A", + "name": "强调色", + "role": "accent", + "theory": "互补色系强调" + }, + { + "hex": "#6B7280", + "name": "文本辅助", + "role": "text-secondary", + "theory": "中性灰色文本" + } + ] + }, + { + "name": "暖色调配色", + "description": "基于暖色系的配色方案,营造温暖、活力和友好的氛围,适合餐饮、儿童产品等", + "colors": [ + { + "hex": "#DE4F99", + "name": "主暖色", + "role": "warm-primary", + "theory": "暖色系基调" + }, + { + "hex": "#DE4FC8", + "name": "暖色变体1", + "role": "warm-variant-1", + "theory": "暖色范围内调整" + }, + { + "hex": "#DE4F5E", + "name": "暖色变体2", + "role": "warm-variant-2", + "theory": "暖色范围内调整" + }, + { + "hex": "#EEA5CB", + "name": "暖色浅调", + "role": "warm-tint", + "theory": "提高明度的暖色" + } + ] + } + ], + "metadata": { + "color_theory": "基于色彩理论生成的专业配色方案", + "total_palettes": 8, + "applications": [ + "Web 设计", + "UI/UX", + "品牌设计", + "室内设计", + "服装搭配" + ] + } + } +} \ No newline at end of file diff --git a/frontend/60sapi/实用功能/随机密码生成器/css/background.css b/frontend/60sapi/实用功能/随机密码生成器/css/background.css new file mode 100644 index 00000000..4108e5b7 --- /dev/null +++ b/frontend/60sapi/实用功能/随机密码生成器/css/background.css @@ -0,0 +1,252 @@ +/* 背景样式文件 */ + +/* 主背景渐变 */ +body { + background: linear-gradient(135deg, #e8f5e8 0%, #f0f9f0 25%, #f8fdf8 50%, #e8f5e8 75%, #f0f9f0 100%); + background-size: 400% 400%; + animation: gradientShift 15s ease infinite; + position: relative; + overflow-x: hidden; +} + +/* 背景渐变动画 */ +@keyframes gradientShift { + 0% { + background-position: 0% 50%; + } + 50% { + background-position: 100% 50%; + } + 100% { + background-position: 0% 50%; + } +} + +/* 装饰性背景元素 */ +body::before { + content: ''; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-image: + radial-gradient(circle at 20% 80%, rgba(76, 175, 80, 0.1) 0%, transparent 50%), + radial-gradient(circle at 80% 20%, rgba(45, 90, 61, 0.08) 0%, transparent 50%), + radial-gradient(circle at 40% 40%, rgba(76, 175, 80, 0.05) 0%, transparent 50%); + pointer-events: none; + z-index: -2; +} + +/* 浮动装饰圆点 */ +body::after { + content: ''; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-image: + radial-gradient(2px 2px at 20px 30px, rgba(76, 175, 80, 0.3), transparent), + radial-gradient(2px 2px at 40px 70px, rgba(45, 90, 61, 0.2), transparent), + radial-gradient(1px 1px at 90px 40px, rgba(76, 175, 80, 0.4), transparent), + radial-gradient(1px 1px at 130px 80px, rgba(45, 90, 61, 0.3), transparent), + radial-gradient(2px 2px at 160px 30px, rgba(76, 175, 80, 0.2), transparent); + background-repeat: repeat; + background-size: 200px 100px; + animation: floatDots 20s linear infinite; + pointer-events: none; + z-index: -1; + opacity: 0.6; +} + +/* 圆点浮动动画 */ +@keyframes floatDots { + 0% { + transform: translateY(0px) translateX(0px); + } + 33% { + transform: translateY(-10px) translateX(5px); + } + 66% { + transform: translateY(5px) translateX(-5px); + } + 100% { + transform: translateY(0px) translateX(0px); + } +} + +/* 网格背景(可选,默认隐藏) */ +.grid-background { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-image: + linear-gradient(rgba(76, 175, 80, 0.03) 1px, transparent 1px), + linear-gradient(90deg, rgba(76, 175, 80, 0.03) 1px, transparent 1px); + background-size: 50px 50px; + pointer-events: none; + z-index: -3; + opacity: 0; + transition: opacity 0.3s ease; +} + +.grid-background.active { + opacity: 1; +} + +/* 响应式背景调整 */ +@media (max-width: 768px) { + body::after { + background-size: 150px 75px; + animation-duration: 25s; + } + + body::before { + background-image: + radial-gradient(circle at 30% 70%, rgba(76, 175, 80, 0.08) 0%, transparent 50%), + radial-gradient(circle at 70% 30%, rgba(45, 90, 61, 0.06) 0%, transparent 50%); + } +} + +@media (max-width: 480px) { + body { + animation-duration: 20s; + } + + body::after { + background-size: 100px 50px; + opacity: 0.4; + } +} + +/* 高对比度模式下的背景调整 */ +@media (prefers-contrast: high) { + body { + background: #f8fdf8; + animation: none; + } + + body::before, + body::after { + display: none; + } +} + +/* 减少动画模式下的背景调整 */ +@media (prefers-reduced-motion: reduce) { + body { + animation: none; + background: linear-gradient(135deg, #e8f5e8 0%, #f0f9f0 50%, #f8fdf8 100%); + } + + body::after { + animation: none; + } + + @keyframes gradientShift { + 0%, 100% { + background-position: 0% 50%; + } + } + + @keyframes floatDots { + 0%, 100% { + transform: translateY(0px) translateX(0px); + } + } +} + +/* 深色模式支持 */ +@media (prefers-color-scheme: dark) { + body { + background: linear-gradient(135deg, #1a2e1a 0%, #2d4a2d 25%, #1f3a1f 50%, #1a2e1a 75%, #2d4a2d 100%); + } + + body::before { + background-image: + radial-gradient(circle at 20% 80%, rgba(76, 175, 80, 0.15) 0%, transparent 50%), + radial-gradient(circle at 80% 20%, rgba(144, 238, 144, 0.1) 0%, transparent 50%), + radial-gradient(circle at 40% 40%, rgba(76, 175, 80, 0.08) 0%, transparent 50%); + } + + body::after { + background-image: + radial-gradient(2px 2px at 20px 30px, rgba(144, 238, 144, 0.4), transparent), + radial-gradient(2px 2px at 40px 70px, rgba(76, 175, 80, 0.3), transparent), + radial-gradient(1px 1px at 90px 40px, rgba(144, 238, 144, 0.5), transparent), + radial-gradient(1px 1px at 130px 80px, rgba(76, 175, 80, 0.4), transparent), + radial-gradient(2px 2px at 160px 30px, rgba(144, 238, 144, 0.3), transparent); + } +} + +/* 打印样式 */ +@media print { + body { + background: white !important; + animation: none !important; + } + + body::before, + body::after { + display: none !important; + } +} + +/* 特殊效果:鼠标悬停时的背景变化 */ +@media (hover: hover) { + .container:hover { + position: relative; + } + + .container:hover::before { + content: ''; + position: absolute; + top: -20px; + left: -20px; + right: -20px; + bottom: -20px; + background: radial-gradient(circle at var(--mouse-x, 50%) var(--mouse-y, 50%), rgba(76, 175, 80, 0.05) 0%, transparent 50%); + border-radius: 30px; + pointer-events: none; + z-index: -1; + transition: opacity 0.3s ease; + } +} + +/* 季节性主题变化(可通过JavaScript控制) */ +.theme-spring body { + background: linear-gradient(135deg, #e8f5e8 0%, #f0f9f0 25%, #e1f5e1 50%, #f8fdf8 75%, #e8f5e8 100%); +} + +.theme-summer body { + background: linear-gradient(135deg, #f0f9f0 0%, #e8f5e8 25%, #f8fdf8 50%, #e1f5e1 75%, #f0f9f0 100%); +} + +.theme-autumn body { + background: linear-gradient(135deg, #f5f0e8 0%, #f9f5f0 25%, #fdf8f0 50%, #f5f0e8 75%, #f9f5f0 100%); +} + +.theme-winter body { + background: linear-gradient(135deg, #f0f5f8 0%, #f5f9fc 25%, #f8fbfd 50%, #f0f5f8 75%, #f5f9fc 100%); +} + +/* 性能优化:GPU加速 */ +body, +body::before, +body::after { + will-change: transform; + transform: translateZ(0); +} + +/* 无障碍支持:为屏幕阅读器隐藏装饰元素 */ +body::before, +body::after { + speak: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} \ No newline at end of file diff --git a/frontend/60sapi/实用功能/随机密码生成器/css/style.css b/frontend/60sapi/实用功能/随机密码生成器/css/style.css new file mode 100644 index 00000000..2793ae86 --- /dev/null +++ b/frontend/60sapi/实用功能/随机密码生成器/css/style.css @@ -0,0 +1,647 @@ +/* 基础样式重置 */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif; + line-height: 1.6; + color: #2d5a3d; + min-height: 100vh; + overflow-x: hidden; +} + +/* 容器布局 */ +.container { + max-width: 800px; + margin: 0 auto; + padding: 20px; + min-height: 100vh; + display: flex; + flex-direction: column; +} + +/* 头部样式 */ +.header { + text-align: center; + margin-bottom: 40px; + padding: 30px 20px; + background: linear-gradient(135deg, #e8f5e8 0%, #f0f9f0 100%); + border-radius: 20px; + box-shadow: 0 4px 20px rgba(45, 90, 61, 0.1); +} + +.header h1 { + font-size: 2.5rem; + font-weight: 700; + color: #2d5a3d; + margin-bottom: 10px; + text-shadow: 0 2px 4px rgba(45, 90, 61, 0.1); +} + +.subtitle { + font-size: 1.1rem; + color: #5a8a6b; + font-weight: 400; +} + +/* 主内容区域 */ +.main-content { + flex: 1; + display: flex; + flex-direction: column; + gap: 30px; +} + +/* 表单容器 */ +.form-container { + background: #ffffff; + border-radius: 16px; + padding: 30px; + box-shadow: 0 8px 32px rgba(45, 90, 61, 0.1); + border: 1px solid #e8f5e8; +} + +.password-form { + display: flex; + flex-direction: column; + gap: 25px; +} + +/* 表单组样式 */ +.form-group { + display: flex; + flex-direction: column; + gap: 12px; +} + +.form-group label { + font-weight: 600; + color: #2d5a3d; + font-size: 1rem; +} + +.section-title { + font-size: 1.1rem; + color: #2d5a3d; + font-weight: 600; + margin-bottom: 8px; +} + +/* 长度控制 */ +.length-control { + display: flex; + align-items: center; + gap: 15px; + padding: 15px; + background: #f8fdf8; + border-radius: 12px; + border: 2px solid #e8f5e8; +} + +.length-slider { + flex: 1; + height: 6px; + background: #e8f5e8; + border-radius: 3px; + outline: none; + -webkit-appearance: none; +} + +.length-slider::-webkit-slider-thumb { + -webkit-appearance: none; + width: 20px; + height: 20px; + background: linear-gradient(135deg, #4caf50, #45a049); + border-radius: 50%; + cursor: pointer; + box-shadow: 0 2px 8px rgba(76, 175, 80, 0.3); +} + +.length-slider::-moz-range-thumb { + width: 20px; + height: 20px; + background: linear-gradient(135deg, #4caf50, #45a049); + border-radius: 50%; + cursor: pointer; + border: none; + box-shadow: 0 2px 8px rgba(76, 175, 80, 0.3); +} + +.length-display { + min-width: 40px; + text-align: center; + font-weight: 700; + font-size: 1.2rem; + color: #2d5a3d; + background: #ffffff; + padding: 8px 12px; + border-radius: 8px; + border: 2px solid #e8f5e8; +} + +/* 复选框组 */ +.checkbox-group { + display: flex; + flex-direction: column; + gap: 12px; +} + +.checkbox-item { + display: flex; + align-items: center; + gap: 12px; + padding: 12px 16px; + background: #f8fdf8; + border-radius: 10px; + border: 2px solid #e8f5e8; + transition: all 0.3s ease; + cursor: pointer; +} + +.checkbox-item:hover { + background: #f0f9f0; + border-color: #d4edda; + transform: translateY(-1px); +} + +.checkbox-item input[type="checkbox"] { + width: 18px; + height: 18px; + accent-color: #4caf50; + cursor: pointer; +} + +.checkbox-item label { + flex: 1; + cursor: pointer; + font-weight: 500; + color: #2d5a3d; + margin: 0; +} + +/* 生成按钮 */ +.generate-btn { + background: linear-gradient(135deg, #4caf50, #45a049); + color: white; + border: none; + padding: 16px 32px; + border-radius: 12px; + font-size: 1.1rem; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; + box-shadow: 0 4px 16px rgba(76, 175, 80, 0.3); + position: relative; + overflow: hidden; +} + +.generate-btn:hover { + transform: translateY(-2px); + box-shadow: 0 6px 20px rgba(76, 175, 80, 0.4); +} + +.generate-btn:active { + transform: translateY(0); +} + +.generate-btn:disabled { + opacity: 0.7; + cursor: not-allowed; + transform: none; +} + +/* 结果容器 */ +.result-container { + background: #ffffff; + border-radius: 16px; + padding: 30px; + box-shadow: 0 8px 32px rgba(45, 90, 61, 0.1); + border: 1px solid #e8f5e8; + animation: slideIn 0.5s ease-out; +} + +@keyframes slideIn { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.result-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 20px; +} + +.result-header h3 { + color: #2d5a3d; + font-size: 1.3rem; + font-weight: 600; +} + +.copy-btn { + background: #4caf50; + color: white; + border: none; + padding: 10px; + border-radius: 8px; + cursor: pointer; + transition: all 0.3s ease; + display: flex; + align-items: center; + justify-content: center; +} + +.copy-btn:hover { + background: #45a049; + transform: scale(1.05); +} + +/* 密码显示 */ +.password-display { + margin-bottom: 25px; +} + +.password-input { + width: 100%; + padding: 16px 20px; + border: 2px solid #e8f5e8; + border-radius: 12px; + font-family: 'Courier New', monospace; + font-size: 1.1rem; + font-weight: 600; + color: #2d5a3d; + background: #f8fdf8; + text-align: center; + letter-spacing: 1px; + word-break: break-all; +} + +.password-input:focus { + outline: none; + border-color: #4caf50; + box-shadow: 0 0 0 3px rgba(76, 175, 80, 0.1); +} + +/* 密码信息 */ +.password-info { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); + gap: 15px; + margin-bottom: 25px; +} + +.info-item { + display: flex; + flex-direction: column; + gap: 5px; + padding: 12px 16px; + background: #f8fdf8; + border-radius: 10px; + border: 1px solid #e8f5e8; +} + +.info-item.full-width { + grid-column: 1 / -1; +} + +.info-label { + font-size: 0.9rem; + color: #5a8a6b; + font-weight: 500; +} + +.info-value { + font-size: 1rem; + color: #2d5a3d; + font-weight: 600; +} + +.info-value.strength { + padding: 4px 8px; + border-radius: 6px; + text-align: center; + color: white; + font-weight: 700; +} + +.strength.weak { + background: #f44336; +} + +.strength.medium { + background: #ff9800; +} + +.strength.strong { + background: #4caf50; +} + +.strength.very-strong { + background: #2e7d32; +} + +/* 字符集显示 */ +.character-sets { + border-top: 1px solid #e8f5e8; + padding-top: 20px; +} + +.character-sets h4 { + color: #2d5a3d; + margin-bottom: 15px; + font-size: 1.1rem; +} + +.sets-list { + display: flex; + flex-wrap: wrap; + gap: 10px; +} + +.set-item { + background: #e8f5e8; + color: #2d5a3d; + padding: 6px 12px; + border-radius: 20px; + font-size: 0.9rem; + font-weight: 500; +} + +/* 错误容器 */ +.error-container { + background: #ffffff; + border-radius: 16px; + padding: 40px 30px; + text-align: center; + box-shadow: 0 8px 32px rgba(244, 67, 54, 0.1); + border: 1px solid #ffebee; +} + +.error-icon { + font-size: 3rem; + margin-bottom: 15px; +} + +.error-container h3 { + color: #d32f2f; + margin-bottom: 10px; + font-size: 1.3rem; +} + +.error-container p { + color: #666; + margin-bottom: 20px; +} + +.retry-btn { + background: #f44336; + color: white; + border: none; + padding: 12px 24px; + border-radius: 8px; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; +} + +.retry-btn:hover { + background: #d32f2f; + transform: translateY(-1px); +} + +/* 页脚 */ +.footer { + text-align: center; + padding: 30px 20px; + color: #5a8a6b; + font-size: 0.9rem; +} + +/* 提示框 */ +.toast { + position: fixed; + top: 20px; + right: 20px; + background: #4caf50; + color: white; + padding: 12px 20px; + border-radius: 8px; + box-shadow: 0 4px 12px rgba(76, 175, 80, 0.3); + z-index: 1000; + animation: toastSlide 0.3s ease-out; +} + +@keyframes toastSlide { + from { + transform: translateX(100%); + opacity: 0; + } + to { + transform: translateX(0); + opacity: 1; + } +} + +/* 平板端适配 (768px - 1024px) */ +@media (min-width: 768px) and (max-width: 1024px) { + .container { + max-width: 700px; + padding: 25px; + } + + .header h1 { + font-size: 2.2rem; + } + + .form-container, + .result-container { + padding: 25px; + } + + .password-info { + grid-template-columns: repeat(2, 1fr); + } +} + +/* 手机端适配 (最大767px) */ +@media (max-width: 767px) { + .container { + padding: 15px; + max-width: 100%; + } + + .header { + padding: 20px 15px; + margin-bottom: 25px; + } + + .header h1 { + font-size: 1.8rem; + } + + .subtitle { + font-size: 1rem; + } + + .form-container, + .result-container { + padding: 20px; + border-radius: 12px; + } + + .password-form { + gap: 20px; + } + + .form-group { + gap: 10px; + } + + .length-control { + padding: 12px; + gap: 12px; + } + + .length-display { + min-width: 35px; + padding: 6px 10px; + font-size: 1.1rem; + } + + .checkbox-item { + padding: 10px 12px; + gap: 10px; + } + + .checkbox-item input[type="checkbox"] { + width: 16px; + height: 16px; + } + + .generate-btn { + padding: 14px 28px; + font-size: 1rem; + } + + .password-input { + padding: 14px 16px; + font-size: 1rem; + letter-spacing: 0.5px; + } + + .password-info { + grid-template-columns: 1fr; + gap: 12px; + } + + .info-item { + padding: 10px 12px; + } + + .result-header { + flex-direction: column; + gap: 15px; + align-items: stretch; + } + + .copy-btn { + align-self: center; + padding: 12px 20px; + border-radius: 10px; + } + + .toast { + right: 15px; + left: 15px; + top: 15px; + text-align: center; + } +} + +/* 小屏手机适配 (最大480px) */ +@media (max-width: 480px) { + .container { + padding: 10px; + } + + .header { + padding: 15px 10px; + margin-bottom: 20px; + } + + .header h1 { + font-size: 1.6rem; + } + + .form-container, + .result-container { + padding: 15px; + } + + .checkbox-item { + padding: 8px 10px; + } + + .generate-btn { + padding: 12px 24px; + } + + .password-input { + padding: 12px 14px; + font-size: 0.95rem; + } +} + +/* 触摸设备优化 */ +@media (hover: none) and (pointer: coarse) { + .checkbox-item, + .generate-btn, + .copy-btn, + .retry-btn { + min-height: 44px; + } + + .checkbox-item input[type="checkbox"] { + width: 20px; + height: 20px; + } + + .length-slider::-webkit-slider-thumb { + width: 24px; + height: 24px; + } +} + +/* 高对比度模式支持 */ +@media (prefers-contrast: high) { + .form-container, + .result-container { + border: 2px solid #2d5a3d; + } + + .checkbox-item { + border: 1px solid #2d5a3d; + } + + .password-input { + border: 2px solid #2d5a3d; + } +} + +/* 减少动画模式支持 */ +@media (prefers-reduced-motion: reduce) { + * { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } +} \ No newline at end of file diff --git a/frontend/60sapi/实用功能/随机密码生成器/index.html b/frontend/60sapi/实用功能/随机密码生成器/index.html new file mode 100644 index 00000000..baada2f2 --- /dev/null +++ b/frontend/60sapi/实用功能/随机密码生成器/index.html @@ -0,0 +1,146 @@ + + + + + + 随机密码生成器 + + + + +
+
+

🔐 随机密码生成器

+

生成安全可靠的随机密码

+
+ +
+
+
+
+ +
+ + 16 +
+
+ +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+ +
+
+ + +
+
+ + +
+
+
+ + +
+
+ + + + +
+ + +
+ + + + + + \ No newline at end of file diff --git a/frontend/60sapi/实用功能/随机密码生成器/js/script.js b/frontend/60sapi/实用功能/随机密码生成器/js/script.js new file mode 100644 index 00000000..a8e56061 --- /dev/null +++ b/frontend/60sapi/实用功能/随机密码生成器/js/script.js @@ -0,0 +1,412 @@ +class PasswordGenerator { + constructor() { + this.apiUrl = 'https://60s.api.shumengya.top/v2/password'; + this.loadStartTime = 0; + this.init(); + } + + init() { + this.bindEvents(); + this.updateLengthDisplay(); + this.preloadResources(); + } + + preloadResources() { + // 预连接API服务器 + const link = document.createElement('link'); + link.rel = 'preconnect'; + link.href = 'https://60s.api.shumengya.top'; + document.head.appendChild(link); + } + + bindEvents() { + // 长度滑块事件 + const lengthSlider = document.getElementById('length'); + lengthSlider.addEventListener('input', () => this.updateLengthDisplay()); + + // 生成按钮事件 + const generateBtn = document.getElementById('generateBtn'); + generateBtn.addEventListener('click', () => this.generatePassword()); + + // 复制按钮事件 + const copyBtn = document.getElementById('copyBtn'); + copyBtn.addEventListener('click', () => this.copyPassword()); + + // 重试按钮事件 + const retryBtn = document.getElementById('retryBtn'); + retryBtn.addEventListener('click', () => this.generatePassword()); + + // 复选框变化事件 + const checkboxes = document.querySelectorAll('input[type="checkbox"]'); + checkboxes.forEach(checkbox => { + checkbox.addEventListener('change', () => this.validateForm()); + }); + + // 键盘快捷键 + document.addEventListener('keydown', (e) => { + if (e.ctrlKey && e.key === 'Enter') { + e.preventDefault(); + this.generatePassword(); + } + if (e.ctrlKey && e.key === 'c' && document.activeElement.id === 'passwordResult') { + this.copyPassword(); + } + }); + } + + updateLengthDisplay() { + const lengthSlider = document.getElementById('length'); + const lengthDisplay = document.getElementById('lengthDisplay'); + lengthDisplay.textContent = lengthSlider.value; + } + + validateForm() { + const checkboxes = document.querySelectorAll('input[type="checkbox"]:checked'); + const generateBtn = document.getElementById('generateBtn'); + + // 至少需要选择一种字符类型 + const hasCharacterType = Array.from(checkboxes).some(cb => + ['numbers', 'uppercase', 'lowercase', 'symbols'].includes(cb.id) + ); + + generateBtn.disabled = !hasCharacterType; + + if (!hasCharacterType) { + this.showToast('请至少选择一种字符类型', 'warning'); + } + } + + async generatePassword() { + this.loadStartTime = Date.now(); + + try { + this.showLoading(true); + this.hideError(); + + const params = this.getFormParams(); + const password = await this.callAPI(params); + + if (password) { + this.displayPassword(password, params); + this.showToast('密码生成成功!', 'success'); + + const loadTime = Date.now() - this.loadStartTime; + console.log(`密码生成完成,耗时: ${loadTime}ms`); + } + } catch (error) { + console.error('生成密码失败:', error); + this.showError(error.message || '生成密码时发生错误,请重试'); + } finally { + this.showLoading(false); + } + } + + getFormParams() { + const length = document.getElementById('length').value; + const numbers = document.getElementById('numbers').checked; + const uppercase = document.getElementById('uppercase').checked; + const lowercase = document.getElementById('lowercase').checked; + const symbols = document.getElementById('symbols').checked; + const excludeSimilar = document.getElementById('excludeSimilar').checked; + const excludeAmbiguous = document.getElementById('excludeAmbiguous').checked; + + return { + length: parseInt(length), + numbers: numbers ? 'true' : 'false', + uppercase: uppercase ? 'true' : 'false', + lowercase: lowercase ? 'true' : 'false', + symbols: symbols ? 'true' : 'false', + exclude_similar: excludeSimilar ? 'true' : 'false', + exclude_ambiguous: excludeAmbiguous ? 'true' : 'false', + encoding: 'json' + }; + } + + async callAPI(params) { + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), 5000); + + try { + const url = new URL(this.apiUrl); + Object.keys(params).forEach(key => { + if (params[key] !== undefined && params[key] !== null) { + url.searchParams.append(key, params[key]); + } + }); + + const response = await fetch(url.toString(), { + method: 'GET', + signal: controller.signal, + headers: { + 'Accept': 'application/json', + 'User-Agent': 'PasswordGenerator/1.0' + } + }); + + clearTimeout(timeoutId); + + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + + const data = await response.json(); + + if (data.code === 200 && data.data && data.data.password) { + return data.data.password; + } else { + throw new Error(data.message || '服务器返回了无效的密码数据'); + } + } catch (error) { + clearTimeout(timeoutId); + + if (error.name === 'AbortError') { + throw new Error('请求超时,请检查网络连接后重试'); + } + + if (error.message.includes('Failed to fetch')) { + throw new Error('网络连接失败,请检查网络后重试'); + } + + throw error; + } + } + + displayPassword(password, params) { + // 显示结果容器 + const resultContainer = document.getElementById('resultContainer'); + const errorContainer = document.getElementById('errorContainer'); + + resultContainer.style.display = 'block'; + errorContainer.style.display = 'none'; + + // 设置密码 + const passwordInput = document.getElementById('passwordResult'); + passwordInput.value = password; + + // 计算并显示密码信息 + this.updatePasswordInfo(password, params); + + // 滚动到结果区域 + resultContainer.scrollIntoView({ behavior: 'smooth', block: 'start' }); + } + + updatePasswordInfo(password, params) { + // 基本信息 + document.getElementById('infoLength').textContent = password.length; + document.getElementById('infoEntropy').textContent = this.calculateEntropy(password).toFixed(1); + + // 密码强度 + const strength = this.calculateStrength(password); + const strengthElement = document.getElementById('infoStrength'); + strengthElement.textContent = strength.text; + strengthElement.className = `info-value strength ${strength.class}`; + + // 字符类型统计 + const stats = this.analyzeCharacters(password); + document.getElementById('infoNumbers').textContent = stats.numbers; + document.getElementById('infoUppercase').textContent = stats.uppercase; + document.getElementById('infoLowercase').textContent = stats.lowercase; + document.getElementById('infoSymbols').textContent = stats.symbols; + + // 使用的字符集 + this.updateCharacterSets(params); + + // 破解时间估算 + document.getElementById('infoCrackTime').textContent = this.estimateCrackTime(password); + } + + calculateEntropy(password) { + const charset = this.getCharsetSize(password); + return Math.log2(Math.pow(charset, password.length)); + } + + getCharsetSize(password) { + let size = 0; + if (/[0-9]/.test(password)) size += 10; + if (/[a-z]/.test(password)) size += 26; + if (/[A-Z]/.test(password)) size += 26; + if (/[^a-zA-Z0-9]/.test(password)) size += 32; + return size; + } + + calculateStrength(password) { + const entropy = this.calculateEntropy(password); + + if (entropy < 30) { + return { text: '弱', class: 'weak' }; + } else if (entropy < 50) { + return { text: '中等', class: 'medium' }; + } else if (entropy < 70) { + return { text: '强', class: 'strong' }; + } else { + return { text: '非常强', class: 'very-strong' }; + } + } + + analyzeCharacters(password) { + return { + numbers: (password.match(/[0-9]/g) || []).length, + uppercase: (password.match(/[A-Z]/g) || []).length, + lowercase: (password.match(/[a-z]/g) || []).length, + symbols: (password.match(/[^a-zA-Z0-9]/g) || []).length + }; + } + + updateCharacterSets(params) { + const setsList = document.getElementById('setsList'); + const sets = []; + + if (params.numbers === 'true') sets.push('数字 (0-9)'); + if (params.uppercase === 'true') sets.push('大写字母 (A-Z)'); + if (params.lowercase === 'true') sets.push('小写字母 (a-z)'); + if (params.symbols === 'true') sets.push('特殊字符 (!@#$...)'); + + setsList.innerHTML = sets.map(set => `${set}`).join(''); + } + + estimateCrackTime(password) { + const charset = this.getCharsetSize(password); + const combinations = Math.pow(charset, password.length); + const guessesPerSecond = 1e9; // 假设每秒10亿次尝试 + const secondsToCrack = combinations / (2 * guessesPerSecond); + + if (secondsToCrack < 60) { + return '不到1分钟'; + } else if (secondsToCrack < 3600) { + return `${Math.ceil(secondsToCrack / 60)}分钟`; + } else if (secondsToCrack < 86400) { + return `${Math.ceil(secondsToCrack / 3600)}小时`; + } else if (secondsToCrack < 31536000) { + return `${Math.ceil(secondsToCrack / 86400)}天`; + } else if (secondsToCrack < 31536000000) { + return `${Math.ceil(secondsToCrack / 31536000)}年`; + } else { + return '数千年以上'; + } + } + + async copyPassword() { + const passwordInput = document.getElementById('passwordResult'); + + try { + if (navigator.clipboard && window.isSecureContext) { + await navigator.clipboard.writeText(passwordInput.value); + } else { + // 降级方案 + passwordInput.select(); + passwordInput.setSelectionRange(0, 99999); + document.execCommand('copy'); + } + + this.showToast('密码已复制到剪贴板!', 'success'); + + // 复制按钮反馈 + const copyBtn = document.getElementById('copyBtn'); + const originalText = copyBtn.innerHTML; + copyBtn.innerHTML = '✓ 已复制'; + copyBtn.style.background = '#2e7d32'; + + setTimeout(() => { + copyBtn.innerHTML = originalText; + copyBtn.style.background = ''; + }, 2000); + + } catch (error) { + console.error('复制失败:', error); + this.showToast('复制失败,请手动选择密码', 'error'); + } + } + + showLoading(show) { + const generateBtn = document.getElementById('generateBtn'); + + if (show) { + generateBtn.disabled = true; + generateBtn.innerHTML = ' 生成中...'; + } else { + generateBtn.disabled = false; + generateBtn.innerHTML = '🔐 生成密码'; + } + } + + showError(message) { + const errorContainer = document.getElementById('errorContainer'); + const resultContainer = document.getElementById('resultContainer'); + const errorMessage = document.getElementById('errorMessage'); + + errorMessage.textContent = message; + errorContainer.style.display = 'block'; + resultContainer.style.display = 'none'; + + errorContainer.scrollIntoView({ behavior: 'smooth', block: 'start' }); + } + + hideError() { + const errorContainer = document.getElementById('errorContainer'); + errorContainer.style.display = 'none'; + } + + showToast(message, type = 'info') { + // 移除现有的toast + const existingToast = document.querySelector('.toast'); + if (existingToast) { + existingToast.remove(); + } + + const toast = document.createElement('div'); + toast.className = 'toast'; + toast.textContent = message; + + // 根据类型设置颜色 + const colors = { + success: '#4caf50', + error: '#f44336', + warning: '#ff9800', + info: '#2196f3' + }; + + toast.style.background = colors[type] || colors.info; + + document.body.appendChild(toast); + + // 3秒后自动移除 + setTimeout(() => { + if (toast.parentNode) { + toast.remove(); + } + }, 3000); + } +} + +// 添加旋转动画样式 +const style = document.createElement('style'); +style.textContent = ` + @keyframes spin { + from { transform: rotate(0deg); } + to { transform: rotate(360deg); } + } +`; +document.head.appendChild(style); + +// 页面加载完成后初始化 +document.addEventListener('DOMContentLoaded', () => { + new PasswordGenerator(); +}); + +// 页面可见性变化时的处理 +document.addEventListener('visibilitychange', () => { + if (document.visibilityState === 'visible') { + // 页面重新可见时,可以进行一些刷新操作 + console.log('页面重新可见'); + } +}); + +// 错误处理 +window.addEventListener('error', (event) => { + console.error('全局错误:', event.error); +}); + +window.addEventListener('unhandledrejection', (event) => { + console.error('未处理的Promise拒绝:', event.reason); + event.preventDefault(); +}); \ No newline at end of file diff --git a/frontend/60sapi/实用功能/随机密码生成器/返回接口.json b/frontend/60sapi/实用功能/随机密码生成器/返回接口.json new file mode 100644 index 00000000..3b91a5e8 --- /dev/null +++ b/frontend/60sapi/实用功能/随机密码生成器/返回接口.json @@ -0,0 +1,32 @@ +{ + "code": 200, + "message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s,反馈群 595941841", + "data": { + "password": "8mr2M7dZ6E3saj3F", + "length": 16, + "config": { + "include_numbers": true, + "include_symbols": false, + "include_lowercase": true, + "include_uppercase": true, + "exclude_similar": true, + "exclude_ambiguous": true + }, + "character_sets": { + "lowercase": "abcdefghjkmnpqrstuvwxyz", + "uppercase": "ABCDEFGHIJKMNPQRSTUVWXYZ", + "numbers": "23456789", + "symbols": "", + "used_sets": [ + "lowercase", + "uppercase", + "numbers" + ] + }, + "generation_info": { + "entropy": 92.5, + "strength": "极强", + "time_to_crack": "数百万年" + } + } +} \ No newline at end of file diff --git a/frontend/60sapi/实用功能/随机颜色/background.css b/frontend/60sapi/实用功能/随机颜色/background.css new file mode 100644 index 00000000..81e610a9 --- /dev/null +++ b/frontend/60sapi/实用功能/随机颜色/background.css @@ -0,0 +1,215 @@ +/* 背景样式文件 - 独立管理背景相关样式 */ + +/* 主体背景 */ +body { + background: linear-gradient(135deg, #e8f5e8 0%, #f0fff0 50%, #e8f5e8 100%); + background-attachment: fixed; + background-size: 400% 400%; + animation: gradientShift 15s ease infinite; +} + +/* 背景动画 */ +@keyframes gradientShift { + 0% { + background-position: 0% 50%; + } + 50% { + background-position: 100% 50%; + } + 100% { + background-position: 0% 50%; + } +} + +/* 容器背景装饰 */ +.container::before { + content: ''; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-image: + radial-gradient(circle at 20% 80%, rgba(144, 205, 144, 0.1) 0%, transparent 50%), + radial-gradient(circle at 80% 20%, rgba(45, 90, 39, 0.05) 0%, transparent 50%), + radial-gradient(circle at 40% 40%, rgba(144, 205, 144, 0.08) 0%, transparent 50%); + pointer-events: none; + z-index: -1; +} + +/* 输入区域背景 */ +.input-section { + background: rgba(255, 255, 255, 0.95); + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); +} + +/* 结果区域背景 */ +.result-section { + background: rgba(255, 255, 255, 0.95); + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); +} + +/* 格式组背景 */ +.format-group { + background: rgba(248, 255, 248, 0.8); + backdrop-filter: blur(5px); + -webkit-backdrop-filter: blur(5px); +} + +/* 属性项背景 */ +.property-item { + background: rgba(248, 255, 248, 0.8); + backdrop-filter: blur(5px); + -webkit-backdrop-filter: blur(5px); +} + +/* 调色板项背景 */ +.palette-item { + background: rgba(248, 255, 248, 0.8); + backdrop-filter: blur(5px); + -webkit-backdrop-filter: blur(5px); +} + +/* 无障碍项背景 */ +.accessibility-item { + background: rgba(248, 255, 248, 0.8); + backdrop-filter: blur(5px); + -webkit-backdrop-filter: blur(5px); +} + +/* 颜色预览背景 */ +.color-preview { + background: rgba(248, 255, 248, 0.6); + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); +} + +/* 输入框背景 */ +.input-group input, +.input-group select { + background: rgba(248, 255, 248, 0.9); + backdrop-filter: blur(5px); + -webkit-backdrop-filter: blur(5px); +} + +.input-group input:focus, +.input-group select:focus { + background: rgba(255, 255, 255, 0.95); +} + +/* 格式组内部元素背景 */ +.format-group p { + background: rgba(255, 255, 255, 0.9); + backdrop-filter: blur(3px); + -webkit-backdrop-filter: blur(3px); +} + +/* 手机端背景优化 */ +@media (max-width: 767px) { + body { + background: linear-gradient(180deg, #e8f5e8 0%, #f0fff0 50%, #e8f5e8 100%); + background-attachment: scroll; /* 手机端使用scroll避免性能问题 */ + } + + .container::before { + background-image: + radial-gradient(circle at 30% 70%, rgba(144, 205, 144, 0.08) 0%, transparent 40%), + radial-gradient(circle at 70% 30%, rgba(45, 90, 39, 0.04) 0%, transparent 40%); + } + + /* 减少手机端的模糊效果以提升性能 */ + .input-section, + .result-section { + backdrop-filter: blur(5px); + -webkit-backdrop-filter: blur(5px); + } + + .format-group, + .property-item, + .palette-item, + .accessibility-item { + backdrop-filter: blur(3px); + -webkit-backdrop-filter: blur(3px); + } +} + +/* 平板端背景优化 */ +@media (min-width: 768px) and (max-width: 1024px) { + .container::before { + background-image: + radial-gradient(circle at 25% 75%, rgba(144, 205, 144, 0.12) 0%, transparent 60%), + radial-gradient(circle at 75% 25%, rgba(45, 90, 39, 0.06) 0%, transparent 60%), + radial-gradient(circle at 50% 50%, rgba(144, 205, 144, 0.04) 0%, transparent 40%); + } +} + +/* 电脑端背景优化 */ +@media (min-width: 1025px) { + body { + background-size: 300% 300%; + animation-duration: 20s; + } + + .container::before { + background-image: + radial-gradient(circle at 15% 85%, rgba(144, 205, 144, 0.15) 0%, transparent 70%), + radial-gradient(circle at 85% 15%, rgba(45, 90, 39, 0.08) 0%, transparent 70%), + radial-gradient(circle at 35% 35%, rgba(144, 205, 144, 0.1) 0%, transparent 50%), + radial-gradient(circle at 65% 65%, rgba(45, 90, 39, 0.05) 0%, transparent 50%); + } + + /* 电脑端增强模糊效果 */ + .input-section, + .result-section { + backdrop-filter: blur(15px); + -webkit-backdrop-filter: blur(15px); + } + + .format-group, + .property-item, + .palette-item, + .accessibility-item { + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + } +} + +/* 深色模式支持(如果用户系统设置为深色模式) */ +@media (prefers-color-scheme: dark) { + body { + background: linear-gradient(135deg, #1a2e1a 0%, #0f1f0f 50%, #1a2e1a 100%); + } + + .container::before { + background-image: + radial-gradient(circle at 20% 80%, rgba(144, 205, 144, 0.05) 0%, transparent 50%), + radial-gradient(circle at 80% 20%, rgba(45, 90, 39, 0.03) 0%, transparent 50%); + } + + .input-section, + .result-section { + background: rgba(26, 46, 26, 0.9); + } + + .format-group, + .property-item, + .palette-item, + .accessibility-item, + .color-preview { + background: rgba(26, 46, 26, 0.6); + } + + .input-group input, + .input-group select { + background: rgba(26, 46, 26, 0.8); + color: #e8f5e8; + border-color: rgba(144, 205, 144, 0.3); + } + + .format-group p { + background: rgba(15, 31, 15, 0.8); + color: #e8f5e8; + } +} \ No newline at end of file diff --git a/frontend/60sapi/实用功能/随机颜色/index.html b/frontend/60sapi/实用功能/随机颜色/index.html new file mode 100644 index 00000000..cf9be12c --- /dev/null +++ b/frontend/60sapi/实用功能/随机颜色/index.html @@ -0,0 +1,187 @@ + + + + + + 随机颜色/颜色转换工具 + + + + +
+
+

随机颜色/颜色转换工具

+

获取随机颜色或转换指定颜色格式

+
+ +
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
+
+

颜色名称

+

#000000

+
+
+ +
+
+

RGB

+
+ 0 + 0 + 0 +
+

rgb(0, 0, 0)

+
+ +
+

HSL

+
+ + 0% + 0% +
+

hsl(0, 0%, 0%)

+
+ +
+

HSV

+
+ + 0% + 0% +
+

hsv(0, 0%, 0%)

+
+ +
+

CMYK

+
+ 0% + 0% + 0% + 0% +
+

cmyk(0%, 0%, 0%, 0%)

+
+ +
+

LAB

+
+ 0 + 0 + 0 +
+

lab(0, 0, 0)

+
+
+ +
+
+ + 0 +
+
+ + 0 +
+
+ + 0 +
+
+ + #000000 +
+
+ +
+

配色方案

+
+
+ +
+ #000000 +
+
+ +
+
+
+
+
+ #000000 + #000000 +
+
+
+ +
+
+
+
+
+ #000000 + #000000 +
+
+
+
+ +
+

无障碍性

+
+
+ AA 普通文本: + +
+
+ AA 大文本: + +
+
+ AAA 普通文本: + +
+
+ AAA 大文本: + +
+
+
+
+ + + + +
+
+ + + + \ No newline at end of file diff --git a/frontend/60sapi/实用功能/随机颜色/script.js b/frontend/60sapi/实用功能/随机颜色/script.js new file mode 100644 index 00000000..e641efe4 --- /dev/null +++ b/frontend/60sapi/实用功能/随机颜色/script.js @@ -0,0 +1,426 @@ +// 随机颜色/颜色转换工具 JavaScript + +class ColorTool { + constructor() { + this.apiUrl = 'https://60s.api.shumengya.top/v2/color'; + this.init(); + } + + init() { + this.bindEvents(); + this.hideResultSection(); + } + + bindEvents() { + const randomBtn = document.getElementById('randomBtn'); + const convertBtn = document.getElementById('convertBtn'); + const colorInput = document.getElementById('colorInput'); + + randomBtn.addEventListener('click', () => this.getRandomColor()); + convertBtn.addEventListener('click', () => this.convertColor()); + + // 回车键支持 + colorInput.addEventListener('keypress', (e) => { + if (e.key === 'Enter') { + this.convertColor(); + } + }); + } + + hideResultSection() { + const resultSection = document.querySelector('.result-section'); + resultSection.style.display = 'none'; + } + + showResultSection() { + const resultSection = document.querySelector('.result-section'); + resultSection.style.display = 'block'; + } + + showLoading() { + const loading = document.getElementById('loading'); + const error = document.getElementById('error'); + loading.style.display = 'block'; + error.style.display = 'none'; + this.hideResultSection(); + } + + hideLoading() { + const loading = document.getElementById('loading'); + loading.style.display = 'none'; + } + + showError(message) { + const error = document.getElementById('error'); + const errorMessage = document.getElementById('errorMessage'); + const loading = document.getElementById('loading'); + + loading.style.display = 'none'; + errorMessage.textContent = message; + error.style.display = 'block'; + this.hideResultSection(); + } + + hideError() { + const error = document.getElementById('error'); + error.style.display = 'none'; + } + + async getRandomColor() { + try { + this.showLoading(); + const encoding = document.getElementById('encodingSelect').value; + const url = `${this.apiUrl}?encoding=${encoding}`; + + const response = await fetch(url); + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + + const data = await response.json(); + + if (data.code === 200) { + this.displayColorData(data.data); + this.hideLoading(); + this.hideError(); + this.showResultSection(); + } else { + throw new Error(data.message || '获取颜色信息失败'); + } + } catch (error) { + console.error('获取随机颜色失败:', error); + this.showError(`获取随机颜色失败: ${error.message}`); + } + } + + async convertColor() { + const colorInput = document.getElementById('colorInput'); + const colorValue = colorInput.value.trim(); + + if (!colorValue) { + this.showError('请输入要转换的颜色值'); + return; + } + + // 简单的颜色格式验证 + if (!this.isValidColor(colorValue)) { + this.showError('请输入有效的颜色值(如 #33AAFF)'); + return; + } + + try { + this.showLoading(); + const encoding = document.getElementById('encodingSelect').value; + const url = `${this.apiUrl}?color=${encodeURIComponent(colorValue)}&encoding=${encoding}`; + + const response = await fetch(url); + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + + const data = await response.json(); + + if (data.code === 200) { + this.displayColorData(data.data); + this.hideLoading(); + this.hideError(); + this.showResultSection(); + } else { + throw new Error(data.message || '转换颜色失败'); + } + } catch (error) { + console.error('转换颜色失败:', error); + this.showError(`转换颜色失败: ${error.message}`); + } + } + + isValidColor(color) { + // 支持十六进制颜色格式 + const hexPattern = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/; + // 支持RGB格式 + const rgbPattern = /^rgb\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\)$/; + // 支持HSL格式 + const hslPattern = /^hsl\(\s*\d+\s*,\s*\d+%\s*,\s*\d+%\s*\)$/; + + return hexPattern.test(color) || rgbPattern.test(color) || hslPattern.test(color); + } + + displayColorData(data) { + // 显示主要颜色信息 + this.updateColorDisplay(data); + + // 显示各种格式 + this.updateColorFormats(data); + + // 显示颜色属性 + this.updateColorProperties(data); + + // 显示配色方案 + this.updateColorPalette(data); + + // 显示无障碍性信息 + this.updateAccessibilityInfo(data); + } + + updateColorDisplay(data) { + const colorDisplay = document.getElementById('colorDisplay'); + const colorName = document.getElementById('colorName'); + const hexValue = document.getElementById('hexValue'); + + colorDisplay.style.backgroundColor = data.hex; + colorName.textContent = data.name || '未知颜色'; + hexValue.textContent = data.hex; + } + + updateColorFormats(data) { + // RGB + if (data.rgb) { + document.getElementById('rgbR').textContent = data.rgb.r; + document.getElementById('rgbG').textContent = data.rgb.g; + document.getElementById('rgbB').textContent = data.rgb.b; + document.getElementById('rgbString').textContent = data.rgb.string; + } + + // HSL + if (data.hsl) { + document.getElementById('hslH').textContent = data.hsl.h + '°'; + document.getElementById('hslS').textContent = data.hsl.s + '%'; + document.getElementById('hslL').textContent = data.hsl.l + '%'; + document.getElementById('hslString').textContent = data.hsl.string; + } + + // HSV + if (data.hsv) { + document.getElementById('hsvH').textContent = data.hsv.h + '°'; + document.getElementById('hsvS').textContent = data.hsv.s + '%'; + document.getElementById('hsvV').textContent = data.hsv.v + '%'; + document.getElementById('hsvString').textContent = data.hsv.string; + } + + // CMYK + if (data.cmyk) { + document.getElementById('cmykC').textContent = data.cmyk.c + '%'; + document.getElementById('cmykM').textContent = data.cmyk.m + '%'; + document.getElementById('cmykY').textContent = data.cmyk.y + '%'; + document.getElementById('cmykK').textContent = data.cmyk.k + '%'; + document.getElementById('cmykString').textContent = data.cmyk.string; + } + + // LAB + if (data.lab) { + document.getElementById('labL').textContent = data.lab.l; + document.getElementById('labA').textContent = data.lab.a; + document.getElementById('labB').textContent = data.lab.b; + document.getElementById('labString').textContent = data.lab.string; + } + } + + updateColorProperties(data) { + // 亮度 + if (data.brightness !== undefined) { + document.getElementById('brightness').textContent = data.brightness.toFixed(2); + } + + // 对比度 + if (data.contrast) { + document.getElementById('contrastWhite').textContent = data.contrast.white.toFixed(2); + document.getElementById('contrastBlack').textContent = data.contrast.black.toFixed(2); + } + + // 最佳文字颜色 + if (data.accessibility && data.accessibility.best_text_color) { + const bestTextColor = document.getElementById('bestTextColor'); + bestTextColor.textContent = data.accessibility.best_text_color; + bestTextColor.style.color = data.accessibility.best_text_color; + } + } + + updateColorPalette(data) { + // 互补色 + if (data.complementary) { + const complementary = document.getElementById('complementary'); + const complementaryHex = document.getElementById('complementaryHex'); + complementary.style.backgroundColor = data.complementary; + complementaryHex.textContent = data.complementary; + } + + // 类似色 + if (data.analogous && data.analogous.length >= 2) { + const analogous1 = document.getElementById('analogous1'); + const analogous2 = document.getElementById('analogous2'); + const analogous1Hex = document.getElementById('analogous1Hex'); + const analogous2Hex = document.getElementById('analogous2Hex'); + + analogous1.style.backgroundColor = data.analogous[0]; + analogous2.style.backgroundColor = data.analogous[1]; + analogous1Hex.textContent = data.analogous[0]; + analogous2Hex.textContent = data.analogous[1]; + } + + // 三角色 + if (data.triadic && data.triadic.length >= 2) { + const triadic1 = document.getElementById('triadic1'); + const triadic2 = document.getElementById('triadic2'); + const triadic1Hex = document.getElementById('triadic1Hex'); + const triadic2Hex = document.getElementById('triadic2Hex'); + + triadic1.style.backgroundColor = data.triadic[0]; + triadic2.style.backgroundColor = data.triadic[1]; + triadic1Hex.textContent = data.triadic[0]; + triadic2Hex.textContent = data.triadic[1]; + } + } + + updateAccessibilityInfo(data) { + if (data.accessibility) { + const aaNormal = document.getElementById('aaNormal'); + const aaLarge = document.getElementById('aaLarge'); + const aaaNormal = document.getElementById('aaaNormal'); + const aaaLarge = document.getElementById('aaaLarge'); + + this.updateAccessibilityStatus(aaNormal, data.accessibility.aa_normal); + this.updateAccessibilityStatus(aaLarge, data.accessibility.aa_large); + this.updateAccessibilityStatus(aaaNormal, data.accessibility.aaa_normal); + this.updateAccessibilityStatus(aaaLarge, data.accessibility.aaa_large); + } + } + + updateAccessibilityStatus(element, status) { + element.textContent = status ? '通过' : '未通过'; + element.className = 'status ' + (status ? 'pass' : 'fail'); + } + + // 复制颜色值到剪贴板 + copyToClipboard(text) { + if (navigator.clipboard) { + navigator.clipboard.writeText(text).then(() => { + this.showToast('已复制到剪贴板'); + }).catch(err => { + console.error('复制失败:', err); + this.fallbackCopyTextToClipboard(text); + }); + } else { + this.fallbackCopyTextToClipboard(text); + } + } + + fallbackCopyTextToClipboard(text) { + const textArea = document.createElement('textarea'); + textArea.value = text; + textArea.style.top = '0'; + textArea.style.left = '0'; + textArea.style.position = 'fixed'; + + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + + try { + const successful = document.execCommand('copy'); + if (successful) { + this.showToast('已复制到剪贴板'); + } else { + this.showToast('复制失败'); + } + } catch (err) { + console.error('复制失败:', err); + this.showToast('复制失败'); + } + + document.body.removeChild(textArea); + } + + showToast(message) { + // 创建简单的提示框 + const toast = document.createElement('div'); + toast.textContent = message; + toast.style.cssText = ` + position: fixed; + top: 20px; + right: 20px; + background: #2d5a27; + color: white; + padding: 12px 20px; + border-radius: 8px; + z-index: 1000; + font-size: 14px; + box-shadow: 0 4px 12px rgba(0,0,0,0.15); + animation: slideIn 0.3s ease; + `; + + // 添加动画样式 + const style = document.createElement('style'); + style.textContent = ` + @keyframes slideIn { + from { transform: translateX(100%); opacity: 0; } + to { transform: translateX(0); opacity: 1; } + } + `; + document.head.appendChild(style); + + document.body.appendChild(toast); + + setTimeout(() => { + toast.style.animation = 'slideIn 0.3s ease reverse'; + setTimeout(() => { + document.body.removeChild(toast); + document.head.removeChild(style); + }, 300); + }, 2000); + } +} + +// 添加点击复制功能 +function addCopyListeners() { + const colorTool = window.colorTool; + + // 为所有颜色值添加点击复制功能 + document.addEventListener('click', (e) => { + const target = e.target; + + // 检查是否点击了颜色值相关元素 + if (target.id === 'hexValue' || + target.id === 'rgbString' || + target.id === 'hslString' || + target.id === 'hsvString' || + target.id === 'cmykString' || + target.id === 'labString' || + target.id === 'complementaryHex' || + target.id === 'analogous1Hex' || + target.id === 'analogous2Hex' || + target.id === 'triadic1Hex' || + target.id === 'triadic2Hex') { + + const text = target.textContent; + if (text && colorTool) { + colorTool.copyToClipboard(text); + } + } + }); +} + +// 页面加载完成后初始化 +document.addEventListener('DOMContentLoaded', () => { + window.colorTool = new ColorTool(); + addCopyListeners(); + + // 添加复制提示 + const style = document.createElement('style'); + style.textContent = ` + #hexValue, #rgbString, #hslString, #hsvString, #cmykString, #labString, + #complementaryHex, #analogous1Hex, #analogous2Hex, #triadic1Hex, #triadic2Hex { + cursor: pointer; + transition: all 0.2s ease; + } + + #hexValue:hover, #rgbString:hover, #hslString:hover, #hsvString:hover, + #cmykString:hover, #labString:hover, #complementaryHex:hover, + #analogous1Hex:hover, #analogous2Hex:hover, #triadic1Hex:hover, #triadic2Hex:hover { + background: rgba(45, 90, 39, 0.1); + border-radius: 4px; + padding: 2px 4px; + margin: -2px -4px; + } + `; + document.head.appendChild(style); +}); \ No newline at end of file diff --git a/frontend/60sapi/实用功能/随机颜色/styles.css b/frontend/60sapi/实用功能/随机颜色/styles.css new file mode 100644 index 00000000..cd53529c --- /dev/null +++ b/frontend/60sapi/实用功能/随机颜色/styles.css @@ -0,0 +1,637 @@ +/* 基础样式重置 */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif; + line-height: 1.6; + color: #2d3748; + min-height: 100vh; +} + +.container { + max-width: 1200px; + margin: 0 auto; + padding: 20px; + min-height: 100vh; +} + +/* 头部样式 */ +.header { + text-align: center; + margin-bottom: 30px; + padding: 20px 0; +} + +.header h1 { + font-size: 2rem; + color: #2d5a27; + margin-bottom: 10px; + font-weight: 600; +} + +.subtitle { + color: #4a5568; + font-size: 1rem; + opacity: 0.8; +} + +/* 主要内容区域 */ +.main-content { + display: flex; + flex-direction: column; + gap: 30px; +} + +/* 输入区域 */ +.input-section { + background: rgba(255, 255, 255, 0.9); + padding: 25px; + border-radius: 15px; + box-shadow: 0 4px 20px rgba(45, 90, 39, 0.1); + border: 1px solid rgba(144, 205, 144, 0.3); +} + +.input-group { + margin-bottom: 20px; +} + +.input-group label { + display: block; + margin-bottom: 8px; + font-weight: 500; + color: #2d5a27; + font-size: 0.95rem; +} + +.input-group input, +.input-group select { + width: 100%; + padding: 12px 15px; + border: 2px solid #90cd90; + border-radius: 10px; + font-size: 1rem; + transition: all 0.3s ease; + background: #f8fff8; +} + +.input-group input:focus, +.input-group select:focus { + outline: none; + border-color: #2d5a27; + box-shadow: 0 0 0 3px rgba(45, 90, 39, 0.1); + background: #ffffff; +} + +.button-group { + display: flex; + gap: 15px; + margin-top: 25px; +} + +.btn { + flex: 1; + padding: 15px 20px; + border: none; + border-radius: 10px; + font-size: 1rem; + font-weight: 500; + cursor: pointer; + transition: all 0.3s ease; + text-transform: none; +} + +.btn-primary { + background: linear-gradient(135deg, #2d5a27, #4a7c59); + color: white; +} + +.btn-primary:hover { + background: linear-gradient(135deg, #1e3a1a, #2d5a27); + transform: translateY(-2px); + box-shadow: 0 6px 20px rgba(45, 90, 39, 0.3); +} + +.btn-secondary { + background: linear-gradient(135deg, #90cd90, #a8d8a8); + color: #2d5a27; +} + +.btn-secondary:hover { + background: linear-gradient(135deg, #7bb87b, #90cd90); + transform: translateY(-2px); + box-shadow: 0 6px 20px rgba(144, 205, 144, 0.4); +} + +/* 结果展示区域 */ +.result-section { + background: rgba(255, 255, 255, 0.9); + padding: 25px; + border-radius: 15px; + box-shadow: 0 4px 20px rgba(45, 90, 39, 0.1); + border: 1px solid rgba(144, 205, 144, 0.3); +} + +/* 颜色预览 */ +.color-preview { + display: flex; + align-items: center; + gap: 20px; + margin-bottom: 30px; + padding: 20px; + background: #f8fff8; + border-radius: 12px; + border: 1px solid rgba(144, 205, 144, 0.2); +} + +.color-box { + width: 80px; + height: 80px; + border-radius: 12px; + border: 3px solid #ffffff; + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); + flex-shrink: 0; +} + +.color-info h3 { + color: #2d5a27; + margin-bottom: 5px; + font-size: 1.2rem; +} + +.color-info p { + color: #4a5568; + font-size: 1.1rem; + font-weight: 500; + font-family: 'Courier New', monospace; +} + +/* 颜色格式展示 */ +.color-formats { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 20px; + margin-bottom: 30px; +} + +.format-group { + background: #f8fff8; + padding: 15px; + border-radius: 10px; + border: 1px solid rgba(144, 205, 144, 0.2); +} + +.format-group h4 { + color: #2d5a27; + margin-bottom: 10px; + font-size: 1rem; + font-weight: 600; +} + +.format-values { + display: flex; + gap: 8px; + margin-bottom: 8px; + flex-wrap: wrap; +} + +.format-values span { + background: #90cd90; + color: #2d5a27; + padding: 4px 8px; + border-radius: 6px; + font-size: 0.85rem; + font-weight: 500; +} + +.format-group p { + font-family: 'Courier New', monospace; + color: #4a5568; + font-size: 0.9rem; + background: #ffffff; + padding: 8px; + border-radius: 6px; + border: 1px solid rgba(144, 205, 144, 0.2); +} + +/* 颜色属性 */ +.color-properties { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 15px; + margin-bottom: 30px; +} + +.property-item { + display: flex; + justify-content: space-between; + align-items: center; + background: #f8fff8; + padding: 12px 15px; + border-radius: 8px; + border: 1px solid rgba(144, 205, 144, 0.2); +} + +.property-item label { + color: #2d5a27; + font-weight: 500; + font-size: 0.9rem; +} + +.property-item span { + color: #4a5568; + font-weight: 600; + font-family: 'Courier New', monospace; +} + +/* 配色方案 */ +.color-palette { + margin-bottom: 30px; +} + +.color-palette h4 { + color: #2d5a27; + margin-bottom: 15px; + font-size: 1.1rem; + font-weight: 600; +} + +.palette-group { + display: flex; + flex-direction: column; + gap: 15px; +} + +.palette-item { + background: #f8fff8; + padding: 15px; + border-radius: 10px; + border: 1px solid rgba(144, 205, 144, 0.2); +} + +.palette-item label { + display: block; + color: #2d5a27; + font-weight: 500; + margin-bottom: 10px; + font-size: 0.95rem; +} + +.color-sample { + width: 40px; + height: 40px; + border-radius: 8px; + border: 2px solid #ffffff; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + display: inline-block; + margin-right: 10px; +} + +.analogous-colors, +.triadic-colors { + display: flex; + gap: 10px; + margin-bottom: 8px; +} + +.analogous-hex, +.triadic-hex { + display: flex; + gap: 10px; + font-family: 'Courier New', monospace; + font-size: 0.85rem; + color: #4a5568; +} + +/* 无障碍性信息 */ +.accessibility-info h4 { + color: #2d5a27; + margin-bottom: 15px; + font-size: 1.1rem; + font-weight: 600; +} + +.accessibility-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 10px; +} + +.accessibility-item { + display: flex; + justify-content: space-between; + align-items: center; + background: #f8fff8; + padding: 10px 15px; + border-radius: 8px; + border: 1px solid rgba(144, 205, 144, 0.2); +} + +.accessibility-item span:first-child { + color: #2d5a27; + font-weight: 500; + font-size: 0.9rem; +} + +.status { + padding: 4px 8px; + border-radius: 6px; + font-size: 0.8rem; + font-weight: 600; +} + +.status.pass { + background: #90cd90; + color: #2d5a27; +} + +.status.fail { + background: #ffcccb; + color: #d32f2f; +} + +/* 加载和错误状态 */ +.loading, +.error { + text-align: center; + padding: 40px 20px; + border-radius: 12px; + margin: 20px 0; +} + +.loading { + background: rgba(144, 205, 144, 0.1); + border: 1px solid rgba(144, 205, 144, 0.3); +} + +.error { + background: rgba(255, 204, 203, 0.3); + border: 1px solid rgba(211, 47, 47, 0.3); +} + +.spinner { + width: 40px; + height: 40px; + border: 4px solid rgba(144, 205, 144, 0.3); + border-top: 4px solid #2d5a27; + border-radius: 50%; + animation: spin 1s linear infinite; + margin: 0 auto 15px; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +.loading p { + color: #2d5a27; + font-weight: 500; +} + +.error p { + color: #d32f2f; + font-weight: 500; +} + +/* 平板端适配 (768px - 1024px) */ +@media (min-width: 768px) and (max-width: 1024px) { + .container { + padding: 30px; + } + + .header h1 { + font-size: 2.5rem; + } + + .main-content { + gap: 35px; + } + + .input-section, + .result-section { + padding: 30px; + } + + .color-preview { + gap: 25px; + } + + .color-box { + width: 100px; + height: 100px; + } + + .color-formats { + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + } + + .palette-group { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: 20px; + } +} + +/* 电脑端适配 (1025px+) */ +@media (min-width: 1025px) { + .container { + padding: 40px; + } + + .header h1 { + font-size: 3rem; + } + + .subtitle { + font-size: 1.1rem; + } + + .main-content { + gap: 40px; + } + + .input-section, + .result-section { + padding: 35px; + } + + .color-preview { + gap: 30px; + padding: 25px; + } + + .color-box { + width: 120px; + height: 120px; + } + + .color-info h3 { + font-size: 1.4rem; + } + + .color-info p { + font-size: 1.2rem; + } + + .color-formats { + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 25px; + } + + .format-group { + padding: 20px; + } + + .palette-group { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 25px; + } + + .button-group { + max-width: 500px; + margin: 25px auto 0; + } + + .btn { + padding: 18px 25px; + font-size: 1.1rem; + } +} + +/* 手机端优化 (最高优先级) */ +@media (max-width: 767px) { + .container { + padding: 15px; + } + + .header { + margin-bottom: 25px; + padding: 15px 0; + } + + .header h1 { + font-size: 1.8rem; + } + + .subtitle { + font-size: 0.9rem; + } + + .main-content { + gap: 25px; + } + + .input-section, + .result-section { + padding: 20px; + border-radius: 12px; + } + + .input-group { + margin-bottom: 18px; + } + + .input-group input, + .input-group select { + padding: 14px 12px; + font-size: 16px; /* 防止iOS缩放 */ + } + + .button-group { + flex-direction: column; + gap: 12px; + margin-top: 20px; + } + + .btn { + padding: 16px 20px; + font-size: 1rem; + border-radius: 8px; + } + + .color-preview { + flex-direction: column; + text-align: center; + gap: 15px; + padding: 15px; + } + + .color-box { + width: 100px; + height: 100px; + margin: 0 auto; + } + + .color-formats { + grid-template-columns: 1fr; + gap: 15px; + } + + .format-group { + padding: 12px; + } + + .format-values { + justify-content: center; + } + + .color-properties { + grid-template-columns: 1fr; + gap: 12px; + } + + .property-item { + flex-direction: column; + gap: 5px; + text-align: center; + padding: 15px; + } + + .palette-group { + gap: 12px; + } + + .palette-item { + padding: 12px; + text-align: center; + } + + .analogous-colors, + .triadic-colors { + justify-content: center; + } + + .analogous-hex, + .triadic-hex { + justify-content: center; + flex-wrap: wrap; + } + + .accessibility-grid { + grid-template-columns: 1fr; + gap: 8px; + } + + .accessibility-item { + flex-direction: column; + gap: 5px; + text-align: center; + padding: 12px; + } + + .loading, + .error { + padding: 30px 15px; + margin: 15px 0; + } + + .spinner { + width: 35px; + height: 35px; + } +} \ No newline at end of file diff --git a/frontend/60sapi/实用功能/随机颜色/返回接口.json b/frontend/60sapi/实用功能/随机颜色/返回接口.json new file mode 100644 index 00000000..46d731ff --- /dev/null +++ b/frontend/60sapi/实用功能/随机颜色/返回接口.json @@ -0,0 +1,60 @@ +{ + "code": 200, + "message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s,反馈群 595941841", + "data": { + "hex": "#A59619", + "name": "红色系", + "rgb": { + "r": 165, + "g": 150, + "b": 25, + "string": "rgb(165, 150, 25)" + }, + "hsl": { + "h": 54, + "s": 74, + "l": 37, + "string": "hsl(54, 74%, 37%)" + }, + "hsv": { + "h": 54, + "s": 85, + "v": 65, + "string": "hsv(54, 85%, 65%)" + }, + "cmyk": { + "c": 0, + "m": 9, + "y": 85, + "k": 35, + "string": "cmyk(0%, 9%, 85%, 35%)" + }, + "lab": { + "l": 62, + "a": -7, + "b": 61, + "string": "lab(62, -7, 61)" + }, + "brightness": 140.235, + "contrast": { + "white": 3.01, + "black": 6.98 + }, + "accessibility": { + "aa_normal": true, + "aa_large": true, + "aaa_normal": false, + "aaa_large": true, + "best_text_color": "#000000" + }, + "complementary": "#1926A4", + "analogous": [ + "#A45019", + "#6CA419" + ], + "triadic": [ + "#19A496", + "#9619A4" + ] + } +} \ No newline at end of file diff --git a/frontend/60sapi/生成要求模板.txt b/frontend/60sapi/生成要求模板.txt index 0a3addc7..975a3074 100755 --- a/frontend/60sapi/生成要求模板.txt +++ b/frontend/60sapi/生成要求模板.txt @@ -4,5 +4,4 @@ 4.尽量不要引用外部css,js,实在要引用就使用中国国内的cdn,否则用户可能加载不出来 5.返回接口.json储存了网页api返回的数据格式 6.严格按照用户要求执行,不得随意添加什么注解,如“以下数据来自...” -7.接口集合.json保存了所有已知的后端API接口,一个访问不了尝试自动切换另一个 8.在css中有关背景的css单独一个css文件,方便我直接迁移 \ No newline at end of file