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/实用功能/公网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 @@
+ + + + +