From 71a648fdf4733865bde59ef452a9544543fdb092 Mon Sep 17 00:00:00 2001 From: Chance_Li <2753591994@qq.com> Date: Thu, 4 Sep 2025 14:31:44 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=96=B0=E7=9A=84=E5=AE=9E=E7=94=A8?= =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../60sapi/实用功能/公网IP地址/js/script.js | 42 +- .../60sapi/实用功能/公网IP地址/接口集合.json | 2 +- .../60sapi/实用功能/公网IP地址/返回接口.json | 17 + .../实用功能/农历信息/css/background.css | 568 ++++++++++++++++-- .../60sapi/实用功能/农历信息/css/style.css | 365 +++++++++-- frontend/60sapi/实用功能/农历信息/index.html | 38 ++ .../60sapi/实用功能/哈希解压压缩/index.html | 9 - .../60sapi/实用功能/哈希解压压缩/js/script.js | 34 +- .../实用功能/哈希解压压缩/返回接口.json | 36 +- .../60sapi/实用功能/链接OG信息/index.html | 12 +- .../60sapi/实用功能/链接OG信息/js/script.js | 84 ++- 11 files changed, 1071 insertions(+), 136 deletions(-) diff --git a/frontend/60sapi/实用功能/公网IP地址/js/script.js b/frontend/60sapi/实用功能/公网IP地址/js/script.js index 4db5e4bd..30bbfb28 100644 --- a/frontend/60sapi/实用功能/公网IP地址/js/script.js +++ b/frontend/60sapi/实用功能/公网IP地址/js/script.js @@ -159,13 +159,24 @@ class IPQueryApp { queryTimeElement.textContent = now.toLocaleString('zh-CN'); } - // 更新详细信息 - this.updateDetailItem('location', data.location || '未知'); - this.updateDetailItem('isp', data.isp || '未知'); - this.updateDetailItem('country', data.country || '未知'); - this.updateDetailItem('region', data.region || '未知'); - this.updateDetailItem('city', data.city || '未知'); - this.updateDetailItem('timezone', data.timezone || '未知'); + // 更新详细信息 - 只显示API提供的数据 + if (data.location) this.updateDetailItem('location', data.location); + else this.hideDetailItem('location'); + + if (data.isp) this.updateDetailItem('isp', data.isp); + else this.hideDetailItem('isp'); + + if (data.country) this.updateDetailItem('country', data.country); + else this.hideDetailItem('country'); + + if (data.region) this.updateDetailItem('region', data.region); + else this.hideDetailItem('region'); + + if (data.city) this.updateDetailItem('city', data.city); + else this.hideDetailItem('city'); + + if (data.timezone) this.updateDetailItem('timezone', data.timezone); + else this.hideDetailItem('timezone'); // 显示IP信息,隐藏错误信息 if (ipInfo) ipInfo.style.display = 'block'; @@ -180,6 +191,23 @@ class IPQueryApp { const element = document.getElementById(id); if (element) { element.textContent = value; + // 显示对应的详细信息行 + const detailRow = element.closest('.detail-item'); + if (detailRow) { + detailRow.style.display = 'flex'; + } + } + } + + // 隐藏详细信息项 + hideDetailItem(id) { + const element = document.getElementById(id); + if (element) { + // 隐藏整个详细信息行 + const detailRow = element.closest('.detail-item'); + if (detailRow) { + detailRow.style.display = 'none'; + } } } diff --git a/frontend/60sapi/实用功能/公网IP地址/接口集合.json b/frontend/60sapi/实用功能/公网IP地址/接口集合.json index 60c81034..46d1e2e7 100644 --- a/frontend/60sapi/实用功能/公网IP地址/接口集合.json +++ b/frontend/60sapi/实用功能/公网IP地址/接口集合.json @@ -1,3 +1,3 @@ [ "https://60s.viki.moe/v2/ip" -] +] \ No newline at end of file diff --git a/frontend/60sapi/实用功能/公网IP地址/返回接口.json b/frontend/60sapi/实用功能/公网IP地址/返回接口.json index e69de29b..d10b040f 100644 --- a/frontend/60sapi/实用功能/公网IP地址/返回接口.json +++ b/frontend/60sapi/实用功能/公网IP地址/返回接口.json @@ -0,0 +1,17 @@ +{ + "code": 200, + "message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s,反馈群 595941841", + "data": { + "ip": "2401:b60:16:83::" + } +} + +// 注意:此API只返回IP地址,不包含以下信息: +// - location (位置信息) +// - isp (网络服务商) +// - country (国家) +// - region (地区) +// - city (城市) +// - timezone (时区) +// +// 如需这些信息,需要使用其他API服务 \ No newline at end of file diff --git a/frontend/60sapi/实用功能/农历信息/css/background.css b/frontend/60sapi/实用功能/农历信息/css/background.css index 254496c1..245ce898 100644 --- a/frontend/60sapi/实用功能/农历信息/css/background.css +++ b/frontend/60sapi/实用功能/农历信息/css/background.css @@ -1,20 +1,21 @@ -/* 玻璃拟态背景相关样式 */ +/* 农历主题背景样式 - 动态调节版本 */ body { background: linear-gradient(135deg, - #667eea 0%, - #764ba2 25%, - #f093fb 50%, - #f5576c 75%, - #4facfe 100% + #fff8dc 0%, /* 玉米丝色 */ + #ffd700 20%, /* 金黄色 */ + #ffcc00 40%, /* 亮金色 */ + #daa520 60%, /* 深金色 */ + #b8860b 80%, /* 暗金色 */ + #fff8dc 100% /* 玉米丝色 */ ); background-size: 400% 400%; - animation: gradientShift 20s ease infinite; + animation: goldenShift 25s ease infinite; background-attachment: fixed; min-height: 100vh; position: relative; } -@keyframes gradientShift { +@keyframes goldenShift { 0% { background-position: 0% 50%; } 25% { background-position: 100% 50%; } 50% { background-position: 100% 100%; } @@ -22,7 +23,56 @@ body { 100% { background-position: 0% 50%; } } -/* 玻璃拟态装饰层 */ +/* 动态颜色调节系统 */ +.adaptive-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: + radial-gradient(circle at 20% 30%, rgba(255, 255, 255, 0.1) 0%, transparent 50%), + radial-gradient(circle at 80% 70%, rgba(255, 255, 255, 0.15) 0%, transparent 50%), + linear-gradient(45deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.2) 100%); + pointer-events: none; + z-index: 1; + animation: adaptiveShift 60s ease infinite; +} + +@keyframes adaptiveShift { + 0% { + background: + radial-gradient(circle at 20% 30%, rgba(255, 255, 255, 0.1) 0%, transparent 50%), + radial-gradient(circle at 80% 70%, rgba(255, 255, 255, 0.15) 0%, transparent 50%), + linear-gradient(45deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.2) 100%); + } + 25% { + background: + radial-gradient(circle at 70% 20%, rgba(255, 255, 255, 0.2) 0%, transparent 50%), + radial-gradient(circle at 30% 80%, rgba(255, 255, 255, 0.1) 0%, transparent 50%), + linear-gradient(135deg, rgba(255, 255, 255, 0.15) 0%, rgba(255, 255, 255, 0.25) 100%); + } + 50% { + background: + radial-gradient(circle at 50% 50%, rgba(255, 255, 255, 0.15) 0%, transparent 50%), + radial-gradient(circle at 10% 90%, rgba(255, 255, 255, 0.12) 0%, transparent 50%), + linear-gradient(225deg, rgba(255, 255, 255, 0.12) 0%, rgba(255, 255, 255, 0.22) 100%); + } + 75% { + background: + radial-gradient(circle at 90% 60%, rgba(255, 255, 255, 0.18) 0%, transparent 50%), + radial-gradient(circle at 40% 10%, rgba(255, 255, 255, 0.08) 0%, transparent 50%), + linear-gradient(315deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.2) 100%); + } + 100% { + background: + radial-gradient(circle at 20% 30%, rgba(255, 255, 255, 0.1) 0%, transparent 50%), + radial-gradient(circle at 80% 70%, rgba(255, 255, 255, 0.15) 0%, transparent 50%), + linear-gradient(45deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.2) 100%); + } +} + +/* 高清稻穗贴图层 */ body::before { content: ''; position: fixed; @@ -30,17 +80,70 @@ body::before { left: 0; width: 100%; height: 100%; - background: - radial-gradient(circle at 20% 20%, rgba(255, 255, 255, 0.1) 0%, transparent 40%), - radial-gradient(circle at 80% 80%, rgba(255, 255, 255, 0.08) 0%, transparent 40%), - radial-gradient(circle at 40% 60%, rgba(255, 255, 255, 0.06) 0%, transparent 30%), - radial-gradient(circle at 60% 30%, rgba(255, 255, 255, 0.05) 0%, transparent 35%); + background-image: + /* 主稻穗束 - 高清细节 */ + radial-gradient(ellipse 1.5px 12px at 50% 45%, #DAA520 0%, #B8860B 30%, transparent 80%), + radial-gradient(ellipse 1px 10px at 48% 50%, #FFD700 0%, #DAA520 40%, transparent 75%), + radial-gradient(ellipse 1.2px 11px at 52% 48%, #FFCC00 0%, #B8860B 35%, transparent 78%), + radial-gradient(ellipse 0.8px 9px at 49% 52%, #F4A460 0%, #DAA520 45%, transparent 70%), + radial-gradient(ellipse 1.3px 13px at 51% 46%, #DEB887 0%, #B8860B 38%, transparent 82%), + + /* 次级稻穗 */ + radial-gradient(ellipse 1px 8px at 30% 35%, #FFD700 0%, #DAA520 50%, transparent 75%), + radial-gradient(ellipse 0.9px 7px at 32% 38%, #FFCC00 0%, #B8860B 45%, transparent 70%), + radial-gradient(ellipse 1.1px 9px at 28% 36%, #DEB887 0%, #DAA520 40%, transparent 78%), + + radial-gradient(ellipse 1px 8px at 70% 65%, #FFD700 0%, #DAA520 50%, transparent 75%), + radial-gradient(ellipse 0.8px 7px at 72% 68%, #F4A460 0%, #B8860B 45%, transparent 70%), + radial-gradient(ellipse 1.2px 9px at 68% 66%, #FFCC00 0%, #DAA520 40%, transparent 78%), + + /* 散落稻粒 */ + radial-gradient(ellipse 0.5px 4px at 20% 80%, #FFD700 0%, transparent 60%), + radial-gradient(ellipse 0.6px 5px at 80% 20%, #FFCC00 0%, transparent 65%), + radial-gradient(ellipse 0.4px 3px at 15% 25%, #DEB887 0%, transparent 55%), + radial-gradient(ellipse 0.7px 6px at 85% 75%, #DAA520 0%, transparent 70%), + + /* 稻穗茎秆 - 更细致 */ + linear-gradient(88deg, transparent 49%, #9ACD32 49.5%, #8FBC8F 50%, #9ACD32 50.5%, transparent 51%), + linear-gradient(92deg, transparent 49%, #8FBC8F 49.5%, #228B22 50%, #8FBC8F 50.5%, transparent 51%), + linear-gradient(85deg, transparent 49%, #32CD32 49.5%, #9ACD32 50%, #32CD32 50.5%, transparent 51%); + + background-size: + 25px 25px, 24px 24px, 26px 26px, 23px 23px, 27px 27px, + 20px 20px, 19px 19px, 21px 21px, + 22px 22px, 18px 18px, 23px 23px, + 15px 15px, 16px 16px, 14px 14px, 17px 17px, + 80px 80px, 85px 85px, 75px 75px; + + background-position: + 0 0, 12px 12px, 6px 18px, 18px 6px, 3px 21px, + 40px 40px, 52px 48px, 35px 55px, + 120px 120px, 135px 115px, 110px 130px, + 200px 200px, 220px 180px, 180px 220px, 240px 160px, + 0 0, 40px 40px, 20px 60px; + + opacity: 0.25; pointer-events: none; - z-index: -1; - animation: glassFloat 25s ease-in-out infinite alternate; + z-index: -2; + animation: wheatSway 20s ease-in-out infinite; } -/* 毛玻璃气泡效果 */ +@keyframes wheatSway { + 0%, 100% { + transform: translateX(0) rotate(0deg); + } + 25% { + transform: translateX(5px) rotate(0.5deg); + } + 50% { + transform: translateX(-3px) rotate(-0.3deg); + } + 75% { + transform: translateX(2px) rotate(0.2deg); + } +} + +/* 大型稻穗背景层 */ body::after { content: ''; position: fixed; @@ -49,41 +152,424 @@ body::after { width: 100%; height: 100%; background-image: - radial-gradient(circle at 10% 20%, rgba(255, 255, 255, 0.3) 2px, transparent 2px), - radial-gradient(circle at 30% 40%, rgba(255, 255, 255, 0.25) 3px, transparent 3px), - radial-gradient(circle at 50% 60%, rgba(255, 255, 255, 0.2) 1.5px, transparent 1.5px), - radial-gradient(circle at 70% 80%, rgba(255, 255, 255, 0.3) 2.5px, transparent 2.5px), - radial-gradient(circle at 90% 10%, rgba(255, 255, 255, 0.25) 2px, transparent 2px), - radial-gradient(circle at 20% 90%, rgba(255, 255, 255, 0.2) 1px, transparent 1px); - background-size: 300px 300px, 250px 250px, 400px 400px, 200px 200px, 350px 350px, 150px 150px; - animation: bubbleFloat 30s linear infinite; + /* 主稻穗茎秆 - 右侧大型 */ + linear-gradient(85deg, transparent 45%, #9ACD32 47%, #8FBC8F 48%, #228B22 49%, #8FBC8F 50%, #9ACD32 51%, transparent 53%), + linear-gradient(87deg, transparent 46%, #32CD32 47.5%, #9ACD32 48.5%, #8FBC8F 49.5%, #9ACD32 50.5%, #32CD32 51.5%, transparent 54%), + + /* 主稻穗穗头 - 大型椭圆稻粒群 */ + radial-gradient(ellipse 8px 25px at 75% 15%, #FFD700 0%, #DAA520 30%, #B8860B 60%, transparent 85%), + radial-gradient(ellipse 7px 23px at 77% 18%, #FFCC00 0%, #DAA520 35%, transparent 80%), + radial-gradient(ellipse 9px 27px at 73% 12%, #F4A460 0%, #B8860B 40%, transparent 88%), + radial-gradient(ellipse 6px 22px at 79% 20%, #DEB887 0%, #DAA520 45%, transparent 75%), + radial-gradient(ellipse 8px 24px at 75% 16%, #FFD700 0%, #B8860B 38%, transparent 82%), + + /* 稻穗分支 */ + radial-gradient(ellipse 5px 18px at 72% 25%, #FFCC00 0%, #DAA520 50%, transparent 75%), + radial-gradient(ellipse 4px 16px at 78% 28%, #F4A460 0%, #B8860B 45%, transparent 70%), + radial-gradient(ellipse 6px 20px at 70% 22%, #DEB887 0%, #DAA520 40%, transparent 78%), + radial-gradient(ellipse 5px 17px at 80% 30%, #FFD700 0%, #B8860B 42%, transparent 76%), + + /* 左侧稻穗茎秆 */ + linear-gradient(95deg, transparent 15%, #9ACD32 17%, #8FBC8F 18%, #228B22 19%, #8FBC8F 20%, #9ACD32 21%, transparent 23%), + + /* 左侧稻穗穗头 */ + radial-gradient(ellipse 6px 20px at 25% 25%, #FFD700 0%, #DAA520 30%, transparent 80%), + radial-gradient(ellipse 5px 18px at 27% 28%, #FFCC00 0%, #B8860B 35%, transparent 75%), + radial-gradient(ellipse 7px 22px at 23% 22%, #F4A460 0%, #DAA520 40%, transparent 85%), + + /* 麦田远景效果 */ + linear-gradient(180deg, transparent 70%, rgba(255, 215, 0, 0.1) 75%, rgba(218, 165, 32, 0.15) 85%, rgba(255, 215, 0, 0.2) 95%, rgba(255, 215, 0, 0.25) 100%), + + /* 散落稻粒 */ + radial-gradient(ellipse 2px 8px at 60% 40%, #FFD700 0%, transparent 60%), + radial-gradient(ellipse 1.5px 6px at 40% 60%, #FFCC00 0%, transparent 65%), + radial-gradient(ellipse 2.5px 10px at 85% 50%, #DEB887 0%, transparent 70%), + radial-gradient(ellipse 1.8px 7px at 15% 80%, #DAA520 0%, transparent 68%); + + background-size: + /* 主茎秆 */ + 100vw 80vh, 100vw 82vh, + /* 主穗头 */ + 50vw 60vh, 48vw 58vh, 52vw 62vh, 46vw 56vh, 50vw 60vh, + /* 分支 */ + 40vw 50vh, 38vw 48vh, 42vw 52vh, 36vw 46vh, + /* 左侧茎秆 */ + 100vw 70vh, + /* 左侧穗头 */ + 35vw 45vh, 33vw 43vh, 37vw 47vh, + /* 麦田远景 */ + 100vw 100vh, + /* 散落稻粒 */ + 20vw 20vh, 25vw 25vh, 30vw 30vh, 22vw 22vh; + + background-position: + /* 主茎秆 */ + 70% 20%, 72% 18%, + /* 主穗头 */ + 60% 0%, 62% 2%, 58% -2%, 64% 4%, 60% 1%, + /* 分支 */ + 65% 15%, 67% 17%, 63% 13%, 69% 19%, + /* 左侧茎秆 */ + 20% 30%, + /* 左侧穗头 */ + 15% 20%, 17% 22%, 13% 18%, + /* 麦田远景 */ + 0% 0%, + /* 散落稻粒 */ + 30% 50%, 50% 70%, 80% 40%, 10% 80%; + + background-repeat: no-repeat; + opacity: 0.4; pointer-events: none; z-index: -1; - opacity: 0.7; + animation: wheatSway 25s ease-in-out infinite; } -@keyframes glassFloat { +@keyframes spiralRotate { 0% { - transform: translateY(0px) rotate(0deg); + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} + +/* 流星效果容器 */ +.meteor-container { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: -1; + overflow: hidden; +} + +/* 流星轨迹 */ +.meteor { + position: absolute; + width: 2px; + height: 2px; + background: radial-gradient(circle, #FFD700 0%, #FFA500 50%, transparent 100%); + border-radius: 50%; + box-shadow: + 0 0 10px #FFD700, + 0 0 20px #FFA500, + 0 0 30px #FF8C00; + animation: meteorFall linear infinite; +} + +/* 流星尾迹 */ +.meteor::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100px; + height: 1px; + background: linear-gradient(90deg, + #FFD700 0%, + #FFA500 30%, + #FF8C00 60%, + transparent 100%); + transform-origin: 0 50%; + transform: rotate(-45deg); + opacity: 0.8; +} + +@keyframes meteorFall { + 0% { + transform: translateX(-100px) translateY(-100px); + opacity: 0; + } + 10% { + opacity: 1; + } + 90% { + opacity: 1; + } + 100% { + transform: translateX(calc(100vw + 100px)) translateY(calc(100vh + 100px)); + opacity: 0; + } +} + +/* 多个流星的不同轨迹 */ +.meteor:nth-child(1) { + top: 10%; + left: -100px; + animation-duration: 8s; + animation-delay: 0s; +} + +.meteor:nth-child(2) { + top: 20%; + left: -100px; + animation-duration: 12s; + animation-delay: 2s; +} + +.meteor:nth-child(3) { + top: 30%; + left: -100px; + animation-duration: 10s; + animation-delay: 4s; +} + +.meteor:nth-child(4) { + top: 50%; + left: -100px; + animation-duration: 15s; + animation-delay: 6s; +} + +.meteor:nth-child(5) { + top: 70%; + left: -100px; + animation-duration: 9s; + animation-delay: 8s; +} + +.meteor:nth-child(6) { + top: 80%; + left: -100px; + animation-duration: 11s; + animation-delay: 10s; +} + +/* 金色粒子效果 */ +.golden-particles { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: -1; +} + +.particle { + position: absolute; + width: 3px; + height: 3px; + background: radial-gradient(circle, #FFD700 0%, #FFA500 70%, transparent 100%); + border-radius: 50%; + animation: particleFloat linear infinite; +} + +@keyframes particleFloat { + 0% { + transform: translateY(100vh) rotate(0deg); + opacity: 0; + } + 10% { + opacity: 1; + } + 90% { + opacity: 1; + } + 100% { + transform: translateY(-100px) rotate(360deg); + opacity: 0; + } +} + +/* 粒子的不同位置和动画时长 */ +.particle:nth-child(1) { left: 10%; animation-duration: 20s; animation-delay: 0s; } +.particle:nth-child(2) { left: 20%; animation-duration: 25s; animation-delay: 2s; } +.particle:nth-child(3) { left: 30%; animation-duration: 18s; animation-delay: 4s; } +.particle:nth-child(4) { left: 40%; animation-duration: 22s; animation-delay: 6s; } +.particle:nth-child(5) { left: 50%; animation-duration: 24s; animation-delay: 8s; } +.particle:nth-child(6) { left: 60%; animation-duration: 19s; animation-delay: 10s; } +.particle:nth-child(7) { left: 70%; animation-duration: 21s; animation-delay: 12s; } +.particle:nth-child(8) { left: 80%; animation-duration: 23s; animation-delay: 14s; } +.particle:nth-child(9) { left: 90%; animation-duration: 26s; animation-delay: 16s; } + +/* 响应式设计 */ +@media (max-width: 768px) { + .meteor { + width: 1px; + height: 1px; + } + + .meteor::before { + width: 50px; + } + + .particle { + width: 2px; + height: 2px; + } + + body::before { + background-size: + 30px 30px, 25px 25px, 35px 35px, 28px 28px, 32px 32px, + 40px 40px, 45px 45px; + } + + body::after { + background-size: 200px 200px, 150px 150px, 100px 100px; + } +} + +/* 麦穗飘舞特效 */ +.wheat-floating { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: 2; + overflow: hidden; +} + +/* 移动设备性能优化 */ +@media (max-width: 768px) { + .wheat-floating { + display: none; + } + + .golden-particles { + display: none; + } + + .meteor-container { + display: none; + } + + .adaptive-overlay { + animation: none; + background: rgba(255, 255, 255, 0.1); + } +} + +.wheat-particle { + position: absolute; + width: 8px; + height: 20px; + background: linear-gradient(180deg, + #FFD700 0%, + #DAA520 50%, + #B8860B 100% + ); + border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%; + opacity: 0.7; + animation: wheatFloat 15s linear infinite; +} + +.wheat-particle::before { + content: ''; + position: absolute; + top: -3px; + left: 50%; + transform: translateX(-50%); + width: 2px; + height: 8px; + background: #8B7355; + border-radius: 1px; +} + +.wheat-particle::after { + content: ''; + position: absolute; + top: 2px; + left: 1px; + width: 2px; + height: 4px; + background: #FFEC8C; + border-radius: 50%; + box-shadow: + 3px 2px 0 #FFEC8C, + 1px 6px 0 #FFEC8C, + 4px 8px 0 #FFEC8C; +} + +@keyframes wheatFloat { + 0% { + transform: translateY(-100vh) translateX(0) rotate(0deg); + opacity: 0; + } + 10% { + opacity: 0.7; + } + 90% { opacity: 0.7; } 100% { - transform: translateY(-20px) rotate(2deg); - opacity: 0.9; + transform: translateY(100vh) translateX(50px) rotate(360deg); + opacity: 0; } } -@keyframes bubbleFloat { - 0%, 100% { - transform: translateX(0) translateY(0); +/* 不同大小和速度的麦穗 */ +.wheat-particle:nth-child(1) { + left: 10%; + animation-duration: 12s; + animation-delay: 0s; + transform: scale(0.8); +} + +.wheat-particle:nth-child(2) { + left: 25%; + animation-duration: 18s; + animation-delay: 2s; + transform: scale(1.2); +} + +.wheat-particle:nth-child(3) { + left: 40%; + animation-duration: 15s; + animation-delay: 4s; + transform: scale(0.9); +} + +.wheat-particle:nth-child(4) { + left: 60%; + animation-duration: 20s; + animation-delay: 1s; + transform: scale(1.1); +} + +.wheat-particle:nth-child(5) { + left: 75%; + animation-duration: 14s; + animation-delay: 3s; + transform: scale(0.7); +} + +.wheat-particle:nth-child(6) { + left: 90%; + animation-duration: 16s; + animation-delay: 5s; + transform: scale(1.0); +} + +.wheat-particle:nth-child(7) { + left: 5%; + animation-duration: 22s; + animation-delay: 6s; + transform: scale(0.6); +} + +.wheat-particle:nth-child(8) { + left: 35%; + animation-duration: 13s; + animation-delay: 2.5s; + transform: scale(1.3); +} + +/* 减少动画偏好设置 */ +@media (prefers-reduced-motion: reduce) { + * { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; } - 25% { - transform: translateX(-15px) translateY(-10px); - } - 50% { - transform: translateX(10px) translateY(-20px); - } - 75% { - transform: translateX(-5px) translateY(-15px); + + .meteor, + .particle { + display: none; } } diff --git a/frontend/60sapi/实用功能/农历信息/css/style.css b/frontend/60sapi/实用功能/农历信息/css/style.css index 1c679c5f..d587d194 100644 --- a/frontend/60sapi/实用功能/农历信息/css/style.css +++ b/frontend/60sapi/实用功能/农历信息/css/style.css @@ -10,6 +10,30 @@ body { line-height: 1.6; color: #2c3e50; overflow-x: hidden; + animation: textColorShift 25s ease infinite; +} + +@keyframes textColorShift { + 0% { + color: #2c3e50; + text-shadow: 1px 1px 2px rgba(255, 255, 255, 0.8); + } + 25% { + color: #1a252f; + text-shadow: 2px 2px 4px rgba(255, 255, 255, 0.9); + } + 50% { + color: #34495e; + text-shadow: 1px 1px 3px rgba(255, 255, 255, 0.7); + } + 75% { + color: #2c3e50; + text-shadow: 2px 2px 4px rgba(255, 255, 255, 0.8); + } + 100% { + color: #2c3e50; + text-shadow: 1px 1px 2px rgba(255, 255, 255, 0.8); + } } /* 容器 */ @@ -31,7 +55,7 @@ body { } } -/* 玻璃拟态基础样式 */ +/* 玻璃拟态基础样式 - 动态调节版本 */ .glass-morphism { background: rgba(255, 255, 255, 0.15); backdrop-filter: blur(20px); @@ -41,9 +65,48 @@ body { 0 8px 32px 0 rgba(31, 38, 135, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.3); border-radius: 20px; + animation: glassColorShift 25s ease infinite; } -/* 头部 */ +@keyframes glassColorShift { + 0% { + background: rgba(255, 255, 255, 0.15); + border-color: rgba(255, 255, 255, 0.2); + box-shadow: + 0 8px 32px 0 rgba(31, 38, 135, 0.15), + inset 0 1px 0 rgba(255, 255, 255, 0.3); + } + 25% { + background: rgba(255, 255, 255, 0.25); + border-color: rgba(255, 255, 255, 0.35); + box-shadow: + 0 8px 32px 0 rgba(31, 38, 135, 0.25), + inset 0 1px 0 rgba(255, 255, 255, 0.5); + } + 50% { + background: rgba(255, 255, 255, 0.18); + border-color: rgba(255, 255, 255, 0.25); + box-shadow: + 0 8px 32px 0 rgba(31, 38, 135, 0.18), + inset 0 1px 0 rgba(255, 255, 255, 0.35); + } + 75% { + background: rgba(255, 255, 255, 0.22); + border-color: rgba(255, 255, 255, 0.3); + box-shadow: + 0 8px 32px 0 rgba(31, 38, 135, 0.2), + inset 0 1px 0 rgba(255, 255, 255, 0.4); + } + 100% { + background: rgba(255, 255, 255, 0.15); + border-color: rgba(255, 255, 255, 0.2); + box-shadow: + 0 8px 32px 0 rgba(31, 38, 135, 0.15), + inset 0 1px 0 rgba(255, 255, 255, 0.3); + } +} + +/* 头部 - 动态调节版本 */ .header { text-align: center; margin-bottom: 40px; @@ -58,6 +121,45 @@ body { inset 0 1px 0 rgba(255, 255, 255, 0.4); position: relative; overflow: hidden; + animation: headerColorShift 25s ease infinite; +} + +@keyframes headerColorShift { + 0% { + background: rgba(255, 255, 255, 0.1); + border-color: rgba(255, 255, 255, 0.2); + box-shadow: + 0 8px 32px 0 rgba(31, 38, 135, 0.2), + inset 0 1px 0 rgba(255, 255, 255, 0.4); + } + 25% { + background: rgba(255, 255, 255, 0.2); + border-color: rgba(255, 255, 255, 0.35); + box-shadow: + 0 8px 32px 0 rgba(31, 38, 135, 0.3), + inset 0 1px 0 rgba(255, 255, 255, 0.6); + } + 50% { + background: rgba(255, 255, 255, 0.15); + border-color: rgba(255, 255, 255, 0.25); + box-shadow: + 0 8px 32px 0 rgba(31, 38, 135, 0.22), + inset 0 1px 0 rgba(255, 255, 255, 0.45); + } + 75% { + background: rgba(255, 255, 255, 0.18); + border-color: rgba(255, 255, 255, 0.3); + box-shadow: + 0 8px 32px 0 rgba(31, 38, 135, 0.25), + inset 0 1px 0 rgba(255, 255, 255, 0.5); + } + 100% { + background: rgba(255, 255, 255, 0.1); + border-color: rgba(255, 255, 255, 0.2); + box-shadow: + 0 8px 32px 0 rgba(31, 38, 135, 0.2), + inset 0 1px 0 rgba(255, 255, 255, 0.4); + } } .header::before { @@ -102,30 +204,77 @@ body { .title { font-size: 3.2em; font-weight: 800; - color: rgba(255, 255, 255, 0.95); + color: #2c3e50; margin-bottom: 10px; - text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3); + text-shadow: 1px 1px 2px rgba(255, 255, 255, 0.8), 0 0 4px rgba(255, 255, 255, 0.6); letter-spacing: 2px; - animation: titleGlow 4s ease-in-out infinite alternate; + animation: titleGlow 4s ease-in-out infinite alternate, titleColorShift 25s ease infinite; +} + +@keyframes titleColorShift { + 0% { + color: #2c3e50; + text-shadow: 1px 1px 2px rgba(255, 255, 255, 0.8), 0 0 4px rgba(255, 255, 255, 0.6); + } + 25% { + color: #3498db; + text-shadow: 1px 1px 3px rgba(255, 255, 255, 0.9), 0 0 6px rgba(52, 152, 219, 0.4); + } + 50% { + color: #e74c3c; + text-shadow: 1px 1px 2px rgba(255, 255, 255, 0.7), 0 0 5px rgba(231, 76, 60, 0.3); + } + 75% { + color: #f39c12; + text-shadow: 1px 1px 3px rgba(255, 255, 255, 0.8), 0 0 6px rgba(243, 156, 18, 0.4); + } + 100% { + color: #2c3e50; + text-shadow: 1px 1px 2px rgba(255, 255, 255, 0.8), 0 0 4px rgba(255, 255, 255, 0.6); + } } @keyframes titleGlow { 0% { - text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3); - color: rgba(255, 255, 255, 0.95); + text-shadow: 1px 1px 2px rgba(255, 255, 255, 0.8), 0 0 4px rgba(255, 255, 255, 0.6); + color: #2c3e50; } 100% { - text-shadow: 0 0 20px rgba(255, 255, 255, 0.8), 0 2px 10px rgba(0, 0, 0, 0.3); - color: rgba(255, 255, 255, 1); + text-shadow: 2px 2px 4px rgba(255, 255, 255, 0.9), 0 0 8px rgba(255, 255, 255, 0.7); + color: #3498db; } } .subtitle { font-size: 1.3em; - color: rgba(255, 255, 255, 0.8); + color: #7f8c8d; margin-bottom: 30px; - font-weight: 500; - text-shadow: 0 1px 5px rgba(0, 0, 0, 0.2); + font-weight: 600; + text-shadow: 0 1px 2px rgba(255, 255, 255, 0.8); + animation: subtitleColorShift 25s ease infinite; +} + +@keyframes subtitleColorShift { + 0% { + color: #7f8c8d; + text-shadow: 0 1px 2px rgba(255, 255, 255, 0.8); + } + 25% { + color: #9b59b6; + text-shadow: 0 1px 3px rgba(255, 255, 255, 0.9); + } + 50% { + color: #e67e22; + text-shadow: 0 1px 2px rgba(255, 255, 255, 0.7); + } + 75% { + color: #27ae60; + text-shadow: 0 1px 3px rgba(255, 255, 255, 0.8); + } + 100% { + color: #7f8c8d; + text-shadow: 0 1px 2px rgba(255, 255, 255, 0.8); + } } /* 日期选择器 */ @@ -149,10 +298,34 @@ body { display: flex; align-items: center; gap: 8px; - color: rgba(255, 255, 255, 0.9); + color: #0f1419; font-weight: 600; font-size: 1em; - text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); + text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.6); + animation: labelColorShift 25s ease infinite; +} + +@keyframes labelColorShift { + 0% { + color: #0f1419; + text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.6); + } + 25% { + color: #1a252f; + text-shadow: 2px 2px 3px rgba(0, 0, 0, 0.7); + } + 50% { + color: #2c3e50; + text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.5); + } + 75% { + color: #0f1419; + text-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6); + } + 100% { + color: #0f1419; + text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.6); + } } .label-icon { @@ -166,13 +339,42 @@ body { border: 1px solid rgba(255, 255, 255, 0.3); border-radius: 15px; padding: 12px 16px; - color: rgba(255, 255, 255, 0.95); + color: #0a0f14; font-size: 1em; font-weight: 500; transition: all 0.3s ease; box-shadow: 0 4px 15px rgba(31, 38, 135, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.2); + animation: inputColorShift 25s ease infinite; +} + +@keyframes inputColorShift { + 0% { + background: rgba(255, 255, 255, 0.1); + border-color: rgba(255, 255, 255, 0.3); + color: #0a0f14; + } + 25% { + background: rgba(255, 255, 255, 0.2); + border-color: rgba(255, 255, 255, 0.4); + color: #1a252f; + } + 50% { + background: rgba(255, 255, 255, 0.15); + border-color: rgba(255, 255, 255, 0.35); + color: #2c3e50; + } + 75% { + background: rgba(255, 255, 255, 0.18); + border-color: rgba(255, 255, 255, 0.38); + color: #0a0f14; + } + 100% { + background: rgba(255, 255, 255, 0.1); + border-color: rgba(255, 255, 255, 0.3); + color: #0a0f14; + } } .date-input:focus { @@ -196,7 +398,7 @@ body { background: rgba(255, 255, 255, 0.15); backdrop-filter: blur(15px); -webkit-backdrop-filter: blur(15px); - color: rgba(255, 255, 255, 0.95); + color: #0a0f14; border: 1px solid rgba(255, 255, 255, 0.3); padding: 12px 28px; border-radius: 20px; @@ -209,10 +411,39 @@ body { gap: 8px; position: relative; overflow: hidden; - text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); + text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5); box-shadow: 0 4px 15px rgba(31, 38, 135, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.3); + animation: buttonColorShift 25s ease infinite; +} + +@keyframes buttonColorShift { + 0% { + background: rgba(255, 255, 255, 0.15); + border-color: rgba(255, 255, 255, 0.3); + color: #0a0f14; + } + 25% { + background: rgba(255, 255, 255, 0.25); + border-color: rgba(255, 255, 255, 0.4); + color: #1a252f; + } + 50% { + background: rgba(255, 255, 255, 0.2); + border-color: rgba(255, 255, 255, 0.35); + color: #2c3e50; + } + 75% { + background: rgba(255, 255, 255, 0.22); + border-color: rgba(255, 255, 255, 0.38); + color: #0a0f14; + } + 100% { + background: rgba(255, 255, 255, 0.15); + border-color: rgba(255, 255, 255, 0.3); + color: #0a0f14; + } } .query-btn::before { @@ -257,7 +488,7 @@ body { align-items: center; justify-content: center; gap: 8px; - color: rgba(255, 255, 255, 0.8); + color: #1a252f; font-size: 1em; padding: 10px 20px; background: rgba(255, 255, 255, 0.08); @@ -266,7 +497,8 @@ body { border-radius: 20px; border: 1px solid rgba(255, 255, 255, 0.15); display: inline-flex; - text-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); + text-shadow: 0 1px 3px rgba(0, 0, 0, 0.4); + font-weight: 600; } .time-icon { @@ -477,8 +709,8 @@ body { .card-title { font-size: 1.5em; font-weight: 700; - color: rgba(255, 255, 255, 0.95); - text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); + color: #0a0f14; + text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6); } .card-content { @@ -512,16 +744,16 @@ body { .item-label { font-weight: 600; - color: rgba(255, 255, 255, 0.9); + color: #1a252f; min-width: 80px; - text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); } .item-value { font-weight: 700; - color: rgba(255, 255, 255, 0.95); + color: #0a0f14; font-size: 1.1em; - text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); } /* 错误信息 */ @@ -558,14 +790,15 @@ body { .error-content h3 { font-size: 1.6em; - color: rgba(255, 255, 255, 0.95); + color: #0a0f14; margin: 0; font-weight: 700; - text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); + text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6); } .error-content p { - color: rgba(255, 255, 255, 0.8); + color: #1a252f; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4); font-size: 1.1em; margin: 0; line-height: 1.6; @@ -576,7 +809,7 @@ body { background: rgba(255, 255, 255, 0.15); backdrop-filter: blur(15px); -webkit-backdrop-filter: blur(15px); - color: rgba(255, 255, 255, 0.95); + color: #0a0f14; border: 1px solid rgba(255, 255, 255, 0.3); padding: 12px 25px; border-radius: 20px; @@ -587,7 +820,7 @@ body { display: inline-flex; align-items: center; gap: 8px; - text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); + text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6); box-shadow: 0 4px 15px rgba(31, 38, 135, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.3); @@ -643,9 +876,9 @@ body { .tip-card h3 { font-size: 1.4em; font-weight: 700; - color: rgba(255, 255, 255, 0.95); + color: #0a0f14; margin-bottom: 20px; - text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); + text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6); } .tip-card ul { @@ -656,7 +889,7 @@ body { } .tip-card li { - color: rgba(255, 255, 255, 0.9); + color: #1a252f; font-size: 1em; padding: 10px 15px; background: rgba(255, 255, 255, 0.08); @@ -665,7 +898,7 @@ body { border-radius: 10px; border: 1px solid rgba(255, 255, 255, 0.15); transition: all 0.3s ease; - text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4); } .tip-card li:hover { @@ -887,6 +1120,35 @@ body { padding: 8px 12px; font-size: 0.9em; } + + /* 手机端性能优化 - 减少动画 */ + .title { + animation: none; + } + + .subtitle { + animation: none; + } + + .input-label { + animation: none; + } + + .date-input { + animation: none; + } + + .query-btn { + animation: none; + } + + .card-icon { + animation: none; + } + + .tip-icon { + animation: none; + } } /* 超小屏幕适配 (480px以下) */ @@ -1004,6 +1266,35 @@ body { display: none; } + /* 禁用复杂动画以提升性能 */ + .title { + animation: none; + } + + .subtitle { + animation: none; + } + + .input-label { + animation: none; + } + + .date-input { + animation: none; + } + + .query-btn { + animation: none; + } + + .card-icon { + animation: none; + } + + .tip-icon { + animation: none; + } + .loading-content { gap: 15px; } @@ -1047,12 +1338,14 @@ body { .hour-name { font-size: 14px; font-weight: 600; - color: #ffffff; + color: #2c3e50; text-align: center; margin-bottom: 8px; padding: 4px 8px; - background: rgba(255, 255, 255, 0.1); + background: rgba(255, 255, 255, 0.8); border-radius: 6px; + text-shadow: 0 1px 2px rgba(255, 255, 255, 0.5); + border: 1px solid rgba(255, 255, 255, 0.9); } .hour-content { diff --git a/frontend/60sapi/实用功能/农历信息/index.html b/frontend/60sapi/实用功能/农历信息/index.html index 0e8aace3..6744ddec 100644 --- a/frontend/60sapi/实用功能/农历信息/index.html +++ b/frontend/60sapi/实用功能/农历信息/index.html @@ -8,6 +8,44 @@ + +
+ + +
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
🏮
diff --git a/frontend/60sapi/实用功能/哈希解压压缩/index.html b/frontend/60sapi/实用功能/哈希解压压缩/index.html index 76cedb0f..5859a369 100644 --- a/frontend/60sapi/实用功能/哈希解压压缩/index.html +++ b/frontend/60sapi/实用功能/哈希解压压缩/index.html @@ -168,15 +168,6 @@
-
- -
- 等待处理... - -
-
diff --git a/frontend/60sapi/实用功能/哈希解压压缩/js/script.js b/frontend/60sapi/实用功能/哈希解压压缩/js/script.js index cc8350b6..4427a177 100644 --- a/frontend/60sapi/实用功能/哈希解压压缩/js/script.js +++ b/frontend/60sapi/实用功能/哈希解压压缩/js/script.js @@ -23,7 +23,6 @@ const resultElements = { urlEncode: document.getElementById('urlEncodeResult'), urlDecode: document.getElementById('urlDecodeResult'), gzipCompress: document.getElementById('gzipCompressResult'), - gzipDecompress: document.getElementById('gzipDecompressResult'), deflateCompress: document.getElementById('deflateCompressResult'), brotliCompress: document.getElementById('brotliCompressResult') }; @@ -142,28 +141,43 @@ function displayResults(data) { // Base64编码 if (data.base64) { - updateResultElement('base64Encode', data.base64.encode || '不可用'); - updateResultElement('base64Decode', data.base64.decode || '不可用'); + updateResultElement('base64Encode', data.base64.encoded || '不可用'); + // BASE64解码:只有当输入本身是BASE64格式时才显示解码结果 + let base64DecodeResult = data.base64.decoded; + if (!base64DecodeResult) { + // 检查输入是否为有效的BASE64格式 + const inputValue = elements.inputText.value.trim(); + const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/; + if (base64Regex.test(inputValue) && inputValue.length % 4 === 0) { + try { + base64DecodeResult = atob(inputValue); + } catch (e) { + base64DecodeResult = '解码失败'; + } + } else { + base64DecodeResult = '输入非BASE64格式'; + } + } + updateResultElement('base64Decode', base64DecodeResult || '不可用'); } // URL编码 if (data.url) { - updateResultElement('urlEncode', data.url.encode || '不可用'); - updateResultElement('urlDecode', data.url.decode || '不可用'); + updateResultElement('urlEncode', data.url.encoded || '不可用'); + updateResultElement('urlDecode', data.url.decoded || '不可用'); } - // 压缩结果 + // 压缩结果(仅显示压缩,不显示解压) if (data.gzip) { - updateResultElement('gzipCompress', data.gzip.compress || '不可用'); - updateResultElement('gzipDecompress', data.gzip.decompress || '不可用'); + updateResultElement('gzipCompress', data.gzip.encoded || '不可用'); } if (data.deflate) { - updateResultElement('deflateCompress', data.deflate.compress || '不可用'); + updateResultElement('deflateCompress', data.deflate.encoded || '不可用'); } if (data.brotli) { - updateResultElement('brotliCompress', data.brotli.compress || '不可用'); + updateResultElement('brotliCompress', data.brotli.encoded || '不可用'); } } catch (error) { diff --git a/frontend/60sapi/实用功能/哈希解压压缩/返回接口.json b/frontend/60sapi/实用功能/哈希解压压缩/返回接口.json index a6b3804b..ed6fc83c 100644 --- a/frontend/60sapi/实用功能/哈希解压压缩/返回接口.json +++ b/frontend/60sapi/实用功能/哈希解压压缩/返回接口.json @@ -1,33 +1,35 @@ { "code": 200, - "message": "处理成功", + "message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s,反馈群 595941841", "data": { - "source": "你好👋", - "md5": "a1b2c3d4e5f6789012345678901234567", + "source": "hello", + "md5": "5d41402abc4b2a76b9719d911017c592", "sha": { - "sha1": "da39a3ee5e6b4b0d3255bfef95601890afd80709", - "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - "sha512": "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e" + "sha1": "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d", + "sha256": "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", + "sha512": "9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043" }, "base64": { - "encode": "5L2g5aW9", - "decode": "你好" + "encoded": "aGVsbG8=", + "decoded": "" }, "url": { - "encode": "%E4%BD%A0%E5%A5%BD%F0%9F%91%8B", - "decode": "你好👋" + "encoded": "hello", + "decoded": "hello" }, "gzip": { - "compress": "H4sIAAAAAAAAA...(压缩后的数据)", - "decompress": "你好👋" + "encoded": "1f8b0800000000000003cb48cdc9c9070086a6103605000000", + "decoded": "" }, "deflate": { - "compress": "eJwrz8kvTUlMy...(压缩后的数据)", - "decompress": "你好👋" + "encoded": "789ccb48cdc9c90700062c0215", + "decoded": "" }, "brotli": { - "compress": "CwWAaGVsbG8g...(压缩后的数据)", - "decompress": "你好👋" + "encoded": "0b028068656c6c6f03", + "decoded": "" } } -} \ No newline at end of file +} + +注意:实际API返回的字段名是 encoded/decoded,不是 encode/decode \ No newline at end of file diff --git a/frontend/60sapi/实用功能/链接OG信息/index.html b/frontend/60sapi/实用功能/链接OG信息/index.html index d3251708..2f603665 100644 --- a/frontend/60sapi/实用功能/链接OG信息/index.html +++ b/frontend/60sapi/实用功能/链接OG信息/index.html @@ -135,8 +135,8 @@
-
- -
-
+ +
-
@@ -161,8 +161,12 @@
-
- -
-
+ +
-
+
+
+ +
-
diff --git a/frontend/60sapi/实用功能/链接OG信息/js/script.js b/frontend/60sapi/实用功能/链接OG信息/js/script.js index 7a25592a..73ccaa00 100644 --- a/frontend/60sapi/实用功能/链接OG信息/js/script.js +++ b/frontend/60sapi/实用功能/链接OG信息/js/script.js @@ -124,6 +124,7 @@ class OGAnalyzer { this.currentUrl = url; this.isAnalyzing = true; + this.startTime = Date.now(); // 记录开始时间 this.showLoading(); this.hideError(); this.hideResults(); @@ -185,23 +186,36 @@ class OGAnalyzer { const resultsElement = document.getElementById('results'); const ogCard = document.getElementById('og-card'); - // 基础信息 - this.updateElement('og-title', data.title || '未获取到标题'); - this.updateElement('og-description', data.description || '未获取到描述'); - this.updateElement('og-url', data.url || this.currentUrl); - this.updateElement('og-site-name', data.site_name || '未知站点'); - this.updateElement('og-type', data.type || 'website'); + // 检查是否有有效数据 - 放宽检查条件,只要有任何非空字段就显示 + const hasValidData = Object.values(data).some(value => { + if (value === null || value === undefined) return false; + if (typeof value === 'string') return value.trim() !== ''; + return true; // 其他类型的值都认为是有效的 + }); + + if (!hasValidData) { + this.showError('该链接暂无可获取的OG信息,请检查链接是否正确或稍后重试'); + return; + } + + // 基础信息 - 只显示有数据的字段 + this.updateElementWithVisibility('og-title', data.title, '标题'); + this.updateElementWithVisibility('og-description', data.description, '描述'); + this.updateElement('og-url', data.url || this.currentUrl); // URL始终显示 + this.updateElementWithVisibility('og-site-name', data.site_name, '网站名称'); + this.updateElement('og-type', data.type || 'website'); // 类型始终显示 // 媒体信息 - this.updateImageElement('og-image', data.image); - this.updateElement('og-image-alt', data.image_alt || '图片描述不可用'); + this.updateImageElementWithVisibility('og-image', data.image); + this.updateElementWithVisibility('og-image-alt', data.image_alt, '图片描述'); // 技术信息 - this.updateElement('og-locale', data.locale || '未指定'); - this.updateElement('og-updated-time', this.formatDate(data.updated_time)); - this.updateElement('response-time', `${Date.now() - this.startTime}ms`); + this.updateElementWithVisibility('og-locale', data.locale, '语言'); + this.updateElementWithVisibility('og-updated-time', this.formatDate(data.updated_time), '更新时间'); + this.updateElement('response-time', `${Date.now() - this.startTime}ms`); // 响应时间始终显示 // 显示结果 + resultsElement.style.display = 'block'; resultsElement.classList.add('active'); // 添加动画效果 @@ -219,6 +233,21 @@ class OGAnalyzer { } } + updateElementWithVisibility(id, content, fieldName) { + const element = document.getElementById(id); + if (!element) return; + + const parentItem = element.closest('.info-item'); + if (!parentItem) return; + + if (content && content.trim() !== '') { + element.textContent = content; + parentItem.style.display = 'block'; + } else { + parentItem.style.display = 'none'; + } + } + updateImageElement(id, imageSrc) { const element = document.getElementById(id); if (element && imageSrc) { @@ -240,6 +269,30 @@ class OGAnalyzer { } } + updateImageElementWithVisibility(id, imageSrc) { + const element = document.getElementById(id); + const mediaSection = document.querySelector('.media-info'); + const mediaPreview = document.getElementById('media-preview'); + + if (imageSrc && imageSrc.trim() !== '') { + element.textContent = imageSrc; + if (mediaSection) mediaSection.style.display = 'block'; + + if (mediaPreview) { + mediaPreview.innerHTML = ` + OG Image + + `; + } + } else { + if (mediaSection) mediaSection.style.display = 'none'; + } + } + formatDate(timestamp) { if (!timestamp) return '未知'; try { @@ -292,6 +345,7 @@ class OGAnalyzer { hideResults() { const resultsElement = document.getElementById('results'); + resultsElement.style.display = 'none'; resultsElement.classList.remove('active'); // 重置动画状态 @@ -358,6 +412,7 @@ class OGAnalyzer { urlInput.value = ''; urlInput.classList.remove('error'); + resultsElement.style.display = 'none'; resultsElement.classList.remove('active'); errorElement.classList.remove('active'); @@ -367,6 +422,13 @@ class OGAnalyzer { this.currentUrl = ''; + // 重置所有字段的显示状态 + const infoItems = document.querySelectorAll('.info-item'); + infoItems.forEach(item => item.style.display = 'block'); + + const mediaSection = document.querySelector('.media-info'); + if (mediaSection) mediaSection.style.display = 'block'; + // 重置动画状态 const cards = document.querySelectorAll('.info-card'); cards.forEach(card => card.classList.remove('animate-in')); From 6f850caad1ff2fb0278348010035e72564b6eb73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A0=91=E8=90=8C=E8=8A=BD?= <3205788256@qq.com> Date: Thu, 4 Sep 2025 16:03:09 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E7=BD=91=E9=A1=B5=E6=A1=86=E6=9E=B6?= =?UTF-8?q?=E9=83=A8=E7=BD=B2=E6=88=90=E5=8A=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 59 +++++++++++++++ backend/.env.production | 14 ++++ backend/app.py | 6 +- backend/deploy.bat | 27 +++++++ backend/modules/api_60s.py | 5 +- build_frontend.bat | 6 ++ .../60sapi/热搜榜单/抖音热搜榜/js/script.js | 2 +- frontend/react-app/.env.production | 2 + frontend/react-app/package.json | 3 +- frontend/react-app/public/sw.js | 48 ++++++++++++ frontend/react-app/src/index.js | 13 ++++ frontend/react-app/src/pages/AiModelPage.js | 7 +- frontend/react-app/src/pages/Api60sPage.js | 73 +++---------------- frontend/react-app/src/pages/SmallGamePage.js | 7 +- frontend/react-app/src/utils/api.js | 39 +++++----- nginx-config-example.conf | 72 ++++++++++++++++++ 16 files changed, 287 insertions(+), 96 deletions(-) create mode 100644 backend/.env.production create mode 100644 backend/deploy.bat create mode 100644 build_frontend.bat create mode 100644 frontend/react-app/.env.production create mode 100644 frontend/react-app/public/sw.js create mode 100644 nginx-config-example.conf diff --git a/README.md b/README.md index 169baa46..61b18be9 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,11 @@ InfoGenie 是一个前后端分离的多功能聚合应用,提供实时数据接口、休闲游戏、AI工具等丰富功能。 +### 🌐 部署环境 + +- **前端部署地址**: https://infogenie.shumengya.top +- **后端部署地址**: https://infogenie.api.shumengya.top + ### 🏗️ 技术架构 - **前端**: React + Styled Components + React Router @@ -48,6 +53,60 @@ cd backend pip install -r requirements.txt ``` +## 🚢 部署指南 + +### 🖥️ 前端部署 + +1. 进入前端目录:`cd frontend/react-app` +2. 安装依赖:`npm install` +3. 构建生产环境应用:`npm run build` +4. 将 `build` 目录下的所有文件上传到前端服务器的网站根目录 + +也可以直接运行 `frontend/react-app/deploy.bat` 脚本进行构建。 + +### ⚙️ 后端部署 + +1. 进入后端目录:`cd backend` +2. 安装依赖:`pip install -r requirements.txt` +3. 配置环境变量或创建 `.env` 文件,包含以下内容: + ``` + MONGO_URI=你的MongoDB连接字符串 + MAIL_USERNAME=你的邮箱地址 + MAIL_PASSWORD=你的邮箱授权码 + SECRET_KEY=你的应用密钥 + SESSION_COOKIE_SECURE=True + ``` +4. 使用 Gunicorn 或 uWSGI 作为 WSGI 服务器启动应用: + ``` + gunicorn -w 4 -b 0.0.0.0:5000 "app:create_app()" + ``` +5. 配置反向代理,将 `https://infogenie.api.shumengya.top` 反向代理到后端服务 + +也可以参考 `backend/deploy.bat` 脚本中的部署说明。 + +### ⚙️ 配置说明 + +#### 前端配置 + +前端通过环境变量配置API基础URL: + +- 开发环境:`.env.development` 文件中设置 `REACT_APP_API_URL=http://localhost:5000` +- 生产环境:`.env.production` 文件中设置 `REACT_APP_API_URL=https://infogenie.api.shumengya.top` + +#### 后端配置 + +后端通过 `config.py` 和环境变量进行配置: + +- MongoDB连接:通过环境变量 `MONGO_URI` 设置 +- 邮件服务:通过环境变量 `MAIL_USERNAME` 和 `MAIL_PASSWORD` 设置 +- CORS配置:在 `app.py` 中配置允许的前端域名 + +#### 60sAPI配置 + +60sAPI模块的静态文件位于 `frontend/60sapi` 目录,通过后端的静态文件服务提供访问。 + +各API模块的接口地址已配置为 `https://infogenie.api.shumengya.top/api/60s`。 + #### 前端依赖 ```bash cd frontend/react-app diff --git a/backend/.env.production b/backend/.env.production new file mode 100644 index 00000000..15d521db --- /dev/null +++ b/backend/.env.production @@ -0,0 +1,14 @@ +# 生产环境配置 + +# MongoDB配置 +MONGO_URI=mongodb://用户名:密码@主机地址:端口/InfoGenie?authSource=admin + +# 邮件配置 +MAIL_USERNAME=your-email@qq.com +MAIL_PASSWORD=your-app-password + +# 应用密钥 +SECRET_KEY=infogenie-production-secret-key-2025 + +# 会话安全配置 +SESSION_COOKIE_SECURE=True \ No newline at end of file diff --git a/backend/app.py b/backend/app.py index 7a381449..24528ab0 100644 --- a/backend/app.py +++ b/backend/app.py @@ -31,7 +31,7 @@ def create_app(): # 加载配置 app.config.from_object(Config) - # 启用CORS跨域支持 + # 启用CORS跨域支持(允许所有源) CORS(app, supports_credentials=True) # 初始化MongoDB @@ -182,6 +182,4 @@ def create_app(): if __name__ == '__main__': app = create_app() print("🚀 启动 InfoGenie 后端服务...") - print("📡 API地址: http://localhost:5000") - print("📚 文档地址: http://localhost:5000/api/health") - app.run(debug=True, host='0.0.0.0', port=5000) + app.run(debug=True, host='0.0.0.0', port=5002) diff --git a/backend/deploy.bat b/backend/deploy.bat new file mode 100644 index 00000000..2492b542 --- /dev/null +++ b/backend/deploy.bat @@ -0,0 +1,27 @@ +@echo off +echo ===== 开始部署后端应用到生产环境 ===== + +cd /d "%~dp0" + +echo 1. 安装依赖... +pip install -r requirements.txt + +echo 2. 部署说明: +echo. +echo 请确保以下配置已完成: +echo 1. 在服务器上配置环境变量或创建 .env 文件,包含以下内容: +echo MONGO_URI=你的MongoDB连接字符串 +echo MAIL_USERNAME=你的邮箱地址 +echo MAIL_PASSWORD=你的邮箱授权码 +echo SECRET_KEY=你的应用密钥 +echo. +echo 3. 启动后端服务: +echo 在生产环境中,建议使用 Gunicorn 或 uWSGI 作为 WSGI 服务器 +echo 示例命令:gunicorn -w 4 -b 0.0.0.0:5000 "app:create_app()" +echo. +echo 4. 配置反向代理: +echo 将 https://infogenie.api.shumengya.top 反向代理到后端服务 +echo. +echo ===== 后端应用部署准备完成 ===== + +pause \ No newline at end of file diff --git a/backend/modules/api_60s.py b/backend/modules/api_60s.py index 9d839809..5b520bb6 100644 --- a/backend/modules/api_60s.py +++ b/backend/modules/api_60s.py @@ -73,10 +73,13 @@ def scan_directories(): except: title = module_name + # 根据环境获取基础URL + base_url = 'https://infogenie.api.shumengya.top' + apis.append({ 'title': title, 'description': f'{module_name}相关功能', - 'link': f'http://localhost:5000/60sapi/{category_name}/{module_name}/index.html', + 'link': f'{base_url}/60sapi/{category_name}/{module_name}/index.html', 'status': 'active', 'color': gradient_colors[i % len(gradient_colors)] }) diff --git a/build_frontend.bat b/build_frontend.bat new file mode 100644 index 00000000..66bfcc0c --- /dev/null +++ b/build_frontend.bat @@ -0,0 +1,6 @@ +@echo off +cd /d "e:\Python\InfoGenie\frontend\react-app" +npm run build + +npx serve -s build +pause \ No newline at end of file diff --git a/frontend/60sapi/热搜榜单/抖音热搜榜/js/script.js b/frontend/60sapi/热搜榜单/抖音热搜榜/js/script.js index 03931e5d..b8501eb8 100644 --- a/frontend/60sapi/热搜榜单/抖音热搜榜/js/script.js +++ b/frontend/60sapi/热搜榜单/抖音热搜榜/js/script.js @@ -1,5 +1,5 @@ // 本地后端API接口 -const LOCAL_API_BASE = 'http://localhost:5000/api/60s'; +const LOCAL_API_BASE = 'https://infogenie.api.shumengya.top/api/60s'; // API接口列表(备用) const API_ENDPOINTS = [ diff --git a/frontend/react-app/.env.production b/frontend/react-app/.env.production new file mode 100644 index 00000000..6a5f6cc6 --- /dev/null +++ b/frontend/react-app/.env.production @@ -0,0 +1,2 @@ +# 生产环境API配置 +REACT_APP_API_URL=https://infogenie.api.shumengya.top \ No newline at end of file diff --git a/frontend/react-app/package.json b/frontend/react-app/package.json index 7016236e..ad0b2ebc 100644 --- a/frontend/react-app/package.json +++ b/frontend/react-app/package.json @@ -44,6 +44,5 @@ "last 1 firefox version", "last 1 safari version" ] - }, - "proxy": "http://localhost:5000" + } } diff --git a/frontend/react-app/public/sw.js b/frontend/react-app/public/sw.js new file mode 100644 index 00000000..e1b7536e --- /dev/null +++ b/frontend/react-app/public/sw.js @@ -0,0 +1,48 @@ +// Service Worker for InfoGenie App +const CACHE_NAME = 'infogenie-cache-v1'; +const urlsToCache = [ + '/', + '/index.html', + '/manifest.json' +]; + +// 安装Service Worker +self.addEventListener('install', event => { + event.waitUntil( + caches.open(CACHE_NAME) + .then(cache => { + console.log('Opened cache'); + return cache.addAll(urlsToCache); + }) + ); +}); + +// 拦截请求并从缓存中响应 +self.addEventListener('fetch', event => { + event.respondWith( + caches.match(event.request) + .then(response => { + // 如果找到缓存的响应,则返回缓存 + if (response) { + return response; + } + return fetch(event.request); + }) + ); +}); + +// 更新Service Worker +self.addEventListener('activate', event => { + const cacheWhitelist = [CACHE_NAME]; + event.waitUntil( + caches.keys().then(cacheNames => { + return Promise.all( + cacheNames.map(cacheName => { + if (cacheWhitelist.indexOf(cacheName) === -1) { + return caches.delete(cacheName); + } + }) + ); + }) + ); +}); \ No newline at end of file diff --git a/frontend/react-app/src/index.js b/frontend/react-app/src/index.js index 882116ee..484c43d2 100644 --- a/frontend/react-app/src/index.js +++ b/frontend/react-app/src/index.js @@ -9,3 +9,16 @@ root.render( ); + +// 注册Service Worker +if ('serviceWorker' in navigator) { + window.addEventListener('load', () => { + navigator.serviceWorker.register('/sw.js') + .then(registration => { + console.log('ServiceWorker registration successful with scope: ', registration.scope); + }) + .catch(error => { + console.error('ServiceWorker registration failed: ', error); + }); + }); +} diff --git a/frontend/react-app/src/pages/AiModelPage.js b/frontend/react-app/src/pages/AiModelPage.js index dd882eba..33dfd0f3 100644 --- a/frontend/react-app/src/pages/AiModelPage.js +++ b/frontend/react-app/src/pages/AiModelPage.js @@ -3,7 +3,7 @@ import { useNavigate } from 'react-router-dom'; import styled from 'styled-components'; import { FiCpu, FiUser, FiExternalLink, FiArrowLeft } from 'react-icons/fi'; import { useUser } from '../contexts/UserContext'; -import axios from 'axios'; +import api from '../utils/api'; const AiContainer = styled.div` min-height: calc(100vh - 140px); @@ -262,7 +262,7 @@ const AiModelPage = () => { const fetchApps = async () => { try { setLoadingApps(true); - const response = await axios.get('/api/aimodelapp/scan-directories'); + const response = await api.get('/api/aimodelapp/scan-directories'); if (response.data.success) { setApps(response.data.apps); } else { @@ -278,7 +278,8 @@ const AiModelPage = () => { const handleLaunchApp = (app) => { // 将相对路径转换为完整的服务器地址 - const fullLink = `http://localhost:5000${app.link}`; + const baseUrl = process.env.REACT_APP_API_URL || 'https://infogenie.api.shumengya.top'; + const fullLink = `${baseUrl}${app.link}`; setEmbeddedApp({ ...app, link: fullLink }); }; diff --git a/frontend/react-app/src/pages/Api60sPage.js b/frontend/react-app/src/pages/Api60sPage.js index 20df365a..85cf7daf 100644 --- a/frontend/react-app/src/pages/Api60sPage.js +++ b/frontend/react-app/src/pages/Api60sPage.js @@ -238,81 +238,26 @@ const Api60sPage = () => { // 从后端API获取目录结构 const scanDirectories = async () => { try { - const response = await fetch('http://localhost:5000/api/60s/scan-directories'); + // 使用环境变量中配置的API URL + const baseUrl = process.env.REACT_APP_API_URL || 'https://infogenie.api.shumengya.top'; + const apiUrl = `${baseUrl}/api/60s/scan-directories`; + console.log('正在请求API目录结构:', apiUrl); + const response = await fetch(apiUrl); if (response.ok) { const data = await response.json(); return data; } } catch (error) { - console.warn('无法从后端获取目录结构,使用前端扫描方式'); + console.warn('无法从后端获取目录结构:', error); } return null; }; - // 前端扫描方式(备用) - const frontendScan = async () => { - const categories = []; - - for (const [categoryName, config] of Object.entries(categoryConfig)) { - const apis = []; - - // 尝试访问已知的模块列表(只包含实际存在的模块) - const knownModules = { - '热搜榜单': ['抖音热搜榜'], - '日更资讯': [], - '实用功能': [], - '娱乐消遣': [] - }; + // 前端扫描方式已移除 - const moduleNames = knownModules[categoryName] || []; - - for (let i = 0; i < moduleNames.length; i++) { - const moduleName = moduleNames[i]; - try { - const indexPath = `/60sapi/${categoryName}/${moduleName}/index.html`; - const fullUrl = `http://localhost:5000${indexPath}`; - const response = await fetch(fullUrl, { method: 'HEAD' }); - - if (response.ok) { - // 获取页面标题 - const htmlResponse = await fetch(fullUrl); - const html = await htmlResponse.text(); - const titleMatch = html.match(/(.*?)<\/title>/i); - const title = titleMatch ? titleMatch[1].trim() : moduleName; - - apis.push({ - title, - description: `${moduleName}相关功能`, - link: fullUrl, - status: 'active', - color: gradientColors[i % gradientColors.length] - }); - } - } catch (error) { - // 忽略访问失败的模块 - } - } - - if (apis.length > 0) { - categories.push({ - title: categoryName, - icon: config.icon, - color: config.color, - apis - }); - } - } - - return categories; - }; - - // 首先尝试后端扫描,失败则使用前端扫描 + // 只使用后端扫描 const backendResult = await scanDirectories(); - if (backendResult && backendResult.success) { - return backendResult.categories || []; - } else { - return await frontendScan(); - } + return backendResult && backendResult.success ? backendResult.categories || [] : []; } catch (error) { console.error('扫描API模块时出错:', error); diff --git a/frontend/react-app/src/pages/SmallGamePage.js b/frontend/react-app/src/pages/SmallGamePage.js index 3c8e6bd5..047d1d93 100644 --- a/frontend/react-app/src/pages/SmallGamePage.js +++ b/frontend/react-app/src/pages/SmallGamePage.js @@ -1,7 +1,7 @@ import React, { useState, useEffect } from 'react'; import styled from 'styled-components'; import { FiGrid, FiPlay, FiExternalLink, FiArrowLeft } from 'react-icons/fi'; -import axios from 'axios'; +import api from '../utils/api'; const GameContainer = styled.div` min-height: calc(100vh - 140px); @@ -233,7 +233,7 @@ const SmallGamePage = () => { const fetchGames = async () => { try { setLoading(true); - const response = await axios.get('/api/smallgame/scan-directories'); + const response = await api.get('/api/smallgame/scan-directories'); if (response.data.success) { setGames(response.data.games); } else { @@ -249,7 +249,8 @@ const SmallGamePage = () => { const handlePlayGame = (game) => { // 将相对路径转换为完整的服务器地址 - const fullLink = `http://localhost:5000${game.link}`; + const baseUrl = process.env.REACT_APP_API_URL || 'https://infogenie.api.shumengya.top'; + const fullLink = `${baseUrl}${game.link}`; setEmbeddedGame({ ...game, link: fullLink }); }; diff --git a/frontend/react-app/src/utils/api.js b/frontend/react-app/src/utils/api.js index 9a033504..4e8810ef 100644 --- a/frontend/react-app/src/utils/api.js +++ b/frontend/react-app/src/utils/api.js @@ -3,7 +3,7 @@ import toast from 'react-hot-toast'; // 创建axios实例 const api = axios.create({ - baseURL: process.env.REACT_APP_API_URL || '/api', + baseURL: process.env.REACT_APP_API_URL || 'https://infogenie.api.shumengya.top', timeout: 10000, withCredentials: true, // 支持携带cookie headers: { @@ -11,6 +11,9 @@ const api = axios.create({ } }); +// 打印当前使用的API URL,便于调试 +console.log('API Base URL:', process.env.REACT_APP_API_URL || 'https://infogenie.api.shumengya.top'); + // 请求拦截器 api.interceptors.request.use( (config) => { @@ -44,63 +47,63 @@ api.interceptors.response.use( // 认证相关API export const authAPI = { // 发送验证码 - sendVerification: (data) => api.post('/auth/send-verification', data), + sendVerification: (data) => api.post('/api/auth/send-verification', data), // 验证验证码 - verifyCode: (data) => api.post('/auth/verify-code', data), + verifyCode: (data) => api.post('/api/auth/verify-code', data), // 登录 - login: (credentials) => api.post('/auth/login', credentials), + login: (credentials) => api.post('/api/auth/login', credentials), // 注册 - register: (userData) => api.post('/auth/register', userData), + register: (userData) => api.post('/api/auth/register', userData), // 登出 - logout: () => api.post('/auth/logout'), + logout: () => api.post('/api/auth/logout'), // 检查登录状态 - checkLogin: () => api.get('/auth/check'), + checkLogin: () => api.get('/api/auth/check'), }; // 用户相关API export const userAPI = { // 获取用户资料 - getProfile: () => api.get('/user/profile'), + getProfile: () => api.get('/api/user/profile'), // 修改密码 - changePassword: (passwordData) => api.post('/user/change-password', passwordData), + changePassword: (passwordData) => api.post('/api/user/change-password', passwordData), // 获取用户统计 - getStats: () => api.get('/user/stats'), + getStats: () => api.get('/api/user/stats'), // 删除账户 - deleteAccount: (password) => api.post('/user/delete', { password }), + deleteAccount: (password) => api.post('/api/user/delete', { password }), }; // 60s API相关接口 export const api60s = { // 抖音热搜 - getDouyinHot: () => api.get('/60s/douyin'), + getDouyinHot: () => api.get('/api/60s/douyin'), // 微博热搜 - getWeiboHot: () => api.get('/60s/weibo'), + getWeiboHot: () => api.get('/api/60s/weibo'), // 猫眼票房 - getMaoyanBoxOffice: () => api.get('/60s/maoyan'), + getMaoyanBoxOffice: () => api.get('/api/60s/maoyan'), // 60秒读懂世界 - get60sNews: () => api.get('/60s/60s'), + get60sNews: () => api.get('/api/60s/60s'), // 必应壁纸 - getBingWallpaper: () => api.get('/60s/bing-wallpaper'), + getBingWallpaper: () => api.get('/api/60s/bing-wallpaper'), // 天气信息 - getWeather: (city = '北京') => api.get(`/60s/weather?city=${encodeURIComponent(city)}`), + getWeather: (city = '北京') => api.get(`/api/60s/weather?city=${encodeURIComponent(city)}`), }; // 健康检查 export const healthAPI = { - check: () => api.get('/health'), + check: () => api.get('/api/health'), }; export default api; diff --git a/nginx-config-example.conf b/nginx-config-example.conf new file mode 100644 index 00000000..c0565ff5 --- /dev/null +++ b/nginx-config-example.conf @@ -0,0 +1,72 @@ +# Nginx配置示例 - InfoGenie部署 + +# 前端配置 - infogenie.shumengya.top +server { + listen 80; + server_name infogenie.shumengya.top; + + # 重定向HTTP到HTTPS + location / { + return 301 https://$host$request_uri; + } +} + +server { + listen 443 ssl; + server_name infogenie.shumengya.top; + + # SSL证书配置 + ssl_certificate /path/to/cert.pem; + ssl_certificate_key /path/to/key.pem; + + # 前端静态文件目录 + root /var/www/infogenie; + index index.html; + + # 处理React路由 + location / { + try_files $uri $uri/ /index.html; + } + + # 安全相关配置 + add_header X-Frame-Options "SAMEORIGIN"; + add_header X-XSS-Protection "1; mode=block"; + add_header X-Content-Type-Options "nosniff"; +} + +# 后端配置 - infogenie.api.shumengya.top +server { + listen 80; + server_name infogenie.api.shumengya.top; + + # 重定向HTTP到HTTPS + location / { + return 301 https://$host$request_uri; + } +} + +server { + listen 443 ssl; + server_name infogenie.api.shumengya.top; + + # SSL证书配置 + ssl_certificate /path/to/cert.pem; + ssl_certificate_key /path/to/key.pem; + + # 反向代理到后端服务 + location / { + proxy_pass http://127.0.0.1:5000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # 安全相关配置 + add_header X-Frame-Options "SAMEORIGIN"; + add_header X-XSS-Protection "1; mode=block"; + add_header X-Content-Type-Options "nosniff"; + + # 允许较大的上传文件 + client_max_body_size 10M; +} \ No newline at end of file