diff --git a/InfoGenie-backend/.dockerignore b/InfoGenie-backend/.dockerignore deleted file mode 100644 index 74b16a7c..00000000 --- a/InfoGenie-backend/.dockerignore +++ /dev/null @@ -1,50 +0,0 @@ -# Git -.git -.gitignore - -# Python -__pycache__/ -*.pyc -*.pyo -*.pyd -.Python -env/ -venv/ -.venv/ -pip-log.txt -pip-delete-this-directory.txt -.tox/ -.coverage -.coverage.* -.pytest_cache/ - -# 环境变量文件 -.env -.env.production - -# IDE -.vscode/ -.idea/ -*.swp -*.swo - -# OS -.DS_Store -Thumbs.db - -# 日志文件 -*.log - -# 测试文件(可选,如果不想包含在镜像中) -test/ - -# 文档文件(可选) -*.md -LICENSE - -# 启动脚本(Windows) -*.bat - -# 其他临时文件 -*.tmp -.cache/ diff --git a/InfoGenie-backend/.env b/InfoGenie-backend/.env index 2e37e79d..a0e30219 100755 --- a/InfoGenie-backend/.env +++ b/InfoGenie-backend/.env @@ -2,12 +2,11 @@ # 请勿将此文件提交到版本控制系统 # 邮件配置 -# 请将下面的邮箱地址替换为您的实际QQ邮箱 -MAIL_USERNAME=3205788256@qq.com -MAIL_PASSWORD=szcaxvbftusqddhi +MAIL_USERNAME=shumengya888@foxmail.com +MAIL_PASSWORD=dpdouefloajfdagd # 数据库配置 -MONGO_URI=mongodb://shumengya:tyh%4019900420@47.108.90.0:27018/InfoGenie?authSource=admin +MONGO_URI=mongodb://shumengya:shumengya520@47.108.90.0:27017/InfoGenie?authSource=admin # 应用密钥 SECRET_KEY=infogenie-secret-key-2025 diff --git a/InfoGenie-backend/.env.production b/InfoGenie-backend/.env.production deleted file mode 100755 index bef38d25..00000000 --- a/InfoGenie-backend/.env.production +++ /dev/null @@ -1,14 +0,0 @@ -# 生产环境配置 - -# 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 - -# 会话安全配置 -HWT_SECURE=True \ No newline at end of file diff --git a/InfoGenie-backend/Dockerfile b/InfoGenie-backend/Dockerfile deleted file mode 100644 index c0aae50c..00000000 --- a/InfoGenie-backend/Dockerfile +++ /dev/null @@ -1,32 +0,0 @@ -# 使用官方Python镜像作为基础镜像 -FROM python:3.10-slim - -# 设置工作目录 -WORKDIR /app - -# 安装系统依赖(如果需要) -RUN apt-get update && apt-get install -y \ - gcc \ - && rm -rf /var/lib/apt/lists/* - -# 复制requirements.txt并安装Python依赖 -COPY requirements.txt . -RUN pip install --no-cache-dir -r requirements.txt - -# 复制应用代码 -COPY . . - -# 创建非root用户(安全最佳实践) -RUN useradd --create-home --shell /bin/bash app \ - && chown -R app:app /app -USER app - -# 暴露端口 -EXPOSE 5002 - -# 设置环境变量 -ENV FLASK_APP=app.py -ENV FLASK_ENV=production - -# 启动命令 -CMD ["python", "app.py"] diff --git a/InfoGenie-backend/app.py b/InfoGenie-backend/app.py index 8f2e1465..7f3c1878 100755 --- a/InfoGenie-backend/app.py +++ b/InfoGenie-backend/app.py @@ -50,8 +50,10 @@ def create_app(): def index(): """API根路径""" return jsonify({ - 'message': '✨ 万象口袋 API 服务运行中 ✨', - 'version': '1.0.0', + 'message': '万象口袋 后端 API 服务运行中', + "description": "提供用户认证、用户管理、聚合API、小游戏接口和AI模型应用接口", + "email":"shumengya666@outlook.com", + 'version': '2.2.0', 'timestamp': datetime.now().isoformat(), 'endpoints': { 'auth': '/api/auth', diff --git a/InfoGenie-backend/build_docker.sh b/InfoGenie-backend/build_docker.sh deleted file mode 100755 index 9abf28a8..00000000 --- a/InfoGenie-backend/build_docker.sh +++ /dev/null @@ -1,118 +0,0 @@ -#!/bin/bash - -# InfoGenie 后端 Docker 镜像构建脚本 -# Created by: 万象口袋 -# Date: 2025-09-16 - -set -e - -# 颜色输出 -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color - -# 配置 -IMAGE_NAME="infogenie-backend" -IMAGE_TAG="latest" -DOCKERFILE_PATH="." - -# 函数:打印信息 -print_info() { - echo -e "${GREEN}[INFO]${NC} $1" -} - -print_warning() { - echo -e "${YELLOW}[WARNING]${NC} $1" -} - -print_error() { - echo -e "${RED}[ERROR]${NC} $1" -} - -# 检查Docker是否安装 -check_docker() { - if ! command -v docker &> /dev/null; then - print_error "Docker 未安装,请先安装 Docker" - exit 1 - fi - print_info "Docker 版本: $(docker --version)" -} - -# 检查Dockerfile是否存在 -check_dockerfile() { - if [ ! -f "Dockerfile" ]; then - print_error "Dockerfile 不存在" - exit 1 - fi - print_info "找到 Dockerfile" -} - -# 构建Docker镜像 -build_image() { - print_info "开始构建 Docker 镜像: ${IMAGE_NAME}:${IMAGE_TAG}" - - # 构建镜像 - docker build \ - --no-cache \ - -t ${IMAGE_NAME}:${IMAGE_TAG} \ - -f ${DOCKERFILE_PATH}/Dockerfile \ - ${DOCKERFILE_PATH} - - if [ $? -eq 0 ]; then - print_info "Docker 镜像构建成功!" - print_info "镜像信息:" - docker images ${IMAGE_NAME}:${IMAGE_TAG} - else - print_error "Docker 镜像构建失败" - exit 1 - fi -} - -# 显示使用说明 -show_usage() { - echo "" - print_info "构建完成! 使用方法:" - echo "" - echo "1. 运行容器 (需要MongoDB):" - echo " docker run -d \\" - echo " --name infogenie-backend \\" - echo " -p 5002:5002 \\" - echo " -e MONGO_URI=mongodb://host.docker.internal:27017/InfoGenie \\" - echo " -e SECRET_KEY=your-secret-key \\" - echo " -e MAIL_USERNAME=your-email@qq.com \\" - echo " -e MAIL_PASSWORD=your-app-password \\" - echo " ${IMAGE_NAME}:${IMAGE_TAG}" - echo "" - echo "2. 使用 Docker Compose (推荐):" - echo " 创建 docker-compose.yml 文件并运行:" - echo " docker-compose up -d" - echo "" - echo "3. 查看日志:" - echo " docker logs infogenie-backend" - echo "" - echo "4. 停止容器:" - echo " docker stop infogenie-backend" - echo " docker rm infogenie-backend" -} - -# 主函数 -main() { - print_info "InfoGenie 后端 Docker 镜像构建脚本" - print_info "==================================" - - # 检查环境 - check_docker - check_dockerfile - - # 构建镜像 - build_image - - # 显示使用说明 - show_usage - - print_info "构建脚本执行完成!" -} - -# 执行主函数 -main "$@" diff --git a/InfoGenie-backend/docker-compose.yml b/InfoGenie-backend/docker-compose.yml deleted file mode 100644 index 96795f45..00000000 --- a/InfoGenie-backend/docker-compose.yml +++ /dev/null @@ -1,53 +0,0 @@ -version: '3.8' - -services: - # InfoGenie 后端服务 - infogenie-backend: - build: - context: . - dockerfile: Dockerfile - ports: - - "5002:5002" - environment: - - FLASK_ENV=production - - SECRET_KEY=${SECRET_KEY:-infogenie-secret-key-2025} - - MONGO_URI=mongodb://mongodb:27017/InfoGenie - - MAIL_USERNAME=${MAIL_USERNAME:-your-email@qq.com} - - MAIL_PASSWORD=${MAIL_PASSWORD:-your-app-password} - - HWT_SECURE=false - depends_on: - - mongodb - networks: - - infogenie-network - restart: unless-stopped - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:5002/api/health"] - interval: 30s - timeout: 10s - retries: 3 - - # MongoDB 数据库 - mongodb: - image: mongo:6.0 - ports: - - "27017:27017" - environment: - - MONGO_INITDB_DATABASE=InfoGenie - volumes: - - mongodb_data:/data/db - - ./mongo-init:/docker-entrypoint-initdb.d - networks: - - infogenie-network - restart: unless-stopped - healthcheck: - test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"] - interval: 30s - timeout: 10s - retries: 3 - -volumes: - mongodb_data: - -networks: - infogenie-network: - driver: bridge diff --git a/InfoGenie-backend/modules/__pycache__/aimodelapp.cpython-313.pyc b/InfoGenie-backend/modules/__pycache__/aimodelapp.cpython-313.pyc index 0a5abfa2..fff27464 100755 Binary files a/InfoGenie-backend/modules/__pycache__/aimodelapp.cpython-313.pyc and b/InfoGenie-backend/modules/__pycache__/aimodelapp.cpython-313.pyc differ diff --git a/InfoGenie-backend/modules/__pycache__/auth.cpython-313.pyc b/InfoGenie-backend/modules/__pycache__/auth.cpython-313.pyc index 0612c4d6..d34a4a37 100755 Binary files a/InfoGenie-backend/modules/__pycache__/auth.cpython-313.pyc and b/InfoGenie-backend/modules/__pycache__/auth.cpython-313.pyc differ diff --git a/InfoGenie-backend/modules/__pycache__/email_service.cpython-313.pyc b/InfoGenie-backend/modules/__pycache__/email_service.cpython-313.pyc index 6ce36174..e992185e 100755 Binary files a/InfoGenie-backend/modules/__pycache__/email_service.cpython-313.pyc and b/InfoGenie-backend/modules/__pycache__/email_service.cpython-313.pyc differ diff --git a/InfoGenie-backend/modules/__pycache__/game_stats.cpython-313.pyc b/InfoGenie-backend/modules/__pycache__/game_stats.cpython-313.pyc new file mode 100644 index 00000000..293c4fae Binary files /dev/null and b/InfoGenie-backend/modules/__pycache__/game_stats.cpython-313.pyc differ diff --git a/InfoGenie-backend/modules/__pycache__/user_management.cpython-313.pyc b/InfoGenie-backend/modules/__pycache__/user_management.cpython-313.pyc index e0d43101..1ad337d1 100755 Binary files a/InfoGenie-backend/modules/__pycache__/user_management.cpython-313.pyc and b/InfoGenie-backend/modules/__pycache__/user_management.cpython-313.pyc differ diff --git a/InfoGenie-backend/modules/email_service.py b/InfoGenie-backend/modules/email_service.py index 1f0e69e0..98e9612f 100755 --- a/InfoGenie-backend/modules/email_service.py +++ b/InfoGenie-backend/modules/email_service.py @@ -66,14 +66,14 @@ def send_verification_email(email, verification_type='register'): # 邮件模板 if verification_type == 'register': - subject = '【InfoGenie】注册验证码' + subject = '【万象口袋】注册验证码' html_content = f'''
-

InfoGenie 万象口袋

-

欢迎注册InfoGenie

+

万象口袋

+

欢迎注册万象口袋

diff --git a/InfoGenie-backend/modules/user_management.py b/InfoGenie-backend/modules/user_management.py index 851a19e8..4d4af285 100755 --- a/InfoGenie-backend/modules/user_management.py +++ b/InfoGenie-backend/modules/user_management.py @@ -57,8 +57,21 @@ def login_required(f): def get_profile(): """获取用户资料""" try: - hwt = getattr(request, 'hwt', {}) - user_id = hwt.get('user_id') + # 优先从JWT token获取用户信息 + user_id = None + if hasattr(request, 'current_user') and request.current_user: + user_id = request.current_user.get('user_id') + else: + # 回退到hwt验证 + hwt = getattr(request, 'hwt', {}) + user_id = hwt.get('user_id') + + if not user_id: + return jsonify({ + 'success': False, + 'message': '无法获取用户信息' + }), 401 + users_collection = current_app.mongo.db.userdata user = users_collection.find_one({'_id': ObjectId(user_id)}) if not user: @@ -68,11 +81,16 @@ def get_profile(): }), 404 # 返回用户信息(不包含密码) profile = { - 'account': user['账号'], + 'account': user.get('邮箱'), + 'username': user.get('用户名'), + 'avatar': user.get('头像'), 'register_time': user.get('注册时间'), 'last_login': user.get('最后登录'), 'login_count': user.get('登录次数', 0), - 'status': user.get('用户状态', 'active') + 'status': user.get('用户状态', 'active'), + 'level': user.get('等级', 1), + 'experience': user.get('经验', 0), + 'coins': user.get('萌芽币', 0) } return jsonify({ 'success': True, diff --git a/InfoGenie-backend/后端架构文档.md b/InfoGenie-backend/后端架构文档.md index c13c8438..f55b0161 100755 --- a/InfoGenie-backend/后端架构文档.md +++ b/InfoGenie-backend/后端架构文档.md @@ -1,166 +1,396 @@ -# InfoGenie后端项目专业技术总结 +# InfoGenie 后端架构文档 -## 项目架构概述 +## 项目概述 -InfoGenie后端采用了**模块化、松耦合**的设计理念,基于Flask框架构建RESTful API服务,实现了前后端完全分离的现代Web应用架构。整体架构遵循了**单一职责原则**和**关注点分离原则**,各模块独立封装,通过清晰定义的API接口进行交互。 +InfoGenie(万象口袋)是一个基于前后端分离架构的多功能聚合软件应用。后端采用Flask框架提供RESTful API服务,前端通过HTTP请求调用后端API,实现数据交互和业务逻辑处理。 -## 核心技术栈 +## 技术栈 -### 基础框架 -- **Web框架**: Flask 2.3.3(轻量、灵活、可扩展) -- **API设计**: RESTful架构(资源导向、无状态通信) -- **数据库**: MongoDB(适用于文档型数据存储,通过Flask-PyMongo 2.3.0集成) -- **认证机制**: JWT Token(PyJWT 2.8.0,支持7天有效期) +### 核心框架 +- **Web框架**: Flask 2.3.3 +- **数据库**: MongoDB (Flask-PyMongo 2.3.0) +- **认证**: JWT (PyJWT 2.8.0) +- **跨域**: Flask-CORS 4.0.0 -### 中间件与辅助工具 -- **CORS支持**: Flask-CORS 4.0.0(解决跨域资源共享问题) -- **密码安全**: Werkzeug 2.3.7(提供高强度密码哈希功能) -- **邮件服务**: 基于SMTP协议的邮件发送(使用smtplib直接实现,无依赖Flask-Mail) -- **环境配置**: python-dotenv 1.0.0(分离配置与代码,增强安全性) -- **API限流**: Flask-Limiter 3.5.0(防止API滥用,提高系统稳定性) +### 辅助工具 +- **邮件服务**: Flask-Mail 0.9.1 +- **密码加密**: Werkzeug 2.3.7 +- **环境配置**: python-dotenv 1.0.0 +- **API限流**: Flask-Limiter 3.5.0 -## 架构设计亮点 +## 架构设计原则 -### 1. 应用工厂模式 -项目采用**应用工厂模式**(Factory Pattern)创建Flask应用实例,便于测试和多环境部署: -```python -def create_app(): - app = Flask(__name__) - app.config.from_object(Config) - # 初始化各种扩展和注册蓝图 - return app +### 前后端分离 +- 后端专注于数据处理和业务逻辑 +- 前端负责用户界面和交互体验 +- 通过RESTful API进行数据交换 +- 完全解耦,便于独立开发和部署 + +### 模块化设计 +- 按功能划分独立模块 +- 每个模块职责单一 +- 便于维护和扩展 + +## 核心模块详解 + +### 1. 认证模块 (auth.py) + +**功能职责**: +- 用户注册和登录 +- JWT Token生成和管理 +- 邮箱验证码验证 +- QQ邮箱格式验证 + +**API端点**: +``` +POST /api/auth/send-verification # 发送验证码 +POST /api/auth/verify-code # 验证验证码 +POST /api/auth/register # 用户注册 +POST /api/auth/login # 用户登录 +POST /api/auth/logout # 用户登出 +GET /api/auth/check # 检查登录状态 ``` -### 2. 蓝图模块化设计 -采用Flask蓝图(Blueprint)实现功能模块化,提高代码复用性和可维护性: -- `auth_bp`: 用户认证模块 -- `user_bp`: 用户管理模块 -- `aimodelapp_bp`: AI模型应用模块 +**数据流程**: +1. 前端发送注册/登录请求 +2. 后端验证邮箱格式(仅支持QQ邮箱) +3. 发送验证码邮件到用户邮箱 +4. 用户输入验证码完成验证 +5. 验证成功后生成JWT Token返回给前端 -### 3. 装饰器模式 -大量使用装饰器模式实现横切关注点(Cross-cutting Concerns)如认证、权限验证、萌芽币消费等: -```python -@verify_user_coins -def ai_function_endpoint(): - # 业务逻辑 +**安全特性**: +- 密码使用Werkzeug进行哈希加密 +- JWT Token 7天有效期 +- 验证码5分钟有效期,限制尝试次数 + +### 2. 用户管理模块 (user_management.py) + +**功能职责**: +- 用户资料管理 +- 密码修改 +- 每日签到系统 +- 用户游戏数据管理 +- 账户删除 + +**API端点**: +``` +GET /api/user/profile # 获取用户资料 +POST /api/user/change-password # 修改密码 +GET /api/user/stats # 获取用户统计 +GET /api/user/game-data # 获取游戏数据 +POST /api/user/checkin # 每日签到 +POST /api/user/delete # 删除账户 ``` -### 4. 统一响应格式 -实现了一致的API响应格式,便于前端处理: -```json -{ - "success": true|false, - "data": {}, - "message": "操作信息", - "timestamp": "ISO格式时间戳" -} -``` - -## 安全设计分析 - -### 1. 多层次认证体系 -- **JWT Token认证**: 无状态认证机制,适合分布式部署 -- **验证码邮箱认证**: 双因素认证提高安全性 -- **QQ邮箱格式验证**: 限制注册邮箱类型,减少垃圾注册 - -### 2. 数据安全措施 -- **密码哈希存储**: 使用Werkzeug提供的高强度哈希算法 -- **敏感配置外部化**: 通过环境变量注入敏感配置 -- **路径遍历防护**: 静态文件服务实现了路径限制检查 -```python -if not os.path.commonpath([base_directory, full_path]) == base_directory: - return jsonify({'error': '非法文件路径'}), 403 -``` - -### 3. 请求安全控制 -- **API限流**: 防止暴力攻击和资源耗尽 -- **CORS限制**: 生产环境可配置严格的跨域策略 -- **请求参数验证**: 严格验证所有客户端输入 - -## 业务模块分析 - -### 1. 认证模块(auth.py) -实现了基于JWT的无状态认证系统,通过邮箱验证码进行用户身份确认,支持注册、登录和会话管理。设计重点包括: -- 验证码5分钟有效期机制 -- JWT token 7天有效期管理 -- 认证装饰器实现代码复用 - -### 2. 用户管理模块(user_management.py) -负责用户资料、签到系统、萌芽币管理等核心业务功能,实现了: -- 用户资料CRUD操作 -- 每日签到奖励系统(经验值和萌芽币) -- 用户等级动态计算逻辑 - -### 3. AI模型应用模块(aimodelapp.py) -集成多种AI服务(DeepSeek、Kimi)并实现统一接口调用,特点: -- 萌芽币消费装饰器模式(每次调用消耗100萌芽币) -- AI调用带重试机制(提高系统稳定性) -- 多模型提供商支持(提高可用性和容错性) - -### 4. 邮件服务模块(email_service.py) -负责验证码邮件发送、QQ邮箱格式验证等功能,特点: -- 直接使用smtplib实现,减少依赖 -- HTML格式邮件模板支持 -- 验证码管理机制(内存存储,生产环境建议使用Redis) - -## 数据库设计 - -采用MongoDB文档型数据库,主要集合为`userdata`,存储用户相关所有数据。MongoDB的选择优势: -- **灵活的数据结构**: 适合存储复杂且不断演化的用户数据 -- **文档自包含**: 减少关联查询,提高读取性能 -- **水平扩展能力**: 支持未来系统规模扩展需求 - -用户数据模型设计合理,包含核心字段: +**数据结构**: ```json { "邮箱": "user@qq.com", "用户名": "用户名", "密码": "哈希密码", "头像": "QQ头像URL", - "注册时间": "ISO时间格式", + "注册时间": "2025-01-01T00:00:00", + "最后登录": "2025-01-01T00:00:00", + "登录次数": 10, + "用户状态": "active", + "等级": 5, + "经验": 1200, "萌芽币": 1500, "签到系统": { "连续签到天数": 7, - "今日是否已签到": true + "今日是否已签到": true, + "签到时间": "2025-01-01" } } ``` -## 部署与运维 +**业务逻辑**: +- 签到奖励:300萌芽币 + 200经验 +- 等级升级:100 × 1.2^(等级) 经验需求 -### 多环境配置支持 -实现了开发、测试和生产环境的配置分离: -```python -config = { - 'development': DevelopmentConfig, - 'production': ProductionConfig, - 'testing': TestingConfig, - 'default': DevelopmentConfig +### 3. 邮件服务模块 (email_service.py) + +**功能职责**: +- 验证码邮件发送 +- QQ邮箱格式验证 +- QQ头像获取 +- 邮件模板管理 + +**邮件模板**: +- 注册验证码邮件(HTML格式) +- 登录验证码邮件(HTML格式) +- 支持自定义邮件内容和样式 + +**安全考虑**: +- 仅支持QQ邮箱(qq.com、vip.qq.com、foxmail.com) +- 使用SSL加密连接 +- 验证码存储在内存中(生产环境建议使用Redis) + +### 4. AI模型应用模块 (aimodelapp.py) + +**功能职责**: +- 集成多种AI服务(DeepSeek、Kimi) +- 提供AI功能API接口 +- 统一AI接口调用 +- 管理用户萌芽币消费(每次调用消耗100萌芽币) + +**支持的AI功能**: +1. **AI聊天接口** (`/api/aimodelapp/chat`) +2. **姓名分析** (`/api/aimodelapp/name-analysis`) +3. **变量命名助手** (`/api/aimodelapp/variable-naming`) +4. **AI写诗助手** (`/api/aimodelapp/poetry`) +5. **AI语言翻译** (`/api/aimodelapp/translation`) +6. **现代文转文言文** (`/api/aimodelapp/classical_conversion`) +7. **AI表情制作器** (`/api/aimodelapp/expression-maker`) +8. **Linux命令生成** (`/api/aimodelapp/linux-command`) +9. **获取可用模型** (`/api/aimodelapp/models`) + +**AI配置**: +```json +{ + "deepseek": { + "api_key": "your-api-key", + "api_base": "https://api.deepseek.com", + "model": ["deepseek-chat", "deepseek-reasoner"] + }, + "kimi": { + "api_key": "your-api-key", + "api_base": "https://api.moonshot.cn", + "model": ["kimi-k2-0905-preview", "kimi-k2-0711-preview"] + } } ``` -### Docker化部署 -提供了完整的Docker化部署方案: -- Dockerfile定义应用容器 -- docker-compose.yml配置多容器协作 -- 支持环境变量注入敏感配置 +**调用流程**: +1. 前端发送AI请求(包含消息、模型提供商等参数) +2. 后端加载AI配置文件 +3. 调用对应AI API(带重试机制) +4. 返回AI响应给前端 -## 技术亮点与优化空间 +## API设计规范 -### 亮点 -1. **模块化设计**: 通过Flask蓝图实现功能解耦 -2. **装饰器封装**: 横切关注点(cross-cutting concerns)集中处理 -3. **统一错误处理**: 全局一致的错误响应机制 -4. **AI服务抽象**: 屏蔽不同AI提供商的实现差异 +### 请求/响应格式 -### 优化空间 -1. **缓存机制**: 可引入Redis缓存验证码、热点数据等 -2. **异步处理**: 邮件发送、AI调用等耗时操作可改为异步执行 -3. **日志系统**: 增强日志记录和监控能力 -4. **单元测试**: 增加自动化测试覆盖率 +**成功响应**: +```json +{ + "success": true, + "data": {...}, + "message": "操作成功", + "timestamp": "2025-01-01T00:00:00" +} +``` -## 结论 +**错误响应**: +```json +{ + "success": false, + "message": "错误信息", + "error": "错误详情" +} +``` -InfoGenie后端项目展现了良好的软件工程实践,采用模块化设计、RESTful API架构和多层次安全控制,构建了一个可扩展、可维护的后端系统。该项目不仅满足了当前的业务需求,还为未来功能扩展和性能优化预留了空间。 +### 认证方式 -特别是在AI功能集成方面,通过抽象接口和装饰器模式,实现了业务逻辑与技术实现的分离,体现了良好的软件设计原则。萌芽币消费系统的实现也展示了面向业务模型的领域设计能力。 +**JWT Token认证**: +``` +Authorization: Bearer +``` + +**支持的认证端点**: +- 所有 `/api/user/*` 端点需要认证 +- 部分 `/api/aimodelapp/*` 端点需要认证 + +### 错误处理 + +**HTTP状态码**: +- 200: 成功 +- 400: 请求参数错误 +- 401: 未认证/认证失败 +- 403: 权限不足 +- 404: 资源不存在 +- 409: 资源冲突 +- 500: 服务器内部错误 + +## 数据库设计 + +### MongoDB集合 + +**主要集合**: `userdata` +- 存储所有用户相关数据 +- 支持动态字段扩展 +- 使用ObjectId作为用户唯一标识 + +### 数据关系 +- 用户数据自包含,无复杂关联 +- 通过用户ID进行数据关联 +- 支持水平扩展 + +## 部署和配置 + +### 环境配置 + +**必需环境变量**: +``` +SECRET_KEY=your-secret-key +MONGO_URI=mongodb://localhost:27017/InfoGenie +MAIL_USERNAME=your-email@qq.com +MAIL_PASSWORD=your-app-password +``` + +### 启动方式 + +**开发环境**: +```bash +python app.py +``` + +**生产环境**: +- 支持Docker部署 +- 提供docker-compose配置 +- 支持Gunicorn WSGI服务器 + +### 静态文件服务 + +**支持的前端资源**: +- `/60sapi/*`: 60秒API相关文件 +- `/smallgame/*`: 小游戏相关文件 +- `/aimodelapp/*`: AI模型应用相关文件 + +## 安全考虑 + +### 数据安全 +- 密码哈希存储 +- JWT Token安全传输 +- 输入数据验证和过滤 + +### API安全 +- CORS配置(生产环境限制域名) +- API限流保护 +- 请求日志记录 + +### 部署安全 +- 环境变量管理敏感信息 +- HTTPS证书配置 +- 防火墙和访问控制 + +## 前后端协作指南 + +### 前端调用示例 + +**用户登录**: +```javascript +// 1. 发送验证码 +fetch('/api/auth/send-verification', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ email: 'user@qq.com', type: 'login' }) +}); + +// 2. 验证验证码并登录 +fetch('/api/auth/login', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + email: 'user@qq.com', + code: '123456' + }) +}); + +// 3. 保存token到localStorage +localStorage.setItem('token', response.token); +``` + +**调用需要认证的API**: +```javascript +fetch('/api/user/profile', { + method: 'GET', + headers: { + 'Authorization': `Bearer ${localStorage.getItem('token')}` + } +}); +``` + +### 数据约定 + +**前端发送数据格式**: +- 所有请求使用JSON格式 +- 必填字段验证 +- 参数命名使用snake_case + +**后端返回数据格式**: +- 统一响应格式 +- 时间戳使用ISO格式 +- 错误信息清晰明确 + +### 开发协作流程 + +1. **API设计阶段**: + - 后端定义API接口规范 + - 前端根据规范开发调用代码 + - 约定数据格式和错误处理 + +2. **联调阶段**: + - 使用统一的测试数据 + - 验证各种边界情况 + - 确认错误处理逻辑 + +3. **部署阶段**: + - 后端部署API服务 + - 前端配置API基础URL + - 验证跨域和认证配置 + +## 新功能添加 + +### 1. AI功能萌芽币消费系统 + +**功能描述**: +- 用户每次调用AI模型应用(aimodelapp)需消耗100萌芽币 +- 当用户萌芽币余额不足时,无法使用AI功能 +- 记录用户的AI使用历史 + +**API端点**: +``` +GET /api/aimodelapp/coins # 查询用户萌芽币余额和使用历史 +``` + +**技术实现**: +- 使用装饰器模式实现请求前验证和扣除萌芽币 +- 在MongoDB中记录用户AI使用历史 +- 通过JWT Token验证用户身份 + +**业务逻辑**: +1. 当用户请求AI功能时,首先验证JWT Token +2. 检查用户萌芽币余额是否≥100 +3. 如余额充足,先扣除萌芽币,然后再调用AI服务 +4. 记录使用历史,包括API类型、时间和消费萌芽币数量 +5. 返回AI服务结果给用户 + +**响应示例(查询萌芽币余额)**: +```json +{ + "success": true, + "data": { + "coins": 200, + "ai_cost": 100, + "can_use_ai": true, + "username": "用户名", + "usage_count": 1, + "recent_usage": [ + { + "api_type": "chat", + "cost": 100, + "timestamp": "2025-09-16T11:15:47.285720" + } + ] + }, + "message": "当前萌芽币余额: 200" +} +``` + +**前端开发注意事项**: +- 每个需要调用AI功能的页面应首先检查用户萌芽币余额 +- 当萌芽币不足时,向用户提示并引导用户通过签到等方式获取萌芽币 +- 可在UI中展示用户最近的AI使用记录和萌芽币消费情况 + +--- diff --git a/InfoGenie-frontend/package-lock.json b/InfoGenie-frontend/package-lock.json index e2ee0482..30a1cf9d 100755 --- a/InfoGenie-frontend/package-lock.json +++ b/InfoGenie-frontend/package-lock.json @@ -19,6 +19,7 @@ "react-icons": "^4.11.0", "react-router-dom": "^6.15.0", "react-scripts": "5.0.1", + "react-transition-group": "^4.4.5", "styled-components": "^6.0.7", "web-vitals": "^2.1.4" } @@ -82,6 +83,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.3.tgz", "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==", "license": "MIT", + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", @@ -731,6 +733,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.27.1.tgz", "integrity": "sha512-p9OkPbZ5G7UT1MofwYFigGebnrzGJacoBSQM0/6bi/PUMVE+qlWDD/OalvQKbwgQzU6dl0xAv6r4X7Jme0RYxA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1614,6 +1617,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz", "integrity": "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==", "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-module-imports": "^7.27.1", @@ -4678,8 +4682,7 @@ "version": "15.7.15", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@types/q": { "version": "1.5.8", @@ -4835,6 +4838,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.4.0", "@typescript-eslint/scope-manager": "5.62.0", @@ -4888,6 +4892,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", "license": "BSD-2-Clause", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "5.62.0", "@typescript-eslint/types": "5.62.0", @@ -5257,6 +5262,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -5355,6 +5361,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -6320,6 +6327,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001737", "electron-to-chromium": "^1.5.211", @@ -7386,7 +7394,8 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/damerau-levenshtein": { "version": "1.0.8", @@ -7746,6 +7755,16 @@ "utila": "~0.4" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/dom-serializer": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", @@ -8242,6 +8261,7 @@ "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -11076,6 +11096,7 @@ "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", "license": "MIT", + "peer": true, "dependencies": { "@jest/core": "^27.5.1", "import-local": "^3.0.2", @@ -15147,6 +15168,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -16334,6 +16356,7 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "license": "MIT", + "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -16699,6 +16722,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -16849,6 +16873,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -16900,6 +16925,7 @@ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -17009,6 +17035,22 @@ } } }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -17402,6 +17444,7 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", "license": "MIT", + "peer": true, "bin": { "rollup": "dist/bin/rollup" }, @@ -17647,6 +17690,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -19352,6 +19396,7 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "license": "(MIT OR CC0-1.0)", + "peer": true, "engines": { "node": ">=10" }, @@ -19781,6 +19826,7 @@ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.101.3.tgz", "integrity": "sha512-7b0dTKR3Ed//AD/6kkx/o7duS8H3f1a4w3BYpIriX4BzIhjkn4teo05cptsxvLesHFKK5KObnadmCHBwGc+51A==", "license": "MIT", + "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", @@ -19852,6 +19898,7 @@ "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz", "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", "license": "MIT", + "peer": true, "dependencies": { "@types/bonjour": "^3.5.9", "@types/connect-history-api-fallback": "^1.3.5", @@ -20264,6 +20311,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", diff --git a/InfoGenie-frontend/package.json b/InfoGenie-frontend/package.json index e93de60e..2a3eb677 100755 --- a/InfoGenie-frontend/package.json +++ b/InfoGenie-frontend/package.json @@ -2,7 +2,12 @@ "name": "infogenie-frontend", "version": "1.0.0", "description": "✨ 万象口袋 - 前端React应用", - "keywords": ["react", "api", "mobile-first", "responsive"], + "keywords": [ + "react", + "api", + "mobile-first", + "responsive" + ], "author": "万象口袋", "license": "MIT", "private": true, @@ -11,14 +16,15 @@ "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^14.5.2", + "axios": "^1.5.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-hot-toast": "^2.4.1", + "react-icons": "^4.11.0", "react-router-dom": "^6.15.0", "react-scripts": "5.0.1", - "axios": "^1.5.0", + "react-transition-group": "^4.4.5", "styled-components": "^6.0.7", - "react-icons": "^4.11.0", - "react-hot-toast": "^2.4.1", "web-vitals": "^2.1.4" }, "scripts": { diff --git a/InfoGenie-frontend/public/60sapi/热搜榜单/Hacker News 榜单/css/background.css b/InfoGenie-frontend/public/60sapi/热搜榜单/Hacker News 榜单/css/background.css index b889760c..a6678b42 100755 --- a/InfoGenie-frontend/public/60sapi/热搜榜单/Hacker News 榜单/css/background.css +++ b/InfoGenie-frontend/public/60sapi/热搜榜单/Hacker News 榜单/css/background.css @@ -2,42 +2,32 @@ body { background: linear-gradient( 135deg, - #ff6b6b 0%, - #4ecdc4 12.5%, - #45b7d1 25%, - #96ceb4 37.5%, - #feca57 50%, - #ff9ff3 62.5%, - #54a0ff 75%, - #5f27cd 87.5%, - #00d2d3 100% + #e8f5e8 0%, + #f1f8e9 25%, + #dcedc8 50%, + #c8e6c8 75%, + #e8f5e8 100% ); - background-size: 400% 400%; - animation: rainbowGradient 15s ease infinite; + background-size: 200% 200%; + animation: gentleGradient 20s ease infinite; background-attachment: fixed; min-height: 100vh; position: relative; } -@keyframes rainbowGradient { +@keyframes gentleGradient { 0% { background-position: 0% 50%; } - 25% { - background-position: 100% 50%; - } 50% { - background-position: 100% 100%; - } - 75% { - background-position: 0% 100%; + background-position: 100% 50%; } 100% { background-position: 0% 50%; } } -/* 彩虹装饰层 */ +/* 淡雅绿色装饰层 */ body::before { content: ''; position: fixed; @@ -46,17 +36,15 @@ body::before { width: 100%; height: 100%; background: - radial-gradient(circle at 20% 20%, rgba(255, 107, 107, 0.15) 0%, transparent 50%), - radial-gradient(circle at 80% 80%, rgba(78, 205, 196, 0.15) 0%, transparent 50%), - radial-gradient(circle at 40% 80%, rgba(69, 183, 209, 0.12) 0%, transparent 40%), - radial-gradient(circle at 60% 20%, rgba(150, 206, 180, 0.12) 0%, transparent 40%), - radial-gradient(circle at 80% 40%, rgba(254, 202, 87, 0.1) 0%, transparent 35%); + radial-gradient(circle at 20% 20%, rgba(129, 199, 132, 0.08) 0%, transparent 50%), + radial-gradient(circle at 80% 80%, rgba(165, 214, 167, 0.06) 0%, transparent 50%), + radial-gradient(circle at 40% 80%, rgba(200, 230, 201, 0.05) 0%, transparent 40%), + radial-gradient(circle at 60% 20%, rgba(220, 237, 200, 0.04) 0%, transparent 40%); pointer-events: none; z-index: -1; - animation: float 20s ease-in-out infinite alternate; } -/* 彩虹粒子效果 */ +/* 淡雅绿色点缀 */ body::after { content: ''; position: fixed; @@ -65,42 +53,13 @@ body::after { width: 100%; height: 100%; background-image: - radial-gradient(circle at 10% 10%, rgba(255, 107, 107, 0.8) 2px, transparent 2px), - radial-gradient(circle at 30% 20%, rgba(78, 205, 196, 0.8) 1.5px, transparent 1.5px), - radial-gradient(circle at 50% 30%, rgba(69, 183, 209, 0.8) 1px, transparent 1px), - radial-gradient(circle at 70% 40%, rgba(150, 206, 180, 0.8) 2px, transparent 2px), - radial-gradient(circle at 90% 50%, rgba(254, 202, 87, 0.8) 1.5px, transparent 1.5px), - radial-gradient(circle at 20% 60%, rgba(255, 159, 243, 0.8) 1px, transparent 1px), - radial-gradient(circle at 40% 70%, rgba(84, 160, 255, 0.8) 2px, transparent 2px), - radial-gradient(circle at 60% 80%, rgba(95, 39, 205, 0.8) 1.5px, transparent 1.5px), - radial-gradient(circle at 80% 90%, rgba(0, 210, 211, 0.8) 1px, transparent 1px); - background-size: 200px 200px, 250px 250px, 180px 180px, 300px 300px, 220px 220px, 160px 160px, 280px 280px, 240px 240px, 200px 200px; - animation: sparkle 25s linear infinite; + radial-gradient(circle at 15% 15%, rgba(129, 199, 132, 0.3) 1px, transparent 1px), + radial-gradient(circle at 45% 25%, rgba(165, 214, 167, 0.25) 1px, transparent 1px), + radial-gradient(circle at 75% 35%, rgba(200, 230, 201, 0.2) 1px, transparent 1px), + radial-gradient(circle at 25% 65%, rgba(220, 237, 200, 0.15) 1px, transparent 1px), + radial-gradient(circle at 85% 75%, rgba(129, 199, 132, 0.2) 1px, transparent 1px); + background-size: 300px 300px, 400px 400px, 350px 350px, 450px 450px, 380px 380px; pointer-events: none; z-index: -1; - opacity: 0.6; -} - -@keyframes float { - 0% { - transform: translateY(0px) rotate(0deg); - } - 100% { - transform: translateY(-15px) rotate(2deg); - } -} - -@keyframes sparkle { - 0%, 100% { - transform: translateX(0) translateY(0) scale(1); - } - 25% { - transform: translateX(-10px) translateY(-5px) scale(1.1); - } - 50% { - transform: translateX(10px) translateY(-10px) scale(0.9); - } - 75% { - transform: translateX(-5px) translateY(-15px) scale(1.05); - } + opacity: 0.4; } diff --git a/InfoGenie-frontend/public/60sapi/热搜榜单/Hacker News 榜单/css/style.css b/InfoGenie-frontend/public/60sapi/热搜榜单/Hacker News 榜单/css/style.css index fe482a48..ebb660af 100755 --- a/InfoGenie-frontend/public/60sapi/热搜榜单/Hacker News 榜单/css/style.css +++ b/InfoGenie-frontend/public/60sapi/热搜榜单/Hacker News 榜单/css/style.css @@ -18,11 +18,11 @@ height: 200%; background: linear-gradient( 135deg, - rgba(64, 169, 255, 0.4) 0%, - rgba(120, 192, 255, 0.3) 25%, - rgba(255, 175, 64, 0.2) 50%, - rgba(255, 140, 50, 0.3) 75%, - rgba(255, 122, 69, 0.4) 100% + rgba(129, 199, 132, 0.4) 0%, + rgba(165, 214, 167, 0.3) 25%, + rgba(200, 230, 201, 0.2) 50%, + rgba(220, 237, 200, 0.3) 75%, + rgba(232, 245, 233, 0.4) 100% ); animation: gradient-flow 20s ease-in-out infinite; border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%; @@ -37,11 +37,11 @@ height: 100%; background: radial-gradient( circle at 30% 70%, - rgba(64, 169, 255, 0.5) 0%, + rgba(129, 199, 132, 0.5) 0%, transparent 50% ), radial-gradient( circle at 70% 30%, - rgba(255, 140, 50, 0.4) 0%, + rgba(165, 214, 167, 0.4) 0%, transparent 50% ); animation: pulse-effect 15s ease-in-out infinite alternate; @@ -123,7 +123,7 @@ header, .header { } header h1, .title { - background: linear-gradient(135deg, #4096ff, #ff7a45); + background: linear-gradient(135deg, #66bb6a, #81c784); -webkit-background-clip: text; background-clip: text; color: transparent; @@ -170,9 +170,9 @@ header h1, .title { } .tab-btn.active { - background: linear-gradient(135deg, #4096ff, #40a9ff); + background: linear-gradient(135deg, #66bb6a, #81c784); color: white; - box-shadow: 0 4px 16px rgba(64, 150, 255, 0.3); + box-shadow: 0 4px 16px rgba(102, 187, 106, 0.3); } .tab-icon { @@ -180,7 +180,7 @@ header h1, .title { } .refresh-btn { - background: linear-gradient(135deg, #52c41a, #73d13d); + background: linear-gradient(135deg, #81c784, #a5d6a7); border: none; padding: 12px 24px; border-radius: 25px; @@ -193,12 +193,12 @@ header h1, .title { display: inline-flex; align-items: center; gap: 8px; - box-shadow: 0 4px 12px rgba(82, 196, 26, 0.3); + box-shadow: 0 4px 12px rgba(129, 199, 132, 0.3); } .refresh-btn:hover { transform: translateY(-2px); - box-shadow: 0 6px 16px rgba(82, 196, 26, 0.4); + box-shadow: 0 6px 16px rgba(129, 199, 132, 0.4); } .btn-icon { @@ -238,17 +238,17 @@ header h1, .title { .hot-item:hover { transform: translateY(-3px); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08); - border-color: rgba(64, 169, 255, 0.3); + border-color: rgba(129, 199, 132, 0.3); } .hot-rank { font-size: 1.2rem; font-weight: bold; - color: #4096ff; + color: #66bb6a; margin-right: 18px; min-width: 38px; text-align: center; - background-color: rgba(64, 169, 255, 0.1); + background-color: rgba(129, 199, 132, 0.1); border-radius: 50%; width: 38px; height: 38px; @@ -258,18 +258,18 @@ header h1, .title { } .hot-rank.top-1 { - background: linear-gradient(135deg, #ff4d4f, #ff7a45); + background: linear-gradient(135deg, #66bb6a, #81c784); color: white; } .hot-rank.top-2 { - background: linear-gradient(135deg, #ff7a45, #ffa940); + background: linear-gradient(135deg, #81c784, #a5d6a7); color: white; } .hot-rank.top-3 { - background: linear-gradient(135deg, #ffa940, #ffec3d); - color: white; + background: linear-gradient(135deg, #a5d6a7, #c8e6c9); + color: #333; } .hot-content { @@ -288,7 +288,7 @@ header h1, .title { } .hot-title:hover { - color: #4096ff; + color: #66bb6a; text-decoration: none; } @@ -310,13 +310,10 @@ header h1, .title { .rainbow-spinner { width: 50px; height: 50px; - border: 4px solid transparent; - border-top: 4px solid #4096ff; + border: 4px solid rgba(129, 199, 132, 0.2); + border-top: 4px solid #81c784; border-radius: 50%; animation: spin 1s linear infinite; - background: linear-gradient(45deg, #ff6b6b, #4ecdc4, #45b7d1, #96ceb4, #feca57, #ff9ff3, #54a0ff, #5f27cd); - background-size: 400% 400%; - animation: spin 1s linear infinite, rainbowGradient 3s ease infinite; } @keyframes spin { @@ -356,7 +353,7 @@ header h1, .title { .loading-dots span { width: 8px; height: 8px; - background: #4096ff; + background: #81c784; border-radius: 50%; animation: loadingDots 1.4s ease-in-out infinite both; } @@ -396,7 +393,7 @@ header h1, .title { .news-item:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(0, 0, 0, 0.1); - border-color: rgba(64, 169, 255, 0.2); + border-color: rgba(129, 199, 132, 0.3); } /* 排名容器 */ @@ -423,21 +420,21 @@ header h1, .title { } .news-rank.rank-1 { - background: linear-gradient(135deg, #ff4d4f, #ff7a45); + background: linear-gradient(135deg, #66bb6a, #81c784); color: white; - box-shadow: 0 4px 12px rgba(255, 77, 79, 0.3); + box-shadow: 0 4px 12px rgba(102, 187, 106, 0.3); } .news-rank.rank-2 { - background: linear-gradient(135deg, #ff7a45, #ffa940); + background: linear-gradient(135deg, #81c784, #a5d6a7); color: white; - box-shadow: 0 4px 12px rgba(255, 122, 69, 0.3); + box-shadow: 0 4px 12px rgba(129, 199, 132, 0.3); } .news-rank.rank-3 { - background: linear-gradient(135deg, #ffa940, #ffec3d); + background: linear-gradient(135deg, #a5d6a7, #c8e6c9); color: #333; - box-shadow: 0 4px 12px rgba(255, 169, 64, 0.3); + box-shadow: 0 4px 12px rgba(165, 214, 167, 0.3); } .rank-number { @@ -478,7 +475,7 @@ header h1, .title { } .news-title:hover { - color: #4096ff; + color: #66bb6a; } /* 元信息行 */ @@ -524,7 +521,7 @@ header h1, .title { display: flex; align-items: center; gap: 4px; - background: linear-gradient(135deg, #ff6b6b, #4ecdc4); + background: linear-gradient(135deg, #81c784, #a5d6a7); color: white; padding: 4px 10px; border-radius: 12px; @@ -545,7 +542,7 @@ header h1, .title { display: flex; align-items: center; gap: 4px; - background: linear-gradient(135deg, #4096ff, #40a9ff); + background: linear-gradient(135deg, #66bb6a, #81c784); color: white; text-decoration: none; padding: 6px 12px; @@ -553,13 +550,13 @@ header h1, .title { font-size: 0.75rem; font-weight: 600; transition: all 0.3s ease; - box-shadow: 0 2px 6px rgba(64, 150, 255, 0.3); + box-shadow: 0 2px 6px rgba(102, 187, 106, 0.3); flex-shrink: 0; } .news-link:hover { transform: translateY(-1px); - box-shadow: 0 4px 10px rgba(64, 150, 255, 0.4); + box-shadow: 0 4px 10px rgba(102, 187, 106, 0.4); text-decoration: none; color: white; } @@ -592,7 +589,7 @@ header h1, .title { } .error-content h3 { - color: #ff4d4f; + color: #66bb6a; margin: 0; font-size: 1.3rem; } @@ -604,7 +601,7 @@ header h1, .title { } .retry-btn { - background: linear-gradient(135deg, #ff4d4f, #ff7a45); + background: linear-gradient(135deg, #66bb6a, #81c784); border: none; padding: 12px 24px; border-radius: 25px; @@ -616,12 +613,12 @@ header h1, .title { display: inline-flex; align-items: center; gap: 8px; - box-shadow: 0 4px 12px rgba(255, 77, 79, 0.3); + box-shadow: 0 4px 12px rgba(102, 187, 106, 0.3); } .retry-btn:hover { transform: translateY(-2px); - box-shadow: 0 6px 16px rgba(255, 77, 79, 0.4); + box-shadow: 0 6px 16px rgba(102, 187, 106, 0.4); } footer { @@ -855,9 +852,9 @@ footer { .modern-gradient { background: linear-gradient( 135deg, - rgba(64, 169, 255, 0.3) 0%, - rgba(255, 175, 64, 0.2) 50%, - rgba(255, 122, 69, 0.25) 100% + rgba(129, 199, 132, 0.3) 0%, + rgba(200, 230, 201, 0.2) 50%, + rgba(232, 245, 233, 0.25) 100% ); } } \ No newline at end of file diff --git a/InfoGenie-frontend/public/60sapi/热搜榜单/Hacker News 榜单/index.html b/InfoGenie-frontend/public/60sapi/热搜榜单/Hacker News 榜单/index.html index 765583af..2dc101fa 100755 --- a/InfoGenie-frontend/public/60sapi/热搜榜单/Hacker News 榜单/index.html +++ b/InfoGenie-frontend/public/60sapi/热搜榜单/Hacker News 榜单/index.html @@ -3,39 +3,33 @@ - 🔥 HackerNews 热门榜单 + HackerNews 热门榜单
-
🌈
-

🔥 HackerNews 热门榜单 💻

+

HackerNews 热门榜单

全球技术社区 · 实时热门话题

- 加载中...
@@ -44,7 +38,6 @@
- 🚀

正在获取最新榜单...

@@ -61,11 +54,9 @@ diff --git a/InfoGenie-frontend/public/60sapi/热搜榜单/头条热搜榜/css/background.css b/InfoGenie-frontend/public/60sapi/热搜榜单/头条热搜榜/css/background.css index d3c2c6e3..2c0951fb 100755 --- a/InfoGenie-frontend/public/60sapi/热搜榜单/头条热搜榜/css/background.css +++ b/InfoGenie-frontend/public/60sapi/热搜榜单/头条热搜榜/css/background.css @@ -16,11 +16,11 @@ height: 200%; background: linear-gradient( 135deg, - rgba(240, 20, 20, 0.3) 0%, - rgba(255, 60, 60, 0.2) 25%, - rgba(255, 100, 100, 0.1) 50%, - rgba(255, 150, 150, 0.2) 75%, - rgba(240, 20, 20, 0.3) 100% + rgba(168, 230, 207, 0.3) 0%, + rgba(220, 237, 193, 0.2) 25%, + rgba(200, 245, 200, 0.1) 50%, + rgba(180, 235, 180, 0.2) 75%, + rgba(168, 230, 207, 0.3) 100% ); animation: green-flow 20s ease-in-out infinite; } @@ -34,11 +34,11 @@ height: 100%; background: radial-gradient( circle at 30% 70%, - rgba(255, 45, 45, 0.4) 0%, + rgba(129, 199, 132, 0.3) 0%, transparent 50% ), radial-gradient( circle at 70% 30%, - rgba(255, 100, 100, 0.3) 0%, + rgba(165, 214, 167, 0.25) 0%, transparent 50% ); animation: green-pulse 15s ease-in-out infinite alternate; diff --git a/InfoGenie-frontend/public/60sapi/热搜榜单/头条热搜榜/css/style.css b/InfoGenie-frontend/public/60sapi/热搜榜单/头条热搜榜/css/style.css index e5904e78..7974d204 100755 --- a/InfoGenie-frontend/public/60sapi/热搜榜单/头条热搜榜/css/style.css +++ b/InfoGenie-frontend/public/60sapi/热搜榜单/头条热搜榜/css/style.css @@ -18,11 +18,11 @@ height: 200%; background: linear-gradient( 135deg, - rgba(64, 169, 255, 0.4) 0%, - rgba(120, 192, 255, 0.3) 25%, - rgba(255, 175, 64, 0.2) 50%, - rgba(255, 140, 50, 0.3) 75%, - rgba(255, 122, 69, 0.4) 100% + rgba(168, 230, 207, 0.3) 0%, + rgba(220, 237, 193, 0.25) 25%, + rgba(200, 245, 200, 0.15) 50%, + rgba(180, 235, 180, 0.25) 75%, + rgba(168, 230, 207, 0.3) 100% ); animation: gradient-flow 20s ease-in-out infinite; border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%; @@ -37,11 +37,11 @@ height: 100%; background: radial-gradient( circle at 30% 70%, - rgba(64, 169, 255, 0.5) 0%, + rgba(129, 199, 132, 0.4) 0%, transparent 50% ), radial-gradient( circle at 70% 30%, - rgba(255, 140, 50, 0.4) 0%, + rgba(165, 214, 167, 0.3) 0%, transparent 50% ); animation: pulse-effect 15s ease-in-out infinite alternate; @@ -106,13 +106,13 @@ body { } .geometric-decoration { - font-size: 20px; - color: #f04040; - margin: 0 15px; - font-weight: bold; - letter-spacing: 5px; - text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - animation: float-effect 3s ease-in-out infinite alternate; + font-size: 16px; + color: #81c784; + margin: 0 10px; + font-weight: normal; + letter-spacing: 3px; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + opacity: 0.6; } .geometric-decoration.left { @@ -140,10 +140,13 @@ body { } .time-decoration { - color: #f04040; - font-size: 18px; - margin: 0 10px; - animation: pulse 2s infinite; + font-size: 14px; + color: #a5d6a7; + margin: 0 8px; + font-weight: normal; + letter-spacing: 2px; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + opacity: 0.5; } @keyframes pulse { @@ -163,11 +166,11 @@ body { .geometric-header, .geometric-footer { text-align: center; - color: #f04040; - margin: 15px 0; - font-size: 16px; - letter-spacing: 3px; - opacity: 0.8; + color: #a5d6a7; + margin: 10px 0; + font-size: 14px; + letter-spacing: 2px; + opacity: 0.5; } .geometric-header { @@ -188,7 +191,7 @@ body { border-radius: 16px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08); backdrop-filter: blur(10px); - border: 2px solid rgba(240, 64, 64, 0.3); + border: 1px solid rgba(129, 199, 132, 0.2); position: relative; } @@ -198,7 +201,7 @@ body { position: absolute; width: 30px; height: 30px; - border-color: #f04040; + border-color: #a5d6a7; opacity: 0.7; } @@ -226,7 +229,7 @@ header { } header h1 { - background: linear-gradient(135deg, #4096ff, #ff7a45); + background: linear-gradient(135deg, #66bb6a, #81c784); -webkit-background-clip: text; background-clip: text; color: transparent; @@ -245,7 +248,7 @@ header h1 { display: inline-block; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04); position: relative; - border: 1px dashed rgba(240, 64, 64, 0.3); + border: 1px dashed rgba(129, 199, 132, 0.3); } .update-time::before { @@ -255,7 +258,7 @@ header h1 { left: -5px; right: -5px; bottom: -5px; - border: 1px solid rgba(240, 64, 64, 0.3); + border: 1px solid rgba(129, 199, 132, 0.3); border-radius: 28px; animation: pulse-border 2s infinite; pointer-events: none; @@ -299,9 +302,9 @@ header h1 { position: absolute; top: 5px; right: 10px; - color: #f04040; - opacity: 0.2; - font-size: 14px; + color: #a5d6a7; + opacity: 0.15; + font-size: 12px; } .hot-item::after { @@ -309,32 +312,33 @@ header h1 { position: absolute; bottom: 5px; left: 10px; - color: #f04040; - opacity: 0.2; - font-size: 14px; + color: #a5d6a7; + opacity: 0.15; + font-size: 12px; } .even-item { - border-left: 3px solid #f04040; + border-left: 2px solid #81c784; } .odd-item { - border-right: 3px solid #f04040; + border-right: 2px solid #81c784; } .title-decoration { - color: #f04040; - font-weight: bold; + color: #81c784; + font-weight: normal; margin-right: 5px; display: inline-block; transform: translateY(1px); + opacity: 0.7; } .source-icon, .time-icon { - color: #f04040; + color: #81c784; font-size: 14px; margin-right: 3px; - opacity: 0.8; + opacity: 0.6; } .hot-title { @@ -353,17 +357,17 @@ header h1 { .hot-item:hover { transform: translateY(-3px); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08); - border-color: rgba(64, 169, 255, 0.3); + border-color: rgba(129, 199, 132, 0.4); } .hot-rank { font-size: 1.2rem; font-weight: bold; - color: #4096ff; + color: #66bb6a; margin-right: 18px; min-width: 38px; text-align: center; - background-color: rgba(64, 169, 255, 0.1); + background-color: rgba(129, 199, 132, 0.1); border-radius: 50%; width: 38px; height: 38px; @@ -373,17 +377,17 @@ header h1 { } .hot-rank.top-1 { - background: linear-gradient(135deg, #ff4d4f, #ff7a45); + background: linear-gradient(135deg, #4caf50, #66bb6a); color: white; } .hot-rank.top-2 { - background: linear-gradient(135deg, #ff7a45, #ffa940); + background: linear-gradient(135deg, #66bb6a, #81c784); color: white; } .hot-rank.top-3 { - background: linear-gradient(135deg, #ffa940, #ffec3d); + background: linear-gradient(135deg, #81c784, #a5d6a7); color: white; } @@ -403,7 +407,7 @@ header h1 { } .hot-title:hover { - color: #4096ff; + color: #66bb6a; text-decoration: none; } @@ -431,11 +435,10 @@ footer { } .geo-symbol { - color: #f04040; - font-size: 16px; - opacity: 0.7; + color: #a5d6a7; + font-size: 14px; + opacity: 0.5; transition: all 0.3s ease; - animation: color-shift 5s infinite alternate; } .geo-symbol:hover { @@ -443,17 +446,7 @@ footer { transform: scale(1.2) rotate(15deg); } -@keyframes color-shift { - 0% { - color: #f04040; - } - 50% { - color: #ff7a45; - } - 100% { - color: #ff4d4f; - } -} + /* 响应式设计 */ @media (max-width: 1024px) and (min-width: 768px) { @@ -570,9 +563,9 @@ footer { .modern-gradient { background: linear-gradient( 135deg, - rgba(64, 169, 255, 0.3) 0%, - rgba(255, 175, 64, 0.2) 50%, - rgba(255, 122, 69, 0.25) 100% + rgba(168, 230, 207, 0.25) 0%, + rgba(200, 245, 200, 0.15) 50%, + rgba(180, 235, 180, 0.2) 100% ); } } \ No newline at end of file diff --git a/InfoGenie-frontend/public/60sapi/热搜榜单/抖音热搜榜/css/background.css b/InfoGenie-frontend/public/60sapi/热搜榜单/抖音热搜榜/css/background.css index fbf1fd3f..bfd3e264 100755 --- a/InfoGenie-frontend/public/60sapi/热搜榜单/抖音热搜榜/css/background.css +++ b/InfoGenie-frontend/public/60sapi/热搜榜单/抖音热搜榜/css/background.css @@ -1,12 +1,12 @@ /* 背景相关样式 */ body { - background: linear-gradient(135deg, #e8f5e8 0%, #c8e6c9 25%, #a5d6a7 50%, #81c784 75%, #66bb6a 100%); + background: linear-gradient(135deg, #f1f8e9 0%, #dcedc8 25%, #c8e6c9 50%, #a8e6cf 75%, #81c784 100%); background-attachment: fixed; min-height: 100vh; position: relative; } -/* 背景装饰元素 */ +/* 简化的背景装饰元素 */ body::before { content: ''; position: fixed; @@ -15,15 +15,13 @@ body::before { width: 100%; height: 100%; background-image: - radial-gradient(circle at 20% 80%, rgba(120, 200, 120, 0.15) 0%, transparent 50%), - radial-gradient(circle at 80% 20%, rgba(100, 180, 100, 0.15) 0%, transparent 50%), - radial-gradient(circle at 40% 40%, rgba(140, 220, 140, 0.1) 0%, transparent 50%), - radial-gradient(circle at 60% 70%, rgba(160, 240, 160, 0.08) 0%, transparent 40%); + radial-gradient(circle at 20% 80%, rgba(76, 175, 80, 0.08) 0%, transparent 40%), + radial-gradient(circle at 80% 20%, rgba(129, 199, 132, 0.06) 0%, transparent 40%); pointer-events: none; z-index: -1; } -/* 浮动装饰圆点 */ +/* 简化的浮动装饰 */ body::after { content: ''; position: fixed; @@ -32,12 +30,10 @@ body::after { width: 100%; height: 100%; background-image: - radial-gradient(circle at 10% 10%, rgba(76, 175, 80, 0.1) 2px, transparent 2px), - radial-gradient(circle at 90% 90%, rgba(76, 175, 80, 0.08) 1px, transparent 1px), - radial-gradient(circle at 30% 80%, rgba(76, 175, 80, 0.06) 1.5px, transparent 1.5px), - radial-gradient(circle at 70% 20%, rgba(76, 175, 80, 0.05) 1px, transparent 1px); - background-size: 100px 100px, 150px 150px, 80px 80px, 120px 120px; - animation: float 20s ease-in-out infinite alternate; + radial-gradient(circle at 30% 70%, rgba(76, 175, 80, 0.04) 1px, transparent 1px), + radial-gradient(circle at 70% 30%, rgba(129, 199, 132, 0.03) 1px, transparent 1px); + background-size: 120px 120px, 180px 180px; + animation: float 25s ease-in-out infinite alternate; pointer-events: none; z-index: -1; } diff --git a/InfoGenie-frontend/public/60sapi/热搜榜单/抖音热搜榜/css/style.css b/InfoGenie-frontend/public/60sapi/热搜榜单/抖音热搜榜/css/style.css index 54646c72..482bc9eb 100755 --- a/InfoGenie-frontend/public/60sapi/热搜榜单/抖音热搜榜/css/style.css +++ b/InfoGenie-frontend/public/60sapi/热搜榜单/抖音热搜榜/css/style.css @@ -18,14 +18,14 @@ height: 200%; background: linear-gradient( 135deg, - rgba(64, 169, 255, 0.4) 0%, - rgba(120, 192, 255, 0.3) 25%, - rgba(255, 175, 64, 0.2) 50%, - rgba(255, 140, 50, 0.3) 75%, - rgba(255, 122, 69, 0.4) 100% + rgba(76, 175, 80, 0.15) 0%, + rgba(129, 199, 132, 0.1) 25%, + rgba(165, 214, 167, 0.08) 50%, + rgba(200, 230, 201, 0.06) 75%, + rgba(232, 245, 233, 0.05) 100% ); - animation: gradient-flow 20s ease-in-out infinite; - border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%; + animation: gradient-flow 30s ease-in-out infinite; + border-radius: 40% 60% 60% 40% / 40% 40% 60% 60%; } .modern-gradient::before { @@ -37,15 +37,15 @@ height: 100%; background: radial-gradient( circle at 30% 70%, - rgba(64, 169, 255, 0.5) 0%, - transparent 50% + rgba(76, 175, 80, 0.1) 0%, + transparent 40% ), radial-gradient( circle at 70% 30%, - rgba(255, 140, 50, 0.4) 0%, - transparent 50% + rgba(129, 199, 132, 0.08) 0%, + transparent 40% ); - animation: pulse-effect 15s ease-in-out infinite alternate; - border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%; + animation: pulse-effect 25s ease-in-out infinite alternate; + border-radius: 40% 60% 60% 40% / 40% 40% 60% 60%; } @keyframes gradient-flow { @@ -103,21 +103,22 @@ body { padding: 24px; position: relative; z-index: 1; - background-color: rgba(255, 255, 255, 0.85); + background-color: rgba(255, 255, 255, 0.9); border-radius: 16px; - box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08); - backdrop-filter: blur(10px); + box-shadow: 0 8px 24px rgba(76, 175, 80, 0.08); + backdrop-filter: blur(12px); + border: 1px solid rgba(76, 175, 80, 0.1); } header { text-align: center; margin-bottom: 28px; padding-bottom: 20px; - border-bottom: 1px solid rgba(0, 0, 0, 0.06); + border-bottom: 1px solid rgba(76, 175, 80, 0.15); } header h1 { - background: linear-gradient(135deg, #4096ff, #ff7a45); + background: linear-gradient(135deg, #2e7d32, #4caf50, #66bb6a); -webkit-background-clip: text; background-clip: text; color: transparent; @@ -128,13 +129,56 @@ header h1 { } .update-time { - color: #666; + color: #4caf50; font-size: 0.9rem; - background-color: rgba(0, 0, 0, 0.03); + background-color: rgba(76, 175, 80, 0.08); padding: 8px 16px; border-radius: 24px; display: inline-block; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04); + box-shadow: 0 2px 8px rgba(76, 175, 80, 0.1); + border: 1px solid rgba(76, 175, 80, 0.15); +} + +.refresh-btn { + background: linear-gradient(135deg, #4caf50, #66bb6a); + color: white; + border: none; + padding: 10px 20px; + border-radius: 24px; + font-size: 0.9rem; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; + margin-top: 12px; + box-shadow: 0 4px 12px rgba(76, 175, 80, 0.25); + display: inline-flex; + align-items: center; + gap: 6px; +} + +.refresh-btn:hover { + background: linear-gradient(135deg, #388e3c, #4caf50); + transform: translateY(-2px); + box-shadow: 0 6px 16px rgba(76, 175, 80, 0.35); +} + +.refresh-btn:active { + transform: translateY(0); + box-shadow: 0 2px 8px rgba(76, 175, 80, 0.3); +} + +.btn-icon { + font-size: 1rem; + animation: rotate 2s linear infinite paused; +} + +.refresh-btn:hover .btn-icon { + animation-play-state: running; +} + +@keyframes rotate { + from { transform: rotate(0deg); } + to { transform: rotate(360deg); } } /* 热搜列表 - 移动端优先设计 */ @@ -143,13 +187,13 @@ header h1 { } .hot-item { - background: white; + background: rgba(255, 255, 255, 0.95); border-radius: 16px; padding: 16px; margin-bottom: 12px; - box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06); + box-shadow: 0 2px 12px rgba(76, 175, 80, 0.08); transition: all 0.3s ease; - border: 1px solid rgba(0, 0, 0, 0.05); + border: 1px solid rgba(76, 175, 80, 0.1); display: flex; align-items: center; gap: 12px; @@ -159,8 +203,9 @@ header h1 { .hot-item:hover { transform: translateY(-2px); - box-shadow: 0 6px 20px rgba(0, 0, 0, 0.1); - border-color: rgba(64, 169, 255, 0.2); + box-shadow: 0 6px 20px rgba(76, 175, 80, 0.15); + border-color: rgba(76, 175, 80, 0.25); + background: rgba(255, 255, 255, 1); } /* 排名容器 */ @@ -186,21 +231,21 @@ header h1 { } .hot-rank.rank-1 { - background: linear-gradient(135deg, #ff4d4f, #ff7a45); + background: linear-gradient(135deg, #4caf50, #66bb6a); color: white; - box-shadow: 0 4px 12px rgba(255, 77, 79, 0.3); + box-shadow: 0 4px 12px rgba(76, 175, 80, 0.3); } .hot-rank.rank-2 { - background: linear-gradient(135deg, #ff7a45, #ffa940); + background: linear-gradient(135deg, #66bb6a, #81c784); color: white; - box-shadow: 0 4px 12px rgba(255, 122, 69, 0.3); + box-shadow: 0 4px 12px rgba(102, 187, 106, 0.3); } .hot-rank.rank-3 { - background: linear-gradient(135deg, #ffa940, #ffec3d); - color: #333; - box-shadow: 0 4px 12px rgba(255, 169, 64, 0.3); + background: linear-gradient(135deg, #81c784, #a5d6a7); + color: #2e7d32; + box-shadow: 0 4px 12px rgba(129, 199, 132, 0.3); } .rank-number { @@ -242,7 +287,7 @@ header h1 { } .hot-title:hover { - color: #4096ff; + color: #4caf50; } /* 底部行 */ @@ -277,13 +322,13 @@ header h1 { display: flex; align-items: center; gap: 4px; - background: linear-gradient(135deg, #ff6b6b, #4ecdc4); - color: white; + background: linear-gradient(135deg, #81c784, #a5d6a7); + color: #2e7d32; padding: 4px 10px; border-radius: 12px; font-size: 0.75rem; font-weight: 600; - box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); + box-shadow: 0 2px 6px rgba(76, 175, 80, 0.15); flex-shrink: 0; } @@ -309,7 +354,7 @@ header h1 { display: flex; align-items: center; gap: 4px; - background: linear-gradient(135deg, #4096ff, #40a9ff); + background: linear-gradient(135deg, #4caf50, #66bb6a); color: white; text-decoration: none; padding: 6px 12px; @@ -317,15 +362,16 @@ header h1 { font-size: 0.75rem; font-weight: 600; transition: all 0.3s ease; - box-shadow: 0 2px 6px rgba(64, 150, 255, 0.3); + box-shadow: 0 2px 6px rgba(76, 175, 80, 0.3); flex-shrink: 0; } .hot-link:hover { transform: translateY(-1px); - box-shadow: 0 4px 10px rgba(64, 150, 255, 0.4); + box-shadow: 0 4px 10px rgba(76, 175, 80, 0.4); text-decoration: none; color: white; + background: linear-gradient(135deg, #388e3c, #4caf50); } .link-icon { @@ -339,16 +385,31 @@ header h1 { .loading { text-align: center; padding: 40px; - color: #666; + color: #4caf50; font-size: 1.1rem; } +.spinner { + width: 40px; + height: 40px; + border: 4px solid rgba(76, 175, 80, 0.2); + border-top: 4px solid #4caf50; + border-radius: 50%; + animation: spin 1s linear infinite; + margin: 0 auto 16px; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + footer { text-align: center; margin-top: 30px; padding-top: 20px; - border-top: 1px solid rgba(0, 0, 0, 0.06); - color: #666; + border-top: 1px solid rgba(76, 175, 80, 0.15); + color: #4caf50; font-size: 0.9rem; } diff --git a/InfoGenie-frontend/public/60sapi/热搜榜单/抖音热搜榜/index.html b/InfoGenie-frontend/public/60sapi/热搜榜单/抖音热搜榜/index.html index 9892695a..a1e9875d 100755 --- a/InfoGenie-frontend/public/60sapi/热搜榜单/抖音热搜榜/index.html +++ b/InfoGenie-frontend/public/60sapi/热搜榜单/抖音热搜榜/index.html @@ -10,15 +10,12 @@
-
🔥
-

📱 抖音热搜榜 🎵

+

抖音热搜榜

实时热门话题 · 紧跟潮流趋势

- 加载中...
@@ -48,7 +45,6 @@

加载失败了

网络连接出现问题,请稍后重试

diff --git a/InfoGenie-frontend/public/60sapi/热搜榜单/抖音热搜榜/js/script.js b/InfoGenie-frontend/public/60sapi/热搜榜单/抖音热搜榜/js/script.js index 68ee67d2..26642b67 100755 --- a/InfoGenie-frontend/public/60sapi/热搜榜单/抖音热搜榜/js/script.js +++ b/InfoGenie-frontend/public/60sapi/热搜榜单/抖音热搜榜/js/script.js @@ -137,8 +137,8 @@ function createHotItem(item, rank) { // 根据热度值添加火焰等级 let fireLevel = ''; - if (item.hot_value >= 10000000) fireLevel = '🔥🔥🔥'; - else if (item.hot_value >= 5000000) fireLevel = '🔥🔥'; + if (item.hot_value >= 10000000) fireLevel = '🔥'; + else if (item.hot_value >= 5000000) fireLevel = '🔥'; else fireLevel = '🔥'; hotItem.innerHTML = ` @@ -153,7 +153,6 @@ function createHotItem(item, rank) {
${escapeHtml(item.title)}
- ${formattedTime}
@@ -161,7 +160,6 @@ function createHotItem(item, rank) { ${formattedHotValue}
- 🎬 观看视频
diff --git a/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电影实时票房/css/background.css b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电影实时票房/css/background.css new file mode 100644 index 00000000..38b225b0 --- /dev/null +++ b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电影实时票房/css/background.css @@ -0,0 +1,79 @@ +.background-container { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: -1; + overflow: hidden; + background: linear-gradient(180deg, #f0f9f2 0%, #f7fff8 55%, #eef7f1 100%); +} + +.floating-blob { + position: absolute; + width: 420px; + height: 420px; + border-radius: 55% 45% 60% 40% / 50% 50% 45% 55%; + filter: blur(0px); + opacity: 0.28; + background: radial-gradient(circle at 30% 30%, rgba(129, 199, 132, 0.6), rgba(129, 199, 132, 0)); + animation: drift 36s ease-in-out infinite; +} + +.blob-1 { + top: -120px; + left: -160px; + animation-delay: 0s; +} + +.blob-2 { + right: -120px; + bottom: -160px; + animation-delay: 8s; + background: radial-gradient(circle at 70% 70%, rgba(76, 175, 80, 0.5), rgba(76, 175, 80, 0)); +} + +.blob-3 { + top: 45%; + left: 55%; + animation-delay: 16s; + background: radial-gradient(circle at 40% 60%, rgba(165, 214, 167, 0.5), rgba(165, 214, 167, 0)); +} + +@keyframes drift { + 0% { + transform: translate3d(0, 0, 0) scale(1); + } + 33% { + transform: translate3d(30px, -40px, 0) scale(1.05); + } + 66% { + transform: translate3d(-25px, 30px, 0) scale(0.95); + } + 100% { + transform: translate3d(0, 0, 0) scale(1); + } +} + +@media (max-width: 768px) { + .floating-blob { + width: 260px; + height: 260px; + opacity: 0.22; + } + + .blob-1 { + top: -80px; + left: -120px; + } + + .blob-2 { + right: -140px; + bottom: -140px; + } + + .blob-3 { + top: 55%; + left: 48%; + } +} diff --git a/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电影实时票房/css/style.css b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电影实时票房/css/style.css new file mode 100644 index 00000000..c419cfdd --- /dev/null +++ b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电影实时票房/css/style.css @@ -0,0 +1,432 @@ +:root { + --primary-50: #f0f9f2; + --primary-100: #d8f3d8; + --primary-200: #bce5c1; + --primary-300: #a0d8a8; + --primary-400: #7fcf8e; + --primary-500: #66bb6a; + --primary-600: #5aa75f; + --primary-700: #4a8c50; + --primary-text: #103a2b; + --muted-text: #49705d; + --card-bg: rgba(255, 255, 255, 0.85); + --border-soft: rgba(102, 187, 106, 0.18); + --shadow-soft: 0 12px 40px rgba(48, 94, 60, 0.12); + --shadow-hover: 0 18px 50px rgba(48, 94, 60, 0.16); + color-scheme: light; +} + +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body { + font-family: "PingFang SC", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif; + background: transparent; + color: var(--primary-text); + line-height: 1.6; + min-height: 100vh; + -webkit-font-smoothing: antialiased; +} + +.page { + position: relative; + margin: 0 auto; + width: min(100%, 960px); + padding: 20px 16px 72px; +} + +.page-header { + display: flex; + flex-direction: column; + gap: 16px; + padding: 20px 18px; + border-radius: 18px; + background: var(--card-bg); + box-shadow: var(--shadow-soft); + border: 1px solid var(--border-soft); + backdrop-filter: blur(18px); +} + +.title-block { + display: flex; + flex-direction: column; + gap: 6px; +} + +.label-pill { + align-self: flex-start; + padding: 4px 12px; + font-size: 0.82rem; + font-weight: 600; + color: var(--primary-700); + background: rgba(102, 187, 106, 0.15); + border-radius: 999px; + letter-spacing: 0.06em; +} + +.page-header h1 { + font-size: 1.6rem; + font-weight: 700; + line-height: 1.3; +} + +.meta-block { + display: flex; + flex-direction: column; + gap: 10px; +} + +.update-time { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 6px 12px; + font-size: 0.9rem; + color: var(--muted-text); + background: rgba(255, 255, 255, 0.7); + border-radius: 10px; + border: 1px solid rgba(102, 187, 106, 0.22); +} + +.refresh-button { + align-self: flex-start; + padding: 10px 18px; + font-size: 0.92rem; + font-weight: 600; + color: #fff; + background: linear-gradient(135deg, var(--primary-500), var(--primary-600)); + border: none; + border-radius: 999px; + cursor: pointer; + box-shadow: 0 10px 24px rgba(102, 187, 106, 0.35); + transition: transform 0.2s ease, box-shadow 0.2s ease; +} + +.refresh-button:active { + transform: scale(0.97); +} + +.summary-section { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 14px; + margin-top: 20px; +} + +.summary-card { + padding: 18px 16px; + background: var(--card-bg); + border-radius: 16px; + border: 1px solid var(--border-soft); + box-shadow: var(--shadow-soft); + backdrop-filter: blur(12px); + display: flex; + flex-direction: column; + gap: 8px; +} + +.card-label { + font-size: 0.92rem; + color: var(--muted-text); + letter-spacing: 0.04em; +} + +.card-value { + font-size: 1.4rem; + font-weight: 700; + display: flex; + align-items: baseline; + gap: 6px; + color: var(--primary-700); +} + +.card-value .unit { + font-size: 0.88rem; + font-weight: 500; + color: var(--muted-text); +} + +.list-section { + margin-top: 28px; + padding: 22px 18px 26px; + background: var(--card-bg); + border-radius: 20px; + border: 1px solid var(--border-soft); + box-shadow: var(--shadow-soft); + backdrop-filter: blur(16px); +} + +.section-header { + display: flex; + flex-direction: column; + gap: 6px; + margin-bottom: 20px; +} + +.section-header h2 { + font-size: 1.3rem; + font-weight: 700; +} + +.section-subtitle { + font-size: 0.88rem; + color: var(--muted-text); +} + +.movie-list { + display: flex; + flex-direction: column; + gap: 16px; +} + +.loading, +.error-message { + padding: 18px 16px; + text-align: center; + color: var(--muted-text); + background: rgba(255, 255, 255, 0.7); + border-radius: 14px; + border: 1px dashed rgba(102, 187, 106, 0.35); +} + +.movie-item { + display: grid; + grid-template-columns: auto 1fr; + gap: 14px; + padding: 16px; + border-radius: 18px; + background: rgba(255, 255, 255, 0.95); + border: 1px solid rgba(102, 187, 106, 0.18); + box-shadow: 0 12px 28px rgba(48, 94, 60, 0.08); + transition: transform 0.2s ease, box-shadow 0.2s ease; +} + +.movie-item:hover { + transform: translateY(-2px); + box-shadow: var(--shadow-hover); +} + +.movie-rank { + width: 46px; + height: 46px; + border-radius: 14px; + display: flex; + align-items: center; + justify-content: center; + font-weight: 700; + font-size: 1.1rem; + color: #fff; + background: var(--primary-500); +} + +.movie-rank.top-1 { + background: linear-gradient(135deg, #4caf50, #43a047); +} + +.movie-rank.top-2 { + background: linear-gradient(135deg, #66bb6a, #5aa75f); +} + +.movie-rank.top-3 { + background: linear-gradient(135deg, #81c784, #66bb6a); +} + +.movie-body { + display: flex; + flex-direction: column; + gap: 12px; +} + +.movie-heading { + display: flex; + flex-direction: column; + gap: 6px; +} + +.movie-title { + font-size: 1.1rem; + font-weight: 700; + color: var(--primary-text); +} + +.release-info { + font-size: 0.9rem; + color: var(--muted-text); +} + +.movie-stats { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 10px 14px; +} + +.stat { + display: flex; + flex-direction: column; + gap: 2px; +} + +.stat-label { + font-size: 0.83rem; + color: var(--muted-text); + letter-spacing: 0.02em; +} + +.stat-value { + font-size: 1rem; + font-weight: 600; + color: var(--primary-700); +} + +.progress-metrics { + display: flex; + flex-direction: column; + gap: 8px; + margin-top: 6px; +} + +.progress-group { + display: flex; + flex-direction: column; + gap: 4px; +} + +.progress-label { + display: flex; + justify-content: space-between; + font-size: 0.8rem; + color: var(--muted-text); +} + +.progress-bar { + width: 100%; + height: 6px; + border-radius: 6px; + background: rgba(102, 187, 106, 0.16); + overflow: hidden; +} + +.progress-bar span { + display: block; + height: 100%; + border-radius: inherit; + background: linear-gradient(135deg, rgba(102, 187, 106, 0.9), rgba(76, 175, 80, 0.85)); + width: 0; + transition: width 0.5s ease; +} + +/* Tablet */ +@media (min-width: 600px) { + .page { + padding: 28px 20px 84px; + } + + .page-header { + flex-direction: row; + align-items: center; + justify-content: space-between; + } + + .title-block h1 { + font-size: 1.8rem; + } + + .meta-block { + align-items: flex-end; + } + + .summary-section { + grid-template-columns: repeat(4, minmax(0, 1fr)); + } + + .movie-item { + grid-template-columns: 80px 1fr; + padding: 18px 20px; + } + + .movie-rank { + width: 54px; + height: 54px; + font-size: 1.25rem; + } + + .movie-heading { + flex-direction: row; + align-items: center; + justify-content: space-between; + } + + .release-info { + font-size: 0.88rem; + } + + .movie-stats { + grid-template-columns: repeat(4, minmax(0, 1fr)); + } + + .progress-metrics { + flex-direction: row; + gap: 16px; + } + + .progress-group { + flex: 1; + } +} + +/* Desktop */ +@media (min-width: 1024px) { + .page { + padding: 36px 24px 96px; + } + + .page-header { + padding: 26px 30px; + } + + .page-header h1 { + font-size: 2.1rem; + } + + .summary-card { + padding: 20px 22px; + } + + .card-value { + font-size: 1.6rem; + } + + .list-section { + padding: 28px 30px 34px; + } + + .movie-item { + grid-template-columns: 96px 1fr; + padding: 22px 26px; + border-radius: 20px; + } + + .movie-title { + font-size: 1.25rem; + } + + .movie-stats { + grid-template-columns: repeat(5, minmax(0, 1fr)); + } + + .progress-metrics { + gap: 18px; + } +} + +@media (prefers-reduced-motion: reduce) { + * { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; + } +} diff --git a/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电影实时票房/index.html b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电影实时票房/index.html new file mode 100644 index 00000000..cbe589f8 --- /dev/null +++ b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电影实时票房/index.html @@ -0,0 +1,67 @@ + + + + + + 猫眼电影实时票房 + + + + +
+
+
+
+
+ +
+ + +
+
+

实时大盘

+

+ -- + +

+
+
+

综合票房

+

+ -- + +

+
+
+

排片场次

+

--

+
+
+

观影人次

+

--

+
+
+ +
+
+

影片实时表现

+ 数据每 5 秒同步一次 +
+
+
正在加载实时票房...
+
+
+
+ + + + diff --git a/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电影实时票房/js/main.js b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电影实时票房/js/main.js new file mode 100644 index 00000000..b0653db8 --- /dev/null +++ b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电影实时票房/js/main.js @@ -0,0 +1,297 @@ +const API_ENDPOINTS = [ + "https://60s.api.shumengya.top/v2/maoyan/realtime/movie" +]; + +const FALLBACK_ENDPOINT = "./返回接口.json"; +const REFRESH_INTERVAL = 5000; +const MAX_MOVIES_TO_RENDER = 40; + +const updateTimeEl = document.getElementById("updateTime"); +const refreshButton = document.getElementById("refreshButton"); +const summaryTitleEl = document.getElementById("summaryTitle"); +const totalBoxOfficeEl = document.getElementById("totalBoxOffice"); +const totalBoxOfficeUnitEl = document.getElementById("totalBoxOfficeUnit"); +const combinedBoxOfficeEl = document.getElementById("combinedBoxOffice"); +const combinedBoxOfficeUnitEl = document.getElementById("combinedBoxOfficeUnit"); +const showCountEl = document.getElementById("showCount"); +const viewCountEl = document.getElementById("viewCount"); +const movieListEl = document.getElementById("movieList"); + +let autoRefreshTimer = null; +let isLoading = false; + +function escapeHtml(value) { + if (value === undefined || value === null) { + return ""; + } + + return String(value) + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); +} + +function safeText(value) { + if (value === undefined || value === null || value === "") { + return "--"; + } + return escapeHtml(value); +} + +function parseRate(rateText) { + if (!rateText || typeof rateText !== "string") { + return { text: "--", ratio: 0 }; + } + + const trimmed = rateText.trim(); + const numeric = parseFloat(trimmed.replace(/[^0-9.]/g, "")); + let ratio = Number.isFinite(numeric) ? Math.max(0, Math.min(numeric, 100)) : 0; + + if (trimmed.startsWith("<")) { + ratio = Math.max(3, ratio); + } + + return { text: escapeHtml(trimmed), ratio }; +} + +function formatUpdateTime(data) { + if (data && typeof data.updated === "string" && data.updated.trim().length > 0) { + return data.updated.trim(); + } + + if (data && typeof data.updated_at === "number" && !Number.isNaN(data.updated_at)) { + return new Date(data.updated_at).toLocaleString("zh-CN", { + hour12: false + }); + } + + return new Date().toLocaleString("zh-CN", { hour12: false }); +} + +function renderSummary(data) { + summaryTitleEl.textContent = data?.title ? data.title : "实时大盘"; + totalBoxOfficeEl.textContent = data?.split_box_office ? data.split_box_office : "--"; + totalBoxOfficeUnitEl.textContent = data?.split_box_office_unit ? data.split_box_office_unit : ""; + combinedBoxOfficeEl.textContent = data?.box_office ? data.box_office : "--"; + combinedBoxOfficeUnitEl.textContent = data?.box_office_unit ? data.box_office_unit : ""; + showCountEl.textContent = data?.show_count_desc ? data.show_count_desc : "--"; + viewCountEl.textContent = data?.view_count_desc ? data.view_count_desc : "--"; +} + +function createStat(label, value) { + return ` +
+ ${label} + ${safeText(value)} +
+ `; +} + +function createMovieItem(movie, index) { + const item = document.createElement("article"); + item.className = "movie-item"; + + const topClass = index < 3 ? ` top-${index + 1}` : ""; + const name = safeText(movie?.movie_name || "未命名影片"); + const releaseInfo = movie?.release_info ? `
${safeText(movie.release_info)}
` : ""; + + const boxOfficeDesc = movie?.box_office_desc || (movie?.box_office ? `${movie.box_office}${movie.box_office_unit || ""}` : "--"); + const splitBoxOfficeDesc = movie?.split_box_office_desc || (movie?.split_box_office ? `${movie.split_box_office}${movie.split_box_office_unit || ""}` : "--"); + const totalBoxOfficeDesc = movie?.sum_box_desc ?? "--"; + const totalSplitBoxOfficeDesc = movie?.sum_split_box_desc ?? "--"; + + let showCountText = "--"; + if (movie?.show_count !== undefined && movie.show_count !== null && movie.show_count !== "") { + const numericShowCount = Number(movie.show_count); + showCountText = Number.isFinite(numericShowCount) + ? `${numericShowCount.toLocaleString("zh-CN")} 场` + : movie.show_count; + } + + const avgShowView = movie?.avg_show_view ?? "--"; + const avgSeatView = movie?.avg_seat_view ?? "--"; + + const boxRate = parseRate(movie?.box_office_rate); + const showRate = parseRate(movie?.show_count_rate); + + item.innerHTML = ` +
${index + 1}
+
+
+
+
${name}
+ ${releaseInfo} +
+
+
+ ${createStat("单日综合票房", boxOfficeDesc)} + ${createStat("单日分账票房", splitBoxOfficeDesc)} + ${createStat("累计综合票房", totalBoxOfficeDesc)} + ${createStat("累计分账票房", totalSplitBoxOfficeDesc)} + ${createStat("排片场次", showCountText)} + ${createStat("场均人次", avgShowView)} + ${createStat("上座率", avgSeatView)} +
+
+
+
+ 综合票房占比 + ${boxRate.text} +
+
+
+
+
+ 排片占比 + ${showRate.text} +
+
+
+
+
+ `; + + const progressBars = item.querySelectorAll(".progress-bar span"); + if (progressBars[0]) { + progressBars[0].style.width = `${boxRate.ratio}%`; + } + if (progressBars[1]) { + progressBars[1].style.width = `${showRate.ratio}%`; + } + + return item; +} + +function renderMovieList(list) { + movieListEl.innerHTML = ""; + + if (!Array.isArray(list) || list.length === 0) { + const empty = document.createElement("div"); + empty.className = "error-message"; + empty.textContent = "暂时没有可展示的实时票房数据"; + movieListEl.appendChild(empty); + return; + } + + const sliced = list.slice(0, MAX_MOVIES_TO_RENDER); + sliced.forEach((movie, index) => { + movieListEl.appendChild(createMovieItem(movie, index)); + }); +} + +async function requestJson(url) { + const response = await fetch(url, { + cache: "no-store" + }); + + if (!response.ok) { + throw new Error(`请求失败: ${response.status}`); + } + + return response.json(); +} + +async function retrieveData() { + for (const endpoint of API_ENDPOINTS) { + try { + const result = await requestJson(endpoint); + if (result?.code === 200 && result?.data) { + return result.data; + } + } catch (error) { + console.warn("主接口请求失败", error); + } + } + + try { + const fallbackResult = await requestJson(FALLBACK_ENDPOINT); + if (fallbackResult?.data) { + return fallbackResult.data; + } + } catch (error) { + console.warn("本地示例数据读取失败", error); + } + + return null; +} + +async function loadData(isManual = false) { + if (isLoading) { + return; + } + + isLoading = true; + + if (isManual) { + refreshButton.disabled = true; + refreshButton.textContent = "刷新中..."; + } + + if (!movieListEl.children.length) { + movieListEl.innerHTML = '
正在加载实时票房...
'; + } + + try { + const data = await retrieveData(); + if (!data) { + throw new Error("无法获取数据"); + } + + renderSummary(data); + renderMovieList(Array.isArray(data.list) ? data.list : []); + updateTimeEl.textContent = `最近更新 ${formatUpdateTime(data)}`; + } catch (error) { + console.error("加载数据失败", error); + movieListEl.innerHTML = ""; + const err = document.createElement("div"); + err.className = "error-message"; + err.textContent = "数据获取暂时遇到问题,系统会稍后自动重试"; + movieListEl.appendChild(err); + updateTimeEl.textContent = "最近更新 --"; + renderSummary(null); + } finally { + if (isManual) { + refreshButton.disabled = false; + refreshButton.textContent = "手动刷新"; + } + isLoading = false; + } +} + +function startAutoRefresh() { + if (autoRefreshTimer) { + clearInterval(autoRefreshTimer); + } + autoRefreshTimer = setInterval(() => { + loadData(false); + }, REFRESH_INTERVAL); +} + +refreshButton.addEventListener("click", () => { + loadData(true); +}); + +document.addEventListener("visibilitychange", () => { + if (document.hidden) { + if (autoRefreshTimer) { + clearInterval(autoRefreshTimer); + autoRefreshTimer = null; + } + } else { + startAutoRefresh(); + loadData(false); + } +}); + +function init() { + loadData(false); + startAutoRefresh(); +} + +if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", init); +} else { + init(); +} diff --git a/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电影实时票房/返回接口.json b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电影实时票房/返回接口.json new file mode 100644 index 00000000..7a06cb86 --- /dev/null +++ b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电影实时票房/返回接口.json @@ -0,0 +1,1861 @@ +{ + "code": 200, + "message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s,反馈群 595941841", + "data": { + "title": "实时大盘", + "show_count_desc": "35.4万", + "view_count_desc": "73.2万", + "split_box_office": "2669.5", + "split_box_office_unit": "万", + "box_office": "2669.5", + "box_office_unit": "万", + "update_gap_second": 5, + "updated": "2025-09-26 08:02:00", + "updated_at": 1758873720693, + "list": [ + { + "movie_id": 1207331, + "movie_name": "731", + "release_info": "上映9天", + "box_office": "1791.41", + "box_office_unit": "万", + "box_office_desc": "1791.41万", + "box_office_rate": "67.1%", + "split_box_office": "1686.17", + "split_box_office_unit": "万", + "split_box_office_desc": "1686.17万", + "split_box_office_rate": "67.2%", + "show_count": 206074, + "show_count_rate": "58.2%", + "avg_show_view": "2.4", + "avg_seat_view": "1.7%", + "sum_box_desc": "13.86亿", + "sum_split_box_desc": "12.59亿" + }, + { + "movie_id": 1505571, + "movie_name": "捕风追影", + "release_info": "上映42天", + "box_office": "226.43", + "box_office_unit": "万", + "box_office_desc": "226.43万", + "box_office_rate": "8.4%", + "split_box_office": "202.53", + "split_box_office_unit": "万", + "split_box_office_desc": "202.53万", + "split_box_office_rate": "8.0%", + "show_count": 44432, + "show_count_rate": "12.5%", + "avg_show_view": "1.4", + "avg_seat_view": "1.3%", + "sum_box_desc": "12.06亿", + "sum_split_box_desc": "10.71亿" + }, + { + "movie_id": 1531082, + "movie_name": "窗外是蓝星", + "release_info": "上映22天", + "box_office": "102.39", + "box_office_unit": "万", + "box_office_desc": "102.39万", + "box_office_rate": "3.8%", + "split_box_office": "100.65", + "split_box_office_unit": "万", + "split_box_office_desc": "100.65万", + "split_box_office_rate": "4.0%", + "show_count": 5681, + "show_count_rate": "1.6%", + "avg_show_view": "5.0", + "avg_seat_view": "4.7%", + "sum_box_desc": "3807.1万", + "sum_split_box_desc": "3634.0万" + }, + { + "movie_id": 1515448, + "movie_name": "浪浪山小妖怪", + "release_info": "上映56天", + "box_office": "88.95", + "box_office_unit": "万", + "box_office_desc": "88.95万", + "box_office_rate": "3.3%", + "split_box_office": "78.92", + "split_box_office_unit": "万", + "split_box_office_desc": "78.92万", + "split_box_office_rate": "3.1%", + "show_count": 28121, + "show_count_rate": "7.9%", + "avg_show_view": "0.9", + "avg_seat_view": "0.8%", + "sum_box_desc": "16.41亿", + "sum_split_box_desc": "14.66亿" + }, + { + "movie_id": 1522657, + "movie_name": "南京照相馆", + "release_info": "上映64天", + "box_office": "82.47", + "box_office_unit": "万", + "box_office_desc": "82.47万", + "box_office_rate": "3.0%", + "split_box_office": "77.50", + "split_box_office_unit": "万", + "split_box_office_desc": "77.50万", + "split_box_office_rate": "3.0%", + "show_count": 19778, + "show_count_rate": "5.5%", + "avg_show_view": "1.2", + "avg_seat_view": "1.2%", + "sum_box_desc": "30.03亿", + "sum_split_box_desc": "26.94亿" + }, + { + "movie_id": 1547369, + "movie_name": "红丝绸", + "release_info": "上映21天", + "box_office": "60.55", + "box_office_unit": "万", + "box_office_desc": "60.55万", + "box_office_rate": "2.2%", + "split_box_office": "60.35", + "split_box_office_unit": "万", + "split_box_office_desc": "60.35万", + "split_box_office_rate": "2.4%", + "show_count": 313, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "50.9", + "avg_seat_view": "46.8%", + "sum_box_desc": "1114.9万", + "sum_split_box_desc": "1095.2万" + }, + { + "movie_id": 1536837, + "movie_name": "营救飞虎", + "release_info": "上映24天", + "box_office": "35.54", + "box_office_unit": "万", + "box_office_desc": "35.54万", + "box_office_rate": "1.3%", + "split_box_office": "35.42", + "split_box_office_unit": "万", + "split_box_office_desc": "35.42万", + "split_box_office_rate": "1.4%", + "show_count": 257, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "32.9", + "avg_seat_view": "32.4%", + "sum_box_desc": "2456.3万", + "sum_split_box_desc": "2431.0万" + }, + { + "movie_id": 1298226, + "movie_name": "死神来了:血脉诅咒", + "release_info": "上映36天", + "box_office": "31.42", + "box_office_unit": "万", + "box_office_desc": "31.42万", + "box_office_rate": "1.1%", + "split_box_office": "27.59", + "split_box_office_unit": "万", + "split_box_office_desc": "27.59万", + "split_box_office_rate": "1.1%", + "show_count": 9723, + "show_count_rate": "2.7%", + "avg_show_view": "0.8", + "avg_seat_view": "0.8%", + "sum_box_desc": "1.91亿", + "sum_split_box_desc": "1.69亿" + }, + { + "movie_id": 1523743, + "movie_name": "坏蛋联盟2", + "release_info": "上映42天", + "box_office": "28.70", + "box_office_unit": "万", + "box_office_desc": "28.70万", + "box_office_rate": "1.0%", + "split_box_office": "27.49", + "split_box_office_unit": "万", + "split_box_office_desc": "27.49万", + "split_box_office_rate": "1.0%", + "show_count": 4622, + "show_count_rate": "1.3%", + "avg_show_view": "1.2", + "avg_seat_view": "1.3%", + "sum_box_desc": "1.98亿", + "sum_split_box_desc": "1.78亿" + }, + { + "movie_id": 1499675, + "movie_name": "毕正明的证明", + "release_info": "点映", + "box_office": "25.80", + "box_office_unit": "万", + "box_office_desc": "25.80万", + "box_office_rate": "0.9%", + "split_box_office": "25.59", + "split_box_office_unit": "万", + "split_box_office_desc": "25.59万", + "split_box_office_rate": "1.0%", + "show_count": 28, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "157.6", + "avg_seat_view": "100.0%", + "sum_box_desc": "25.8万", + "sum_split_box_desc": "25.5万" + }, + { + "movie_id": 1572273, + "movie_name": "山河为证", + "release_info": "上映43天", + "box_office": "24.89", + "box_office_unit": "万", + "box_office_desc": "24.89万", + "box_office_rate": "0.9%", + "split_box_office": "24.88", + "split_box_office_unit": "万", + "split_box_office_desc": "24.88万", + "split_box_office_rate": "0.9%", + "show_count": 126, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "44.3", + "avg_seat_view": "37.1%", + "sum_box_desc": "2904.6万", + "sum_split_box_desc": "2894.9万" + }, + { + "movie_id": 1250679, + "movie_name": "洛桑的家事", + "release_info": "上映16天", + "box_office": "20.09", + "box_office_unit": "万", + "box_office_desc": "20.09万", + "box_office_rate": "0.7%", + "split_box_office": "20.08", + "split_box_office_unit": "万", + "split_box_office_desc": "20.08万", + "split_box_office_rate": "0.8%", + "show_count": 167, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "22.4", + "avg_seat_view": "20.7%", + "sum_box_desc": "519.8万", + "sum_split_box_desc": "517.7万" + }, + { + "movie_id": 1542730, + "movie_name": "奇遇", + "release_info": "上映50天", + "box_office": "16.11", + "box_office_unit": "万", + "box_office_desc": "16.11万", + "box_office_rate": "0.6%", + "split_box_office": "13.96", + "split_box_office_unit": "万", + "split_box_office_desc": "13.96万", + "split_box_office_rate": "0.5%", + "show_count": 4473, + "show_count_rate": "1.2%", + "avg_show_view": "1.1", + "avg_seat_view": "1.3%", + "sum_box_desc": "1.86亿", + "sum_split_box_desc": "1.63亿" + }, + { + "movie_id": 1500636, + "movie_name": "罗小黑战记2", + "release_info": "上映71天", + "box_office": "15.94", + "box_office_unit": "万", + "box_office_desc": "15.94万", + "box_office_rate": "0.5%", + "split_box_office": "14.14", + "split_box_office_unit": "万", + "split_box_office_desc": "14.14万", + "split_box_office_rate": "0.5%", + "show_count": 3761, + "show_count_rate": "1.0%", + "avg_show_view": "1.1", + "avg_seat_view": "1.2%", + "sum_box_desc": "5.21亿", + "sum_split_box_desc": "4.64亿" + }, + { + "movie_id": 1489329, + "movie_name": "浪浪人生", + "release_info": "点映", + "box_office": "15.34", + "box_office_unit": "万", + "box_office_desc": "15.34万", + "box_office_rate": "0.5%", + "split_box_office": "15.34", + "split_box_office_unit": "万", + "split_box_office_desc": "15.34万", + "split_box_office_rate": "0.6%", + "show_count": 19, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "143.8", + "avg_seat_view": "84.7%", + "sum_box_desc": "69.2万", + "sum_split_box_desc": "66.7万" + }, + { + "movie_id": 1454962, + "movie_name": "F1:狂飙飞车", + "release_info": "上映92天", + "box_office": "13.84", + "box_office_unit": "万", + "box_office_desc": "13.84万", + "box_office_rate": "0.5%", + "split_box_office": "12.42", + "split_box_office_unit": "万", + "split_box_office_desc": "12.42万", + "split_box_office_rate": "0.4%", + "show_count": 979, + "show_count_rate": "0.2%", + "avg_show_view": "2.5", + "avg_seat_view": "1.5%", + "sum_box_desc": "4.41亿", + "sum_split_box_desc": "3.94亿" + }, + { + "movie_id": 1584781, + "movie_name": "生还", + "release_info": "上映24天", + "box_office": "12.97", + "box_office_unit": "万", + "box_office_desc": "12.97万", + "box_office_rate": "0.4%", + "split_box_office": "12.94", + "split_box_office_unit": "万", + "split_box_office_desc": "12.94万", + "split_box_office_rate": "0.5%", + "show_count": 115, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "29.4", + "avg_seat_view": "26.0%", + "sum_box_desc": "358.2万", + "sum_split_box_desc": "354.7万" + }, + { + "movie_id": 1552050, + "movie_name": "汉斯·季默与朋友们:沙漠之钻音乐会", + "release_info": "上映7天", + "box_office": "9.52", + "box_office_unit": "万", + "box_office_desc": "9.52万", + "box_office_rate": "0.3%", + "split_box_office": "8.50", + "split_box_office_unit": "万", + "split_box_office_desc": "8.50万", + "split_box_office_rate": "0.3%", + "show_count": 822, + "show_count_rate": "0.2%", + "avg_show_view": "2.4", + "avg_seat_view": "1.8%", + "sum_box_desc": "181.7万", + "sum_split_box_desc": "164.7万" + }, + { + "movie_id": 343898, + "movie_name": "东极岛", + "release_info": "上映50天", + "box_office": "9.05", + "box_office_unit": "万", + "box_office_desc": "9.05万", + "box_office_rate": "0.3%", + "split_box_office": "8.67", + "split_box_office_unit": "万", + "split_box_office_desc": "8.67万", + "split_box_office_rate": "0.3%", + "show_count": 1837, + "show_count_rate": "0.5%", + "avg_show_view": "1.3", + "avg_seat_view": "1.4%", + "sum_box_desc": "3.96亿", + "sum_split_box_desc": "3.54亿" + }, + { + "movie_id": 1520596, + "movie_name": "轻于鸿毛", + "release_info": "上映14天", + "box_office": "8.85", + "box_office_unit": "万", + "box_office_desc": "8.85万", + "box_office_rate": "0.3%", + "split_box_office": "8.14", + "split_box_office_unit": "万", + "split_box_office_desc": "8.14万", + "split_box_office_rate": "0.3%", + "show_count": 4420, + "show_count_rate": "1.2%", + "avg_show_view": "0.5", + "avg_seat_view": "0.6%", + "sum_box_desc": "1479.7万", + "sum_split_box_desc": "1325.2万" + }, + { + "movie_id": 431882, + "movie_name": "新三峡", + "release_info": "上映93天", + "box_office": "4.82", + "box_office_unit": "万", + "box_office_desc": "4.82万", + "box_office_rate": "0.1%", + "split_box_office": "4.82", + "split_box_office_unit": "万", + "split_box_office_desc": "4.82万", + "split_box_office_rate": "0.1%", + "show_count": 12, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "78.9", + "avg_seat_view": "38.8%", + "sum_box_desc": "893.9万", + "sum_split_box_desc": "891.7万" + }, + { + "movie_id": 1511555, + "movie_name": "有朵云像你", + "release_info": "上映29天", + "box_office": "4.78", + "box_office_unit": "万", + "box_office_desc": "4.78万", + "box_office_rate": "0.1%", + "split_box_office": "4.09", + "split_box_office_unit": "万", + "split_box_office_desc": "4.09万", + "split_box_office_rate": "0.1%", + "show_count": 2017, + "show_count_rate": "0.5%", + "avg_show_view": "0.7", + "avg_seat_view": "0.8%", + "sum_box_desc": "5131.8万", + "sum_split_box_desc": "4540.4万" + }, + { + "movie_id": 1489326, + "movie_name": "7天", + "release_info": "上映29天", + "box_office": "4.19", + "box_office_unit": "万", + "box_office_desc": "4.19万", + "box_office_rate": "0.1%", + "split_box_office": "4.01", + "split_box_office_unit": "万", + "split_box_office_desc": "4.01万", + "split_box_office_rate": "0.1%", + "show_count": 842, + "show_count_rate": "0.2%", + "avg_show_view": "1.3", + "avg_seat_view": "1.6%", + "sum_box_desc": "6214.2万", + "sum_split_box_desc": "5481.7万" + }, + { + "movie_id": 1538211, + "movie_name": "临时决斗", + "release_info": "上映8天", + "box_office": "4.04", + "box_office_unit": "万", + "box_office_desc": "4.04万", + "box_office_rate": "0.1%", + "split_box_office": "3.73", + "split_box_office_unit": "万", + "split_box_office_desc": "3.73万", + "split_box_office_rate": "0.1%", + "show_count": 1843, + "show_count_rate": "0.5%", + "avg_show_view": "0.6", + "avg_seat_view": "0.6%", + "sum_box_desc": "126.1万", + "sum_split_box_desc": "112.0万" + }, + { + "movie_id": 1523868, + "movie_name": "三国的星空第一部", + "release_info": "点映", + "box_office": "3.36", + "box_office_unit": "万", + "box_office_desc": "3.36万", + "box_office_rate": "0.1%", + "split_box_office": "3.19", + "split_box_office_unit": "万", + "split_box_office_desc": "3.19万", + "split_box_office_rate": "0.1%", + "show_count": 3, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "261.0", + "avg_seat_view": "94.6%", + "sum_box_desc": "13.8万", + "sum_split_box_desc": "13.6万" + }, + { + "movie_id": 1547424, + "movie_name": "关于约会的一切", + "release_info": "上映22天", + "box_office": "3.15", + "box_office_unit": "万", + "box_office_desc": "3.15万", + "box_office_rate": "0.1%", + "split_box_office": "2.83", + "split_box_office_unit": "万", + "split_box_office_desc": "2.83万", + "split_box_office_rate": "0.1%", + "show_count": 441, + "show_count_rate": "0.1%", + "avg_show_view": "1.6", + "avg_seat_view": "1.5%", + "sum_box_desc": "381.5万", + "sum_split_box_desc": "342.6万" + }, + { + "movie_id": 1593640, + "movie_name": "疯狂电脑城", + "release_info": "点映", + "box_office": "3.07", + "box_office_unit": "万", + "box_office_desc": "3.07万", + "box_office_rate": "0.1%", + "split_box_office": "3.01", + "split_box_office_unit": "万", + "split_box_office_desc": "3.01万", + "split_box_office_rate": "0.1%", + "show_count": 10, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "101.0", + "avg_seat_view": "98.9%", + "sum_box_desc": "3.0万", + "sum_split_box_desc": "3.0万" + }, + { + "movie_id": 1462786, + "movie_name": "爱心之拳", + "release_info": "上映29天", + "box_office": "2.84", + "box_office_unit": "万", + "box_office_desc": "2.84万", + "box_office_rate": "0.1%", + "split_box_office": "2.84", + "split_box_office_unit": "万", + "split_box_office_desc": "2.84万", + "split_box_office_rate": "0.1%", + "show_count": 14, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "101.5", + "avg_seat_view": "27.0%", + "sum_box_desc": "93.6万", + "sum_split_box_desc": "93.6万" + }, + { + "movie_id": 1575780, + "movie_name": "蛟龙行动(特别版)", + "release_info": "上映28天", + "box_office": "2.79", + "box_office_unit": "万", + "box_office_desc": "2.79万", + "box_office_rate": "0.1%", + "split_box_office": "2.69", + "split_box_office_unit": "万", + "split_box_office_desc": "2.69万", + "split_box_office_rate": "0.1%", + "show_count": 952, + "show_count_rate": "0.2%", + "avg_show_view": "0.7", + "avg_seat_view": "0.7%", + "sum_box_desc": "2463.4万", + "sum_split_box_desc": "2194.8万" + }, + { + "movie_id": 1591480, + "movie_name": "白马姐妹", + "release_info": "", + "box_office": "2.09", + "box_office_unit": "万", + "box_office_desc": "2.09万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "2.09", + "split_box_office_unit": "万", + "split_box_office_desc": "2.09万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 2, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "418.0", + "avg_seat_view": "65.7%", + "sum_box_desc": "2.0万", + "sum_split_box_desc": "2.0万" + }, + { + "movie_id": 1519217, + "movie_name": "坪石先生", + "release_info": "上映43天", + "box_office": "1.76", + "box_office_unit": "万", + "box_office_desc": "1.76万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "1.76", + "split_box_office_unit": "万", + "split_box_office_desc": "1.76万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 11, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "61.4", + "avg_seat_view": "84.2%", + "sum_box_desc": "233.0万", + "sum_split_box_desc": "228.0万" + }, + { + "movie_id": 1499719, + "movie_name": "只此青绿", + "release_info": "", + "box_office": "1.66", + "box_office_unit": "万", + "box_office_desc": "1.66万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "1.44", + "split_box_office_unit": "万", + "split_box_office_desc": "1.44万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 823, + "show_count_rate": "0.2%", + "avg_show_view": "0.7", + "avg_seat_view": "0.6%", + "sum_box_desc": "5318.8万", + "sum_split_box_desc": "4830.5万" + }, + { + "movie_id": 1496400, + "movie_name": "天大的事", + "release_info": "上映12天", + "box_office": "1.29", + "box_office_unit": "万", + "box_office_desc": "1.29万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "1.18", + "split_box_office_unit": "万", + "split_box_office_desc": "1.18万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 4936, + "show_count_rate": "1.3%", + "avg_show_view": "\u003C0.1", + "avg_seat_view": "0.0%", + "sum_box_desc": "31.4万", + "sum_split_box_desc": "28.4万" + }, + { + "movie_id": 1461072, + "movie_name": "长空之王", + "release_info": "", + "box_office": "1.15", + "box_office_unit": "万", + "box_office_desc": "1.15万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "1.09", + "split_box_office_unit": "万", + "split_box_office_desc": "1.09万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 70, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "4.4", + "avg_seat_view": "5.7%", + "sum_box_desc": "8.54亿", + "sum_split_box_desc": "7.85亿" + }, + { + "movie_id": 1522287, + "movie_name": "长安的荔枝", + "release_info": "上映71天", + "box_office": "1.10", + "box_office_unit": "万", + "box_office_desc": "1.10万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.97", + "split_box_office_unit": "万", + "split_box_office_desc": "0.97万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 397, + "show_count_rate": "0.1%", + "avg_show_view": "0.8", + "avg_seat_view": "1.0%", + "sum_box_desc": "6.90亿", + "sum_split_box_desc": "6.15亿" + }, + { + "movie_id": 1562636, + "movie_name": "爱的暂停键", + "release_info": "上映22天", + "box_office": "1.06", + "box_office_unit": "万", + "box_office_desc": "1.06万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.94", + "split_box_office_unit": "万", + "split_box_office_desc": "0.94万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 182, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "1.3", + "avg_seat_view": "1.5%", + "sum_box_desc": "140.4万", + "sum_split_box_desc": "125.1万" + }, + { + "movie_id": 1592162, + "movie_name": "地球脉动:万物有道", + "release_info": "上映15天", + "box_office": "0.97", + "box_office_unit": "万", + "box_office_desc": "0.97万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.88", + "split_box_office_unit": "万", + "split_box_office_desc": "0.88万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 288, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "0.8", + "avg_seat_view": "0.7%", + "sum_box_desc": "43.4万", + "sum_split_box_desc": "39.2万" + }, + { + "movie_id": 1498162, + "movie_name": "午夜怪谈2", + "release_info": "上映15天", + "box_office": "0.97", + "box_office_unit": "万", + "box_office_desc": "0.97万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.87", + "split_box_office_unit": "万", + "split_box_office_desc": "0.87万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 1792, + "show_count_rate": "0.5%", + "avg_show_view": "0.2", + "avg_seat_view": "0.1%", + "sum_box_desc": "156.3万", + "sum_split_box_desc": "138.9万" + }, + { + "movie_id": 1288259, + "movie_name": "如果悲伤可以解释", + "release_info": "上映30天", + "box_office": "0.82", + "box_office_unit": "万", + "box_office_desc": "0.82万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.75", + "split_box_office_unit": "万", + "split_box_office_desc": "0.75万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 2, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "110.0", + "avg_seat_view": "70.5%", + "sum_box_desc": "8.6万", + "sum_split_box_desc": "8.1万" + }, + { + "movie_id": 1470241, + "movie_name": "以法之名", + "release_info": "", + "box_office": "0.54", + "box_office_unit": "万", + "box_office_desc": "0.54万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.54", + "split_box_office_unit": "万", + "split_box_office_desc": "0.54万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 9, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "25.1", + "avg_seat_view": "29.6%", + "sum_box_desc": "93.9万", + "sum_split_box_desc": "93.8万" + }, + { + "movie_id": 1435060, + "movie_name": "夏雨来", + "release_info": "上映42天", + "box_office": "0.50", + "box_office_unit": "万", + "box_office_desc": "0.50万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.45", + "split_box_office_unit": "万", + "split_box_office_desc": "0.45万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 207, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "0.8", + "avg_seat_view": "0.8%", + "sum_box_desc": "2784.3万", + "sum_split_box_desc": "2498.7万" + }, + { + "movie_id": 1395730, + "movie_name": "老墙", + "release_info": "", + "box_office": "0.49", + "box_office_unit": "万", + "box_office_desc": "0.49万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.49", + "split_box_office_unit": "万", + "split_box_office_desc": "0.49万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 10, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "16.5", + "avg_seat_view": "11.0%", + "sum_box_desc": "123.5万", + "sum_split_box_desc": "121.5万" + }, + { + "movie_id": 1573266, + "movie_name": "带你回家", + "release_info": "点映", + "box_office": "0.47", + "box_office_unit": "万", + "box_office_desc": "0.47万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.45", + "split_box_office_unit": "万", + "split_box_office_desc": "0.45万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 1, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "131.0", + "avg_seat_view": "100.0%", + "sum_box_desc": "1.9万", + "sum_split_box_desc": "1.8万" + }, + { + "movie_id": 1360592, + "movie_name": "当男人恋爱时", + "release_info": "", + "box_office": "0.43", + "box_office_unit": "万", + "box_office_desc": "0.43万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.37", + "split_box_office_unit": "万", + "split_box_office_desc": "0.37万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 403, + "show_count_rate": "0.1%", + "avg_show_view": "0.3", + "avg_seat_view": "0.2%", + "sum_box_desc": "2.64亿", + "sum_split_box_desc": "2.32亿" + }, + { + "movie_id": 1449451, + "movie_name": "人生一世", + "release_info": "展映", + "box_office": "0.36", + "box_office_unit": "万", + "box_office_desc": "0.36万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.34", + "split_box_office_unit": "万", + "split_box_office_desc": "0.34万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 1, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "68.0", + "avg_seat_view": "68.0%", + "sum_box_desc": "2.2万", + "sum_split_box_desc": "2.1万" + }, + { + "movie_id": 1530212, + "movie_name": "蔡伦传奇", + "release_info": "上映首日", + "box_office": "0.33", + "box_office_unit": "万", + "box_office_desc": "0.33万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.33", + "split_box_office_unit": "万", + "split_box_office_desc": "0.33万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 1, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "134.0", + "avg_seat_view": "76.5%", + "sum_box_desc": "3352", + "sum_split_box_desc": "3352" + }, + { + "movie_id": 1530145, + "movie_name": "蜗牛回忆录", + "release_info": "上映22天", + "box_office": "0.28", + "box_office_unit": "万", + "box_office_desc": "0.28万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.25", + "split_box_office_unit": "万", + "split_box_office_desc": "0.25万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 88, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "0.8", + "avg_seat_view": "0.8%", + "sum_box_desc": "73.8万", + "sum_split_box_desc": "66.4万" + }, + { + "movie_id": 1469373, + "movie_name": "逃离抢钱镇", + "release_info": "上映14天", + "box_office": "0.28", + "box_office_unit": "万", + "box_office_desc": "0.28万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.25", + "split_box_office_unit": "万", + "split_box_office_desc": "0.25万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 110, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "0.6", + "avg_seat_view": "0.7%", + "sum_box_desc": "38.5万", + "sum_split_box_desc": "34.5万" + }, + { + "movie_id": 1490948, + "movie_name": "聊斋:兰若寺", + "release_info": "上映77天", + "box_office": "0.26", + "box_office_unit": "万", + "box_office_desc": "0.26万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.23", + "split_box_office_unit": "万", + "split_box_office_desc": "0.23万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 99, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "0.8", + "avg_seat_view": "0.9%", + "sum_box_desc": "2.43亿", + "sum_split_box_desc": "2.15亿" + }, + { + "movie_id": 1518617, + "movie_name": "小鹿斑比:清算", + "release_info": "上映21天", + "box_office": "0.26", + "box_office_unit": "万", + "box_office_desc": "0.26万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.23", + "split_box_office_unit": "万", + "split_box_office_desc": "0.23万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 590, + "show_count_rate": "0.1%", + "avg_show_view": "0.1", + "avg_seat_view": "0.1%", + "sum_box_desc": "217.6万", + "sum_split_box_desc": "194.5万" + }, + { + "movie_id": 1524059, + "movie_name": "别把作文当回事儿", + "release_info": "上映15天", + "box_office": "0.25", + "box_office_unit": "万", + "box_office_desc": "0.25万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.23", + "split_box_office_unit": "万", + "split_box_office_desc": "0.23万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 2, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "33.5", + "avg_seat_view": "20.1%", + "sum_box_desc": "55.8万", + "sum_split_box_desc": "55.0万" + }, + { + "movie_id": 1427899, + "movie_name": "天宝", + "release_info": "上映79天", + "box_office": "0.23", + "box_office_unit": "万", + "box_office_desc": "0.23万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.23", + "split_box_office_unit": "万", + "split_box_office_desc": "0.23万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 3, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "21.3", + "avg_seat_view": "16.9%", + "sum_box_desc": "351.2万", + "sum_split_box_desc": "343.0万" + }, + { + "movie_id": 1593298, + "movie_name": "海洋之谜", + "release_info": "展映", + "box_office": "0.20", + "box_office_unit": "万", + "box_office_desc": "0.20万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.19", + "split_box_office_unit": "万", + "split_box_office_desc": "0.19万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 1, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "41.0", + "avg_seat_view": "12.0%", + "sum_box_desc": "6.4万", + "sum_split_box_desc": "6.0万" + }, + { + "movie_id": 1487834, + "movie_name": "熊孩子·探险熊兵", + "release_info": "上映14天", + "box_office": "0.17", + "box_office_unit": "万", + "box_office_desc": "0.17万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.16", + "split_box_office_unit": "万", + "split_box_office_desc": "0.16万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 651, + "show_count_rate": "0.1%", + "avg_show_view": "\u003C0.1", + "avg_seat_view": "0.0%", + "sum_box_desc": "172.8万", + "sum_split_box_desc": "165.3万" + }, + { + "movie_id": 1491476, + "movie_name": "超人", + "release_info": "上映78天", + "box_office": "0.13", + "box_office_unit": "万", + "box_office_desc": "0.13万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.12", + "split_box_office_unit": "万", + "split_box_office_desc": "0.12万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 44, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "0.5", + "avg_seat_view": "0.5%", + "sum_box_desc": "6392.8万", + "sum_split_box_desc": "5729.0万" + }, + { + "movie_id": 1527997, + "movie_name": "大别山久生", + "release_info": "上映17天", + "box_office": "0.12", + "box_office_unit": "万", + "box_office_desc": "0.12万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.12", + "split_box_office_unit": "万", + "split_box_office_desc": "0.12万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 2, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "25.5", + "avg_seat_view": "18.8%", + "sum_box_desc": "3.1万", + "sum_split_box_desc": "3.1万" + }, + { + "movie_id": 1528424, + "movie_name": "午夜凶镜", + "release_info": "上映29天", + "box_office": "0.12", + "box_office_unit": "万", + "box_office_desc": "0.12万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.11", + "split_box_office_unit": "万", + "split_box_office_desc": "0.11万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 292, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "0.1", + "avg_seat_view": "0.1%", + "sum_box_desc": "172.0万", + "sum_split_box_desc": "152.2万" + }, + { + "movie_id": 1289244, + "movie_name": "吉普赛女王", + "release_info": "展映", + "box_office": "0.09", + "box_office_unit": "万", + "box_office_desc": "0.09万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.08", + "split_box_office_unit": "万", + "split_box_office_desc": "0.08万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 1, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "20.0", + "avg_seat_view": "10.1%", + "sum_box_desc": "6553", + "sum_split_box_desc": "6117" + }, + { + "movie_id": 1509826, + "movie_name": "伊甸", + "release_info": "上映36天", + "box_office": "0.08", + "box_office_unit": "万", + "box_office_desc": "0.08万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.07", + "split_box_office_unit": "万", + "split_box_office_desc": "0.07万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 15, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "1.5", + "avg_seat_view": "1.7%", + "sum_box_desc": "235.0万", + "sum_split_box_desc": "208.4万" + }, + { + "movie_id": 1320548, + "movie_name": "家庭简史", + "release_info": "上映15天", + "box_office": "0.08", + "box_office_unit": "万", + "box_office_desc": "0.08万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.07", + "split_box_office_unit": "万", + "split_box_office_desc": "0.07万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 41, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "0.5", + "avg_seat_view": "0.7%", + "sum_box_desc": "29.9万", + "sum_split_box_desc": "28.8万" + }, + { + "movie_id": 1470975, + "movie_name": "这周五的游乐场", + "release_info": "上映8天", + "box_office": "0.08", + "box_office_unit": "万", + "box_office_desc": "0.08万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.07", + "split_box_office_unit": "万", + "split_box_office_desc": "0.07万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 17, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "1.3", + "avg_seat_view": "1.5%", + "sum_box_desc": "15.0万", + "sum_split_box_desc": "14.7万" + }, + { + "movie_id": 1593302, + "movie_name": "飓风", + "release_info": "展映", + "box_office": "0.07", + "box_office_unit": "万", + "box_office_desc": "0.07万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.07", + "split_box_office_unit": "万", + "split_box_office_desc": "0.07万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 1, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "15.0", + "avg_seat_view": "4.4%", + "sum_box_desc": "3.3万", + "sum_split_box_desc": "3.1万" + }, + { + "movie_id": 1487768, + "movie_name": "巴扎喜事", + "release_info": "上映36天", + "box_office": "0.07", + "box_office_unit": "万", + "box_office_desc": "0.07万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.07", + "split_box_office_unit": "万", + "split_box_office_desc": "0.07万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 22, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "0.8", + "avg_seat_view": "0.9%", + "sum_box_desc": "144.9万", + "sum_split_box_desc": "137.1万" + }, + { + "movie_id": 1568020, + "movie_name": "喜羊羊与灰太狼之异国破晓", + "release_info": "上映63天", + "box_office": "0.07", + "box_office_unit": "万", + "box_office_desc": "0.07万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.06", + "split_box_office_unit": "万", + "split_box_office_desc": "0.06万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 80, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "0.3", + "avg_seat_view": "0.2%", + "sum_box_desc": "6206.1万", + "sum_split_box_desc": "5555.4万" + }, + { + "movie_id": 1525122, + "movie_name": "康熙与路易十四", + "release_info": "", + "box_office": "0.06", + "box_office_unit": "万", + "box_office_desc": "0.06万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.05", + "split_box_office_unit": "万", + "split_box_office_desc": "0.05万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 1, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "10.0", + "avg_seat_view": "40.0%", + "sum_box_desc": "304.0万", + "sum_split_box_desc": "298.6万" + }, + { + "movie_id": 1250604, + "movie_name": "里斯本丸沉没", + "release_info": "", + "box_office": "0.05", + "box_office_unit": "万", + "box_office_desc": "0.05万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.05", + "split_box_office_unit": "万", + "split_box_office_desc": "0.05万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 30, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "0.5", + "avg_seat_view": "0.6%", + "sum_box_desc": "4763.2万", + "sum_split_box_desc": "4345.3万" + }, + { + "movie_id": 1432141, + "movie_name": "戏台", + "release_info": "上映64天", + "box_office": "0.05", + "box_office_unit": "万", + "box_office_desc": "0.05万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.04", + "split_box_office_unit": "万", + "split_box_office_desc": "0.04万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 24, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "0.6", + "avg_seat_view": "0.7%", + "sum_box_desc": "4.11亿", + "sum_split_box_desc": "3.66亿" + }, + { + "movie_id": 40308, + "movie_name": "玛丽和麦克斯", + "release_info": "上映50天", + "box_office": "0.04", + "box_office_unit": "万", + "box_office_desc": "0.04万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.04", + "split_box_office_unit": "万", + "split_box_office_desc": "0.04万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 10, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "1.3", + "avg_seat_view": "1.7%", + "sum_box_desc": "107.1万", + "sum_split_box_desc": "97.2万" + }, + { + "movie_id": 1451361, + "movie_name": "我们的那一年", + "release_info": "上映29天", + "box_office": "0.04", + "box_office_unit": "万", + "box_office_desc": "0.04万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.04", + "split_box_office_unit": "万", + "split_box_office_desc": "0.04万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 1, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "9.0", + "avg_seat_view": "4.0%", + "sum_box_desc": "1.5万", + "sum_split_box_desc": "1.5万" + }, + { + "movie_id": 1431675, + "movie_name": "赎梦", + "release_info": "上映35天", + "box_office": "0.04", + "box_office_unit": "万", + "box_office_desc": "0.04万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.03", + "split_box_office_unit": "万", + "split_box_office_desc": "0.03万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 53, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "0.2", + "avg_seat_view": "0.2%", + "sum_box_desc": "561.8万", + "sum_split_box_desc": "503.4万" + }, + { + "movie_id": 308316, + "movie_name": "蜡笔小新:大人王国的反击", + "release_info": "上映91天", + "box_office": "0.04", + "box_office_unit": "万", + "box_office_desc": "0.04万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.03", + "split_box_office_unit": "万", + "split_box_office_desc": "0.03万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 9, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "1.2", + "avg_seat_view": "1.2%", + "sum_box_desc": "6827.9万", + "sum_split_box_desc": "6120.8万" + }, + { + "movie_id": 122157, + "movie_name": "孩子王", + "release_info": "", + "box_office": "0.03", + "box_office_unit": "万", + "box_office_desc": "0.03万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.03", + "split_box_office_unit": "万", + "split_box_office_desc": "0.03万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 1, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "6.0", + "avg_seat_view": "6.0%", + "sum_box_desc": "1.1万", + "sum_split_box_desc": "1.0万" + }, + { + "movie_id": 1452520, + "movie_name": "一生交给党", + "release_info": "", + "box_office": "0.03", + "box_office_unit": "万", + "box_office_desc": "0.03万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.03", + "split_box_office_unit": "万", + "split_box_office_desc": "0.03万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 4, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "2.3", + "avg_seat_view": "2.0%", + "sum_box_desc": "675.7万", + "sum_split_box_desc": "671.2万" + }, + { + "movie_id": 1481712, + "movie_name": "寻找1999的月老", + "release_info": "上映29天", + "box_office": "0.02", + "box_office_unit": "万", + "box_office_desc": "0.02万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.02", + "split_box_office_unit": "万", + "split_box_office_desc": "0.02万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 2, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "2.0", + "avg_seat_view": "2.2%", + "sum_box_desc": "52.3万", + "sum_split_box_desc": "50.1万" + }, + { + "movie_id": 1552267, + "movie_name": "山庄·惊魂", + "release_info": "上映92天", + "box_office": "0.02", + "box_office_unit": "万", + "box_office_desc": "0.02万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.02", + "split_box_office_unit": "万", + "split_box_office_desc": "0.02万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 3, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "1.3", + "avg_seat_view": "1.2%", + "sum_box_desc": "201.5万", + "sum_split_box_desc": "177.2万" + }, + { + "movie_id": 1551836, + "movie_name": "麦克白", + "release_info": "上映56天", + "box_office": "0.02", + "box_office_unit": "万", + "box_office_desc": "0.02万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.02", + "split_box_office_unit": "万", + "split_box_office_desc": "0.02万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 1, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "7.0", + "avg_seat_view": "14.0%", + "sum_box_desc": "37.9万", + "sum_split_box_desc": "34.7万" + }, + { + "movie_id": 1302189, + "movie_name": "零卡社团", + "release_info": "展映", + "box_office": "0.02", + "box_office_unit": "万", + "box_office_desc": "0.02万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.02", + "split_box_office_unit": "万", + "split_box_office_desc": "0.02万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 2, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "1.5", + "avg_seat_view": "1.7%", + "sum_box_desc": "3.9万", + "sum_split_box_desc": "3.7万" + }, + { + "movie_id": 1547375, + "movie_name": "同甘共苦", + "release_info": "展映", + "box_office": "0.02", + "box_office_unit": "万", + "box_office_desc": "0.02万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.01", + "split_box_office_unit": "万", + "split_box_office_desc": "0.01万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 18, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "0.3", + "avg_seat_view": "0.2%", + "sum_box_desc": "31.8万", + "sum_split_box_desc": "28.4万" + }, + { + "movie_id": 1462651, + "movie_name": "我们终将要和世界握手言和", + "release_info": "上映17天", + "box_office": "0.01", + "box_office_unit": "万", + "box_office_desc": "0.01万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.01", + "split_box_office_unit": "万", + "split_box_office_desc": "0.01万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 2, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "2.0", + "avg_seat_view": "1.6%", + "sum_box_desc": "3.4万", + "sum_split_box_desc": "3.3万" + }, + { + "movie_id": 1415196, + "movie_name": "无名", + "release_info": "", + "box_office": "0.01", + "box_office_unit": "万", + "box_office_desc": "0.01万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.01", + "split_box_office_unit": "万", + "split_box_office_desc": "0.01万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 4, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "1.0", + "avg_seat_view": "1.3%", + "sum_box_desc": "9.43亿", + "sum_split_box_desc": "8.88亿" + }, + { + "movie_id": 1301793, + "movie_name": "掬水月在手", + "release_info": "", + "box_office": "0.01", + "box_office_unit": "万", + "box_office_desc": "0.01万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.01", + "split_box_office_unit": "万", + "split_box_office_desc": "0.01万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 1, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "4.0", + "avg_seat_view": "4.0%", + "sum_box_desc": "790.8万", + "sum_split_box_desc": "728.3万" + }, + { + "movie_id": 1501764, + "movie_name": "威风锣鼓", + "release_info": "上映50天", + "box_office": "0.01", + "box_office_unit": "万", + "box_office_desc": "0.01万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.01", + "split_box_office_unit": "万", + "split_box_office_desc": "0.01万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 1, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "4.0", + "avg_seat_view": "4.3%", + "sum_box_desc": "1.3万", + "sum_split_box_desc": "1.2万" + }, + { + "movie_id": 1187439, + "movie_name": "侏罗纪世界3", + "release_info": "", + "box_office": "0.01", + "box_office_unit": "万", + "box_office_desc": "0.01万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.01", + "split_box_office_unit": "万", + "split_box_office_desc": "0.01万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 1, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "3.0", + "avg_seat_view": "2.7%", + "sum_box_desc": "10.59亿", + "sum_split_box_desc": "9.45亿" + }, + { + "movie_id": 1532831, + "movie_name": "潜艇总动员:冒险岛", + "release_info": "", + "box_office": "0.01", + "box_office_unit": "万", + "box_office_desc": "0.01万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.01", + "split_box_office_unit": "万", + "split_box_office_desc": "0.01万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 2, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "1.5", + "avg_seat_view": "1.0%", + "sum_box_desc": "1053.3万", + "sum_split_box_desc": "1002.9万" + }, + { + "movie_id": 1566861, + "movie_name": "血色牢笼", + "release_info": "上映22天", + "box_office": "0.01", + "box_office_unit": "万", + "box_office_desc": "0.01万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.01", + "split_box_office_unit": "万", + "split_box_office_desc": "0.01万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 8, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "0.4", + "avg_seat_view": "0.5%", + "sum_box_desc": "7.2万", + "sum_split_box_desc": "6.7万" + }, + { + "movie_id": 443609, + "movie_name": "圆梦餐厅", + "release_info": "上映50天", + "box_office": "0.01", + "box_office_unit": "万", + "box_office_desc": "0.01万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.01", + "split_box_office_unit": "万", + "split_box_office_desc": "0.01万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 1, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "3.0", + "avg_seat_view": "3.3%", + "sum_box_desc": "7.1万", + "sum_split_box_desc": "6.8万" + }, + { + "movie_id": 1524039, + "movie_name": "潍遗灯火阑珊处", + "release_info": "上映8天", + "box_office": "0.01", + "box_office_unit": "万", + "box_office_desc": "0.01万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.00", + "split_box_office_unit": "万", + "split_box_office_desc": "0.00万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 1, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "3.0", + "avg_seat_view": "6.2%", + "sum_box_desc": "673", + "sum_split_box_desc": "515" + }, + { + "movie_id": 1227946, + "movie_name": "甜蜜恰好也三十", + "release_info": "上映22天", + "box_office": "0.00", + "box_office_unit": "万", + "box_office_desc": "0.00万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.00", + "split_box_office_unit": "万", + "split_box_office_desc": "0.00万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 6, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "0.3", + "avg_seat_view": "0.4%", + "sum_box_desc": "10.3万", + "sum_split_box_desc": "10.1万" + }, + { + "movie_id": 246386, + "movie_name": "小王子", + "release_info": "", + "box_office": "0.00", + "box_office_unit": "万", + "box_office_desc": "0.00万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.00", + "split_box_office_unit": "万", + "split_box_office_desc": "0.00万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 1, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "2.0", + "avg_seat_view": "2.7%", + "sum_box_desc": "1.59亿", + "sum_split_box_desc": "1.59亿" + }, + { + "movie_id": 1583990, + "movie_name": "与世界的最后一眼相遇", + "release_info": "上映42天", + "box_office": "0.00", + "box_office_unit": "万", + "box_office_desc": "0.00万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.00", + "split_box_office_unit": "万", + "split_box_office_desc": "0.00万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 4, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "0.5", + "avg_seat_view": "0.6%", + "sum_box_desc": "75.5万", + "sum_split_box_desc": "68.5万" + }, + { + "movie_id": 1581104, + "movie_name": "生死狙杀", + "release_info": "上映26天", + "box_office": "0.00", + "box_office_unit": "万", + "box_office_desc": "0.00万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.00", + "split_box_office_unit": "万", + "split_box_office_desc": "0.00万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 18, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "0.1", + "avg_seat_view": "0.1%", + "sum_box_desc": "1849", + "sum_split_box_desc": "1635" + }, + { + "movie_id": 1547294, + "movie_name": "翡翠城巫师", + "release_info": "上映29天", + "box_office": "0.00", + "box_office_unit": "万", + "box_office_desc": "0.00万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.00", + "split_box_office_unit": "万", + "split_box_office_desc": "0.00万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 7, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "0.3", + "avg_seat_view": "0.2%", + "sum_box_desc": "11.7万", + "sum_split_box_desc": "10.5万" + }, + { + "movie_id": 1475139, + "movie_name": "魔法鼠乐园·神秘魔法球", + "release_info": "上映28天", + "box_office": "0.00", + "box_office_unit": "万", + "box_office_desc": "0.00万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.00", + "split_box_office_unit": "万", + "split_box_office_desc": "0.00万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 21, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "\u003C0.1", + "avg_seat_view": "0.1%", + "sum_box_desc": "25.8万", + "sum_split_box_desc": "22.9万" + }, + { + "movie_id": 78602, + "movie_name": "侏罗纪世界", + "release_info": "", + "box_office": "0.00", + "box_office_unit": "万", + "box_office_desc": "0.00万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.00", + "split_box_office_unit": "万", + "split_box_office_desc": "0.00万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 1, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "1.0", + "avg_seat_view": "0.8%", + "sum_box_desc": "14.18亿", + "sum_split_box_desc": "14.18亿" + }, + { + "movie_id": 296020, + "movie_name": "开国大典", + "release_info": "", + "box_office": "0.00", + "box_office_unit": "万", + "box_office_desc": "0.00万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.00", + "split_box_office_unit": "万", + "split_box_office_desc": "0.00万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 1, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "1.0", + "avg_seat_view": "1.0%", + "sum_box_desc": "4.4万", + "sum_split_box_desc": "4.4万" + }, + { + "movie_id": 246339, + "movie_name": "平原游击队", + "release_info": "展映", + "box_office": "0.00", + "box_office_unit": "万", + "box_office_desc": "0.00万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.00", + "split_box_office_unit": "万", + "split_box_office_desc": "0.00万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 1, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "1.0", + "avg_seat_view": "2.6%", + "sum_box_desc": "952", + "sum_split_box_desc": "916" + }, + { + "movie_id": 1387874, + "movie_name": "大突围", + "release_info": "", + "box_office": "0.00", + "box_office_unit": "万", + "box_office_desc": "0.00万", + "box_office_rate": "\u003C0.1%", + "split_box_office": "0.00", + "split_box_office_unit": "万", + "split_box_office_desc": "0.00万", + "split_box_office_rate": "\u003C0.1%", + "show_count": 1, + "show_count_rate": "\u003C0.1%", + "avg_show_view": "1.0", + "avg_seat_view": "0.6%", + "sum_box_desc": "1330.9万", + "sum_split_box_desc": "1313.2万" + } + ] + } +} \ No newline at end of file diff --git a/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电视收视排行/css/background.css b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电视收视排行/css/background.css new file mode 100644 index 00000000..13a58f4c --- /dev/null +++ b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电视收视排行/css/background.css @@ -0,0 +1,79 @@ +.background-layer { + position: fixed; + inset: 0; + overflow: hidden; + z-index: -1; + background: linear-gradient(180deg, #e8f5e8 0%, #f0f8e8 55%, #e8f5e8 100%); +} + +.aurora { + position: absolute; + width: 480px; + height: 480px; + border-radius: 58% 42% 53% 47% / 52% 46% 54% 48%; + filter: blur(0px); + opacity: 0.28; + background: radial-gradient(circle at 40% 40%, rgba(168, 230, 207, 0.4), rgba(168, 230, 207, 0)); + animation: float 32s ease-in-out infinite; +} + +.aurora-1 { + top: -160px; + left: -140px; + animation-delay: 0s; +} + +.aurora-2 { + top: 50%; + left: 60%; + animation-delay: 6s; + background: radial-gradient(circle at 60% 60%, rgba(220, 237, 193, 0.35), rgba(220, 237, 193, 0)); +} + +.aurora-3 { + bottom: -180px; + right: -160px; + animation-delay: 12s; + background: radial-gradient(circle at 50% 50%, rgba(129, 199, 132, 0.3), rgba(129, 199, 132, 0)); +} + +@keyframes float { + 0% { + transform: translate3d(0, 0, 0) scale(1); + } + 25% { + transform: translate3d(40px, -30px, 0) scale(1.05); + } + 50% { + transform: translate3d(-35px, 25px, 0) scale(0.95); + } + 75% { + transform: translate3d(20px, 35px, 0) scale(1.08); + } + 100% { + transform: translate3d(0, 0, 0) scale(1); + } +} + +@media (max-width: 768px) { + .aurora { + width: 280px; + height: 280px; + opacity: 0.24; + } + + .aurora-1 { + top: -110px; + left: -130px; + } + + .aurora-2 { + top: 45%; + left: 35%; + } + + .aurora-3 { + bottom: -140px; + right: -120px; + } +} diff --git a/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电视收视排行/css/style.css b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电视收视排行/css/style.css new file mode 100644 index 00000000..8fb5f5d8 --- /dev/null +++ b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电视收视排行/css/style.css @@ -0,0 +1,414 @@ +:root { + --bg-base: rgba(255, 255, 255, 0.85); + --panel-bg: rgba(248, 252, 248, 0.9); + --panel-border: rgba(129, 199, 132, 0.25); + --accent-1: #4caf50; + --accent-2: #81c784; + --accent-3: #a5d6a7; + --text-primary: #2e7d32; + --text-secondary: #558b2f; + --chip-bg: rgba(76, 175, 80, 0.15); + --shadow-soft: 0 16px 40px rgba(46, 125, 50, 0.15); + color-scheme: light; +} + +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body { + background: transparent; + color: var(--text-primary); + font-family: "PingFang SC", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif; + line-height: 1.6; + min-height: 100vh; + -webkit-font-smoothing: antialiased; +} + +.screen { + width: min(100%, 840px); + margin: 0 auto; + padding: 18px 16px 72px; + display: flex; + flex-direction: column; + gap: 18px; +} + +.screen-header { + display: flex; + flex-direction: column; + gap: 18px; + padding: 20px 18px; + border-radius: 20px; + background: var(--bg-base); + border: 1px solid var(--panel-border); + box-shadow: var(--shadow-soft); + backdrop-filter: blur(18px); +} + +.title-group { + display: flex; + flex-direction: column; + gap: 10px; +} + +.eyebrow { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 4px 12px; + font-size: 0.8rem; + letter-spacing: 0.08em; + text-transform: uppercase; + border-radius: 999px; + color: var(--accent-1); + background: var(--chip-bg); +} + +.screen-header h1 { + font-size: 1.6rem; + font-weight: 700; +} + +.tagline { + font-size: 0.95rem; + color: var(--text-secondary); +} + +.actions { + display: flex; + flex-direction: column; + gap: 10px; + align-items: flex-start; +} + +.refresh { + padding: 10px 20px; + border-radius: 999px; + border: none; + background: linear-gradient(135deg, rgba(76, 175, 80, 0.9), rgba(129, 199, 132, 0.9)); + color: var(--text-primary); + font-size: 0.92rem; + font-weight: 600; + cursor: pointer; + transition: transform 0.2s ease, box-shadow 0.2s ease; + box-shadow: 0 12px 30px rgba(76, 175, 80, 0.25); +} + +.refresh:active { + transform: scale(0.97); +} + +.refresh:disabled { + opacity: 0.6; + cursor: not-allowed; +} + +.timestamp { + font-size: 0.85rem; + color: var(--text-secondary); +} + +.insights { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 12px; +} + +.insight-card { + padding: 16px 18px; + background: var(--panel-bg); + border-radius: 16px; + border: 1px solid rgba(129, 199, 132, 0.3); + box-shadow: var(--shadow-soft); + display: flex; + flex-direction: column; + gap: 6px; +} + +.insight-label { + font-size: 0.85rem; + color: var(--text-secondary); + letter-spacing: 0.02em; +} + +.insight-value { + font-size: 1.3rem; + font-weight: 700; + display: flex; + align-items: baseline; + gap: 4px; + color: var(--text-primary); +} + +.insight-value .unit { + font-size: 0.9rem; + font-weight: 500; + color: var(--text-secondary); +} + +.ranking { + padding: 22px 18px 28px; + background: var(--bg-base); + border-radius: 24px; + border: 1px solid var(--panel-border); + box-shadow: var(--shadow-soft); + backdrop-filter: blur(22px); + display: flex; + flex-direction: column; + gap: 18px; +} + +.ranking-header { + display: flex; + flex-direction: column; + gap: 6px; +} + +.ranking-header h2 { + font-size: 1.25rem; + font-weight: 700; +} + +.subtitle { + font-size: 0.88rem; + color: var(--text-secondary); +} + +.programme-list { + display: flex; + flex-direction: column; + gap: 14px; +} + +.loading, +.error-message, +.empty-message { + padding: 18px 16px; + text-align: center; + color: var(--text-secondary); + border-radius: 14px; + border: 1px dashed rgba(129, 199, 132, 0.4); + background: rgba(248, 252, 248, 0.6); +} + +.programme-item { + display: grid; + grid-template-columns: auto 1fr; + gap: 14px; + padding: 16px; + border-radius: 18px; + background: rgba(248, 252, 248, 0.95); + border: 1px solid rgba(129, 199, 132, 0.3); + box-shadow: 0 14px 30px rgba(46, 125, 50, 0.1); + transition: transform 0.2s ease, box-shadow 0.2s ease; +} + +.programme-item:hover { + transform: translateY(-2px); + box-shadow: 0 18px 36px rgba(46, 125, 50, 0.15); +} + +.rank-badge { + width: 44px; + height: 44px; + border-radius: 14px; + display: flex; + align-items: center; + justify-content: center; + font-weight: 700; + font-size: 1.05rem; + color: #ffffff; + background: linear-gradient(135deg, rgba(76, 175, 80, 0.9), rgba(129, 199, 132, 0.9)); +} + +.rank-badge.top-1 { + background: linear-gradient(135deg, #2e7d32, #4caf50); +} + +.rank-badge.top-2 { + background: linear-gradient(135deg, #388e3c, #66bb6a); +} + +.rank-badge.top-3 { + background: linear-gradient(135deg, #4caf50, #81c784); +} + +.programme-body { + display: flex; + flex-direction: column; + gap: 12px; +} + +.programme-head { + display: flex; + flex-direction: column; + gap: 6px; +} + +.programme-name { + font-size: 1.05rem; + font-weight: 700; +} + +.channel-name { + font-size: 0.9rem; + color: var(--text-secondary); +} + +.metric-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 10px; +} + +.metric { + display: flex; + flex-direction: column; + gap: 2px; +} + +.metric-label { + font-size: 0.78rem; + color: var(--text-secondary); + letter-spacing: 0.04em; + text-transform: uppercase; +} + +.metric-value { + font-size: 0.98rem; + font-weight: 600; +} + +.progress-trend { + display: flex; + flex-direction: column; + gap: 8px; + margin-top: 4px; +} + +.progress-row { + display: flex; + flex-direction: column; + gap: 4px; +} + +.progress-label { + display: flex; + justify-content: space-between; + font-size: 0.8rem; + color: var(--text-secondary); +} + +.progress-bar { + width: 100%; + height: 6px; + border-radius: 6px; + background: rgba(116, 210, 255, 0.16); + overflow: hidden; +} + +.progress-bar span { + display: block; + height: 100%; + border-radius: inherit; + background: linear-gradient(135deg, rgba(116, 210, 255, 0.95), rgba(122, 185, 255, 0.95)); + width: 0; + transition: width 0.5s ease; +} + +.progress-row.attention .progress-bar span { + background: linear-gradient(135deg, rgba(244, 156, 224, 0.95), rgba(116, 210, 255, 0.9)); +} + +/* Tablet layout */ +@media (min-width: 600px) { + .screen { + padding: 24px 20px 88px; + gap: 20px; + } + + .screen-header { + flex-direction: row; + justify-content: space-between; + align-items: center; + padding: 26px 28px; + } + + .screen-header h1 { + font-size: 1.9rem; + } + + .tagline { + font-size: 1rem; + } + + .actions { + align-items: flex-end; + } + + .insights { + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 16px; + } + + .programme-item { + grid-template-columns: 72px 1fr; + padding: 18px 20px; + } + + .rank-badge { + width: 54px; + height: 54px; + font-size: 1.25rem; + } + + .metric-grid { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } +} + +/* Desktop layout */ +@media (min-width: 1024px) { + .screen { + width: min(100%, 960px); + padding: 32px 28px 104px; + } + + .insight-card { + padding: 20px 22px; + } + + .insight-value { + font-size: 1.6rem; + } + + .ranking { + padding: 30px 32px 36px; + } + + .programme-item { + grid-template-columns: 96px 1fr; + padding: 22px 26px; + border-radius: 22px; + } + + .programme-name { + font-size: 1.25rem; + } + + .metric-grid { + grid-template-columns: repeat(4, minmax(0, 1fr)); + } +} + +@media (prefers-reduced-motion: reduce) { + * { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; + } +} diff --git a/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电视收视排行/index.html b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电视收视排行/index.html new file mode 100644 index 00000000..d8d34dd3 --- /dev/null +++ b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电视收视排行/index.html @@ -0,0 +1,62 @@ + + + + + + 猫眼电视收视排行 + + + + +
+
+
+
+
+ +
+
+
+ 实时收视 +

猫眼电视收视排行

+

聚焦全国频道实时关注度,让你不错过热门节目

+
+
+ + 正在同步最新数据... +
+
+ +
+
+

节目数量

+

--

+
+
+

最高市场份额

+

--%

+
+
+

最高关注指数

+

--%

+
+
+

官方刷新频率

+

--

+
+
+ +
+
+

频道节目排行榜

+ 实时榜单,数据持续刷新 +
+
+
正在载入电视收视排行...
+
+
+
+ + + + diff --git a/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电视收视排行/js/main.js b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电视收视排行/js/main.js new file mode 100644 index 00000000..2d2764dd --- /dev/null +++ b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电视收视排行/js/main.js @@ -0,0 +1,290 @@ +const API_ENDPOINTS = [ + "https://60s.api.shumengya.top/v2/maoyan/realtime/tv" +]; + +const FALLBACK_ENDPOINT = "./返回接口.json"; +const REFRESH_INTERVAL = 4000; +const MAX_ITEMS = 40; + +const refreshButton = document.getElementById("refreshButton"); +const updateTimeEl = document.getElementById("updateTime"); +const programmeListEl = document.getElementById("programmeList"); +const programmeCountEl = document.getElementById("programmeCount"); +const topMarketRateEl = document.getElementById("topMarketRate"); +const topAttentionRateEl = document.getElementById("topAttentionRate"); +const refreshGapEl = document.getElementById("refreshGap"); + +let isLoading = false; +let autoTimer = null; + +function escapeHtml(value) { + if (value === undefined || value === null) { + return ""; + } + return String(value) + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); +} + +function safeText(value, fallback = "--") { + if (value === undefined || value === null || value === "") { + return fallback; + } + return escapeHtml(value); +} + +function formatNumber(value, fractionDigits = 2) { + const numeric = Number(value); + if (!Number.isFinite(numeric)) { + return "--"; + } + return numeric.toFixed(fractionDigits); +} + +function formatGapText(seconds) { + const numeric = Number(seconds); + if (!Number.isFinite(numeric) || numeric <= 0) { + return "--"; + } + if (numeric < 60) { + return `约每 ${Math.round(numeric)} 秒`; + } + const minutes = Math.floor(numeric / 60); + const remaining = Math.round(numeric % 60); + if (remaining === 0) { + return `约每 ${minutes} 分钟`; + } + return `约每 ${minutes} 分 ${remaining} 秒`; +} + +function parseRate(value) { + const numeric = Number(value); + if (Number.isFinite(numeric) && numeric >= 0) { + return { + text: numeric.toFixed(4).replace(/0+$/, "").replace(/\.$/, ""), + ratio: Math.max(0, Math.min(numeric, 100)) + }; + } + return { text: "--", ratio: 0 }; +} + +function formatUpdateTime(data) { + if (data && typeof data.updated === "string" && data.updated.trim().length > 0) { + return data.updated.trim(); + } + if (data && typeof data.updated_at === "number" && Number.isFinite(data.updated_at)) { + return new Date(data.updated_at).toLocaleString("zh-CN", { hour12: false }); + } + return new Date().toLocaleString("zh-CN", { hour12: false }); +} + +function renderInsights(list, gapSecond) { + const total = Array.isArray(list) ? list.length : 0; + programmeCountEl.textContent = total ? total.toString() : "--"; + + if (total) { + const topMarket = list.reduce((max, item) => { + const value = Number(item?.market_rate); + return value > max ? value : max; + }, 0); + const topAttention = list.reduce((max, item) => { + const value = Number(item?.attention_rate); + return value > max ? value : max; + }, 0); + + topMarketRateEl.textContent = topMarket ? topMarket.toFixed(2) : "--"; + topAttentionRateEl.textContent = topAttention ? topAttention.toFixed(2) : "--"; + } else { + topMarketRateEl.textContent = "--"; + topAttentionRateEl.textContent = "--"; + } + + refreshGapEl.textContent = formatGapText(gapSecond); +} + +function createMetric(label, value) { + return ` +
+ ${label} + ${safeText(value)} +
+ `; +} + +function createProgrammeItem(programme, index) { + const article = document.createElement("article"); + article.className = "programme-item"; + + const topClass = index < 3 ? ` top-${index + 1}` : ""; + const name = safeText(programme?.programme_name || "未命名节目"); + const channel = safeText(programme?.channel_name || "--"); + + const market = parseRate(programme?.market_rate); + const attention = parseRate(programme?.attention_rate); + const marketDesc = safeText(programme?.market_rate_desc || formatNumber(programme?.market_rate)); + const attentionDesc = safeText(programme?.attention_rate_desc || formatNumber(programme?.attention_rate)); + + article.innerHTML = ` +
${index + 1}
+
+
+
${name}
+
${channel}
+
+
+ ${createMetric("市场占有率", marketDesc)} + ${createMetric("关注指数", attentionDesc)} + ${createMetric("排序位置", `第 ${index + 1} 名`)} + ${createMetric("排名趋势", programme?.rank_trend ? safeText(programme.rank_trend) : "--")} +
+
+
+
+ 市场份额 + ${market.text === "--" ? "--" : `${market.text}%`} +
+
+
+
+
+ 关注份额 + ${attention.text === "--" ? "--" : `${attention.text}%`} +
+
+
+
+
+ `; + + return article; +} + +function renderProgrammeList(list) { + programmeListEl.innerHTML = ""; + + if (!Array.isArray(list) || list.length === 0) { + const empty = document.createElement("div"); + empty.className = "empty-message"; + empty.textContent = "暂时没有可展示的节目数据"; + programmeListEl.appendChild(empty); + return; + } + + list.slice(0, MAX_ITEMS).forEach((item, index) => { + programmeListEl.appendChild(createProgrammeItem(item, index)); + }); +} + +async function requestJson(url) { + const response = await fetch(url, { cache: "no-store" }); + if (!response.ok) { + throw new Error(`请求失败: ${response.status}`); + } + return response.json(); +} + +async function retrieveData() { + for (const endpoint of API_ENDPOINTS) { + try { + const result = await requestJson(endpoint); + if (result?.code === 200 && result?.data) { + return result.data; + } + } catch (error) { + console.warn("主接口请求失败", error); + } + } + + try { + const fallbackResult = await requestJson(FALLBACK_ENDPOINT); + if (fallbackResult?.data) { + return fallbackResult.data; + } + } catch (fallbackError) { + console.warn("本地示例数据读取失败", fallbackError); + } + + return null; +} + +async function loadData(isManual = false) { + if (isLoading) { + return; + } + + isLoading = true; + + if (isManual) { + refreshButton.disabled = true; + refreshButton.textContent = "刷新中..."; + } + + if (!programmeListEl.children.length) { + programmeListEl.innerHTML = '
正在载入电视收视排行...
'; + } + + try { + const data = await retrieveData(); + if (!data) { + throw new Error("无法获取数据"); + } + + renderProgrammeList(Array.isArray(data.list) ? data.list : []); + renderInsights(data.list, data.update_gap_second); + updateTimeEl.textContent = `最近更新 ${formatUpdateTime(data)}`; + } catch (error) { + console.error("加载数据失败", error); + programmeListEl.innerHTML = ''; + const errorBox = document.createElement("div"); + errorBox.className = "error-message"; + errorBox.textContent = "数据获取暂时不可用,系统稍后会自动重试"; + programmeListEl.appendChild(errorBox); + updateTimeEl.textContent = "最近更新 --"; + renderInsights([], 0); + } finally { + if (isManual) { + refreshButton.disabled = false; + refreshButton.textContent = "手动刷新"; + } + isLoading = false; + } +} + +function startAutoRefresh() { + if (autoTimer) { + clearInterval(autoTimer); + } + autoTimer = setInterval(() => { + loadData(false); + }, REFRESH_INTERVAL); +} + +refreshButton.addEventListener("click", () => { + loadData(true); +}); + +document.addEventListener("visibilitychange", () => { + if (document.hidden) { + if (autoTimer) { + clearInterval(autoTimer); + autoTimer = null; + } + } else { + startAutoRefresh(); + loadData(false); + } +}); + +function init() { + loadData(false); + startAutoRefresh(); +} + +if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", init); +} else { + init(); +} diff --git a/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电视收视排行/返回接口.json b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电视收视排行/返回接口.json new file mode 100644 index 00000000..509e4ae9 --- /dev/null +++ b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼电视收视排行/返回接口.json @@ -0,0 +1,435 @@ +{ + "code": 200, + "message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s,反馈群 595941841", + "data": { + "update_gap_second": 3, + "updated": "2025-09-26 16:22:45", + "updated_at": 1758874965018, + "list": [ + { + "programme_name": "六姊妹37", + "channel_name": "CCTV-1", + "market_rate": 16.1709, + "market_rate_desc": "16.1709%", + "attention_rate": 1.2816, + "attention_rate_desc": "1.2816%" + }, + { + "programme_name": "太行山上6", + "channel_name": "CCTV-4", + "market_rate": 8.2684, + "market_rate_desc": "8.2684%", + "attention_rate": 0.6553, + "attention_rate_desc": "0.6553%" + }, + { + "programme_name": "星推荐", + "channel_name": "CCTV-8", + "market_rate": 7.3725, + "market_rate_desc": "7.3725%", + "attention_rate": 0.5843, + "attention_rate_desc": "0.5843%" + }, + { + "programme_name": "炮兵司令朱瑞", + "channel_name": "CCTV-6", + "market_rate": 7.3315, + "market_rate_desc": "7.3315%", + "attention_rate": 0.5811, + "attention_rate_desc": "0.5811%" + }, + { + "programme_name": "新闻直播间", + "channel_name": "CCTV-13", + "market_rate": 4.4396, + "market_rate_desc": "4.4396%", + "attention_rate": 0.3519, + "attention_rate_desc": "0.3519%" + }, + { + "programme_name": "百姓剧场二:征服15", + "channel_name": "浙江卫视", + "market_rate": 4.3651, + "market_rate_desc": "4.3651%", + "attention_rate": 0.346, + "attention_rate_desc": "0.346%" + }, + { + "programme_name": "新相亲大会精华版", + "channel_name": "江苏卫视", + "market_rate": 4.0919, + "market_rate_desc": "4.0919%", + "attention_rate": 0.3243, + "attention_rate_desc": "0.3243%" + }, + { + "programme_name": "青春独播剧场:底线11", + "channel_name": "湖南卫视", + "market_rate": 3.9014, + "market_rate_desc": "3.9014%", + "attention_rate": 0.3092, + "attention_rate_desc": "0.3092%" + }, + { + "programme_name": "全景自然:黄石公园-飞翔的生命", + "channel_name": "CCTV-9", + "market_rate": 2.504, + "market_rate_desc": "2.504%", + "attention_rate": 0.1985, + "attention_rate_desc": "0.1985%" + }, + { + "programme_name": "运动一起赢", + "channel_name": "CCTV-5", + "market_rate": 2.0781, + "market_rate_desc": "2.0781%", + "attention_rate": 0.1647, + "attention_rate_desc": "0.1647%" + }, + { + "programme_name": "小日子19", + "channel_name": "东方卫视", + "market_rate": 1.9804, + "market_rate_desc": "1.9804%", + "attention_rate": 0.157, + "attention_rate_desc": "0.157%" + }, + { + "programme_name": "向幸福出发", + "channel_name": "CCTV-3", + "market_rate": 1.8832, + "market_rate_desc": "1.8832%", + "attention_rate": 0.1493, + "attention_rate_desc": "0.1493%" + }, + { + "programme_name": "浴血十四年16", + "channel_name": "CCTV-7", + "market_rate": 1.8485, + "market_rate_desc": "1.8485%", + "attention_rate": 0.1465, + "attention_rate_desc": "0.1465%" + }, + { + "programme_name": "正点财经", + "channel_name": "CCTV-2", + "market_rate": 1.7255, + "market_rate_desc": "1.7255%", + "attention_rate": 0.1368, + "attention_rate_desc": "0.1368%" + }, + { + "programme_name": "热播剧场:太行山上6", + "channel_name": "深圳卫视", + "market_rate": 1.6132, + "market_rate_desc": "1.6132%", + "attention_rate": 0.1279, + "attention_rate_desc": "0.1279%" + }, + { + "programme_name": "爱家剧场:父母爱情37", + "channel_name": "山东卫视", + "market_rate": 1.5558, + "market_rate_desc": "1.5558%", + "attention_rate": 0.1233, + "attention_rate_desc": "0.1233%" + }, + { + "programme_name": "刘家媳妇4", + "channel_name": "CCTV-17", + "market_rate": 1.3905, + "market_rate_desc": "1.3905%", + "attention_rate": 0.1102, + "attention_rate_desc": "0.1102%" + }, + { + "programme_name": "午茶剧场:归队8", + "channel_name": "北京卫视", + "market_rate": 1.1078, + "market_rate_desc": "1.1078%", + "attention_rate": 0.0878, + "attention_rate_desc": "0.0878%" + }, + { + "programme_name": "吉视剧场:武工队传奇46", + "channel_name": "吉林卫视", + "market_rate": 0.9407, + "market_rate_desc": "0.9407%", + "attention_rate": 0.0745, + "attention_rate_desc": "0.0745%" + }, + { + "programme_name": "情感剧场:朱元璋64", + "channel_name": "河北卫视", + "market_rate": 0.9211, + "market_rate_desc": "0.9211%", + "attention_rate": 0.073, + "attention_rate_desc": "0.073%" + }, + { + "programme_name": "下午剧场:战火青春3", + "channel_name": "广东卫视", + "market_rate": 0.9211, + "market_rate_desc": "0.9211%", + "attention_rate": 0.073, + "attention_rate_desc": "0.073%" + }, + { + "programme_name": "探索.发现-奥秘54", + "channel_name": "CCTV-10", + "market_rate": 0.822, + "market_rate_desc": "0.822%", + "attention_rate": 0.0652, + "attention_rate_desc": "0.0652%" + }, + { + "programme_name": "一线", + "channel_name": "CCTV-12", + "market_rate": 0.7949, + "market_rate_desc": "0.7949%", + "attention_rate": 0.063, + "attention_rate_desc": "0.063%" + }, + { + "programme_name": "海豚真情剧场:重案六组Ⅱ-45", + "channel_name": "安徽卫视", + "market_rate": 0.7684, + "market_rate_desc": "0.7684%", + "attention_rate": 0.0609, + "attention_rate_desc": "0.0609%" + }, + { + "programme_name": "中国女子围棋甲级联赛-第10轮", + "channel_name": "CCTV-5+", + "market_rate": 0.7621, + "market_rate_desc": "0.7621%", + "attention_rate": 0.0604, + "attention_rate_desc": "0.0604%" + }, + { + "programme_name": "休闲剧场:女子特战队2", + "channel_name": "天津卫视", + "market_rate": 0.6694, + "market_rate_desc": "0.6694%", + "attention_rate": 0.0531, + "attention_rate_desc": "0.0531%" + }, + { + "programme_name": "动画大放映:猪猪侠之超星五灵侠第八季", + "channel_name": "CCTV-14", + "market_rate": 0.6637, + "market_rate_desc": "0.6637%", + "attention_rate": 0.0526, + "attention_rate_desc": "0.0526%" + }, + { + "programme_name": "昆仑剧场:康熙微服私访记第三部30", + "channel_name": "青海卫视", + "market_rate": 0.6511, + "market_rate_desc": "0.6511%", + "attention_rate": 0.0516, + "attention_rate_desc": "0.0516%" + }, + { + "programme_name": "京剧电影工程-大闹天宫", + "channel_name": "CCTV-11", + "market_rate": 0.6069, + "market_rate_desc": "0.6069%", + "attention_rate": 0.0481, + "attention_rate_desc": "0.0481%" + }, + { + "programme_name": "温情剧场:神探狄仁杰Ⅱ-14", + "channel_name": "陕西卫视", + "market_rate": 0.571, + "market_rate_desc": "0.571%", + "attention_rate": 0.0453, + "attention_rate_desc": "0.0453%" + }, + { + "programme_name": "下午剧场:狙击部队30", + "channel_name": "贵州卫视", + "market_rate": 0.5558, + "market_rate_desc": "0.5558%", + "attention_rate": 0.0441, + "attention_rate_desc": "0.0441%" + }, + { + "programme_name": "白天剧场:西游记26", + "channel_name": "湖北卫视", + "market_rate": 0.5463, + "market_rate_desc": "0.5463%", + "attention_rate": 0.0433, + "attention_rate_desc": "0.0433%" + }, + { + "programme_name": "中国爱大剧场:神枪21", + "channel_name": "四川卫视", + "market_rate": 0.5388, + "market_rate_desc": "0.5388%", + "attention_rate": 0.0427, + "attention_rate_desc": "0.0427%" + }, + { + "programme_name": "全民开麦", + "channel_name": "CCTV-15", + "market_rate": 0.4915, + "market_rate_desc": "0.4915%", + "attention_rate": 0.039, + "attention_rate_desc": "0.039%" + }, + { + "programme_name": "下午剧场:仁心俱乐部10", + "channel_name": "东南卫视", + "market_rate": 0.4858, + "market_rate_desc": "0.4858%", + "attention_rate": 0.0385, + "attention_rate_desc": "0.0385%" + }, + { + "programme_name": "生活服务", + "channel_name": "江西卫视", + "market_rate": 0.4113, + "market_rate_desc": "0.4113%", + "attention_rate": 0.0326, + "attention_rate_desc": "0.0326%" + }, + { + "programme_name": "白天剧场:神医喜来乐25", + "channel_name": "宁夏卫视", + "market_rate": 0.4044, + "market_rate_desc": "0.4044%", + "attention_rate": 0.032, + "attention_rate_desc": "0.032%" + }, + { + "programme_name": "传奇剧场:铁血玫瑰15", + "channel_name": "黑龙江卫视", + "market_rate": 0.4031, + "market_rate_desc": "0.4031%", + "attention_rate": 0.032, + "attention_rate_desc": "0.032%" + }, + { + "programme_name": "经典剧场:亮剑30", + "channel_name": "广西卫视", + "market_rate": 0.3836, + "market_rate_desc": "0.3836%", + "attention_rate": 0.0304, + "attention_rate_desc": "0.0304%" + }, + { + "programme_name": "中国网球公开赛-女单-第二轮", + "channel_name": "CCTV-16", + "market_rate": 0.3539, + "market_rate_desc": "0.3539%", + "attention_rate": 0.0281, + "attention_rate_desc": "0.0281%" + }, + { + "programme_name": "生活服务", + "channel_name": "河南卫视", + "market_rate": 0.3413, + "market_rate_desc": "0.3413%", + "attention_rate": 0.0271, + "attention_rate_desc": "0.0271%" + }, + { + "programme_name": "生活服务", + "channel_name": "辽宁卫视", + "market_rate": 0.3318, + "market_rate_desc": "0.3318%", + "attention_rate": 0.0263, + "attention_rate_desc": "0.0263%" + }, + { + "programme_name": "传奇剧场:狼烟21", + "channel_name": "内蒙古卫视", + "market_rate": 0.3262, + "market_rate_desc": "0.3262%", + "attention_rate": 0.0258, + "attention_rate_desc": "0.0258%" + }, + { + "programme_name": "炫酷剧场:薛平贵与王宝钏19", + "channel_name": "云南卫视", + "market_rate": 0.3079, + "market_rate_desc": "0.3079%", + "attention_rate": 0.0244, + "attention_rate_desc": "0.0244%" + }, + { + "programme_name": "休闲剧场:历史转折中的邓小平17", + "channel_name": "兵团卫视", + "market_rate": 0.3035, + "market_rate_desc": "0.3035%", + "attention_rate": 0.0241, + "attention_rate_desc": "0.0241%" + }, + { + "programme_name": "亮剑12", + "channel_name": "重庆卫视", + "market_rate": 0.2656, + "market_rate_desc": "0.2656%", + "attention_rate": 0.0211, + "attention_rate_desc": "0.0211%" + }, + { + "programme_name": "阳光剧场:飞哥大英雄39", + "channel_name": "海南卫视", + "market_rate": 0.2643, + "market_rate_desc": "0.2643%", + "attention_rate": 0.021, + "attention_rate_desc": "0.021%" + }, + { + "programme_name": "劫中劫15-17", + "channel_name": "厦门卫视", + "market_rate": 0.246, + "market_rate_desc": "0.246%", + "attention_rate": 0.0195, + "attention_rate_desc": "0.0195%" + }, + { + "programme_name": "生活服务", + "channel_name": "甘肃卫视", + "market_rate": 0.2448, + "market_rate_desc": "0.2448%", + "attention_rate": 0.0194, + "attention_rate_desc": "0.0194%" + }, + { + "programme_name": "花季剧场:神枪7", + "channel_name": "中国教育台-1", + "market_rate": 0.1703, + "market_rate_desc": "0.1703%", + "attention_rate": 0.0135, + "attention_rate_desc": "0.0135%" + }, + { + "programme_name": "雪莲剧场:南来北往21", + "channel_name": "西藏卫视", + "market_rate": 0.1634, + "market_rate_desc": "0.1634%", + "attention_rate": 0.013, + "attention_rate_desc": "0.013%" + }, + { + "programme_name": "生活服务", + "channel_name": "山西卫视", + "market_rate": 0.1438, + "market_rate_desc": "0.1438%", + "attention_rate": 0.0114, + "attention_rate_desc": "0.0114%" + }, + { + "programme_name": "生活服务", + "channel_name": "新疆卫视", + "market_rate": 0.0656, + "market_rate_desc": "0.0656%", + "attention_rate": 0.0052, + "attention_rate_desc": "0.0052%" + } + ] + } +} \ No newline at end of file diff --git a/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼票房排行榜/css/style.css b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼票房排行榜/css/style.css index 7f70c9a0..c6e8a215 100755 --- a/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼票房排行榜/css/style.css +++ b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼票房排行榜/css/style.css @@ -52,7 +52,7 @@ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif; line-height: 1.6; color: var(--text-primary); - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + background: linear-gradient(135deg, #a8e6cf 0%, #dcedc1 50%, #ffd3a5 100%); min-height: 100vh; position: relative; overflow-x: hidden; @@ -67,11 +67,11 @@ body::before { width: 100%; height: 100%; background: - radial-gradient(circle at 20% 80%, rgba(120, 119, 198, 0.3) 0%, transparent 50%), - radial-gradient(circle at 80% 20%, rgba(255, 119, 198, 0.3) 0%, transparent 50%), - radial-gradient(circle at 40% 40%, rgba(120, 219, 255, 0.2) 0%, transparent 50%); + radial-gradient(circle at 20% 80%, rgba(168, 230, 207, 0.15) 0%, transparent 40%), + radial-gradient(circle at 80% 20%, rgba(220, 237, 193, 0.12) 0%, transparent 40%), + radial-gradient(circle at 40% 40%, rgba(255, 211, 165, 0.1) 0%, transparent 40%); z-index: -1; - animation: backgroundShift 20s ease-in-out infinite; + animation: backgroundShift 30s ease-in-out infinite; } @keyframes backgroundShift { @@ -90,11 +90,11 @@ body::before { max-width: 900px; margin: var(--space-lg) auto; padding: var(--space-xl); - background: rgba(255, 255, 255, 0.95); - backdrop-filter: blur(20px); + background: rgba(255, 255, 255, 0.92); + backdrop-filter: blur(15px); border-radius: var(--radius-xl); - box-shadow: var(--shadow-xl); - border: 1px solid rgba(255, 255, 255, 0.2); + box-shadow: 0 8px 32px rgba(76, 175, 80, 0.15); + border: 1px solid rgba(168, 230, 207, 0.3); position: relative; animation: slideUp 0.8s ease-out; } @@ -127,7 +127,7 @@ body::before { transform: translateX(-50%); width: 60px; height: 4px; - background: linear-gradient(90deg, var(--primary-color), var(--secondary-color)); + background: linear-gradient(90deg, #4caf50, #81c784); border-radius: 2px; } @@ -162,7 +162,7 @@ body::before { } .header h1 .title-text { - background: linear-gradient(135deg, var(--primary-color), var(--primary-light)); + background: linear-gradient(135deg, #2e7d32, #4caf50); -webkit-background-clip: text; background-clip: text; color: transparent; @@ -171,12 +171,12 @@ body::before { .header h1 .update-badge { font-size: 0.4em; - background: linear-gradient(135deg, var(--accent-color), var(--secondary-color)); + background: linear-gradient(135deg, #66bb6a, #a5d6a7); color: white; padding: var(--space-xs) var(--space-md); border-radius: var(--radius-xl); font-weight: 600; - box-shadow: var(--shadow-md); + box-shadow: 0 4px 6px rgba(76, 175, 80, 0.3); animation: pulse 3s infinite; white-space: nowrap; } @@ -210,8 +210,8 @@ body::before { width: 40px; height: 40px; margin: 0 auto var(--space-md); - border: 3px solid var(--bg-tertiary); - border-top: 3px solid var(--primary-color); + border: 3px solid rgba(76, 175, 80, 0.2); + border-top: 3px solid #4caf50; border-radius: 50%; animation: spin 1s linear infinite; } @@ -274,15 +274,15 @@ body::before { left: 0; width: 100%; height: 100%; - background: linear-gradient(135deg, transparent 0%, rgba(102, 126, 234, 0.02) 100%); + background: linear-gradient(135deg, transparent 0%, rgba(76, 175, 80, 0.03) 100%); opacity: 0; transition: opacity 0.3s ease; } .movie-item:hover { transform: translateY(-4px); - box-shadow: var(--shadow-lg); - border-color: rgba(102, 126, 234, 0.2); + box-shadow: 0 10px 25px rgba(76, 175, 80, 0.15); + border-color: rgba(76, 175, 80, 0.3); } .movie-item:hover::before { @@ -291,18 +291,18 @@ body::before { /* 特殊排名样式 */ .movie-item.top-1 { - background: linear-gradient(135deg, rgba(255, 215, 0, 0.1) 0%, var(--bg-primary) 100%); - border-color: rgba(255, 215, 0, 0.3); + background: linear-gradient(135deg, rgba(76, 175, 80, 0.08) 0%, var(--bg-primary) 100%); + border-color: rgba(76, 175, 80, 0.4); } .movie-item.top-2 { - background: linear-gradient(135deg, rgba(192, 192, 192, 0.1) 0%, var(--bg-primary) 100%); - border-color: rgba(192, 192, 192, 0.3); + background: linear-gradient(135deg, rgba(129, 199, 132, 0.06) 0%, var(--bg-primary) 100%); + border-color: rgba(129, 199, 132, 0.3); } .movie-item.top-3 { - background: linear-gradient(135deg, rgba(205, 127, 50, 0.1) 0%, var(--bg-primary) 100%); - border-color: rgba(205, 127, 50, 0.3); + background: linear-gradient(135deg, rgba(165, 214, 167, 0.05) 0%, var(--bg-primary) 100%); + border-color: rgba(165, 214, 167, 0.3); } /* 排名徽章 */ @@ -325,27 +325,27 @@ body::before { } .movie-rank.gold { - background: linear-gradient(135deg, #ffd700, #ffb700); + background: linear-gradient(135deg, #2e7d32, #4caf50); color: white; - box-shadow: 0 4px 15px rgba(255, 215, 0, 0.4); + box-shadow: 0 4px 15px rgba(46, 125, 50, 0.4); } .movie-rank.silver { - background: linear-gradient(135deg, #c0c0c0, #a0a0a0); + background: linear-gradient(135deg, #388e3c, #66bb6a); color: white; - box-shadow: 0 4px 15px rgba(192, 192, 192, 0.4); + box-shadow: 0 4px 15px rgba(56, 142, 60, 0.4); } .movie-rank.bronze { - background: linear-gradient(135deg, #cd7f32, #b06728); + background: linear-gradient(135deg, #4caf50, #81c784); color: white; - box-shadow: 0 4px 15px rgba(205, 127, 50, 0.4); + box-shadow: 0 4px 15px rgba(76, 175, 80, 0.4); } .movie-rank.regular { - background: linear-gradient(135deg, var(--primary-color), var(--accent-color)); + background: linear-gradient(135deg, #66bb6a, #a5d6a7); color: white; - box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3); + box-shadow: 0 4px 15px rgba(102, 187, 106, 0.3); } /* 电影内容 */ diff --git a/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼网剧实时热度/css/background.css b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼网剧实时热度/css/background.css new file mode 100644 index 00000000..d0f81de8 --- /dev/null +++ b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼网剧实时热度/css/background.css @@ -0,0 +1,76 @@ +.background-canvas { + position: fixed; + inset: 0; + z-index: -1; + overflow: hidden; + background: linear-gradient(180deg, #f4fff6 0%, #e7f8eb 45%, #def1e4 100%); +} + +.glow { + position: absolute; + width: 420px; + height: 420px; + border-radius: 55% 45% 60% 40% / 48% 52% 45% 55%; + opacity: 0.25; + filter: blur(0px); + background: radial-gradient(circle at 35% 35%, rgba(140, 214, 167, 0.65), rgba(140, 214, 167, 0)); + animation: floaty 32s ease-in-out infinite; +} + +.glow-1 { + top: -140px; + left: -160px; + animation-delay: 0s; +} + +.glow-2 { + top: 55%; + left: 60%; + animation-delay: 8s; + background: radial-gradient(circle at 60% 60%, rgba(120, 192, 152, 0.55), rgba(120, 192, 152, 0)); +} + +.glow-3 { + bottom: -160px; + right: -120px; + animation-delay: 16s; + background: radial-gradient(circle at 40% 40%, rgba(176, 229, 197, 0.6), rgba(176, 229, 197, 0)); +} + +@keyframes floaty { + 0% { + transform: translate3d(0, 0, 0) scale(1); + } + 30% { + transform: translate3d(35px, -25px, 0) scale(1.05); + } + 60% { + transform: translate3d(-30px, 30px, 0) scale(0.95); + } + 100% { + transform: translate3d(0, 0, 0) scale(1); + } +} + +@media (max-width: 768px) { + .glow { + width: 260px; + height: 260px; + opacity: 0.22; + } + + .glow-1 { + top: -110px; + left: -140px; + } + + .glow-2 { + top: 48%; + left: 38%; + } + + .glow-3 { + bottom: -140px; + right: -120px; + } +} diff --git a/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼网剧实时热度/css/style.css b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼网剧实时热度/css/style.css new file mode 100644 index 00000000..295f26e9 --- /dev/null +++ b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼网剧实时热度/css/style.css @@ -0,0 +1,393 @@ +:root { + --surface-base: rgba(255, 255, 255, 0.85); + --surface-soft: rgba(248, 253, 249, 0.9); + --border-soft: rgba(120, 192, 152, 0.22); + --accent-strong: #4caf7a; + --accent-soft: #8fd5a4; + --accent-pale: #c6efd5; + --text-primary: #134a32; + --text-muted: #528169; + --chip-bg: rgba(140, 214, 167, 0.18); + --shadow-soft: 0 16px 40px rgba(31, 74, 53, 0.14); + color-scheme: light; +} + +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body { + font-family: "PingFang SC", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif; + color: var(--text-primary); + background: transparent; + line-height: 1.6; + min-height: 100vh; + -webkit-font-smoothing: antialiased; +} + +.app { + width: min(100%, 930px); + margin: 0 auto; + padding: 20px 16px 80px; + display: flex; + flex-direction: column; + gap: 18px; +} + +.hero { + display: flex; + flex-direction: column; + gap: 18px; + background: var(--surface-base); + border: 1px solid var(--border-soft); + border-radius: 22px; + padding: 22px 18px; + box-shadow: var(--shadow-soft); + backdrop-filter: blur(16px); +} + +.hero-text { + display: flex; + flex-direction: column; + gap: 10px; +} + +.badge { + align-self: flex-start; + padding: 4px 12px; + font-size: 0.82rem; + letter-spacing: 0.08em; + border-radius: 999px; + background: var(--chip-bg); + color: var(--accent-strong); +} + +.hero h1 { + font-size: 1.65rem; + font-weight: 700; +} + +.subtitle { + color: var(--text-muted); + font-size: 0.96rem; +} + +.hero-actions { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 10px; +} + +.refresh { + padding: 10px 20px; + border-radius: 999px; + border: none; + background: linear-gradient(135deg, #66bb86, #4caf7a); + color: #ffffff; + font-size: 0.95rem; + font-weight: 600; + cursor: pointer; + box-shadow: 0 12px 30px rgba(76, 175, 122, 0.36); + transition: transform 0.2s ease, box-shadow 0.2s ease; +} + +.refresh:active { + transform: scale(0.97); +} + +.refresh:disabled { + opacity: 0.65; + cursor: not-allowed; +} + +.update-time { + font-size: 0.85rem; + color: var(--text-muted); +} + +.quick-stats { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 12px; +} + +.stat-card { + background: var(--surface-soft); + border-radius: 18px; + border: 1px solid rgba(143, 213, 164, 0.24); + padding: 16px 18px; + box-shadow: var(--shadow-soft); + display: flex; + flex-direction: column; + gap: 6px; +} + +.stat-label { + font-size: 0.84rem; + color: var(--text-muted); + letter-spacing: 0.04em; +} + +.stat-value { + font-size: 1.35rem; + font-weight: 700; + color: var(--accent-strong); + display: flex; + align-items: baseline; + gap: 4px; +} + +.stat-value .unit { + font-size: 0.9rem; + font-weight: 500; + color: var(--text-muted); +} + +.list-section { + background: var(--surface-base); + border: 1px solid var(--border-soft); + border-radius: 24px; + padding: 24px 18px 28px; + box-shadow: var(--shadow-soft); + display: flex; + flex-direction: column; + gap: 18px; +} + +.list-header { + display: flex; + flex-direction: column; + gap: 6px; +} + +.list-header h2 { + font-size: 1.28rem; + font-weight: 700; +} + +.list-tag { + font-size: 0.88rem; + color: var(--text-muted); +} + +.series-list { + display: flex; + flex-direction: column; + gap: 14px; +} + +.loading, +.error-message, +.empty-message { + padding: 18px 16px; + text-align: center; + color: var(--text-muted); + background: rgba(255, 255, 255, 0.75); + border-radius: 14px; + border: 1px dashed rgba(120, 192, 152, 0.32); +} + +.series-item { + display: grid; + grid-template-columns: auto 1fr; + gap: 14px; + background: rgba(255, 255, 255, 0.92); + border-radius: 20px; + border: 1px solid rgba(120, 192, 152, 0.2); + padding: 16px; + box-shadow: 0 14px 32px rgba(31, 74, 53, 0.12); + transition: transform 0.2s ease, box-shadow 0.2s ease; +} + +.series-item:hover { + transform: translateY(-2px); + box-shadow: 0 18px 40px rgba(31, 74, 53, 0.16); +} + +.rank-pill { + width: 44px; + height: 44px; + border-radius: 14px; + display: flex; + align-items: center; + justify-content: center; + font-weight: 700; + font-size: 1.05rem; + color: #ffffff; + background: linear-gradient(135deg, #7ed49b, #5cc88a); +} + +.rank-pill.top-1 { + background: linear-gradient(135deg, #5cc88a, #3da36b); +} + +.rank-pill.top-2 { + background: linear-gradient(135deg, #72d0a0, #55be85); +} + +.rank-pill.top-3 { + background: linear-gradient(135deg, #8fe0b4, #6fd09a); +} + +.series-body { + display: flex; + flex-direction: column; + gap: 12px; +} + +.series-head { + display: flex; + flex-direction: column; + gap: 6px; +} + +.series-name { + font-size: 1.05rem; + font-weight: 700; + color: var(--text-primary); +} + +.series-meta { + font-size: 0.9rem; + color: var(--text-muted); +} + +.metric-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 10px 14px; +} + +.metric { + display: flex; + flex-direction: column; + gap: 2px; +} + +.metric-label { + font-size: 0.78rem; + color: var(--text-muted); + letter-spacing: 0.04em; +} + +.metric-value { + font-size: 0.98rem; + font-weight: 600; + color: var(--accent-strong); +} + +.progress-wrap { + display: flex; + flex-direction: column; + gap: 6px; + margin-top: 6px; +} + +.progress-row { + display: flex; + flex-direction: column; + gap: 4px; +} + +.progress-label { + display: flex; + justify-content: space-between; + font-size: 0.8rem; + color: var(--text-muted); +} + +.progress-bar { + width: 100%; + height: 6px; + border-radius: 6px; + background: rgba(120, 192, 152, 0.18); + overflow: hidden; +} + +.progress-bar span { + display: block; + height: 100%; + border-radius: inherit; + background: linear-gradient(135deg, rgba(120, 192, 152, 0.9), rgba(76, 175, 122, 0.95)); + width: 0; + transition: width 0.45s ease; +} + +/* Tablet */ +@media (min-width: 600px) { + .app { + padding: 26px 20px 96px; + gap: 22px; + } + + .hero { + flex-direction: row; + justify-content: space-between; + align-items: center; + padding: 26px 28px; + } + + .hero h1 { + font-size: 1.9rem; + } + + .hero-actions { + align-items: flex-end; + } + + .quick-stats { + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 16px; + } + + .series-item { + grid-template-columns: 70px 1fr; + padding: 18px 22px; + } + + .rank-pill { + width: 54px; + height: 54px; + font-size: 1.2rem; + } + + .metric-grid { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } +} + +/* Desktop */ +@media (min-width: 1024px) { + .app { + padding: 34px 24px 110px; + } + + .list-section { + padding: 30px 32px 36px; + } + + .series-item { + grid-template-columns: 96px 1fr; + padding: 22px 26px; + } + + .series-name { + font-size: 1.22rem; + } + + .metric-grid { + grid-template-columns: repeat(4, minmax(0, 1fr)); + } +} + +@media (prefers-reduced-motion: reduce) { + * { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; + } +} diff --git a/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼网剧实时热度/index.html b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼网剧实时热度/index.html new file mode 100644 index 00000000..83480eae --- /dev/null +++ b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼网剧实时热度/index.html @@ -0,0 +1,62 @@ + + + + + + 猫眼网剧实时热度 + + + + +
+
+
+
+
+ +
+
+
+ 实时热度 +

猫眼网剧实时热度

+

网剧热度榜单即时更新,洞察全网追剧风向

+
+
+ + 正在获取最新数据... +
+
+ +
+
+

上榜剧集

+

--

+
+
+

最高热度值

+

--热度

+
+
+

平均热度值

+

--热度

+
+
+

官方刷新频率

+

--

+
+
+ +
+
+

网剧热度排行

+ 数据持续刷新 +
+
+
正在载入网剧热度...
+
+
+
+ + + + diff --git a/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼网剧实时热度/js/main.js b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼网剧实时热度/js/main.js new file mode 100644 index 00000000..67b44e88 --- /dev/null +++ b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼网剧实时热度/js/main.js @@ -0,0 +1,293 @@ +const API_ENDPOINTS = [ + "https://60s.api.shumengya.top/v2/maoyan/realtime/web" +]; + +const FALLBACK_ENDPOINT = "./返回接口.json"; +const REFRESH_INTERVAL = 4500; +const MAX_ITEMS = 40; + +const refreshButton = document.getElementById("refreshButton"); +const updateTimeEl = document.getElementById("updateTime"); +const seriesListEl = document.getElementById("seriesList"); +const seriesCountEl = document.getElementById("seriesCount"); +const topHeatEl = document.getElementById("topHeat"); +const avgHeatEl = document.getElementById("avgHeat"); +const refreshGapEl = document.getElementById("refreshGap"); + +let isLoading = false; +let autoTimer = null; + +function escapeHtml(value) { + if (value === undefined || value === null) { + return ""; + } + return String(value) + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); +} + +function safeText(value, fallback = "--") { + if (value === undefined || value === null || value === "") { + return fallback; + } + return escapeHtml(value); +} + +function formatNumber(value, fractionDigits = 2) { + const numeric = Number(value); + if (!Number.isFinite(numeric)) { + return "--"; + } + return numeric.toFixed(fractionDigits); +} + +function formatGap(seconds) { + const numeric = Number(seconds); + if (!Number.isFinite(numeric) || numeric <= 0) { + return "--"; + } + + if (numeric < 60) { + return `约每 ${Math.round(numeric)} 秒`; + } + + const minutes = Math.floor(numeric / 60); + const remainder = Math.round(numeric % 60); + if (remainder === 0) { + return `约每 ${minutes} 分钟`; + } + return `约每 ${minutes} 分 ${remainder} 秒`; +} + +function formatUpdateTime(data) { + if (data && typeof data.updated === "string" && data.updated.trim()) { + return data.updated.trim(); + } + if (data && typeof data.updated_at === "number" && Number.isFinite(data.updated_at)) { + return new Date(data.updated_at).toLocaleString("zh-CN", { hour12: false }); + } + return new Date().toLocaleString("zh-CN", { hour12: false }); +} + +function renderStats(list, gapSeconds) { + const total = Array.isArray(list) ? list.length : 0; + seriesCountEl.textContent = total ? total.toString() : "--"; + + if (total) { + let maxHeat = 0; + let sumHeat = 0; + list.forEach(item => { + const heat = Number(item?.curr_heat); + if (Number.isFinite(heat)) { + if (heat > maxHeat) { + maxHeat = heat; + } + sumHeat += heat; + } + }); + + topHeatEl.textContent = maxHeat ? maxHeat.toFixed(2) : "--"; + const average = sumHeat && total ? (sumHeat / total) : 0; + avgHeatEl.textContent = average ? average.toFixed(2) : "--"; + } else { + topHeatEl.textContent = "--"; + avgHeatEl.textContent = "--"; + } + + refreshGapEl.textContent = formatGap(gapSeconds); +} + +function createMetric(label, value) { + return ` +
+ ${label} + ${safeText(value)} +
+ `; +} + +function normalizeBarValue(list) { + let maxValue = 0; + if (Array.isArray(list)) { + list.forEach(item => { + const bar = Number(item?.bar_value ?? item?.curr_heat); + if (Number.isFinite(bar) && bar > maxValue) { + maxValue = bar; + } + }); + } + return maxValue || 1; +} + +function createSeriesItem(series, index, maxBar) { + const article = document.createElement("article"); + article.className = "series-item"; + + const rankClass = index < 3 ? ` top-${index + 1}` : ""; + const name = safeText(series?.series_name || "未命名剧集"); + const releaseInfo = safeText(series?.release_info || "--"); + const platform = safeText(series?.platform_desc || "--"); + const heatDesc = safeText(series?.curr_heat_desc || formatNumber(series?.curr_heat)); + + const barValue = Number(series?.bar_value ?? series?.curr_heat); + const ratio = Number.isFinite(barValue) && maxBar > 0 ? Math.min(100, Math.max(0, (barValue / maxBar) * 100)) : 0; + + article.innerHTML = ` +
${index + 1}
+
+
+
${name}
+
${releaseInfo} · ${platform}
+
+
+ ${createMetric("实时热度", heatDesc)} + ${createMetric("上线信息", releaseInfo)} + ${createMetric("播出平台", platform)} + ${createMetric("剧集ID", safeText(series?.series_id))} +
+
+
+
+ 热度走势 + ${heatDesc} +
+
+
+
+
+ `; + + return article; +} + +function renderSeriesList(list) { + seriesListEl.innerHTML = ""; + + if (!Array.isArray(list) || list.length === 0) { + const empty = document.createElement("div"); + empty.className = "empty-message"; + empty.textContent = "暂时没有可展示的剧集数据"; + seriesListEl.appendChild(empty); + return; + } + + const maxBar = normalizeBarValue(list); + list.slice(0, MAX_ITEMS).forEach((series, index) => { + seriesListEl.appendChild(createSeriesItem(series, index, maxBar)); + }); +} + +async function requestJson(url) { + const response = await fetch(url, { cache: "no-store" }); + if (!response.ok) { + throw new Error(`请求失败: ${response.status}`); + } + return response.json(); +} + +async function retrieveData() { + for (const endpoint of API_ENDPOINTS) { + try { + const result = await requestJson(endpoint); + if (result?.code === 200 && result?.data) { + return result.data; + } + } catch (error) { + console.warn("主接口请求失败", error); + } + } + + try { + const fallbackResult = await requestJson(FALLBACK_ENDPOINT); + if (fallbackResult?.data) { + return fallbackResult.data; + } + } catch (fallbackError) { + console.warn("本地示例数据读取失败", fallbackError); + } + + return null; +} + +async function loadData(isManual = false) { + if (isLoading) { + return; + } + + isLoading = true; + + if (isManual) { + refreshButton.disabled = true; + refreshButton.textContent = "刷新中..."; + } + + if (!seriesListEl.children.length) { + seriesListEl.innerHTML = '
正在载入网剧热度...
'; + } + + try { + const data = await retrieveData(); + if (!data) { + throw new Error("无法获取数据"); + } + + const list = Array.isArray(data.list) ? data.list : []; + renderSeriesList(list); + renderStats(list, data.update_gap_second); + updateTimeEl.textContent = `最近更新 ${formatUpdateTime(data)}`; + } catch (error) { + console.error("加载数据失败", error); + seriesListEl.innerHTML = ""; + const errBox = document.createElement("div"); + errBox.className = "error-message"; + errBox.textContent = "数据获取暂时不可用,系统稍后会自动重试"; + seriesListEl.appendChild(errBox); + updateTimeEl.textContent = "最近更新 --"; + renderStats([], 0); + } finally { + if (isManual) { + refreshButton.disabled = false; + refreshButton.textContent = "手动刷新"; + } + isLoading = false; + } +} + +function startAutoRefresh() { + if (autoTimer) { + clearInterval(autoTimer); + } + autoTimer = setInterval(() => { + loadData(false); + }, REFRESH_INTERVAL); +} + +refreshButton.addEventListener("click", () => { + loadData(true); +}); + +document.addEventListener("visibilitychange", () => { + if (document.hidden) { + if (autoTimer) { + clearInterval(autoTimer); + autoTimer = null; + } + } else { + startAutoRefresh(); + loadData(false); + } +}); + +function init() { + loadData(false); + startAutoRefresh(); +} + +if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", init); +} else { + init(); +} diff --git a/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼网剧实时热度/返回接口.json b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼网剧实时热度/返回接口.json new file mode 100644 index 00000000..7afcbc25 --- /dev/null +++ b/InfoGenie-frontend/public/60sapi/热搜榜单/猫眼网剧实时热度/返回接口.json @@ -0,0 +1,311 @@ +{ + "code": 200, + "message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s,反馈群 595941841", + "data": { + "update_gap_second": 3, + "updated": "2025-09-26 16:36:56", + "updated_at": 1758875816062, + "list": [ + { + "series_id": 1517707, + "series_name": "赴山海", + "release_info": "上线16天", + "platform_desc": "多平台播放", + "platform_txt": -1, + "curr_heat": 6290.29, + "curr_heat_desc": "6290.29", + "bar_value": 6290.29 + }, + { + "series_id": 1528168, + "series_name": "许我耀眼", + "release_info": "上线首日", + "platform_desc": "腾讯视频独播", + "platform_txt": -1, + "curr_heat": 6231.35, + "curr_heat_desc": "6231.35", + "bar_value": 5749.54721862606 + }, + { + "series_id": 1528151, + "series_name": "欢乐家长群2", + "release_info": "上线12天", + "platform_desc": "芒果TV独播", + "platform_txt": -1, + "curr_heat": 6012.95, + "curr_heat_desc": "6012.95", + "bar_value": 5119.06438712135 + }, + { + "series_id": 1492955, + "series_name": "吴邪私家笔记", + "release_info": "上线7天", + "platform_desc": "腾讯视频独播", + "platform_txt": -1, + "curr_heat": 5851.91, + "curr_heat_desc": "5851.91", + "bar_value": 4596.76326056356 + }, + { + "series_id": 1538034, + "series_name": "不眠日", + "release_info": "上线10天", + "platform_desc": "多平台播放", + "platform_txt": -1, + "curr_heat": 5804.09, + "curr_heat_desc": "5804.09", + "bar_value": 4206.68639815508 + }, + { + "series_id": 1501684, + "series_name": "灼灼韶华", + "release_info": "上线16天", + "platform_desc": "优酷独播", + "platform_txt": 0, + "curr_heat": 5799.01, + "curr_heat_desc": "5799.01", + "bar_value": 3878.03171596132 + }, + { + "series_id": 1474248, + "series_name": "围猎", + "release_info": "上线2天", + "platform_desc": "多平台播放", + "platform_txt": -1, + "curr_heat": 5752.05, + "curr_heat_desc": "5752.05", + "bar_value": 3549.20963005863 + }, + { + "series_id": 1501687, + "series_name": "守护者们", + "release_info": "上线4天", + "platform_desc": "多平台播放", + "platform_txt": -1, + "curr_heat": 5730.63, + "curr_heat_desc": "5730.63", + "bar_value": 3262.59275525736 + }, + { + "series_id": 1520710, + "series_name": "生万物", + "release_info": "上线45天", + "platform_desc": "爱奇艺独播", + "platform_txt": 1, + "curr_heat": 5475.27, + "curr_heat_desc": "5475.27", + "bar_value": 2876.18977832356 + }, + { + "series_id": 1520734, + "series_name": "芬芳喜事", + "release_info": "上线5天", + "platform_desc": "腾讯视频独播", + "platform_txt": -1, + "curr_heat": 5462.54, + "curr_heat_desc": "5462.54", + "bar_value": 2647.63508938203 + }, + { + "series_id": 1506349, + "series_name": "子夜归", + "release_info": "上线40天", + "platform_desc": "腾讯视频独播", + "platform_txt": -1, + "curr_heat": 5414.09, + "curr_heat_desc": "5414.09", + "bar_value": 2421.25465526037 + }, + { + "series_id": 1568466, + "series_name": "照镜辞", + "release_info": "上线8天", + "platform_desc": "哔哩哔哩独播", + "platform_txt": -1, + "curr_heat": 5405.94, + "curr_heat_desc": "5405.94", + "bar_value": 2230.68228745166 + }, + { + "series_id": 1501665, + "series_name": "足迹", + "release_info": "上线23天", + "platform_desc": "多平台播放", + "platform_txt": -1, + "curr_heat": 5345.55, + "curr_heat_desc": "5345.55", + "bar_value": 2035.21546242053 + }, + { + "series_id": 1481475, + "series_name": "与晋长安", + "release_info": "上线34天", + "platform_desc": "爱奇艺独播", + "platform_txt": 1, + "curr_heat": 5231.26, + "curr_heat_desc": "5231.26", + "bar_value": 1837.70502435479 + }, + { + "series_id": 1500426, + "series_name": "归队", + "release_info": "上线33天", + "platform_desc": "腾讯视频独播", + "platform_txt": -1, + "curr_heat": 5167.29, + "curr_heat_desc": "5167.29", + "bar_value": 1674.88052510491 + }, + { + "series_id": 1513970, + "series_name": "阵地", + "release_info": "上线11天", + "platform_desc": "多平台播放", + "platform_txt": -1, + "curr_heat": 5155.5, + "curr_heat_desc": "5155.50", + "bar_value": 1541.8541283172 + }, + { + "series_id": 1578416, + "series_name": "金式森林", + "release_info": "上线10天", + "platform_desc": "腾讯视频独播", + "platform_txt": -1, + "curr_heat": 5098.99, + "curr_heat_desc": "5098.99", + "bar_value": 1407.04554929882 + }, + { + "series_id": 1500365, + "series_name": "锦月如歌", + "release_info": "上线52天", + "platform_desc": "多平台播放", + "platform_txt": -1, + "curr_heat": 5082.9, + "curr_heat_desc": "5082.90", + "bar_value": 1294.15728646218 + }, + { + "series_id": 1481543, + "series_name": "凡人修仙传", + "release_info": "上线62天", + "platform_desc": "优酷独播", + "platform_txt": 0, + "curr_heat": 5064.74, + "curr_heat_desc": "5064.74", + "bar_value": 1189.82790916312 + }, + { + "series_id": 1521009, + "series_name": "十二封信", + "release_info": "上线29天", + "platform_desc": "腾讯视频独播", + "platform_txt": -1, + "curr_heat": 5029.58, + "curr_heat_desc": "5029.58", + "bar_value": 1090.21013799029 + }, + { + "series_id": 1492917, + "series_name": "献鱼", + "release_info": "上线42天", + "platform_desc": "优酷独播", + "platform_txt": 0, + "curr_heat": 5010.95, + "curr_heat_desc": "5010.95", + "bar_value": 1002.19 + }, + { + "series_id": 1444502, + "series_name": "利剑·玫瑰", + "release_info": "上线61天", + "platform_desc": "多平台播放", + "platform_txt": -1, + "curr_heat": 4972.54, + "curr_heat_desc": "4972.54", + "bar_value": 917.613471447017 + }, + { + "series_id": 1518217, + "series_name": "扫毒风暴", + "release_info": "上线77天", + "platform_desc": "腾讯视频独播", + "platform_txt": -1, + "curr_heat": 4896.37, + "curr_heat_desc": "4896.37", + "bar_value": 833.695051286619 + }, + { + "series_id": 1500364, + "series_name": "桃花映江山", + "release_info": "上线94天", + "platform_desc": "腾讯视频独播", + "platform_txt": -1, + "curr_heat": 4806.34, + "curr_heat_desc": "4806.34", + "bar_value": 755.090462080828 + }, + { + "series_id": 1505465, + "series_name": "定风波", + "release_info": "上线57天", + "platform_desc": "爱奇艺独播", + "platform_txt": 1, + "curr_heat": 4744.14, + "curr_heat_desc": "4744.14", + "bar_value": 687.69123872798 + }, + { + "series_id": 1531702, + "series_name": "书卷一梦", + "release_info": "上线93天", + "platform_desc": "爱奇艺独播", + "platform_txt": 1, + "curr_heat": 4733.39, + "curr_heat_desc": "4733.39", + "bar_value": 633.081734434469 + }, + { + "series_id": 1500328, + "series_name": "蓄意宠爱", + "release_info": "上线5天", + "platform_desc": "优酷独播", + "platform_txt": 0, + "curr_heat": 4730.18, + "curr_heat_desc": "4730.18", + "bar_value": 583.736247352187 + }, + { + "series_id": 1532221, + "series_name": "目之所及", + "release_info": "上线30天", + "platform_desc": "爱奇艺独播", + "platform_txt": 1, + "curr_heat": 4712.48, + "curr_heat_desc": "4712.48", + "bar_value": 536.586836256929 + }, + { + "series_id": 1524115, + "series_name": "白夜宸缘起三生", + "release_info": "上线13天", + "platform_desc": "腾讯视频独播", + "platform_txt": -1, + "curr_heat": 4653.77, + "curr_heat_desc": "4653.77", + "bar_value": 488.930252012005 + }, + { + "series_id": 1491942, + "series_name": "朝雪录", + "release_info": "上线76天", + "platform_desc": "爱奇艺独播", + "platform_txt": 1, + "curr_heat": 4623.3, + "curr_heat_desc": "4623.30", + "bar_value": 448.172875941959 + } + ] + } +} \ No newline at end of file diff --git a/InfoGenie-frontend/public/aimodelapp/AI文章转文言文/styles.css b/InfoGenie-frontend/public/aimodelapp/AI文章转文言文/styles.css index 8be6fdfe..d37a84cf 100755 --- a/InfoGenie-frontend/public/aimodelapp/AI文章转文言文/styles.css +++ b/InfoGenie-frontend/public/aimodelapp/AI文章转文言文/styles.css @@ -8,10 +8,10 @@ /* 主体样式 - iOS风格 */ body { font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Helvetica Neue', Arial, sans-serif; - background: linear-gradient(135deg, #8B4513 0%, #D2691E 50%, #F4A460 100%); + background: linear-gradient(135deg, #a8e6cf 0%, #dcedc8 50%, #f1f8e9 100%); min-height: 100vh; padding: 20px; - color: #1D1D1F; + color: #2e7d32; line-height: 1.47; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; @@ -24,9 +24,9 @@ body { background: rgba(255, 255, 255, 0.85); border-radius: 24px; padding: 32px; - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.08); + box-shadow: 0 8px 32px rgba(76, 175, 80, 0.15), 0 2px 8px rgba(76, 175, 80, 0.1); backdrop-filter: blur(20px) saturate(180%); - border: 1px solid rgba(255, 255, 255, 0.2); + border: 1px solid rgba(76, 175, 80, 0.2); } /* 头部样式 - iOS风格 */ @@ -37,14 +37,14 @@ body { .title { font-size: 2.25rem; - color: #8B4513; + color: #1b5e20; margin-bottom: 8px; font-weight: 600; letter-spacing: -0.02em; } .subtitle { - color: #D2691E; + color: #4caf50; font-size: 1.0625rem; margin-bottom: 24px; font-weight: 400; @@ -73,14 +73,14 @@ body { display: block; margin-bottom: 8px; font-weight: 600; - color: #1D1D1F; + color: #2e7d32; font-size: 1rem; } .form-input { width: 100%; padding: 16px; - border: 1px solid rgba(0, 0, 0, 0.1); + border: 1px solid rgba(76, 175, 80, 0.2); border-radius: 12px; font-size: 1rem; transition: all 0.2s ease; @@ -91,9 +91,9 @@ body { .form-input:focus { outline: none; - border-color: #D2691E; + border-color: #4caf50; background: rgba(255, 255, 255, 0.95); - box-shadow: 0 0 0 4px rgba(210, 105, 30, 0.1); + box-shadow: 0 0 0 4px rgba(76, 175, 80, 0.15); } .textarea { @@ -117,7 +117,7 @@ body { .btn { width: 100%; padding: 16px; - background: #D2691E; + background: linear-gradient(135deg, #4caf50 0%, #66bb6a 100%); color: white; border: none; border-radius: 12px; @@ -126,18 +126,18 @@ body { cursor: pointer; transition: all 0.2s ease; margin-bottom: 24px; - box-shadow: 0 2px 8px rgba(210, 105, 30, 0.25); + box-shadow: 0 2px 8px rgba(76, 175, 80, 0.3); } .btn:hover { - background: #B8860B; + background: linear-gradient(135deg, #388e3c 0%, #4caf50 100%); transform: translateY(-1px); - box-shadow: 0 4px 16px rgba(210, 105, 30, 0.35); + box-shadow: 0 4px 16px rgba(76, 175, 80, 0.4); } .btn:active { transform: translateY(0); - background: #A0522D; + background: linear-gradient(135deg, #2e7d32 0%, #388e3c 100%); } .btn:disabled { @@ -154,7 +154,7 @@ body { .result-title { font-size: 1.25rem; - color: #8B4513; + color: #1b5e20; margin-bottom: 16px; text-align: center; font-weight: 600; @@ -163,7 +163,7 @@ body { .loading { display: none; text-align: center; - color: #D2691E; + color: #4caf50; font-style: normal; padding: 24px; font-weight: 500; @@ -192,8 +192,8 @@ body { } .conversion-info { - background: rgba(139, 69, 19, 0.1); - border: 1px solid rgba(139, 69, 19, 0.2); + background: rgba(76, 175, 80, 0.1); + border: 1px solid rgba(76, 175, 80, 0.2); border-radius: 12px; padding: 16px; margin-bottom: 20px; @@ -210,11 +210,11 @@ body { .info-item .label { font-weight: 600; - color: #8B4513; + color: #1b5e20; } .info-item .value { - color: #1D1D1F; + color: #2e7d32; background: rgba(255, 255, 255, 0.8); padding: 4px 12px; border-radius: 8px; @@ -233,8 +233,8 @@ body { } .classical-text { - background: rgba(244, 164, 96, 0.1); - border: 1px solid rgba(244, 164, 96, 0.3); + background: rgba(129, 199, 132, 0.1); + border: 1px solid rgba(129, 199, 132, 0.3); } .text-header { @@ -246,13 +246,13 @@ body { .text-header .label { font-weight: 600; - color: #1D1D1F; + color: #2e7d32; font-size: 1rem; } .text-content { font-size: 1.125rem; - color: #1D1D1F; + color: #2e7d32; line-height: 1.8; font-weight: 400; } @@ -261,7 +261,7 @@ body { font-family: 'STKaiti', 'KaiTi', '楷体', serif; font-size: 1.25rem; line-height: 2; - color: #8B4513; + color: #1b5e20; font-weight: 500; } @@ -276,7 +276,7 @@ body { .transformations-title { font-weight: 600; - color: #1D1D1F; + color: #2e7d32; margin-bottom: 16px; font-size: 1rem; } @@ -286,7 +286,7 @@ body { align-items: flex-start; gap: 8px; padding: 8px 0; - border-bottom: 1px solid rgba(0, 0, 0, 0.05); + border-bottom: 1px solid rgba(76, 175, 80, 0.1); } .transformation-item:last-child { @@ -294,20 +294,20 @@ body { } .transformation-item .number { - color: #D2691E; + color: #4caf50; font-weight: 600; min-width: 20px; } .transformation-item .text { - color: #1D1D1F; + color: #2e7d32; line-height: 1.6; } /* 文言文特色分析 */ .classical-features { - background: rgba(210, 105, 30, 0.1); - border: 1px solid rgba(210, 105, 30, 0.2); + background: rgba(76, 175, 80, 0.1); + border: 1px solid rgba(76, 175, 80, 0.2); border-radius: 12px; padding: 20px; margin-bottom: 20px; @@ -315,7 +315,7 @@ body { .features-title { font-weight: 600; - color: #D2691E; + color: #4caf50; margin-bottom: 16px; font-size: 1rem; } @@ -333,20 +333,20 @@ body { .feature-label { font-weight: 600; - color: #8B4513; + color: #1b5e20; min-width: 80px; font-size: 0.9375rem; } .feature-text { - color: #1D1D1F; + color: #2e7d32; line-height: 1.6; flex: 1; } .explanation { - background: rgba(139, 69, 19, 0.1); - border: 1px solid rgba(139, 69, 19, 0.2); + background: rgba(76, 175, 80, 0.1); + border: 1px solid rgba(76, 175, 80, 0.2); border-radius: 12px; padding: 20px; margin-bottom: 20px; @@ -354,20 +354,20 @@ body { .explanation .label { font-weight: 600; - color: #8B4513; + color: #1b5e20; margin-bottom: 12px; display: block; } .explanation-text { - color: #1D1D1F; + color: #2e7d32; line-height: 1.6; font-size: 0.9375rem; } .pronunciation { - background: rgba(255, 149, 0, 0.1); - border: 1px solid rgba(255, 149, 0, 0.2); + background: rgba(129, 199, 132, 0.1); + border: 1px solid rgba(129, 199, 132, 0.2); border-radius: 12px; padding: 16px; margin-bottom: 16px; @@ -376,18 +376,18 @@ body { .pronunciation .label { font-weight: 600; - color: #FF9500; + color: #4caf50; margin-right: 8px; } .pronunciation .value { - color: #1D1D1F; + color: #2e7d32; font-family: 'SF Mono', 'Monaco', 'Consolas', 'Courier New', monospace; } /* 复制按钮样式 */ .copy-btn { - background: #D2691E; + background: #4caf50; color: white; border: none; border-radius: 8px; @@ -396,16 +396,16 @@ body { font-weight: 600; cursor: pointer; transition: all 0.2s ease; - box-shadow: 0 2px 4px rgba(210, 105, 30, 0.25); + box-shadow: 0 2px 4px rgba(76, 175, 80, 0.3); } .copy-btn:hover { - background: #B8860B; + background: #388e3c; transform: translateY(-1px); } .copy-btn-small { - background: #D2691E; + background: #4caf50; color: white; border: none; border-radius: 6px; @@ -414,11 +414,11 @@ body { font-weight: 600; cursor: pointer; transition: all 0.2s ease; - box-shadow: 0 1px 2px rgba(210, 105, 30, 0.25); + box-shadow: 0 1px 2px rgba(76, 175, 80, 0.3); } .copy-btn-small:hover { - background: #B8860B; + background: #388e3c; transform: translateY(-1px); } @@ -584,7 +584,7 @@ body { top: 15px; left: 15px; font-size: 1.5rem; - color: #D2691E; + color: #4caf50; opacity: 0.6; } @@ -594,7 +594,7 @@ body { bottom: 15px; right: 15px; font-size: 1.5rem; - color: #D2691E; + color: #4caf50; opacity: 0.6; } diff --git a/InfoGenie-frontend/public/aimodelapp/AI生成Linux命令/styles.css b/InfoGenie-frontend/public/aimodelapp/AI生成Linux命令/styles.css index 0761c4c5..a385d79a 100755 --- a/InfoGenie-frontend/public/aimodelapp/AI生成Linux命令/styles.css +++ b/InfoGenie-frontend/public/aimodelapp/AI生成Linux命令/styles.css @@ -8,10 +8,10 @@ /* 主体样式 - iOS风格 */ body { font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Helvetica Neue', Arial, sans-serif; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + background: linear-gradient(135deg, #a8e6cf 0%, #dcedc8 100%); min-height: 100vh; padding: 20px; - color: #1D1D1F; + color: #2e7d32; line-height: 1.47; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; @@ -24,9 +24,9 @@ body { background: rgba(255, 255, 255, 0.85); border-radius: 24px; padding: 32px; - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.08); + box-shadow: 0 8px 32px rgba(76, 175, 80, 0.15), 0 2px 8px rgba(76, 175, 80, 0.1); backdrop-filter: blur(20px) saturate(180%); - border: 1px solid rgba(255, 255, 255, 0.2); + border: 1px solid rgba(76, 175, 80, 0.2); } /* 头部样式 - iOS风格 */ @@ -37,14 +37,14 @@ body { .title { font-size: 2.25rem; - color: #1D1D1F; + color: #1b5e20; margin-bottom: 8px; font-weight: 600; letter-spacing: -0.02em; } .subtitle { - color: #86868B; + color: #4caf50; font-size: 1.0625rem; margin-bottom: 24px; font-weight: 400; @@ -63,14 +63,14 @@ body { display: block; margin-bottom: 8px; font-weight: 600; - color: #1D1D1F; + color: #2e7d32; font-size: 1rem; } .form-input { width: 100%; padding: 16px; - border: 1px solid rgba(0, 0, 0, 0.1); + border: 1px solid rgba(76, 175, 80, 0.2); border-radius: 12px; font-size: 1rem; transition: all 0.2s ease; @@ -81,9 +81,9 @@ body { .form-input:focus { outline: none; - border-color: #667eea; + border-color: #4caf50; background: rgba(255, 255, 255, 0.95); - box-shadow: 0 0 0 4px rgba(102, 126, 234, 0.1); + box-shadow: 0 0 0 4px rgba(76, 175, 80, 0.15); } .textarea { @@ -105,7 +105,7 @@ body { .btn { width: 100%; padding: 16px; - background: #667eea; + background: linear-gradient(135deg, #4caf50 0%, #66bb6a 100%); color: white; border: none; border-radius: 12px; @@ -114,18 +114,18 @@ body { cursor: pointer; transition: all 0.2s ease; margin-bottom: 24px; - box-shadow: 0 2px 8px rgba(102, 126, 234, 0.25); + box-shadow: 0 2px 8px rgba(76, 175, 80, 0.3); } .btn:hover { - background: #5a67d8; + background: linear-gradient(135deg, #388e3c 0%, #4caf50 100%); transform: translateY(-1px); - box-shadow: 0 4px 16px rgba(102, 126, 234, 0.35); + box-shadow: 0 4px 16px rgba(76, 175, 80, 0.4); } .btn:active { transform: translateY(0); - background: #4c51bf; + background: linear-gradient(135deg, #2e7d32 0%, #388e3c 100%); } .btn:disabled { @@ -142,7 +142,7 @@ body { .result-title { font-size: 1.25rem; - color: #1D1D1F; + color: #1b5e20; margin-bottom: 16px; text-align: center; font-weight: 600; @@ -151,7 +151,7 @@ body { .loading { display: none; text-align: center; - color: #667eea; + color: #4caf50; font-style: normal; padding: 24px; font-weight: 500; @@ -181,10 +181,10 @@ body { color: white; margin: 20px 0 12px 0; padding: 12px 16px; - background: #667eea; + background: linear-gradient(135deg, #4caf50 0%, #66bb6a 100%); border-radius: 12px; text-align: center; - box-shadow: 0 2px 8px rgba(102, 126, 234, 0.25); + box-shadow: 0 2px 8px rgba(76, 175, 80, 0.3); } .section-title:first-child { @@ -214,8 +214,8 @@ body { } .command-item:hover { - border-color: rgba(102, 126, 234, 0.3); - box-shadow: 0 4px 16px rgba(102, 126, 234, 0.1); + border-color: rgba(76, 175, 80, 0.3); + box-shadow: 0 4px 16px rgba(76, 175, 80, 0.15); background: rgba(255, 255, 255, 0.95); } @@ -312,7 +312,7 @@ body { } .copy-btn { - background: #667eea; + background: #4caf50; color: white; border: none; border-radius: 8px; @@ -321,14 +321,14 @@ body { font-weight: 600; cursor: pointer; transition: all 0.2s ease; - box-shadow: 0 2px 4px rgba(102, 126, 234, 0.25); + box-shadow: 0 2px 4px rgba(76, 175, 80, 0.3); position: absolute; top: 20px; right: 20px; } .copy-btn:hover { - background: #5a67d8; + background: #388e3c; transform: translateY(-1px); } @@ -562,15 +562,15 @@ code { } ::-webkit-scrollbar-track { - background: rgba(0, 0, 0, 0.1); + background: rgba(76, 175, 80, 0.1); border-radius: 4px; } ::-webkit-scrollbar-thumb { - background: rgba(102, 126, 234, 0.3); + background: rgba(76, 175, 80, 0.3); border-radius: 4px; } ::-webkit-scrollbar-thumb:hover { - background: rgba(102, 126, 234, 0.5); + background: rgba(76, 175, 80, 0.5); } \ No newline at end of file diff --git a/InfoGenie-frontend/public/aimodelapp/AI生成表情包/styles.css b/InfoGenie-frontend/public/aimodelapp/AI生成表情包/styles.css index 54689967..3c3bece8 100755 --- a/InfoGenie-frontend/public/aimodelapp/AI生成表情包/styles.css +++ b/InfoGenie-frontend/public/aimodelapp/AI生成表情包/styles.css @@ -8,10 +8,10 @@ /* 主体样式 - iOS风格 */ body { font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Helvetica Neue', Arial, sans-serif; - background: linear-gradient(135deg, #FFB6C1 0%, #FFE4E1 100%); + background: linear-gradient(135deg, #a8e6cf 0%, #dcedc8 50%, #f1f8e9 100%); min-height: 100vh; padding: 20px; - color: #1D1D1F; + color: #2e7d32; line-height: 1.47; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; @@ -24,9 +24,9 @@ body { background: rgba(255, 255, 255, 0.85); border-radius: 24px; padding: 32px; - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.08); + box-shadow: 0 8px 32px rgba(76, 175, 80, 0.15), 0 2px 8px rgba(76, 175, 80, 0.1); backdrop-filter: blur(20px) saturate(180%); - border: 1px solid rgba(255, 255, 255, 0.2); + border: 1px solid rgba(76, 175, 80, 0.2); } /* 头部样式 - iOS风格 */ @@ -37,14 +37,14 @@ body { .title { font-size: 2.25rem; - color: #1D1D1F; + color: #1b5e20; margin-bottom: 8px; font-weight: 600; letter-spacing: -0.02em; } .subtitle { - color: #86868B; + color: #4caf50; font-size: 1.0625rem; margin-bottom: 24px; font-weight: 400; @@ -63,14 +63,14 @@ body { display: block; margin-bottom: 8px; font-weight: 600; - color: #1D1D1F; + color: #2e7d32; font-size: 1rem; } .form-input { width: 100%; padding: 16px; - border: 1px solid rgba(0, 0, 0, 0.1); + border: 1px solid rgba(76, 175, 80, 0.2); border-radius: 12px; font-size: 1rem; transition: all 0.2s ease; @@ -81,9 +81,9 @@ body { .form-input:focus { outline: none; - border-color: #FF69B4; + border-color: #4caf50; background: rgba(255, 255, 255, 0.95); - box-shadow: 0 0 0 4px rgba(255, 105, 180, 0.1); + box-shadow: 0 0 0 4px rgba(76, 175, 80, 0.15); } .textarea { @@ -105,7 +105,7 @@ body { .btn { width: 100%; padding: 16px; - background: #FF69B4; + background: linear-gradient(135deg, #4caf50 0%, #66bb6a 100%); color: white; border: none; border-radius: 12px; @@ -114,18 +114,18 @@ body { cursor: pointer; transition: all 0.2s ease; margin-bottom: 24px; - box-shadow: 0 2px 8px rgba(255, 105, 180, 0.25); + box-shadow: 0 2px 8px rgba(76, 175, 80, 0.3); } .btn:hover { - background: #FF1493; + background: linear-gradient(135deg, #388e3c 0%, #4caf50 100%); transform: translateY(-1px); - box-shadow: 0 4px 16px rgba(255, 105, 180, 0.35); + box-shadow: 0 4px 16px rgba(76, 175, 80, 0.4); } .btn:active { transform: translateY(0); - background: #DC143C; + background: linear-gradient(135deg, #2e7d32 0%, #388e3c 100%); } .btn:disabled { @@ -142,7 +142,7 @@ body { .result-title { font-size: 1.25rem; - color: #1D1D1F; + color: #1b5e20; margin-bottom: 16px; text-align: center; font-weight: 600; @@ -151,7 +151,7 @@ body { .loading { display: none; text-align: center; - color: #FF69B4; + color: #4caf50; font-style: normal; padding: 24px; font-weight: 500; @@ -181,10 +181,10 @@ body { color: white; margin: 20px 0 12px 0; padding: 12px 16px; - background: #FF69B4; + background: linear-gradient(135deg, #4caf50 0%, #66bb6a 100%); border-radius: 12px; text-align: center; - box-shadow: 0 2px 8px rgba(255, 105, 180, 0.25); + box-shadow: 0 2px 8px rgba(76, 175, 80, 0.3); } .expression-group-title:first-child { @@ -208,8 +208,8 @@ body { } .expression-item:hover { - border-color: rgba(255, 105, 180, 0.3); - box-shadow: 0 4px 16px rgba(255, 105, 180, 0.1); + border-color: rgba(76, 175, 80, 0.3); + box-shadow: 0 4px 16px rgba(76, 175, 80, 0.15); background: rgba(255, 255, 255, 0.95); } @@ -248,7 +248,7 @@ body { } .copy-btn { - background: #FF69B4; + background: #4caf50; color: white; border: none; border-radius: 8px; @@ -257,13 +257,13 @@ body { font-weight: 600; cursor: pointer; transition: all 0.2s ease; - box-shadow: 0 2px 4px rgba(255, 105, 180, 0.25); + box-shadow: 0 2px 4px rgba(76, 175, 80, 0.3); margin-top: 8px; align-self: center; } .copy-btn:hover { - background: #FF1493; + background: #388e3c; transform: translateY(-1px); } diff --git a/InfoGenie-frontend/public/aimodelapp/AI语言翻译助手/styles.css b/InfoGenie-frontend/public/aimodelapp/AI语言翻译助手/styles.css index 5e1806c2..30669ad3 100755 --- a/InfoGenie-frontend/public/aimodelapp/AI语言翻译助手/styles.css +++ b/InfoGenie-frontend/public/aimodelapp/AI语言翻译助手/styles.css @@ -5,28 +5,28 @@ box-sizing: border-box; } -/* 主体样式 - iOS风格 */ +/* 主体样式 - 清新绿色风格 */ body { font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Helvetica Neue', Arial, sans-serif; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + background: linear-gradient(135deg, #a8e6cf 0%, #dcedc8 50%, #f1f8e9 100%); min-height: 100vh; padding: 20px; - color: #1D1D1F; + color: #2e7d32; line-height: 1.47; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } -/* 容器样式 - iOS毛玻璃效果 */ +/* 容器样式 - 清新绿色毛玻璃效果 */ .container { max-width: 800px; margin: 0 auto; - background: rgba(255, 255, 255, 0.85); + background: rgba(255, 255, 255, 0.9); border-radius: 24px; padding: 32px; - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.08); + box-shadow: 0 8px 32px rgba(46, 125, 50, 0.15), 0 2px 8px rgba(46, 125, 50, 0.08); backdrop-filter: blur(20px) saturate(180%); - border: 1px solid rgba(255, 255, 255, 0.2); + border: 1px solid rgba(168, 230, 207, 0.3); } /* 头部样式 - iOS风格 */ @@ -37,14 +37,14 @@ body { .title { font-size: 2.25rem; - color: #1D1D1F; + color: #1b5e20; margin-bottom: 8px; font-weight: 600; letter-spacing: -0.02em; } .subtitle { - color: #86868B; + color: #4caf50; font-size: 1.0625rem; margin-bottom: 24px; font-weight: 400; @@ -63,7 +63,7 @@ body { display: block; margin-bottom: 8px; font-weight: 600; - color: #1D1D1F; + color: #2e7d32; font-size: 1rem; } @@ -81,9 +81,9 @@ body { .form-input:focus { outline: none; - border-color: #007AFF; + border-color: #4caf50; background: rgba(255, 255, 255, 0.95); - box-shadow: 0 0 0 4px rgba(0, 122, 255, 0.1); + box-shadow: 0 0 0 4px rgba(76, 175, 80, 0.15); } .textarea { @@ -101,11 +101,11 @@ body { padding-right: 40px; } -/* 按钮样式 - iOS风格 */ +/* 按钮样式 - 清新绿色风格 */ .btn { width: 100%; padding: 16px; - background: #007AFF; + background: linear-gradient(135deg, #4caf50 0%, #66bb6a 100%); color: white; border: none; border-radius: 12px; @@ -114,18 +114,18 @@ body { cursor: pointer; transition: all 0.2s ease; margin-bottom: 24px; - box-shadow: 0 2px 8px rgba(0, 122, 255, 0.25); + box-shadow: 0 2px 8px rgba(76, 175, 80, 0.3); } .btn:hover { - background: #0056CC; + background: linear-gradient(135deg, #388e3c 0%, #4caf50 100%); transform: translateY(-1px); - box-shadow: 0 4px 16px rgba(0, 122, 255, 0.35); + box-shadow: 0 4px 16px rgba(76, 175, 80, 0.4); } .btn:active { transform: translateY(0); - background: #004499; + background: linear-gradient(135deg, #2e7d32 0%, #388e3c 100%); } .btn:disabled { @@ -142,7 +142,7 @@ body { .result-title { font-size: 1.25rem; - color: #1D1D1F; + color: #2e7d32; margin-bottom: 16px; text-align: center; font-weight: 600; @@ -151,7 +151,7 @@ body { .loading { display: none; text-align: center; - color: #007AFF; + color: #4caf50; font-style: normal; padding: 24px; font-weight: 500; @@ -195,12 +195,12 @@ body { } .detected-language .value { - color: #1D1D1F; + color: #2e7d32; } .main-translation { background: rgba(255, 255, 255, 0.9); - border: 1px solid rgba(0, 0, 0, 0.06); + border: 1px solid rgba(76, 175, 80, 0.1); border-radius: 12px; padding: 20px; margin-bottom: 16px; @@ -216,13 +216,13 @@ body { .translation-header .label { font-weight: 600; - color: #1D1D1F; + color: #2e7d32; font-size: 1rem; } .translation-text { font-size: 1.125rem; - color: #1D1D1F; + color: #2e7d32; line-height: 1.6; font-weight: 500; } @@ -243,13 +243,13 @@ body { } .pronunciation .value { - color: #1D1D1F; + color: #2e7d32; font-family: 'SF Mono', 'Monaco', 'Consolas', 'Courier New', monospace; } .alternatives { background: rgba(255, 255, 255, 0.8); - border: 1px solid rgba(0, 0, 0, 0.06); + border: 1px solid rgba(76, 175, 80, 0.1); border-radius: 12px; padding: 16px; margin-bottom: 16px; @@ -257,7 +257,7 @@ body { .alternatives-title { font-weight: 600; - color: #1D1D1F; + color: #2e7d32; margin-bottom: 12px; font-size: 1rem; } @@ -282,33 +282,33 @@ body { } .alternative-text { - color: #1D1D1F; + color: #2e7d32; font-size: 1rem; } .explanation { - background: rgba(0, 122, 255, 0.1); - border: 1px solid rgba(0, 122, 255, 0.2); + background: rgba(76, 175, 80, 0.1); + border: 1px solid rgba(76, 175, 80, 0.2); border-radius: 12px; padding: 16px; } .explanation .label { font-weight: 600; - color: #007AFF; + color: #4caf50; margin-bottom: 8px; display: block; } .explanation-text { - color: #1D1D1F; + color: #2e7d32; line-height: 1.6; font-size: 0.9375rem; } /* 复制按钮样式 */ .copy-btn { - background: #007AFF; + background: #4caf50; color: white; border: none; border-radius: 8px; @@ -317,16 +317,16 @@ body { font-weight: 600; cursor: pointer; transition: all 0.2s ease; - box-shadow: 0 2px 4px rgba(0, 122, 255, 0.25); + box-shadow: 0 2px 4px rgba(76, 175, 80, 0.3); } .copy-btn:hover { - background: #0056CC; + background: #388e3c; transform: translateY(-1px); } .copy-btn-small { - background: #007AFF; + background: #4caf50; color: white; border: none; border-radius: 6px; @@ -335,11 +335,11 @@ body { font-weight: 600; cursor: pointer; transition: all 0.2s ease; - box-shadow: 0 1px 2px rgba(0, 122, 255, 0.25); + box-shadow: 0 1px 2px rgba(76, 175, 80, 0.3); } .copy-btn-small:hover { - background: #0056CC; + background: #388e3c; transform: translateY(-1px); } diff --git a/InfoGenie-frontend/public/index.html b/InfoGenie-frontend/public/index.html index 694e9da8..effd9954 100755 --- a/InfoGenie-frontend/public/index.html +++ b/InfoGenie-frontend/public/index.html @@ -49,53 +49,238 @@ z-index: 9999; color: white; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif; + overflow: hidden; } + /* 背景粒子动画 */ + #loading::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: + radial-gradient(circle at 20% 80%, rgba(255, 255, 255, 0.1) 0%, transparent 50%), + radial-gradient(circle at 80% 20%, rgba(255, 255, 255, 0.1) 0%, transparent 50%), + radial-gradient(circle at 40% 40%, rgba(255, 255, 255, 0.05) 0%, transparent 50%); + animation: backgroundFloat 8s ease-in-out infinite; + } + + /* 流动渐变背景 */ + #loading::after { + content: ''; + position: absolute; + top: -50%; + left: -50%; + width: 200%; + height: 200%; + background: linear-gradient( + 45deg, + transparent, + rgba(255, 255, 255, 0.03), + transparent, + rgba(255, 255, 255, 0.03), + transparent + ); + animation: gradientFlow 6s linear infinite; + } + + /* Logo容器 */ + .loading-logo-container { + position: relative; + margin-bottom: 24px; + } + + /* Logo增强动画 */ #loading .loading-logo { width: 90px; height: 90px; - margin-bottom: 24px; - animation: pulse 2s infinite; - border-radius: 8px; + border-radius: 12px; + position: relative; + z-index: 2; + animation: logoEnhanced 3s ease-in-out infinite; + filter: drop-shadow(0 0 20px rgba(255, 255, 255, 0.3)); } - #loading .loading-text { - font-size: 34px; - font-weight: bold; + /* Logo光晕效果 */ + .loading-logo-container::before { + content: ''; + position: absolute; + top: -10px; + left: -10px; + right: -10px; + bottom: -10px; + background: linear-gradient(45deg, rgba(144, 238, 144, 0.3), rgba(240, 230, 140, 0.3), rgba(144, 238, 144, 0.3)); + border-radius: 20px; + z-index: 1; + animation: logoGlow 3s ease-in-out infinite; + opacity: 0.4; + } + + /* 文字容器 */ + .loading-text-container { + position: relative; margin-bottom: 16px; } - #loading .loading-desc { - font-size: 20px; - color: rgba(255, 255, 255, 0.8); - margin-bottom: 32px; + /* 标题文字增强动画 */ + #loading .loading-text { + font-size: 34px; + font-weight: bold; + background: linear-gradient(45deg, #ffffff, #f0f8ff, #ffffff, #e6f3ff); + background-size: 300% 300%; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + animation: textGradient 3s ease-in-out infinite, textFloat 4s ease-in-out infinite; + text-shadow: 0 0 30px rgba(255, 255, 255, 0.5); } + /* 描述文字动画 */ + #loading .loading-desc { + font-size: 20px; + color: rgba(255, 255, 255, 0.9); + margin-bottom: 32px; + animation: descFloat 5s ease-in-out infinite; + text-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); + } + + /* 加载器容器 */ + .loading-spinner-container { + position: relative; + width: 80px; + height: 80px; + } + + /* 主加载器 */ #loading .loading-spinner { width: 56px; height: 56px; - border: 6px solid rgba(255, 255, 255, 0.3); - border-top: 6px solid #ffffff; + border: 4px solid transparent; + border-top: 4px solid #ffffff; + border-right: 4px solid rgba(255, 255, 255, 0.8); + border-bottom: 4px solid rgba(255, 255, 255, 0.6); + border-left: 4px solid rgba(255, 255, 255, 0.4); border-radius: 50%; - animation: spin 1s linear infinite; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + animation: spinEnhanced 1.2s linear infinite; } - @keyframes pulse { - 0%, 100% { transform: scale(1); } - 50% { transform: scale(1.1); } + /* 外层加载器 */ + .loading-spinner-container::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 80px; + height: 80px; + border: 3px solid transparent; + border-top: 3px solid rgba(255, 255, 255, 0.4); + border-radius: 50%; + animation: spinSlow 2s linear infinite reverse; } - @keyframes spin { + /* 内层加载器 */ + .loading-spinner-container::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 30px; + height: 30px; + border: 2px solid transparent; + border-top: 2px solid rgba(255, 255, 255, 0.6); + border-radius: 50%; + transform: translate(-50%, -50%); + animation: spinFast 0.8s linear infinite; + } + + /* 动画定义 */ + @keyframes logoEnhanced { + 0%, 100% { + transform: scale(1) rotate(0deg); + filter: drop-shadow(0 0 20px rgba(255, 255, 255, 0.3)); + } + 25% { + transform: scale(1.05) rotate(2deg); + filter: drop-shadow(0 0 25px rgba(255, 255, 255, 0.4)); + } + 50% { + transform: scale(1.1) rotate(0deg); + filter: drop-shadow(0 0 30px rgba(255, 255, 255, 0.5)); + } + 75% { + transform: scale(1.05) rotate(-2deg); + filter: drop-shadow(0 0 25px rgba(255, 255, 255, 0.4)); + } + } + + @keyframes logoGlow { + 0% { transform: scale(1); opacity: 0.2; } + 50% { transform: scale(1.02); opacity: 0.4; } + 100% { transform: scale(1); opacity: 0.2; } + } + + @keyframes textGradient { + 0%, 100% { background-position: 0% 50%; } + 50% { background-position: 100% 50%; } + } + + @keyframes textFloat { + 0%, 100% { transform: translateY(0px); } + 50% { transform: translateY(-5px); } + } + + @keyframes descFloat { + 0%, 100% { transform: translateY(0px); opacity: 0.9; } + 50% { transform: translateY(-3px); opacity: 1; } + } + + @keyframes spinEnhanced { + 0% { transform: translate(-50%, -50%) rotate(0deg); } + 100% { transform: translate(-50%, -50%) rotate(360deg); } + } + + @keyframes spinSlow { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } + @keyframes spinFast { + 0% { transform: translate(-50%, -50%) rotate(0deg); } + 100% { transform: translate(-50%, -50%) rotate(360deg); } + } + + @keyframes backgroundFloat { + 0%, 100% { transform: translateY(0px) translateX(0px); } + 25% { transform: translateY(-10px) translateX(5px); } + 50% { transform: translateY(-5px) translateX(-5px); } + 75% { transform: translateY(-15px) translateX(3px); } + } + + @keyframes gradientFlow { + 0% { transform: translateX(-100%) translateY(-100%) rotate(0deg); } + 100% { transform: translateX(100%) translateY(100%) rotate(360deg); } + } + + /* 响应式设计 */ @media (max-width: 768px) { #loading .loading-logo { width: 67px; height: 67px; } + .loading-logo-container::before { + top: -8px; + left: -8px; + right: -8px; + bottom: -8px; + } + #loading .loading-text { font-size: 28px; } @@ -104,11 +289,27 @@ font-size: 17px; } + .loading-spinner-container { + width: 60px; + height: 60px; + } + #loading .loading-spinner { width: 42px; height: 42px; - border: 4px solid rgba(255, 255, 255, 0.3); - border-top: 4px solid #ffffff; + border-width: 3px; + } + + .loading-spinner-container::before { + width: 60px; + height: 60px; + border-width: 2px; + } + + .loading-spinner-container::after { + width: 24px; + height: 24px; + border-width: 2px; } } @@ -118,10 +319,16 @@
- -
万象口袋
+
+ +
+
+
万象口袋
+
🎨 一个跨平台的多功能聚合应用(´。• ω •。`) 💬
-
+
+
+
diff --git a/InfoGenie-frontend/public/smallgame/2048/controls.js b/InfoGenie-frontend/public/smallgame/2048/controls.js index 8def4b81..83d25e16 100755 --- a/InfoGenie-frontend/public/smallgame/2048/controls.js +++ b/InfoGenie-frontend/public/smallgame/2048/controls.js @@ -26,7 +26,15 @@ class GameControls { } initKeyboardControls() { - document.addEventListener('keydown', (e) => { + // 确保iframe能够获得焦点并接收键盘事件 + const gameContainer = document.querySelector('.container'); + if (gameContainer) { + gameContainer.setAttribute('tabindex', '0'); + gameContainer.focus(); + } + + // 为document和window都添加键盘事件监听器,确保在iframe中也能工作 + const handleKeyDown = (e) => { if (!this.isGameActive || !window.game2048) { console.log('Game not ready:', { isGameActive: this.isGameActive, game2048: !!window.game2048 }); return; @@ -69,7 +77,18 @@ class GameControls { this.togglePause(); break; } - }); + }; + + // 同时监听document和window的键盘事件 + document.addEventListener('keydown', handleKeyDown); + window.addEventListener('keydown', handleKeyDown); + + // 确保游戏容器在点击时获得焦点 + if (gameContainer) { + gameContainer.addEventListener('click', () => { + gameContainer.focus(); + }); + } } initTouchControls() { @@ -389,90 +408,6 @@ class GameControls { enable() { this.isGameActive = true; } - - // 显示控制提示 - showControlHints() { - const hints = document.createElement('div'); - hints.className = 'control-hints'; - hints.innerHTML = ` -
-

操作说明

-
-

📱 手机操作

-

在游戏区域滑动手指移动方块

-
- 👆 上滑 - 👇 下滑 - 👈 左滑 - 👉 右滑 -
-
-
-

⌨️ 键盘操作

-
-
- - W - 上移 -
-
- - S - 下移 -
-
- - A - 左移 -
-
- - D - 右移 -
-
- R - 重新开始 -
-
- ESC - 暂停/继续 -
-
-
- -
- `; - - // 添加样式 - hints.style.cssText = ` - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: rgba(0, 0, 0, 0.8); - display: flex; - justify-content: center; - align-items: center; - z-index: 10000; - backdrop-filter: blur(5px); - `; - - document.body.appendChild(hints); - - // 关闭按钮事件 - hints.querySelector('.close-hints').addEventListener('click', () => { - hints.remove(); - }); - - // 点击背景关闭 - hints.addEventListener('click', (e) => { - if (e.target === hints) { - hints.remove(); - } - }); - } } // 创建全局控制实例 @@ -486,8 +421,7 @@ document.addEventListener('DOMContentLoaded', () => { gameControls = new GameControls(); console.log('Game controls initialized successfully'); - // 创建帮助按钮 - createHelpButton(); + } else { console.log('Waiting for game2048 to initialize...'); setTimeout(initControls, 100); @@ -497,41 +431,7 @@ document.addEventListener('DOMContentLoaded', () => { initControls(); }); -// 创建帮助按钮函数 -function createHelpButton() { - const helpBtn = document.createElement('button'); - helpBtn.textContent = '❓'; - helpBtn.title = '操作说明'; - helpBtn.style.cssText = ` - position: fixed; - top: 20px; - right: 20px; - width: 50px; - height: 50px; - border-radius: 50%; - background: rgba(255, 255, 255, 0.9); - border: none; - font-size: 20px; - cursor: pointer; - box-shadow: 0 4px 12px rgba(0,0,0,0.2); - z-index: 1000; - transition: all 0.3s ease; - `; - - helpBtn.addEventListener('click', () => { - gameControls.showControlHints(); - }); - - helpBtn.addEventListener('mouseenter', () => { - helpBtn.style.transform = 'scale(1.1)'; - }); - - helpBtn.addEventListener('mouseleave', () => { - helpBtn.style.transform = 'scale(1)'; - }); - - document.body.appendChild(helpBtn); -} + // 导出控制实例 window.gameControls = gameControls; \ No newline at end of file diff --git a/InfoGenie-frontend/public/smallgame/2048/game-logic.js b/InfoGenie-frontend/public/smallgame/2048/game-logic.js index d442b5d0..910dce86 100755 --- a/InfoGenie-frontend/public/smallgame/2048/game-logic.js +++ b/InfoGenie-frontend/public/smallgame/2048/game-logic.js @@ -4,7 +4,7 @@ class Game2048 { this.size = 4; this.grid = []; this.score = 0; - this.bestScore = parseInt(localStorage.getItem('2048-best-score')) || 0; + this.gameWon = false; this.gameOver = false; this.moved = false; @@ -98,7 +98,6 @@ class Game2048 { // 更新分数 document.getElementById('score').textContent = this.score; - document.getElementById('best-score').textContent = this.bestScore; // 更新统计数据显示 if (window.gameStats) { @@ -359,9 +358,7 @@ class Game2048 { this.startTimer(); } - keepPlaying() { - document.getElementById('game-message').style.display = 'none'; - } + startTimer() { this.stats.startTime = Date.now(); @@ -381,28 +378,13 @@ class Game2048 { } bindEvents() { - // 重新开始按钮 - document.getElementById('restart-btn').addEventListener('click', () => { - this.restart(); - }); - - // 继续游戏按钮 - document.getElementById('keep-playing').addEventListener('click', () => { - this.keepPlaying(); - }); - // 重试按钮 document.getElementById('retry-btn').addEventListener('click', () => { this.restart(); }); } - updateBestScore() { - if (this.score > this.bestScore) { - this.bestScore = this.score; - localStorage.setItem('2048-best-score', this.bestScore.toString()); - } - } + } // 游戏实例 @@ -412,12 +394,7 @@ let game; document.addEventListener('DOMContentLoaded', () => { game = new Game2048(); - // 监听分数变化以更新最高分 - const originalUpdateDisplay = game.updateDisplay.bind(game); - game.updateDisplay = function() { - originalUpdateDisplay(); - this.updateBestScore(); - }; + // 导出游戏实例供其他模块使用 window.game2048 = game; diff --git a/InfoGenie-frontend/public/smallgame/2048/gamedata.js b/InfoGenie-frontend/public/smallgame/2048/gamedata.js new file mode 100644 index 00000000..dc7b775d --- /dev/null +++ b/InfoGenie-frontend/public/smallgame/2048/gamedata.js @@ -0,0 +1,20 @@ +const playerdata = [ + { + "名称":"树萌芽", + "账号":"3205788256@qq.com", + "分数":1232, + "时间":"2025-09-08" + }, + { + "名称":"柚大青", + "账号":"2143323382@qq.com", + "分数":132, + "时间":"2025-09-21" + }, + { + "名称":"牛马", + "账号":"2973419538@qq.com", + "分数":876, + "时间":"2025-09-25" + } +] \ No newline at end of file diff --git a/InfoGenie-frontend/public/smallgame/2048/index.html b/InfoGenie-frontend/public/smallgame/2048/index.html index e3b1cc17..41e1a707 100755 --- a/InfoGenie-frontend/public/smallgame/2048/index.html +++ b/InfoGenie-frontend/public/smallgame/2048/index.html @@ -7,7 +7,7 @@ -
+

2048

@@ -15,25 +15,14 @@
分数
0
-
-
最高分
-
0
-
+
-
-

- 合并相同数字,达到2048! -

-
新游戏
-
-
@@ -70,96 +59,12 @@
-
-

游戏统计

-
-
- 移动次数: - 0 -
-
- 游戏时间: - 00:00 -
-
- 最大数字: - 2 -
-
- 合并次数: - 0 -
-
-
- -
-

操作说明:

-

手机: 滑动屏幕移动方块

-

电脑: 使用方向键 ↑↓←→ 或 WASD 键

-
+
- - + - \ No newline at end of file diff --git a/InfoGenie-frontend/public/smallgame/2048/statistics.js b/InfoGenie-frontend/public/smallgame/2048/statistics.js deleted file mode 100755 index f01543ed..00000000 --- a/InfoGenie-frontend/public/smallgame/2048/statistics.js +++ /dev/null @@ -1,381 +0,0 @@ -// 游戏统计模块 -class GameStatistics { - constructor() { - this.achievements = { - firstWin: false, - speedRunner: false, // 5分钟内达到2048 - efficient: false, // 少于500步达到2048 - persistent: false, // 游戏时间超过30分钟 - merger: false, // 单局合并超过100次 - highScorer: false // 分数超过50000 - }; - - this.loadAchievements(); - this.initializeModal(); - } - - updateDisplay() { - if (!window.game2048) return; - - const game = window.game2048; - - // 更新实时统计显示 - document.getElementById('moves-count').textContent = game.stats.moves; - document.getElementById('game-time').textContent = this.formatTime(game.stats.gameTime); - document.getElementById('max-tile').textContent = game.stats.maxTile; - document.getElementById('merge-count').textContent = game.stats.mergeCount; - } - - formatTime(seconds) { - const minutes = Math.floor(seconds / 60); - const remainingSeconds = seconds % 60; - return `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`; - } - - showFinalStats() { - if (!window.game2048) return; - - const game = window.game2048; - const modal = document.getElementById('stats-modal'); - - // 更新最终统计数据 - document.getElementById('final-score').textContent = game.score; - document.getElementById('final-moves').textContent = game.stats.moves; - document.getElementById('final-time').textContent = this.formatTime(game.stats.gameTime); - document.getElementById('final-max-tile').textContent = game.stats.maxTile; - document.getElementById('final-merges').textContent = game.stats.mergeCount; - - // 计算平均每步得分 - const avgScore = game.stats.moves > 0 ? Math.round(game.score / game.stats.moves) : 0; - document.getElementById('avg-score').textContent = avgScore; - - // 检查成就 - this.checkAchievements(game); - - // 显示模态框 - modal.style.display = 'block'; - - // 添加动画效果 - setTimeout(() => { - modal.querySelector('.modal-content').style.transform = 'scale(1)'; - }, 10); - } - - checkAchievements(game) { - let newAchievements = []; - - // 首次胜利 - if (game.gameWon && !this.achievements.firstWin) { - this.achievements.firstWin = true; - newAchievements.push('🏆 首次胜利!达到了2048!'); - } - - // 速度跑者 - 5分钟内达到2048 - if (game.gameWon && game.stats.gameTime <= 300 && !this.achievements.speedRunner) { - this.achievements.speedRunner = true; - newAchievements.push('⚡ 速度跑者!5分钟内达到2048!'); - } - - // 高效玩家 - 少于500步达到2048 - if (game.gameWon && game.stats.moves < 500 && !this.achievements.efficient) { - this.achievements.efficient = true; - newAchievements.push('🎯 高效玩家!少于500步达到2048!'); - } - - // 坚持不懈 - 游戏时间超过30分钟 - if (game.stats.gameTime >= 1800 && !this.achievements.persistent) { - this.achievements.persistent = true; - newAchievements.push('⏰ 坚持不懈!游戏时间超过30分钟!'); - } - - // 合并大师 - 单局合并超过100次 - if (game.stats.mergeCount >= 100 && !this.achievements.merger) { - this.achievements.merger = true; - newAchievements.push('🔥 合并大师!单局合并超过100次!'); - } - - // 高分玩家 - 分数超过50000 - if (game.score >= 50000 && !this.achievements.highScorer) { - this.achievements.highScorer = true; - newAchievements.push('💎 高分玩家!分数超过50000!'); - } - - // 保存成就 - if (newAchievements.length > 0) { - this.saveAchievements(); - this.showAchievementNotifications(newAchievements); - } - } - - showAchievementNotifications(achievements) { - // 在成就区域显示新获得的成就 - const achievementSection = document.querySelector('.achievement-section'); - - achievements.forEach((achievement, index) => { - setTimeout(() => { - const notification = document.createElement('div'); - notification.className = 'achievement-notification'; - notification.innerHTML = ` -
- ${achievement} -
- `; - - achievementSection.appendChild(notification); - - // 添加样式 - const popup = notification.querySelector('.achievement-popup'); - popup.style.cssText = ` - background: linear-gradient(45deg, #ff6b6b, #feca57); - color: white; - padding: 10px 15px; - border-radius: 20px; - margin: 5px 0; - font-weight: bold; - text-align: center; - animation: achievementSlide 0.5s ease-out; - box-shadow: 0 4px 12px rgba(0,0,0,0.2); - `; - - // 添加动画样式 - if (!document.getElementById('achievement-styles')) { - const style = document.createElement('style'); - style.id = 'achievement-styles'; - style.textContent = ` - @keyframes achievementSlide { - from { - opacity: 0; - transform: translateX(-100%); - } - to { - opacity: 1; - transform: translateX(0); - } - } - `; - document.head.appendChild(style); - } - - // 3秒后移除通知 - setTimeout(() => { - if (notification.parentNode) { - notification.remove(); - } - }, 3000); - }, index * 500); - }); - } - - saveAchievements() { - localStorage.setItem('2048-achievements', JSON.stringify(this.achievements)); - } - - loadAchievements() { - const saved = localStorage.getItem('2048-achievements'); - if (saved) { - this.achievements = { ...this.achievements, ...JSON.parse(saved) }; - } - } - - initializeModal() { - const modal = document.getElementById('stats-modal'); - const closeBtn = document.getElementById('close-modal'); - const newGameBtn = document.getElementById('new-game-btn'); - const shareBtn = document.getElementById('share-btn'); - - // 关闭模态框 - closeBtn.addEventListener('click', () => { - modal.style.display = 'none'; - }); - - // 点击模态框外部关闭 - modal.addEventListener('click', (e) => { - if (e.target === modal) { - modal.style.display = 'none'; - } - }); - - // 新游戏按钮 - newGameBtn.addEventListener('click', () => { - modal.style.display = 'none'; - if (window.game2048) { - window.game2048.restart(); - } - }); - - // 分享按钮 - shareBtn.addEventListener('click', () => { - this.shareScore(); - }); - - // ESC键关闭模态框 - document.addEventListener('keydown', (e) => { - if (e.key === 'Escape' && modal.style.display === 'block') { - modal.style.display = 'none'; - } - }); - } - - shareScore() { - if (!window.game2048) return; - - const game = window.game2048; - const shareText = `我在2048游戏中获得了${game.score}分!\n` + - `最大数字: ${game.stats.maxTile}\n` + - `移动次数: ${game.stats.moves}\n` + - `游戏时间: ${this.formatTime(game.stats.gameTime)}\n` + - `来挑战一下吧!`; - - // 尝试使用Web Share API - if (navigator.share) { - navigator.share({ - title: '2048游戏成绩', - text: shareText, - url: window.location.href - }).catch(err => { - console.log('分享失败:', err); - this.fallbackShare(shareText); - }); - } else { - this.fallbackShare(shareText); - } - } - - fallbackShare(text) { - // 复制到剪贴板 - if (navigator.clipboard) { - navigator.clipboard.writeText(text).then(() => { - this.showToast('成绩已复制到剪贴板!'); - }).catch(() => { - this.showShareModal(text); - }); - } else { - this.showShareModal(text); - } - } - - showShareModal(text) { - // 创建分享文本显示框 - const shareModal = document.createElement('div'); - shareModal.innerHTML = ` -
-

分享你的成绩

- -
- - -
-
- `; - - document.body.appendChild(shareModal); - } - - showToast(message) { - const toast = document.createElement('div'); - toast.textContent = message; - toast.style.cssText = ` - position: fixed; - top: 20px; - left: 50%; - transform: translateX(-50%); - background: rgba(0, 0, 0, 0.8); - color: white; - padding: 12px 24px; - border-radius: 25px; - z-index: 10000; - font-weight: bold; - animation: toastSlide 0.3s ease-out; - `; - - document.body.appendChild(toast); - - setTimeout(() => { - toast.remove(); - }, 3000); - } - - // 获取游戏统计摘要 - getStatsSummary() { - if (!window.game2048) return null; - - const game = window.game2048; - return { - score: game.score, - bestScore: game.bestScore, - moves: game.stats.moves, - gameTime: game.stats.gameTime, - maxTile: game.stats.maxTile, - mergeCount: game.stats.mergeCount, - achievements: this.achievements - }; - } - - // 重置所有统计数据 - resetAllStats() { - this.achievements = { - firstWin: false, - speedRunner: false, - efficient: false, - persistent: false, - merger: false, - highScorer: false - }; - - localStorage.removeItem('2048-achievements'); - localStorage.removeItem('2048-best-score'); - - this.showToast('所有统计数据已重置!'); - } -} - -// 创建全局统计实例 -window.gameStats = new GameStatistics(); - -// 页面加载完成后初始化 -document.addEventListener('DOMContentLoaded', () => { - // 确保统计模块正确初始化 - if (!window.gameStats) { - window.gameStats = new GameStatistics(); - } -}); \ No newline at end of file diff --git a/InfoGenie-frontend/public/smallgame/2048/styles.css b/InfoGenie-frontend/public/smallgame/2048/styles.css index 0e28186f..0fb12299 100755 --- a/InfoGenie-frontend/public/smallgame/2048/styles.css +++ b/InfoGenie-frontend/public/smallgame/2048/styles.css @@ -7,8 +7,8 @@ body { font-family: 'Arial', 'Microsoft YaHei', sans-serif; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - color: #776e65; + background: linear-gradient(135deg, #a8e6cf 0%, #dcedc8 50%, #f1f8e9 100%); + color: #2e7d32; font-size: 18px; margin: 0; padding: 0; @@ -21,6 +21,12 @@ body { margin: 0 auto; padding: 20px; position: relative; + outline: none; /* 移除默认的焦点轮廓 */ +} + +.container:focus { + /* 当容器获得焦点时的样式,用于iframe环境 */ + outline: none; } /* 头部样式 */ @@ -35,8 +41,8 @@ body { .title { font-size: 48px; font-weight: bold; - color: #ffffff; - text-shadow: 2px 2px 4px rgba(0,0,0,0.3); + color: #1b5e20; + text-shadow: 2px 2px 4px rgba(255,255,255,0.5); margin: 0; } @@ -46,17 +52,18 @@ body { } .score-box { - background: rgba(255, 255, 255, 0.9); + background: linear-gradient(135deg, #c8e6c9 0%, #e8f5e8 100%); padding: 10px 15px; border-radius: 8px; text-align: center; min-width: 80px; - box-shadow: 0 2px 8px rgba(0,0,0,0.1); + box-shadow: 0 2px 8px rgba(46,125,50,0.2); + border: 1px solid rgba(129,199,132,0.3); } .score-label { font-size: 12px; - color: #776e65; + color: #2e7d32; text-transform: uppercase; font-weight: bold; } @@ -64,54 +71,22 @@ body { .score { font-size: 20px; font-weight: bold; - color: #ffffff; - background: linear-gradient(45deg, #ff6b6b, #ee5a24); + color: #1b5e20; + background: linear-gradient(45deg, #4caf50, #66bb6a); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } -/* 游戏介绍区域 */ -.game-intro { - background: rgba(255, 255, 255, 0.9); - padding: 15px; - border-radius: 12px; - margin-bottom: 20px; - text-align: center; - box-shadow: 0 4px 12px rgba(0,0,0,0.1); -} - -.game-explanation { - margin-bottom: 15px; - font-size: 16px; - line-height: 1.5; -} - -.restart-button { - background: linear-gradient(45deg, #4ecdc4, #44a08d); - color: white; - padding: 12px 24px; - border-radius: 25px; - cursor: pointer; - font-weight: bold; - transition: all 0.3s ease; - display: inline-block; - box-shadow: 0 4px 12px rgba(0,0,0,0.2); -} - -.restart-button:hover { - transform: translateY(-2px); - box-shadow: 0 6px 16px rgba(0,0,0,0.3); -} - /* 游戏容器 */ .game-container { position: relative; - background: rgba(255, 255, 255, 0.9); + background: linear-gradient(135deg, #e8f5e8 0%, #f1f8e9 100%); border-radius: 12px; padding: 15px; margin-bottom: 20px; - box-shadow: 0 4px 12px rgba(0,0,0,0.1); + box-shadow: 0 4px 12px rgba(46,125,50,0.15); + border: 1px solid rgba(129,199,132,0.2); } /* 网格样式 */ @@ -132,7 +107,7 @@ body { .grid-cell { width: calc(25% - 6px); height: 80px; - background: rgba(238, 228, 218, 0.35); + background: rgba(200, 230, 201, 0.4); border-radius: 8px; margin-right: 8px; position: relative; @@ -168,17 +143,17 @@ body { } /* 不同数字的颜色 */ -.tile-2 { background: #eee4da; color: #776e65; } -.tile-4 { background: #ede0c8; color: #776e65; } -.tile-8 { background: #f2b179; color: #f9f6f2; } -.tile-16 { background: #f59563; color: #f9f6f2; } -.tile-32 { background: #f67c5f; color: #f9f6f2; } -.tile-64 { background: #f65e3b; color: #f9f6f2; } -.tile-128 { background: #edcf72; color: #f9f6f2; font-size: 28px; } -.tile-256 { background: #edcc61; color: #f9f6f2; font-size: 28px; } -.tile-512 { background: #edc850; color: #f9f6f2; font-size: 28px; } -.tile-1024 { background: #edc53f; color: #f9f6f2; font-size: 24px; } -.tile-2048 { background: #edc22e; color: #f9f6f2; font-size: 24px; box-shadow: 0 0 20px rgba(237, 194, 46, 0.5); } +.tile-2 { background: #e8f5e8; color: #2e7d32; } +.tile-4 { background: #c8e6c9; color: #1b5e20; } +.tile-8 { background: #a5d6a7; color: #ffffff; } +.tile-16 { background: #81c784; color: #ffffff; } +.tile-32 { background: #66bb6a; color: #ffffff; } +.tile-64 { background: #4caf50; color: #ffffff; } +.tile-128 { background: #43a047; color: #ffffff; font-size: 28px; } +.tile-256 { background: #388e3c; color: #ffffff; font-size: 28px; } +.tile-512 { background: #2e7d32; color: #ffffff; font-size: 28px; } +.tile-1024 { background: #1b5e20; color: #ffffff; font-size: 24px; } +.tile-2048 { background: #0d4e14; color: #ffffff; font-size: 24px; box-shadow: 0 0 20px rgba(76, 175, 80, 0.6); } .tile-super { background: #3c3a32; color: #f9f6f2; font-size: 20px; } /* 动画效果 */ @@ -251,7 +226,6 @@ body { gap: 15px; } -.keep-playing-button, .retry-button { background: #8f7a66; color: #f9f6f2; @@ -263,237 +237,16 @@ body { transition: all 0.3s ease; } -.keep-playing-button:hover, .retry-button:hover { background: #9f8a76; transform: translateY(-2px); } -/* 游戏统计 */ -.game-stats { - background: rgba(255, 255, 255, 0.9); - padding: 15px; - border-radius: 12px; - margin-bottom: 20px; - box-shadow: 0 4px 12px rgba(0,0,0,0.1); -} -.game-stats h3 { - text-align: center; - margin-bottom: 15px; - color: #776e65; - font-size: 20px; -} -.stats-grid { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 10px; -} -.stat-item { - display: flex; - justify-content: space-between; - align-items: center; - padding: 8px 12px; - background: rgba(238, 228, 218, 0.3); - border-radius: 6px; -} -.stat-label { - font-size: 14px; - color: #776e65; -} -.stat-value { - font-weight: bold; - color: #f67c5f; - font-size: 16px; -} - -/* 操作提示 */ -.controls-hint { - background: rgba(255, 255, 255, 0.9); - padding: 15px; - border-radius: 12px; - text-align: center; - font-size: 14px; - line-height: 1.6; - box-shadow: 0 4px 12px rgba(0,0,0,0.1); -} - -.controls-hint p { - margin-bottom: 5px; -} - -.controls-hint p:last-child { - margin-bottom: 0; -} - -/* 模态框样式 */ -.modal { - display: none; - position: fixed; - z-index: 1000; - left: 0; - top: 0; - width: 100%; - height: 100%; - background-color: rgba(0, 0, 0, 0.5); - backdrop-filter: blur(5px); -} - -.modal-content { - background-color: #fefefe; - margin: 5% auto; - border-radius: 15px; - width: 90%; - max-width: 500px; - max-height: 90vh; - overflow-y: auto; - box-shadow: 0 10px 30px rgba(0,0,0,0.3); - animation: modalSlideIn 0.3s ease-out; -} - -@keyframes modalSlideIn { - from { - opacity: 0; - transform: translateY(-50px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -.modal-header { - padding: 20px; - border-bottom: 1px solid #eee; - display: flex; - justify-content: space-between; - align-items: center; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - color: white; - border-radius: 15px 15px 0 0; -} - -.modal-header h2 { - margin: 0; - font-size: 24px; -} - -.close { - color: white; - font-size: 28px; - font-weight: bold; - cursor: pointer; - transition: color 0.3s ease; -} - -.close:hover { - color: #ddd; -} - -.modal-body { - padding: 20px; -} - -.final-score { - text-align: center; - margin-bottom: 25px; - padding: 20px; - background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%); - border-radius: 10px; - color: white; -} - -.final-score h3 { - margin: 0; - font-size: 28px; - text-shadow: 1px 1px 2px rgba(0,0,0,0.2); -} - -.achievement-section h4 { - text-align: center; - margin-bottom: 20px; - color: #776e65; - font-size: 20px; -} - -.achievement-grid { - display: grid; - grid-template-columns: 1fr; - gap: 15px; - margin-bottom: 25px; -} - -.achievement-item { - display: flex; - align-items: center; - padding: 15px; - background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%); - border-radius: 10px; - box-shadow: 0 2px 8px rgba(0,0,0,0.1); - transition: transform 0.3s ease; -} - -.achievement-item:hover { - transform: translateY(-2px); -} - -.achievement-icon { - font-size: 32px; - margin-right: 15px; -} - -.achievement-info { - flex: 1; -} - -.achievement-title { - font-size: 14px; - color: #666; - margin-bottom: 5px; -} - -.achievement-value { - font-size: 20px; - font-weight: bold; - color: #333; -} - -.modal-actions { - display: flex; - gap: 15px; - justify-content: center; -} - -.btn { - padding: 12px 24px; - border: none; - border-radius: 25px; - font-size: 16px; - font-weight: bold; - cursor: pointer; - transition: all 0.3s ease; - text-decoration: none; - display: inline-block; -} - -.btn-primary { - background: linear-gradient(45deg, #4ecdc4, #44a08d); - color: white; -} - -.btn-secondary { - background: linear-gradient(45deg, #ff9a9e, #fecfef); - color: white; -} - -.btn:hover { - transform: translateY(-2px); - box-shadow: 0 6px 16px rgba(0,0,0,0.2); -} /* 手机端优化 */ @media (max-width: 480px) { @@ -540,18 +293,7 @@ body { font-size: 28px; } - .modal-content { - margin: 10% auto; - width: 95%; - } - - .achievement-grid { - grid-template-columns: 1fr; - } - - .modal-actions { - flex-direction: column; - } + } /* 超小屏幕优化 */ @@ -590,21 +332,12 @@ body { font-size: 36px; } - .achievement-grid { - grid-template-columns: 1fr 1fr; - } - - .modal-actions { - flex-direction: row; - } + } /* 触摸优化 */ @media (hover: none) and (pointer: coarse) { - .restart-button, - .keep-playing-button, - .retry-button, - .btn { + .retry-button { min-height: 44px; min-width: 44px; } diff --git a/InfoGenie-frontend/public/smallgame/俄罗斯方块/game-controls.js b/InfoGenie-frontend/public/smallgame/俄罗斯方块/game-controls.js index 99a5a22b..a5f9f34c 100755 --- a/InfoGenie-frontend/public/smallgame/俄罗斯方块/game-controls.js +++ b/InfoGenie-frontend/public/smallgame/俄罗斯方块/game-controls.js @@ -35,24 +35,32 @@ class GameControls { switch(key) { case 'ArrowLeft': + case 'a': + case 'A': e.preventDefault(); this.game.moveLeft(); - this.startKeyRepeat('ArrowLeft', () => this.game.moveLeft()); + this.startKeyRepeat(key, () => this.game.moveLeft()); break; case 'ArrowRight': + case 'd': + case 'D': e.preventDefault(); this.game.moveRight(); - this.startKeyRepeat('ArrowRight', () => this.game.moveRight()); + this.startKeyRepeat(key, () => this.game.moveRight()); break; case 'ArrowDown': + case 's': + case 'S': e.preventDefault(); this.game.moveDown(); - this.startKeyRepeat('ArrowDown', () => this.game.moveDown()); + this.startKeyRepeat(key, () => this.game.moveDown()); break; case 'ArrowUp': + case 'w': + case 'W': e.preventDefault(); this.game.rotatePiece(); break; diff --git a/InfoGenie-frontend/public/smallgame/俄罗斯方块/gamedata.js b/InfoGenie-frontend/public/smallgame/俄罗斯方块/gamedata.js new file mode 100644 index 00000000..dc7b775d --- /dev/null +++ b/InfoGenie-frontend/public/smallgame/俄罗斯方块/gamedata.js @@ -0,0 +1,20 @@ +const playerdata = [ + { + "名称":"树萌芽", + "账号":"3205788256@qq.com", + "分数":1232, + "时间":"2025-09-08" + }, + { + "名称":"柚大青", + "账号":"2143323382@qq.com", + "分数":132, + "时间":"2025-09-21" + }, + { + "名称":"牛马", + "账号":"2973419538@qq.com", + "分数":876, + "时间":"2025-09-25" + } +] \ No newline at end of file diff --git a/InfoGenie-frontend/public/smallgame/俄罗斯方块/index.html b/InfoGenie-frontend/public/smallgame/俄罗斯方块/index.html index c7cf159d..76caa7cb 100755 --- a/InfoGenie-frontend/public/smallgame/俄罗斯方块/index.html +++ b/InfoGenie-frontend/public/smallgame/俄罗斯方块/index.html @@ -40,30 +40,6 @@
-
-

下一个

- -
- -
-

操作说明

-
- ←→ - 移动 -
-
- - 快速下降 -
-
- - 旋转 -
-
- 空格 - 暂停/继续 -
-
diff --git a/InfoGenie-frontend/public/smallgame/俄罗斯方块/styles.css b/InfoGenie-frontend/public/smallgame/俄罗斯方块/styles.css index 58d03476..cd9ff0e4 100755 --- a/InfoGenie-frontend/public/smallgame/俄罗斯方块/styles.css +++ b/InfoGenie-frontend/public/smallgame/俄罗斯方块/styles.css @@ -8,8 +8,8 @@ body { font-family: 'Arial', sans-serif; - background: linear-gradient(135deg, #1e3c72, #2a5298); - color: white; + background: linear-gradient(135deg, #e8f5e8 0%, #f1f8e9 30%, #f9fbe7 70%, #f0f4c3 100%); + color: #2e7d32; height: 100vh; overflow: hidden; user-select: none; @@ -23,6 +23,10 @@ body { max-width: 800px; margin: 0 auto; padding: 10px; + background: linear-gradient(135deg, rgba(232, 245, 232, 0.4) 0%, rgba(241, 248, 233, 0.4) 50%, rgba(249, 251, 231, 0.4) 100%); + border-radius: 20px; + box-shadow: 0 10px 30px rgba(139, 195, 74, 0.2); + backdrop-filter: blur(10px); } /* 游戏头部 */ @@ -34,7 +38,12 @@ body { .game-header h1 { font-size: 2rem; margin-bottom: 10px; - text-shadow: 2px 2px 4px rgba(0,0,0,0.5); + background: linear-gradient(135deg, #4caf50 0%, #8bc34a 50%, #cddc39 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + text-shadow: 2px 2px 4px rgba(255, 255, 255, 0.3); + font-weight: bold; } .score-board { @@ -45,16 +54,24 @@ body { } .score-item { - background: rgba(255,255,255,0.1); + background: linear-gradient(135deg, #66bb6a 0%, #8bc34a 50%, #aed581 100%); + color: white; padding: 8px 15px; border-radius: 20px; backdrop-filter: blur(10px); - border: 1px solid rgba(255,255,255,0.2); + border: 1px solid rgba(139, 195, 74, 0.3); + box-shadow: 0 4px 12px rgba(139, 195, 74, 0.3); + transition: all 0.3s ease; +} + +.score-item:hover { + transform: translateY(-2px); + box-shadow: 0 6px 16px rgba(139, 195, 74, 0.4); } .score-item .label { font-size: 0.9rem; - opacity: 0.8; + opacity: 0.9; } .score-item span:last-child { @@ -73,15 +90,30 @@ body { .game-board { position: relative; - border-radius: 10px; + border-radius: 15px; overflow: hidden; - box-shadow: 0 10px 30px rgba(0,0,0,0.3); + box-shadow: 0 15px 35px rgba(139, 195, 74, 0.3); + background: linear-gradient(135deg, #e8f5e8 0%, #f1f8e9 50%, #f9fbe7 100%); + border: 3px solid transparent; + background-clip: padding-box; +} + +.game-board::before { + content: ''; + position: absolute; + top: -3px; + left: -3px; + right: -3px; + bottom: -3px; + background: linear-gradient(135deg, #66bb6a 0%, #8bc34a 50%, #aed581 100%); + border-radius: 15px; + z-index: -1; } #gameCanvas { display: block; - background: #1a1a1a; - border: 2px solid #333; + background: linear-gradient(135deg, #2e7d32 0%, #388e3c 50%, #4caf50 100%); + border-radius: 12px; } /* 游戏覆盖层 */ @@ -91,34 +123,44 @@ body { left: 0; right: 0; bottom: 0; - background: rgba(0,0,0,0.8); + background: rgba(139, 195, 74, 0.8); display: flex; align-items: center; justify-content: center; - backdrop-filter: blur(5px); + backdrop-filter: blur(8px); + border-radius: 12px; } .overlay-content { text-align: center; - background: rgba(255,255,255,0.1); + background: linear-gradient(135deg, #e8f5e8 0%, #f1f8e9 50%, #f9fbe7 100%); + color: #2e7d32; padding: 30px; - border-radius: 15px; - border: 1px solid rgba(255,255,255,0.2); + border-radius: 20px; + border: 2px solid rgba(139, 195, 74, 0.4); + box-shadow: 0 15px 30px rgba(139, 195, 74, 0.3); + backdrop-filter: blur(10px); } .overlay-content h2 { margin-bottom: 15px; font-size: 1.8rem; + background: linear-gradient(135deg, #4caf50 0%, #8bc34a 50%, #cddc39 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + font-weight: bold; } .overlay-content p { margin-bottom: 20px; opacity: 0.8; + color: #388e3c; } /* 游戏按钮 */ .game-btn { - background: linear-gradient(45deg, #667eea, #764ba2); + background: linear-gradient(45deg, #66bb6a 0%, #8bc34a 50%, #aed581 100%); border: none; color: white; padding: 12px 24px; @@ -127,12 +169,14 @@ body { font-size: 1rem; margin: 5px; transition: all 0.3s ease; - box-shadow: 0 4px 15px rgba(0,0,0,0.2); + box-shadow: 0 4px 15px rgba(139, 195, 74, 0.3); + font-weight: 600; } .game-btn:hover { transform: translateY(-2px); - box-shadow: 0 6px 20px rgba(0,0,0,0.3); + box-shadow: 0 6px 20px rgba(139, 195, 74, 0.4); + background: linear-gradient(45deg, #8bc34a 0%, #aed581 50%, #c5e1a5 100%); } .game-btn:active { @@ -147,58 +191,7 @@ body { min-width: 150px; } -.next-piece { - background: rgba(255,255,255,0.1); - padding: 15px; - border-radius: 10px; - border: 1px solid rgba(255,255,255,0.2); - text-align: center; -} -.next-piece h3 { - margin-bottom: 10px; - font-size: 1.1rem; -} - -#nextCanvas { - background: #1a1a1a; - border: 1px solid #333; - border-radius: 5px; -} - -.controls-info { - background: rgba(255,255,255,0.1); - padding: 15px; - border-radius: 10px; - border: 1px solid rgba(255,255,255,0.2); -} - -.controls-info h3 { - margin-bottom: 15px; - font-size: 1.1rem; - text-align: center; -} - -.control-item { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 8px; - padding: 5px 0; -} - -.control-item .key { - background: rgba(255,255,255,0.2); - padding: 4px 8px; - border-radius: 4px; - font-family: monospace; - font-size: 0.9rem; -} - -.control-item .desc { - font-size: 0.9rem; - opacity: 0.8; -} /* 手机端控制 */ .mobile-controls { @@ -234,15 +227,15 @@ body { height: 55px; border: none; border-radius: 50%; - background: linear-gradient(45deg, #667eea, #764ba2); + background: linear-gradient(45deg, #66bb6a 0%, #8bc34a 50%, #aed581 100%); color: white; font-size: 1.4rem; cursor: pointer; transition: all 0.2s ease; - box-shadow: 0 4px 15px rgba(0,0,0,0.3); + box-shadow: 0 4px 15px rgba(139, 195, 74, 0.3); user-select: none; backdrop-filter: blur(10px); - border: 2px solid rgba(255,255,255,0.2); + border: 2px solid rgba(255, 255, 255, 0.2); } .control-btn:active { @@ -257,7 +250,7 @@ body { left: 0; width: 100%; height: 100%; - background: rgba(0,0,0,0.9); + background: rgba(46, 125, 50, 0.9); display: none; align-items: center; justify-content: center; @@ -266,13 +259,15 @@ body { } .stats-content { - background: linear-gradient(135deg, #667eea, #764ba2); + background: linear-gradient(135deg, #e8f5e8 0%, #f1f8e9 100%); + color: #1b5e20; padding: 30px; border-radius: 20px; text-align: center; max-width: 90%; width: 400px; - box-shadow: 0 20px 40px rgba(0,0,0,0.3); + box-shadow: 0 20px 40px rgba(46, 125, 50, 0.4); + border: 1px solid rgba(46, 125, 50, 0.3); } .stats-content h2 { @@ -289,16 +284,18 @@ body { } .stat-item { - background: rgba(255,255,255,0.1); + background: linear-gradient(135deg, #2e7d32 0%, #388e3c 100%); + color: white; padding: 15px; border-radius: 10px; - border: 1px solid rgba(255,255,255,0.2); + border: 1px solid rgba(46, 125, 50, 0.3); + box-shadow: 0 4px 8px rgba(46, 125, 50, 0.2); } .stat-label { display: block; font-size: 0.9rem; - opacity: 0.8; + opacity: 0.9; margin-bottom: 5px; } @@ -309,7 +306,8 @@ body { } .achievement { - background: linear-gradient(45deg, #f093fb, #f5576c); + background: linear-gradient(45deg, #81c784, #66bb6a); + color: white; padding: 15px; border-radius: 10px; margin-bottom: 25px; @@ -318,6 +316,7 @@ body { display: flex; align-items: center; justify-content: center; + box-shadow: 0 4px 8px rgba(46, 125, 50, 0.3); } /* 响应式设计 */ @@ -359,11 +358,7 @@ body { width: 100%; } - .next-piece, - .controls-info { - flex: 1; - max-width: 200px; - } + .mobile-controls { display: block; @@ -428,10 +423,7 @@ body { gap: 10px; } - .next-piece, - .controls-info { - max-width: unset; - } + } /* 隐藏类 */ diff --git a/InfoGenie-frontend/public/smallgame/俄罗斯方块/tetris.js b/InfoGenie-frontend/public/smallgame/俄罗斯方块/tetris.js index 1b49cf31..5b3820f9 100755 --- a/InfoGenie-frontend/public/smallgame/俄罗斯方块/tetris.js +++ b/InfoGenie-frontend/public/smallgame/俄罗斯方块/tetris.js @@ -3,8 +3,6 @@ class TetrisGame { constructor() { this.canvas = document.getElementById('gameCanvas'); this.ctx = this.canvas.getContext('2d'); - this.nextCanvas = document.getElementById('nextCanvas'); - this.nextCtx = this.nextCanvas.getContext('2d'); // 游戏配置 this.BOARD_WIDTH = 10; @@ -140,7 +138,6 @@ class TetrisGame { return false; } - this.drawNextPiece(); return true; } @@ -348,39 +345,7 @@ class TetrisGame { } } - drawNextPiece() { - this.nextCtx.clearRect(0, 0, this.nextCanvas.width, this.nextCanvas.height); - - if (this.nextPiece) { - const size = 20; - const matrix = this.nextPiece.matrix; - const offsetX = (this.nextCanvas.width - matrix[0].length * size) / 2; - const offsetY = (this.nextCanvas.height - matrix.length * size) / 2; - - this.nextCtx.fillStyle = this.nextPiece.color; - - for (let row = 0; row < matrix.length; row++) { - for (let col = 0; col < matrix[row].length; col++) { - if (matrix[row][col] !== 0) { - this.nextCtx.fillRect( - offsetX + col * size, - offsetY + row * size, - size, - size - ); - this.nextCtx.strokeStyle = '#333'; - this.nextCtx.lineWidth = 1; - this.nextCtx.strokeRect( - offsetX + col * size, - offsetY + row * size, - size, - size - ); - } - } - } - } - } + updateDisplay() { document.getElementById('score').textContent = this.score; diff --git a/InfoGenie-frontend/public/smallgame/别踩白方块/gamedata.js b/InfoGenie-frontend/public/smallgame/别踩白方块/gamedata.js new file mode 100644 index 00000000..dc7b775d --- /dev/null +++ b/InfoGenie-frontend/public/smallgame/别踩白方块/gamedata.js @@ -0,0 +1,20 @@ +const playerdata = [ + { + "名称":"树萌芽", + "账号":"3205788256@qq.com", + "分数":1232, + "时间":"2025-09-08" + }, + { + "名称":"柚大青", + "账号":"2143323382@qq.com", + "分数":132, + "时间":"2025-09-21" + }, + { + "名称":"牛马", + "账号":"2973419538@qq.com", + "分数":876, + "时间":"2025-09-25" + } +] \ No newline at end of file diff --git a/InfoGenie-frontend/public/smallgame/别踩白方块/index.html b/InfoGenie-frontend/public/smallgame/别踩白方块/index.html index b86e9b55..494c1b37 100755 --- a/InfoGenie-frontend/public/smallgame/别踩白方块/index.html +++ b/InfoGenie-frontend/public/smallgame/别踩白方块/index.html @@ -11,7 +11,7 @@ } body { - background: #f5f5f5; + background: linear-gradient(135deg, #a8e6cf 0%, #dcedc8 50%, #f1f8e9 100%); font-family: 'Arial', 'Microsoft YaHei', sans-serif; display: flex; justify-content: center; @@ -25,41 +25,45 @@ display: flex; flex-direction: column; align-items: center; - background: white; - border-radius: 10px; - box-shadow: 0 10px 30px rgba(0,0,0,0.2); + background: linear-gradient(135deg, #e8f5e8 0%, #f1f8e9 100%); + border-radius: 15px; + box-shadow: 0 10px 30px rgba(46,125,50,0.3); padding: 20px; position: relative; + border: 1px solid rgba(129,199,132,0.2); } .game-title { font-size: 24px; font-weight: bold; - color: #333; + color: #1b5e20; margin-bottom: 10px; text-align: center; + text-shadow: 1px 1px 2px rgba(255,255,255,0.5); } .score-display { position: relative; width: 300px; height: 60px; - background: #333; + background: linear-gradient(135deg, #2e7d32 0%, #388e3c 100%); border-radius: 8px 8px 0 0; display: flex; align-items: center; justify-content: center; + box-shadow: 0 2px 8px rgba(46,125,50,0.3); } .game-container { position: relative; width: 300px; height: 600px; - border: 3px solid #333; + border: 3px solid #2e7d32; border-top: none; border-radius: 0 0 8px 8px; overflow: hidden; background: white; + box-shadow: 0 4px 12px rgba(46,125,50,0.2); } .control-panel { @@ -82,28 +86,32 @@ } .start-btn { - background: #4CAF50; + background: linear-gradient(45deg, #66bb6a, #4caf50); color: white; + box-shadow: 0 4px 12px rgba(76,175,80,0.3); } .start-btn:hover { - background: #45a049; + background: linear-gradient(45deg, #4caf50, #388e3c); transform: translateY(-2px); + box-shadow: 0 6px 16px rgba(76,175,80,0.4); } .pause-btn { - background: #ff9800; + background: linear-gradient(45deg, #81c784, #66bb6a); color: white; + box-shadow: 0 4px 12px rgba(129,199,132,0.3); } .pause-btn:hover { - background: #e68900; + background: linear-gradient(45deg, #66bb6a, #4caf50); transform: translateY(-2px); + box-shadow: 0 6px 16px rgba(129,199,132,0.4); } .instructions { text-align: center; - color: #666; + color: #2e7d32; font-size: 14px; margin-top: 10px; line-height: 1.4; @@ -124,30 +132,32 @@ } .modal-content { - background: white; + background: linear-gradient(135deg, #e8f5e8 0%, #f1f8e9 100%); padding: 30px; border-radius: 15px; text-align: center; - box-shadow: 0 20px 40px rgba(0,0,0,0.3); + box-shadow: 0 20px 40px rgba(46,125,50,0.3); max-width: 300px; width: 90%; + border: 1px solid rgba(129,199,132,0.3); } .modal-title { font-size: 24px; font-weight: bold; - color: #e74c3c; + color: #c62828; margin-bottom: 15px; + text-shadow: 1px 1px 2px rgba(255,255,255,0.5); } .final-score, .final-speed { font-size: 18px; margin: 15px 0; - color: #333; + color: #1b5e20; } .final-speed { - color: #666; + color: #2e7d32; font-size: 16px; } @@ -163,12 +173,14 @@ } .restart-btn { - background: #4CAF50; + background: linear-gradient(45deg, #66bb6a, #4caf50); color: white; + box-shadow: 0 4px 12px rgba(76,175,80,0.3); } .restart-btn:hover { - background: #45a049; + background: linear-gradient(45deg, #4caf50, #388e3c); + box-shadow: 0 6px 16px rgba(76,175,80,0.4); } /* 移动端适配 */ diff --git a/InfoGenie-frontend/public/smallgame/扫雷/css/style.css b/InfoGenie-frontend/public/smallgame/扫雷/css/style.css index 28b2da6a..df5eb7ad 100755 --- a/InfoGenie-frontend/public/smallgame/扫雷/css/style.css +++ b/InfoGenie-frontend/public/smallgame/扫雷/css/style.css @@ -1,62 +1,62 @@ /* 经典扫雷 - 手机竖屏优先 + 电脑端适配 */ :root{ - --bg:#0f172a; - --panel:#111827; - --accent:#22d3ee; - --accent-2:#60a5fa; - --text:#e5e7eb; - --muted:#94a3b8; - --danger:#ef4444; + --bg:#e8f5e8; + --panel:#c8e6c9; + --accent:#2e7d32; + --accent-2:#388e3c; + --text:#1b5e20; + --muted:#4caf50; + --danger:#d32f2f; --success:#22c55e; - --warn:#f59e0b; - --cell:#1f2937; - --cell-hover:#273244; - --flag:#fb7185; + --warn:#f57c00; + --cell:#f1f8e9; + --cell-hover:#dcedc8; + --flag:#4caf50; } *{box-sizing:border-box} html,body{height:100%;} -body{margin:0;background:linear-gradient(180deg,#0b1220,#0f172a);color:var(--text);font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,"PingFang SC","Microsoft Yahei",sans-serif;-webkit-tap-highlight-color:transparent} +body{margin:0;background:linear-gradient(135deg, #a8e6cf 0%, #dcedc8 50%, #f1f8e9 100%);color:var(--text);font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,"PingFang SC","Microsoft Yahei",sans-serif;-webkit-tap-highlight-color:transparent} .app{min-height:100dvh;display:flex;flex-direction:column;gap:12px;padding:12px;} -.header{display:flex;flex-direction:column;gap:10px;background:rgba(255,255,255,0.02);border:1px solid rgba(255,255,255,0.06);border-radius:14px;padding:12px 12px 10px;backdrop-filter:blur(6px)} -.title{margin:0;font-size:20px;letter-spacing:1px} +.header{display:flex;flex-direction:column;gap:10px;background:linear-gradient(135deg, #c8e6c9 0%, #e8f5e8 100%);border:1px solid rgba(46, 125, 50, 0.2);border-radius:14px;padding:12px 12px 10px;backdrop-filter:blur(6px);box-shadow:0 4px 8px rgba(46, 125, 50, 0.1)} +.title{margin:0;font-size:20px;letter-spacing:1px;color:#1b5e20;text-shadow:1px 1px 2px rgba(255,255,255,0.5)} .hud{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;align-items:center} -.hud-item{display:flex;flex-direction:column;align-items:center;justify-content:center;background:var(--panel);border:1px solid rgba(255,255,255,0.06);border-radius:10px;padding:8px 6px} -.hud-item .label{font-size:12px;color:var(--muted)} -.hud-item .value{font-size:18px;font-weight:700;color:#fff} -.btn{appearance:none;border:none;background:#1e293b;color:#fff;padding:10px 12px;border-radius:10px;cursor:pointer;outline:none;transition:.15s transform,.15s background;display:inline-flex;align-items:center;justify-content:center} +.hud-item{display:flex;flex-direction:column;align-items:center;justify-content:center;background:linear-gradient(135deg, #a5d6a7 0%, #c8e6c9 100%);border:1px solid rgba(46, 125, 50, 0.2);border-radius:10px;padding:8px 6px;box-shadow:0 2px 4px rgba(46, 125, 50, 0.1)} +.hud-item .label{font-size:12px;color:#2e7d32} +.hud-item .value{font-size:18px;font-weight:700;color:#1b5e20} +.btn{appearance:none;border:none;background:linear-gradient(135deg, #81c784 0%, #a5d6a7 100%);color:#fff;padding:10px 12px;border-radius:10px;cursor:pointer;outline:none;transition:.15s transform,.15s background;display:inline-flex;align-items:center;justify-content:center;box-shadow:0 2px 4px rgba(46, 125, 50, 0.2)} .btn:active{transform:scale(.98)} -.btn.primary{background:linear-gradient(90deg,var(--accent),var(--accent-2))} +.btn.primary{background:linear-gradient(135deg,var(--accent),var(--accent-2));color:#fff} .btn.primary:active{filter:brightness(.95)} .main{display:flex;flex-direction:column;gap:12px} .board-wrapper{display:flex;justify-content:center;align-items:center} -.board{display:grid;gap:4px;touch-action:manipulation;user-select:none;background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.06);border-radius:12px;padding:6px;width:100%;max-width:92vw} -.cell{display:grid;place-items:center;background:var(--cell);border-radius:8px;border:1px solid rgba(255,255,255,0.06);font-weight:700;color:#9ca3af;box-shadow:inset 0 -1px 0 rgba(255,255,255,0.04);aspect-ratio:1/1;font-size:clamp(12px, 2.2vw, 18px)} -.cell.revealed{background:#0b1220;color:#e5e7eb} +.board{display:grid;gap:4px;touch-action:manipulation;user-select:none;background:linear-gradient(135deg, #c8e6c9 0%, #e8f5e8 100%);border:1px solid rgba(46, 125, 50, 0.2);border-radius:12px;padding:6px;width:100%;max-width:92vw;box-shadow:0 4px 8px rgba(46, 125, 50, 0.1)} +.cell{display:grid;place-items:center;background:var(--cell);border-radius:8px;border:1px solid rgba(46, 125, 50, 0.15);font-weight:700;color:#4caf50;box-shadow:inset 0 -1px 0 rgba(255,255,255,0.3);aspect-ratio:1/1;font-size:clamp(12px, 2.2vw, 18px)} +.cell.revealed{background:#e8f5e8;color:#2e7d32} .cell:hover{background:var(--cell-hover)} .cell.flag::after{content:"🚩"} -.cell.mine.revealed{background:#3b0d0d;color:#fff} +.cell.mine.revealed{background:#ffcdd2;color:#d32f2f} .cell.mine.revealed::after{content:"💣"} -.cell[data-n="1"].revealed{color:#60a5fa} -.cell[data-n="2"].revealed{color:#34d399} -.cell[data-n="3"].revealed{color:#f87171} -.cell[data-n="4"].revealed{color:#a78bfa} -.cell[data-n="5"].revealed{color:#fbbf24} -.cell[data-n="6"].revealed{color:#22d3ee} -.cell[data-n="7"].revealed{color:#e879f9} -.cell[data-n="8"].revealed{color:#cbd5e1} +.cell[data-n="1"].revealed{color:#1976d2} +.cell[data-n="2"].revealed{color:#388e3c} +.cell[data-n="3"].revealed{color:#d32f2f} +.cell[data-n="4"].revealed{color:#7b1fa2} +.cell[data-n="5"].revealed{color:#f57c00} +.cell[data-n="6"].revealed{color:#00796b} +.cell[data-n="7"].revealed{color:#c2185b} +.cell[data-n="8"].revealed{color:#455a64} .tips{font-size:12px;color:var(--muted);text-align:center} -.toast{position:fixed;left:50%;bottom:18px;transform:translateX(-50%);background:rgba(17,24,39,.95);border:1px solid rgba(255,255,255,.08);padding:10px 14px;border-radius:10px} +.toast{position:fixed;left:50%;bottom:18px;transform:translateX(-50%);background:linear-gradient(135deg, #c8e6c9 0%, #e8f5e8 100%);border:1px solid rgba(46, 125, 50, 0.2);padding:10px 14px;border-radius:10px;color:#1b5e20;box-shadow:0 4px 8px rgba(46, 125, 50, 0.2)} -.modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,.45);display:grid;place-items:center;padding:14px} -.modal{width:min(520px,92vw);background:linear-gradient(180deg,#0f172a,#0b1320);border:1px solid rgba(255,255,255,0.08);border-radius:14px;padding:16px 14px} -.modal h2{margin:4px 0 8px;font-size:20px} +.modal-overlay{position:fixed;inset:0;background:rgba(46, 125, 50, 0.3);display:grid;place-items:center;padding:14px} +.modal{width:min(520px,92vw);background:linear-gradient(135deg, #e8f5e8 0%, #f1f8e9 100%);border:1px solid rgba(46, 125, 50, 0.2);border-radius:14px;padding:16px 14px;box-shadow:0 8px 16px rgba(46, 125, 50, 0.2)} +.modal h2{margin:4px 0 8px;font-size:20px;color:#1b5e20} .stats{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin:8px 0 14px} -.stats .card{background:var(--panel);border:1px solid rgba(255,255,255,0.06);border-radius:10px;padding:10px} -.stats .card .k{font-size:12px;color:var(--muted)} -.stats .card .v{font-size:18px;font-weight:700} +.stats .card{background:linear-gradient(135deg, #c8e6c9 0%, #e8f5e8 100%);border:1px solid rgba(46, 125, 50, 0.2);border-radius:10px;padding:10px;box-shadow:0 2px 4px rgba(46, 125, 50, 0.1)} +.stats .card .k{font-size:12px;color:#2e7d32} +.stats .card .v{font-size:18px;font-weight:700;color:#1b5e20} .modal-actions{display:flex;gap:10px;justify-content:flex-end} /* 响应式:手机竖屏优先 */ diff --git a/InfoGenie-frontend/public/smallgame/扫雷/gamedata.js b/InfoGenie-frontend/public/smallgame/扫雷/gamedata.js new file mode 100644 index 00000000..dc7b775d --- /dev/null +++ b/InfoGenie-frontend/public/smallgame/扫雷/gamedata.js @@ -0,0 +1,20 @@ +const playerdata = [ + { + "名称":"树萌芽", + "账号":"3205788256@qq.com", + "分数":1232, + "时间":"2025-09-08" + }, + { + "名称":"柚大青", + "账号":"2143323382@qq.com", + "分数":132, + "时间":"2025-09-21" + }, + { + "名称":"牛马", + "账号":"2973419538@qq.com", + "分数":876, + "时间":"2025-09-25" + } +] \ No newline at end of file diff --git a/InfoGenie-frontend/public/smallgame/贪吃蛇/game-controls.js b/InfoGenie-frontend/public/smallgame/贪吃蛇/game-controls.js index 4c0f5c2d..bbfae549 100755 --- a/InfoGenie-frontend/public/smallgame/贪吃蛇/game-controls.js +++ b/InfoGenie-frontend/public/smallgame/贪吃蛇/game-controls.js @@ -6,28 +6,6 @@ class GameControls { } initControls() { - // 方向按钮控制 - document.getElementById('upBtn').addEventListener('click', () => { - this.game.changeDirection(0, -1); - }); - - document.getElementById('downBtn').addEventListener('click', () => { - this.game.changeDirection(0, 1); - }); - - document.getElementById('leftBtn').addEventListener('click', () => { - this.game.changeDirection(-1, 0); - }); - - document.getElementById('rightBtn').addEventListener('click', () => { - this.game.changeDirection(1, 0); - }); - - // 暂停/继续按钮 - document.getElementById('pauseBtn').addEventListener('click', () => { - this.game.togglePause(); - }); - // 重新开始按钮 document.getElementById('restartBtn').addEventListener('click', () => { this.game.restart(); @@ -46,62 +24,82 @@ class GameControls { this.game.restart(); } break; - case 'p': - case 'P': - this.game.togglePause(); - break; - case 'Escape': - if (this.game.gameOver) { - document.getElementById('gameOverModal').style.display = 'none'; - } - break; } }); } initTouchControls() { const canvas = document.getElementById('gameCanvas'); - let touchStartX = 0; - let touchStartY = 0; + let isDragging = false; + let lastTouchX = 0; + let lastTouchY = 0; + let lastDirectionChange = 0; + const directionChangeDelay = 200; // 防止方向变化过快 + // 触摸开始 canvas.addEventListener('touchstart', (e) => { - touchStartX = e.touches[0].clientX; - touchStartY = e.touches[0].clientY; + isDragging = true; + lastTouchX = e.touches[0].clientX; + lastTouchY = e.touches[0].clientY; e.preventDefault(); }, { passive: false }); + // 拖动过程中实时检测方向 canvas.addEventListener('touchmove', (e) => { - e.preventDefault(); - }, { passive: false }); - - canvas.addEventListener('touchend', (e) => { - const touchEndX = e.changedTouches[0].clientX; - const touchEndY = e.changedTouches[0].clientY; + if (!isDragging) return; - const deltaX = touchEndX - touchStartX; - const deltaY = touchEndY - touchStartY; - const minSwipeDistance = 30; - - if (Math.abs(deltaX) > Math.abs(deltaY)) { - // 水平滑动 - if (Math.abs(deltaX) > minSwipeDistance) { - if (deltaX > 0) { - this.game.changeDirection(1, 0); // 右滑 - } else { - this.game.changeDirection(-1, 0); // 左滑 - } - } - } else { - // 垂直滑动 - if (Math.abs(deltaY) > minSwipeDistance) { - if (deltaY > 0) { - this.game.changeDirection(0, 1); // 下滑 - } else { - this.game.changeDirection(0, -1); // 上滑 - } - } + const currentTime = Date.now(); + if (currentTime - lastDirectionChange < directionChangeDelay) { + e.preventDefault(); + return; } + const currentTouchX = e.touches[0].clientX; + const currentTouchY = e.touches[0].clientY; + + const deltaX = currentTouchX - lastTouchX; + const deltaY = currentTouchY - lastTouchY; + const minDragDistance = 20; // 最小拖动距离 + + // 检查是否达到最小拖动距离 + if (Math.abs(deltaX) > minDragDistance || Math.abs(deltaY) > minDragDistance) { + if (Math.abs(deltaX) > Math.abs(deltaY)) { + // 水平拖动 + if (deltaX > 0) { + this.game.changeDirection(1, 0); // 向右拖动 + } else { + this.game.changeDirection(-1, 0); // 向左拖动 + } + } else { + // 垂直拖动 + if (deltaY > 0) { + this.game.changeDirection(0, 1); // 向下拖动 + } else { + this.game.changeDirection(0, -1); // 向上拖动 + } + } + + // 更新最后触摸位置和方向变化时间 + lastTouchX = currentTouchX; + lastTouchY = currentTouchY; + lastDirectionChange = currentTime; + + // 添加触觉反馈 + this.vibrate(30); + } + + e.preventDefault(); + }, { passive: false }); + + // 触摸结束 + canvas.addEventListener('touchend', (e) => { + isDragging = false; + e.preventDefault(); + }, { passive: false }); + + // 触摸取消 + canvas.addEventListener('touchcancel', (e) => { + isDragging = false; e.preventDefault(); }, { passive: false }); @@ -111,8 +109,71 @@ class GameControls { e.preventDefault(); } }, { passive: false }); + + // 添加鼠标拖动支持(用于桌面测试) + this.initMouseDragControls(canvas); } + // 鼠标拖动控制(用于桌面测试) + initMouseDragControls(canvas) { + let isDragging = false; + let lastMouseX = 0; + let lastMouseY = 0; + let lastDirectionChange = 0; + const directionChangeDelay = 200; + + canvas.addEventListener('mousedown', (e) => { + isDragging = true; + lastMouseX = e.clientX; + lastMouseY = e.clientY; + e.preventDefault(); + }); + + canvas.addEventListener('mousemove', (e) => { + if (!isDragging) return; + + const currentTime = Date.now(); + if (currentTime - lastDirectionChange < directionChangeDelay) { + return; + } + + const currentMouseX = e.clientX; + const currentMouseY = e.clientY; + + const deltaX = currentMouseX - lastMouseX; + const deltaY = currentMouseY - lastMouseY; + const minDragDistance = 20; + + if (Math.abs(deltaX) > minDragDistance || Math.abs(deltaY) > minDragDistance) { + if (Math.abs(deltaX) > Math.abs(deltaY)) { + if (deltaX > 0) { + this.game.changeDirection(1, 0); // 向右拖动 + } else { + this.game.changeDirection(-1, 0); // 向左拖动 + } + } else { + if (deltaY > 0) { + this.game.changeDirection(0, 1); // 向下拖动 + } else { + this.game.changeDirection(0, -1); // 向上拖动 + } + } + + lastMouseX = currentMouseX; + lastMouseY = currentMouseY; + lastDirectionChange = currentTime; + } + }); + + canvas.addEventListener('mouseup', () => { + isDragging = false; + }); + + canvas.addEventListener('mouseleave', () => { + isDragging = false; + }); + } + // 震动反馈(移动端) vibrate(duration = 50) { if ('vibrate' in navigator) { diff --git a/InfoGenie-frontend/public/smallgame/贪吃蛇/game-core.js b/InfoGenie-frontend/public/smallgame/贪吃蛇/game-core.js index 46b5c8c1..faad209c 100755 --- a/InfoGenie-frontend/public/smallgame/贪吃蛇/game-core.js +++ b/InfoGenie-frontend/public/smallgame/贪吃蛇/game-core.js @@ -23,8 +23,7 @@ class SnakeGame { this.dy = 0; this.score = 0; this.level = 1; - this.gameSpeed = 10; // 初始速度 - this.isPaused = false; + this.gameSpeed = 6.5; // 初始速度 (10 * 0.65) this.gameOver = false; this.startTime = Date.now(); this.foodEaten = 0; @@ -43,7 +42,7 @@ class SnakeGame { // 监听键盘事件 document.addEventListener('keydown', (e) => { - if (this.isPaused || this.gameOver) return; + if (this.gameOver) return; switch(e.key) { case 'ArrowUp': @@ -201,7 +200,7 @@ class SnakeGame { const newLevel = Math.floor(this.foodEaten / 5) + 1; if (newLevel > this.level) { this.level = newLevel; - this.gameSpeed = Math.min(20, 10 + this.level); // 速度上限20 + this.gameSpeed = Math.min(13, 6.5 + this.level * 0.65); // 速度上限13 (20 * 0.65) } } @@ -297,17 +296,10 @@ class SnakeGame { } } - togglePause() { - this.isPaused = !this.isPaused; - document.getElementById('pauseBtn').textContent = this.isPaused ? '继续' : '暂停'; - - if (!this.isPaused && !this.gameOver) { - this.gameLoop(); - } - } + changeDirection(dx, dy) { - if (this.isPaused || this.gameOver) return; + if (this.gameOver) return; // 防止180度转弯 if ((this.dx !== 0 && dx !== 0) || (this.dy !== 0 && dy !== 0)) { @@ -319,18 +311,13 @@ class SnakeGame { } showGameOver() { - const modal = document.getElementById('gameOverModal'); + // 游戏结束时只记录最终状态,不显示弹窗 const gameTime = Math.floor((Date.now() - this.startTime) / 1000); - - document.getElementById('finalScore').textContent = this.score; - document.getElementById('finalLength').textContent = this.snake.length; - document.getElementById('finalLevel').textContent = this.level; - document.getElementById('gameTime').textContent = gameTime; - document.getElementById('foodEaten').textContent = this.foodEaten; - - modal.style.display = 'flex'; + console.log(`游戏结束! 分数: ${this.score}, 长度: ${this.snake.length}, 等级: ${this.level}, 时间: ${gameTime}秒`); } + + restart() { this.snake = [ {x: 10, y: 10}, @@ -341,8 +328,7 @@ class SnakeGame { this.dy = 0; this.score = 0; this.level = 1; - this.gameSpeed = 10; - this.isPaused = false; + this.gameSpeed = 6.5; this.gameOver = false; this.startTime = Date.now(); this.foodEaten = 0; @@ -351,9 +337,6 @@ class SnakeGame { this.generateFood(); this.updateUI(); - document.getElementById('gameOverModal').style.display = 'none'; - document.getElementById('pauseBtn').textContent = '暂停'; - this.gameLoop(); } } diff --git a/InfoGenie-frontend/public/smallgame/贪吃蛇/gamedata.js b/InfoGenie-frontend/public/smallgame/贪吃蛇/gamedata.js new file mode 100644 index 00000000..a00d422c --- /dev/null +++ b/InfoGenie-frontend/public/smallgame/贪吃蛇/gamedata.js @@ -0,0 +1,62 @@ +const playerdata = [ + { + "名称":"树萌芽", + "账号":"3205788256@qq.com", + "分数":1568, + "时间":"2025-09-08" + }, + { + "名称":"柚大青", + "账号":"2143323382@qq.com", + "分数":245, + "时间":"2025-09-21" + }, + { + "名称":"牛马", + "账号":"2973419538@qq.com", + "分数":1123, + "时间":"2025-09-25" + }, + { + "名称":"风行者", + "账号":"4456723190@qq.com", + "分数":1987, + "时间":"2025-09-30" + }, + { + "名称":"月光骑士", + "账号":"5832197462@qq.com", + "分数":876, + "时间":"2025-10-02" + }, + { + "名称":"星河", + "账号":"6724981532@qq.com", + "分数":1345, + "时间":"2025-10-05" + }, + { + "名称":"雷霆", + "账号":"7891234567@qq.com", + "分数":2105, + "时间":"2025-10-08" + }, + { + "名称":"火焰猫", + "账号":"8912345678@qq.com", + "分数":654, + "时间":"2025-10-10" + }, + { + "名称":"冰雪女王", + "账号":"9123456789@qq.com", + "分数":1789, + "时间":"2025-10-12" + }, + { + "名称":"😊", + "账号":"1125234890@qq.com", + "分数":1432, + "时间":"2025-10-15" + } +] \ No newline at end of file diff --git a/InfoGenie-frontend/public/smallgame/贪吃蛇/index.html b/InfoGenie-frontend/public/smallgame/贪吃蛇/index.html index 2302c8a5..4b1f20a0 100755 --- a/InfoGenie-frontend/public/smallgame/贪吃蛇/index.html +++ b/InfoGenie-frontend/public/smallgame/贪吃蛇/index.html @@ -23,37 +23,18 @@
- -
-
- - - -
-
- +
-

使用方向键或触摸按钮控制蛇的方向

+

使用方向键或拖动手势控制蛇的方向

- + + diff --git a/InfoGenie-frontend/public/smallgame/贪吃蛇/styles.css b/InfoGenie-frontend/public/smallgame/贪吃蛇/styles.css index edc0d223..217e45a3 100755 --- a/InfoGenie-frontend/public/smallgame/贪吃蛇/styles.css +++ b/InfoGenie-frontend/public/smallgame/贪吃蛇/styles.css @@ -6,7 +6,7 @@ body { font-family: 'Arial', sans-serif; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + background: linear-gradient(135deg, #a8e6cf 0%, #dcedc8 50%, #f1f8e9 100%); min-height: 100vh; display: flex; justify-content: center; @@ -16,13 +16,14 @@ body { } .game-container { - background: rgba(255, 255, 255, 0.95); + background: linear-gradient(135deg, #e8f5e8 0%, #f1f8e9 100%); border-radius: 20px; padding: 20px; - box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3); + box-shadow: 0 20px 40px rgba(46, 125, 50, 0.3); max-width: 400px; width: 95%; margin: 20px auto; + border: 1px solid rgba(46, 125, 50, 0.2); } .game-header { @@ -31,21 +32,22 @@ body { } .game-header h1 { - color: #333; + color: #1b5e20; font-size: 2.5rem; margin-bottom: 15px; - text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1); + text-shadow: 2px 2px 4px rgba(255, 255, 255, 0.5); } .score-board { display: flex; justify-content: space-around; - background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); + background: linear-gradient(135deg, #2e7d32 0%, #388e3c 100%); padding: 12px; border-radius: 15px; color: white; font-weight: bold; font-size: 1.1rem; + box-shadow: 0 4px 8px rgba(46, 125, 50, 0.2); } .score-board span { @@ -61,10 +63,10 @@ body { } #gameCanvas { - border: 3px solid #333; + border: 3px solid #2e7d32; border-radius: 10px; - background: #222; - box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2); + background: #1b5e20; + box-shadow: 0 8px 16px rgba(46, 125, 50, 0.3); } .game-controls { @@ -83,33 +85,32 @@ body { margin: 0 10px; border: none; border-radius: 50%; - background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); + background: linear-gradient(135deg, #4caf50 0%, #66bb6a 100%); color: white; font-size: 1.5rem; font-weight: bold; cursor: pointer; transition: all 0.3s ease; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); + box-shadow: 0 4px 8px rgba(46, 125, 50, 0.3); } .control-btn:hover { - transform: scale(1.1); - box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3); + box-shadow: 0 6px 12px rgba(46, 125, 50, 0.4); } .control-btn:active { - transform: scale(0.95); + box-shadow: 0 2px 4px rgba(46, 125, 50, 0.2); } #pauseBtn { - background: linear-gradient(135deg, #ff9a9e 0%, #fad0c4 100%); - color: #333; + background: linear-gradient(135deg, #81c784 0%, #a5d6a7 100%); + color: #1b5e20; font-size: 1.2rem; } .game-instructions { text-align: center; - color: #666; + color: #2e7d32; font-size: 0.9rem; margin-top: 15px; } @@ -121,41 +122,43 @@ body { left: 0; width: 100%; height: 100%; - background: rgba(0, 0, 0, 0.8); + background: rgba(46, 125, 50, 0.6); z-index: 1000; justify-content: center; align-items: center; } .modal-content { - background: white; + background: linear-gradient(135deg, #e8f5e8 0%, #f1f8e9 100%); padding: 30px; border-radius: 20px; text-align: center; max-width: 400px; width: 90%; - box-shadow: 0 20px 40px rgba(0, 0, 0, 0.4); + box-shadow: 0 20px 40px rgba(46, 125, 50, 0.4); + border: 1px solid rgba(46, 125, 50, 0.2); } .modal-content h2 { - color: #e74c3c; + color: #1b5e20; margin-bottom: 20px; font-size: 2rem; + text-shadow: 1px 1px 2px rgba(255, 255, 255, 0.5); } .stats p { margin: 10px 0; font-size: 1.1rem; - color: #333; + color: #2e7d32; } .stats span { font-weight: bold; - color: #e74c3c; + color: #1b5e20; } .restart-btn { - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + background: linear-gradient(135deg, #2e7d32 0%, #388e3c 100%); color: white; border: none; padding: 15px 30px; @@ -165,11 +168,70 @@ body { cursor: pointer; margin-top: 20px; transition: all 0.3s ease; + box-shadow: 0 4px 8px rgba(46, 125, 50, 0.2); } .restart-btn:hover { - transform: scale(1.05); - box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3); + box-shadow: 0 8px 16px rgba(46, 125, 50, 0.3); +} + +/* 排行榜样式 */ +.leaderboard { + margin: 20px 0; + padding: 15px; + background: rgba(255, 255, 255, 0.3); + border-radius: 15px; + border: 1px solid rgba(46, 125, 50, 0.2); +} + +.leaderboard h3 { + color: #1b5e20; + margin-bottom: 15px; + font-size: 1.3rem; + text-align: center; +} + +.leaderboard-list { + display: flex; + flex-direction: column; + gap: 8px; +} + +.leaderboard-item { + display: flex; + justify-content: space-between; + align-items: center; + padding: 8px 12px; + background: rgba(255, 255, 255, 0.5); + border-radius: 10px; + font-size: 0.9rem; + transition: all 0.2s ease; +} + +.leaderboard-item.current-player { + background: linear-gradient(135deg, #ffeb3b 0%, #fff176 100%); + font-weight: bold; + border: 2px solid #f57f17; +} + +.leaderboard-item .rank { + font-weight: bold; + min-width: 30px; + text-align: left; +} + +.leaderboard-item .player-name { + flex: 1; + text-align: left; + margin-left: 10px; + color: #2e7d32; +} + +.leaderboard-item .player-score { + font-weight: bold; + color: #1b5e20; + min-width: 50px; + text-align: right; } /* 手机端优化 */ @@ -246,13 +308,4 @@ body { -ms-user-select: none; } -/* 动画效果 */ -@keyframes pulse { - 0% { transform: scale(1); } - 50% { transform: scale(1.05); } - 100% { transform: scale(1); } -} - -.score-board { - animation: pulse 2s infinite; -} \ No newline at end of file +/* 动画效果已删除 */ \ No newline at end of file diff --git a/InfoGenie-frontend/src/App.js b/InfoGenie-frontend/src/App.js index ae2d7115..5b736754 100755 --- a/InfoGenie-frontend/src/App.js +++ b/InfoGenie-frontend/src/App.js @@ -10,11 +10,14 @@ import Api60sPage from './pages/Api60sPage'; import SmallGamePage from './pages/SmallGamePage'; import AiModelPage from './pages/AiModelPage'; import UserProfilePage from './pages/UserProfilePage'; +import AboutPage from './pages/AboutPage'; // 公共组件 import Header from './components/Header'; import Navigation from './components/Navigation'; import Footer from './components/Footer'; +import ParticleEffect from './components/ParticleEffect'; +import ScrollToTop from './components/ScrollToTop'; // 上下文 import { UserProvider } from './contexts/UserContext'; @@ -39,6 +42,7 @@ function App() { return ( +
@@ -49,6 +53,7 @@ function App() { } /> } /> } /> + } /> } /> {/* 通配符路由 - 所有未匹配的路径都重定向到首页 */} } /> @@ -83,6 +88,9 @@ function App() { } }} /> + + {/* 全局粒子效果 */} + diff --git a/InfoGenie-frontend/src/components/Header.js b/InfoGenie-frontend/src/components/Header.js index 002a1e83..d9b414a1 100755 --- a/InfoGenie-frontend/src/components/Header.js +++ b/InfoGenie-frontend/src/components/Header.js @@ -1,7 +1,7 @@ import React, { useState } from 'react'; -import { Link, useNavigate } from 'react-router-dom'; +import { Link, useNavigate, useLocation } from 'react-router-dom'; import styled from 'styled-components'; -import { FiUser, FiMenu, FiX, FiLogOut } from 'react-icons/fi'; +import { FiUser, FiMenu, FiX, FiLogOut, FiInfo } from 'react-icons/fi'; import { useUser } from '../contexts/UserContext'; const HeaderContainer = styled.header` @@ -59,16 +59,48 @@ const Nav = styled.nav` } `; -const NavLink = styled(Link)` - color: rgba(255, 255, 255, 0.9); +const NavLink = styled(Link).withConfig({ + shouldForwardProp: (prop) => prop !== 'isActive' +})` + color: ${props => props.isActive ? 'white' : 'rgba(255, 255, 255, 0.9)'}; text-decoration: none; - padding: 8px 16px; - border-radius: 6px; - transition: all 0.2s ease; + padding: 10px 18px; + border-radius: 12px; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + position: relative; + font-weight: ${props => props.isActive ? '600' : '500'}; + background: ${props => props.isActive ? 'rgba(255, 255, 255, 0.2)' : 'transparent'}; + box-shadow: ${props => props.isActive ? '0 4px 12px rgba(0, 0, 0, 0.15)' : 'none'}; + transform: ${props => props.isActive ? 'translateY(-1px)' : 'translateY(0)'}; + + &::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(135deg, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0.1) 100%); + border-radius: 12px; + opacity: 0; + transition: opacity 0.3s ease; + z-index: -1; + } &:hover { - background: rgba(255, 255, 255, 0.1); + background: rgba(255, 255, 255, 0.15); color: white; + transform: translateY(-2px); + box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2); + + &::before { + opacity: 1; + } + } + + &:active { + transform: translateY(0); + transition: transform 0.1s ease; } `; @@ -194,20 +226,67 @@ const CloseButton = styled.button` cursor: pointer; `; -const MobileNavLink = styled(Link)` +const MobileNavLink = styled(Link).withConfig({ + shouldForwardProp: (prop) => prop !== 'isActive' +})` display: block; - color: #374151; + color: ${props => props.isActive ? '#4ade80' : '#374151'}; text-decoration: none; - padding: 12px 0; - border-bottom: 1px solid #f3f4f6; - transition: color 0.2s ease; + padding: 16px 20px; + margin: 4px 0; + border-radius: 12px; + border-bottom: none; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + position: relative; + font-weight: ${props => props.isActive ? '600' : '500'}; + background: ${props => props.isActive ? 'rgba(74, 222, 128, 0.1)' : 'transparent'}; + transform: ${props => props.isActive ? 'translateX(8px)' : 'translateX(0)'}; + + &::before { + content: ''; + position: absolute; + left: 0; + top: 50%; + transform: translateY(-50%); + width: ${props => props.isActive ? '4px' : '0'}; + height: 60%; + background: linear-gradient(135deg, #4ade80 0%, #22c55e 100%); + border-radius: 0 2px 2px 0; + transition: width 0.3s ease; + } + + &::after { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(135deg, rgba(74, 222, 128, 0.05) 0%, rgba(34, 197, 94, 0.05) 100%); + border-radius: 12px; + opacity: 0; + transition: opacity 0.3s ease; + z-index: -1; + } &:hover { color: #4ade80; + background: rgba(74, 222, 128, 0.08); + transform: translateX(12px); + box-shadow: 0 4px 12px rgba(74, 222, 128, 0.15); + + &::after { + opacity: 1; + } + + &::before { + width: 4px; + } } - &:last-child { - border-bottom: none; + &:active { + transform: translateX(6px); + transition: transform 0.1s ease; } `; @@ -215,6 +294,11 @@ const Header = () => { const { user, isLoggedIn, logout, getQQAvatar } = useUser(); const [isMenuOpen, setIsMenuOpen] = useState(false); const navigate = useNavigate(); + const location = useLocation(); + + const isActive = (path) => { + return location.pathname.startsWith(path); + }; const handleLogout = async () => { await logout(); @@ -240,10 +324,10 @@ const Header = () => { @@ -291,19 +375,22 @@ const Header = () => { - + 首页 - + 聚合应用 - + 休闲游戏 - + AI工具 - + + 关于 + + 个人中心 diff --git a/InfoGenie-frontend/src/components/Navigation.js b/InfoGenie-frontend/src/components/Navigation.js index a056e3cb..2a6b579f 100755 --- a/InfoGenie-frontend/src/components/Navigation.js +++ b/InfoGenie-frontend/src/components/Navigation.js @@ -37,33 +37,110 @@ const NavItem = styled(Link).withConfig({ align-items: center; text-decoration: none; color: ${props => props.isActive ? '#66bb6a' : '#6b7280'}; - transition: all 0.2s ease; - padding: 8px 12px; - border-radius: 12px; - min-width: 60px; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + padding: 10px 14px; + border-radius: 16px; + min-width: 64px; + position: relative; + overflow: hidden; + + /* 基础状态 */ + background: ${props => props.isActive + ? 'linear-gradient(135deg, rgba(102, 187, 106, 0.15), rgba(129, 199, 132, 0.1))' + : 'transparent'}; + box-shadow: ${props => props.isActive + ? '0 2px 8px rgba(102, 187, 106, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.3)' + : '0 0 0 rgba(0, 0, 0, 0)'}; + transform: ${props => props.isActive ? 'translateY(-2px)' : 'translateY(0)'}; + + /* 伪元素用于悬停效果 */ + &::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(135deg, rgba(102, 187, 106, 0.1), rgba(129, 199, 132, 0.05)); + opacity: 0; + transition: opacity 0.3s ease; + border-radius: 16px; + } &:hover { color: #66bb6a; - background: rgba(129, 199, 132, 0.1); + transform: translateY(-3px); + box-shadow: 0 4px 12px rgba(102, 187, 106, 0.25), + inset 0 1px 0 rgba(255, 255, 255, 0.4); + + &::before { + opacity: 1; + } + } + + &:active { + transform: translateY(-1px); + transition: all 0.1s ease; } .nav-icon { - font-size: 20px; - margin-bottom: 4px; - transition: transform 0.2s ease; + font-size: 22px; + margin-bottom: 6px; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + position: relative; + z-index: 1; + filter: ${props => props.isActive ? 'drop-shadow(0 1px 2px rgba(102, 187, 106, 0.3))' : 'none'}; } .nav-text { font-size: 11px; - font-weight: 500; + font-weight: ${props => props.isActive ? '600' : '500'}; line-height: 1; + position: relative; + z-index: 1; + text-shadow: ${props => props.isActive ? '0 1px 2px rgba(102, 187, 106, 0.2)' : 'none'}; } ${props => props.isActive && ` .nav-icon { - transform: scale(1.1); + transform: scale(1.15) rotate(5deg); + animation: bounce 0.6s ease; + } + + .nav-text { + animation: fadeInUp 0.4s ease 0.1s both; } `} + + &:hover .nav-icon { + transform: scale(1.2) rotate(-2deg); + } + + @keyframes bounce { + 0%, 20%, 53%, 80%, 100% { + transform: scale(1.15) rotate(5deg) translateY(0); + } + 40%, 43% { + transform: scale(1.15) rotate(5deg) translateY(-4px); + } + 70% { + transform: scale(1.15) rotate(5deg) translateY(-2px); + } + 90% { + transform: scale(1.15) rotate(5deg) translateY(-1px); + } + } + + @keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(4px); + } + to { + opacity: 1; + transform: translateY(0); + } + } `; const Navigation = () => { diff --git a/InfoGenie-frontend/src/components/ParticleEffect.js b/InfoGenie-frontend/src/components/ParticleEffect.js new file mode 100644 index 00000000..eb5ef372 --- /dev/null +++ b/InfoGenie-frontend/src/components/ParticleEffect.js @@ -0,0 +1,194 @@ +import React, { useEffect, useRef, useCallback, useMemo } from 'react'; +import styled from 'styled-components'; + +const ParticleContainer = styled.div` + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: 9999; + overflow: hidden; +`; + +const ParticleEffect = () => { + const containerRef = useRef(null); + const particleId = useRef(0); + + const colors = useMemo(() => [ + '#4caf50', '#81c784', '#a5d6a7', '#c8e6c9', + '#66bb6a', '#8bc34a', '#cddc39', '#ffeb3b', + '#ffc107', '#ff9800', '#ff5722', '#e91e63', + '#9c27b0', '#673ab7', '#3f51b5', '#2196f3', + '#03a9f4', '#00bcd4', '#009688', '#4caf50' + ], []); + + const createParticle = useCallback((x, y) => { + if (!containerRef.current) return; + + const particleCount = Math.random() * 8 + 6; // 6-14个粒子 + + for (let i = 0; i < particleCount; i++) { + const particle = document.createElement('div'); + particle.className = 'click-particle'; + particle.id = `particle-${particleId.current++}`; + + // 随机颜色 + const color = colors[Math.floor(Math.random() * colors.length)]; + + // 随机大小 + const size = Math.random() * 8 + 4; // 4-12px + + // 随机方向和距离 + const angle = (Math.PI * 2 * i) / particleCount + Math.random() * 0.5; + const distance = Math.random() * 100 + 50; // 50-150px + const dx = Math.cos(angle) * distance; + const dy = Math.sin(angle) * distance - Math.random() * 50; // 向上偏移 + + // 设置样式 + particle.style.cssText = ` + position: absolute; + left: ${x - size/2}px; + top: ${y - size/2}px; + width: ${size}px; + height: ${size}px; + background: ${color}; + border-radius: 50%; + pointer-events: none; + box-shadow: 0 0 6px ${color}40; + --dx: ${dx}px; + --dy: ${dy}px; + animation: particleAnimation 1.2s ease-out forwards; + z-index: 9999; + `; + + containerRef.current.appendChild(particle); + + // 动画结束后移除粒子 + setTimeout(() => { + if (particle && particle.parentNode) { + particle.parentNode.removeChild(particle); + } + }, 1200); + } + }, [colors]); + + const createRipple = useCallback((x, y) => { + if (!containerRef.current) return; + + const ripple = document.createElement('div'); + ripple.className = 'click-ripple'; + ripple.id = `ripple-${particleId.current++}`; + + const color = colors[Math.floor(Math.random() * colors.length)]; + + ripple.style.cssText = ` + position: absolute; + left: ${x}px; + top: ${y}px; + width: 0; + height: 0; + border-radius: 50%; + background: radial-gradient(circle, ${color}20 0%, transparent 70%); + border: 2px solid ${color}40; + pointer-events: none; + animation: rippleAnimation 0.8s ease-out forwards; + z-index: 9998; + transform: translate(-50%, -50%); + `; + + // 添加涟漪动画 + const style = document.createElement('style'); + style.textContent = ` + @keyframes rippleAnimation { + 0% { + width: 0; + height: 0; + opacity: 1; + } + 100% { + width: 100px; + height: 100px; + opacity: 0; + } + } + `; + + if (!document.querySelector('#ripple-animation-style')) { + style.id = 'ripple-animation-style'; + document.head.appendChild(style); + } + + containerRef.current.appendChild(ripple); + + setTimeout(() => { + if (ripple && ripple.parentNode) { + ripple.parentNode.removeChild(ripple); + } + }, 800); + }, [colors]); + + const handleClick = useCallback((event) => { + const x = event.clientX; + const y = event.clientY; + + // 创建粒子效果 + createParticle(x, y); + + // 创建涟漪效果 + createRipple(x, y); + }, [createParticle, createRipple]); + + useEffect(() => { + // 添加全局点击监听器 + document.addEventListener('click', handleClick); + + // 添加粒子动画样式 + const style = document.createElement('style'); + style.id = 'particle-animation-style'; + style.textContent = ` + @keyframes particleAnimation { + 0% { + transform: translate(0, 0) scale(1); + opacity: 1; + } + 100% { + transform: translate(var(--dx), var(--dy)) scale(0); + opacity: 0; + } + } + + .click-particle { + animation: particleAnimation 1.2s ease-out forwards; + } + + .click-ripple { + animation: rippleAnimation 0.8s ease-out forwards; + } + `; + + if (!document.querySelector('#particle-animation-style')) { + document.head.appendChild(style); + } + + return () => { + document.removeEventListener('click', handleClick); + + // 清理样式 + const existingStyle = document.querySelector('#particle-animation-style'); + if (existingStyle) { + existingStyle.remove(); + } + + const rippleStyle = document.querySelector('#ripple-animation-style'); + if (rippleStyle) { + rippleStyle.remove(); + } + }; + }, [handleClick]); + + return ; +}; + +export default ParticleEffect; \ No newline at end of file diff --git a/InfoGenie-frontend/src/components/ScrollToTop.js b/InfoGenie-frontend/src/components/ScrollToTop.js new file mode 100644 index 00000000..ea93fc0d --- /dev/null +++ b/InfoGenie-frontend/src/components/ScrollToTop.js @@ -0,0 +1,23 @@ +import { useEffect } from 'react'; +import { useLocation } from 'react-router-dom'; + +/** + * ScrollToTop 组件 + * 监听路由变化,在页面切换时自动滚动到顶部 + */ +function ScrollToTop() { + const { pathname } = useLocation(); + + useEffect(() => { + // 页面切换时滚动到顶部 + window.scrollTo({ + top: 0, + left: 0, + behavior: 'instant' // 立即滚动,不使用平滑动画 + }); + }, [pathname]); // 依赖于路径变化 + + return null; // 这个组件不渲染任何内容 +} + +export default ScrollToTop; \ No newline at end of file diff --git a/InfoGenie-frontend/src/config/StaticPageConfig.js b/InfoGenie-frontend/src/config/StaticPageConfig.js index 969631f7..2730467d 100755 --- a/InfoGenie-frontend/src/config/StaticPageConfig.js +++ b/InfoGenie-frontend/src/config/StaticPageConfig.js @@ -114,17 +114,21 @@ export const API_60S_CATEGORIES = [ apis: [ { title: '哔哩哔哩热搜榜', link: '/60sapi/热搜榜单/哔哩哔哩热搜榜/index.html', icon: '📺', IsShow: true }, { title: '抖音热搜榜', link: '/60sapi/热搜榜单/抖音热搜榜/index.html', icon: '🎵', IsShow: true }, + { title: '小红书热搜榜', link: '/60sapi/热搜榜单/小红书热点/index.html', icon: '📖', IsShow: true }, { title: '猫眼票房排行榜', link: '/60sapi/热搜榜单/猫眼票房排行榜/index.html', icon: '🎬', IsShow: true }, - { title: '头条热搜榜', link: '/60sapi/热搜榜单/头条热搜榜/index.html', icon: '📰', IsShow: true }, + { title: '猫眼电视收视率排行榜', link: '/60sapi/热搜榜单/猫眼电视收视排行/index.html', icon: '📺', IsShow: true }, + { title: '猫眼电影实时票房', link: '/60sapi/热搜榜单/猫眼电影实时票房/index.html', icon: '🎬', IsShow: true }, + { title: '猫眼网剧实时热搜榜', link: '/60sapi/热搜榜单/猫眼网剧实时热度/index.html', icon: '💻', IsShow: true }, + { title: '今日头条热搜榜', link: '/60sapi/热搜榜单/头条热搜榜/index.html', icon: '📰', IsShow: true }, { title: '网易云榜单', link: '/60sapi/热搜榜单/网易云榜单/index.html', icon: '🎶', IsShow: true }, { title: '微博热搜榜', link: '/60sapi/热搜榜单/微博热搜榜/index.html', icon: '📱', IsShow: true }, { title: '知乎热门话题', link: '/60sapi/热搜榜单/知乎热门话题/index.html', icon: '💡', IsShow: true }, - { title: 'Hacker News 榜单', link: '/60sapi/热搜榜单/Hacker News 榜单/index.html', icon: '💻', IsShow: true }, - { title: '小红书热点', link: '/60sapi/热搜榜单/小红书热点/index.html', icon: '📖', IsShow: true }, - { title: '百度实时热搜', link: '/60sapi/热搜榜单/百度实时热搜/index.html', icon: '🔍', IsShow: true }, - { title: '百度电视剧榜', link: '/60sapi/热搜榜单/百度电视剧榜/index.html', icon: '📺', IsShow: true }, + { title: 'HackerNews HotRanks', link: '/60sapi/热搜榜单/Hacker News 榜单/index.html', icon: '💻', IsShow: true }, + + { title: '百度实时热搜榜', link: '/60sapi/热搜榜单/百度实时热搜/index.html', icon: '🔍', IsShow: true }, + { title: '百度电视剧热搜榜', link: '/60sapi/热搜榜单/百度电视剧榜/index.html', icon: '📺', IsShow: true }, { title: '百度贴吧话题榜', link: '/60sapi/热搜榜单/百度贴吧话题榜/index.html', icon: '💬', IsShow: true }, - { title: '懂车帝热搜', link: '/60sapi/热搜榜单/懂车帝热搜/index.html', icon: '🚗', IsShow: true }, + { title: '懂车帝热搜榜', link: '/60sapi/热搜榜单/懂车帝热搜/index.html', icon: '🚗', IsShow: true }, ] }, { diff --git a/InfoGenie-frontend/src/config/env.js b/InfoGenie-frontend/src/config/env.js index 9913ea6d..770cd243 100644 --- a/InfoGenie-frontend/src/config/env.js +++ b/InfoGenie-frontend/src/config/env.js @@ -3,7 +3,8 @@ // 统一环境配置 const config = { - API_URL: 'https://infogenie.api.shumengya.top', + //API_URL: 'https://infogenie.api.shumengya.top', + API_URL: 'http://127.0.0.1:5002', // 确保本地开发环境正常工作 DEBUG: true, LOG_LEVEL: 'debug' }; diff --git a/InfoGenie-frontend/src/md/前端邮件功能测试指南.md b/InfoGenie-frontend/src/md/前端邮件功能测试指南.md deleted file mode 100755 index 61e8d9c1..00000000 --- a/InfoGenie-frontend/src/md/前端邮件功能测试指南.md +++ /dev/null @@ -1,118 +0,0 @@ -# 前端邮件功能测试指南 - -## 问题修复说明 - -### 修复的问题 -- **响应拦截器问题**:修复了 `api.js` 中响应拦截器直接返回 `response.data` 导致前端无法正确访问 `response.data.success` 的问题 -- **API响应格式不匹配**:现在前端代码可以正确处理后端返回的响应格式 - -### 修复内容 -在 `src/utils/api.js` 文件中: -```javascript -// 修复前 -api.interceptors.response.use( - (response) => { - return response.data; // 这里直接返回了data,导致前端无法访问response.data.success - }, - // ... -); - -// 修复后 -api.interceptors.response.use( - (response) => { - return response; // 现在返回完整的response对象 - }, - // ... -); -``` - -## 测试步骤 - -### 1. 启动服务 -确保以下服务正在运行: -- **后端服务**:`http://localhost:5000` -- **前端服务**:`http://localhost:3001` - -### 2. 测试注册功能 -1. 打开浏览器访问 `http://localhost:3001` -2. 点击登录按钮或直接访问 `/login` 页面 -3. 切换到「注册」标签 -4. 填写以下信息: - - **邮箱**:输入有效的QQ邮箱(如:your_qq@qq.com) - - **用户名**:输入用户名 - - **密码**:输入密码(至少6位) - - **确认密码**:再次输入相同密码 -5. 点击「发送验证码」按钮 -6. 检查是否显示成功提示:"验证码已发送到您的邮箱" -7. 检查邮箱是否收到验证码邮件 -8. 输入收到的验证码 -9. 点击「注册」按钮完成注册 - -### 3. 测试登录功能(验证码登录) -1. 在登录页面选择「验证码登录」 -2. 输入已注册的QQ邮箱 -3. 点击「发送验证码」按钮 -4. 检查是否显示成功提示 -5. 检查邮箱是否收到登录验证码 -6. 输入验证码并点击「登录」 - -### 4. 测试登录功能(密码登录) -1. 在登录页面选择「密码登录」 -2. 输入邮箱和密码 -3. 点击「登录」按钮 - -## 预期结果 - -### 成功的表现 -- ✅ 点击「发送验证码」后显示绿色成功提示 -- ✅ 倒计时正常显示(60秒) -- ✅ 邮箱收到格式正确的验证码邮件 -- ✅ 后端日志显示:"验证码邮件发送成功: your_email@qq.com" -- ✅ 验证码验证成功,注册/登录流程完整 - -### 失败的表现 -- ❌ 显示红色错误提示 -- ❌ 邮箱未收到验证码 -- ❌ 后端日志显示SMTP错误 - -## 技术细节 - -### API调用流程 -1. 前端调用 `authAPI.sendVerification(data)` -2. 请求发送到 `/api/auth/send-verification` -3. 后端处理邮件发送 -4. 返回响应格式:`{ success: true/false, message: "...", data: {...} }` -5. 前端通过 `response.data.success` 判断是否成功 - -### 环境变量要求 -确保后端设置了正确的环境变量: -```bash -MAIL_USERNAME=your_qq_email@qq.com -MAIL_PASSWORD=your_qq_auth_code -``` - -## 故障排除 - -### 如果仍然无法发送邮件 -1. 检查后端环境变量是否正确设置 -2. 确认QQ邮箱已开启SMTP服务并获取授权码 -3. 检查网络连接是否正常 -4. 查看浏览器开发者工具的Network标签,确认API请求状态 -5. 查看后端控制台日志,确认具体错误信息 - -### 常见错误 -- **535 Authentication failed**:QQ邮箱授权码错误 -- **Network Error**:前后端连接问题 -- **Timeout**:网络超时或SMTP服务器响应慢 - -## 注意事项 -- 仅支持QQ邮箱系列(qq.com、vip.qq.com、foxmail.com) -- 验证码有效期为10分钟 -- 同一邮箱60秒内只能发送一次验证码 -- 验证码最多尝试5次 - ---- - -**修复完成时间**:2025年9月2日 -**修复内容**:API响应拦截器格式问题 -**测试状态**:✅ 后端功能正常,前端API调用已修复 \ No newline at end of file diff --git a/InfoGenie-frontend/src/pages/AboutPage.js b/InfoGenie-frontend/src/pages/AboutPage.js new file mode 100644 index 00000000..20cab754 --- /dev/null +++ b/InfoGenie-frontend/src/pages/AboutPage.js @@ -0,0 +1,294 @@ +import React from 'react'; +import styled from 'styled-components'; +import { FiInfo, FiGlobe, FiDownload, FiStar, FiHeart } from 'react-icons/fi'; + +const AboutContainer = styled.div` + min-height: calc(100vh - 140px); + padding: 20px 0; + opacity: 0; + transform: translateY(20px); + animation: pageEnter 0.8s ease-out forwards; + + @keyframes pageEnter { + 0% { + opacity: 0; + transform: translateY(20px); + } + 100% { + opacity: 1; + transform: translateY(0); + } + } +`; + +const Container = styled.div` + max-width: 800px; + margin: 0 auto; + padding: 0 16px; +`; + +const PageHeader = styled.div` + text-align: center; + margin-bottom: 40px; +`; + +const PageTitle = styled.h1` + color: white; + font-size: 44.8px; + font-weight: 700; + margin-bottom: 10px; + text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3); + + @media (max-width: 768px) { + font-size: 33.6px; + } +`; + +const PageDescription = styled.p` + color: rgba(255, 255, 255, 0.8); + font-size: 18px; + max-width: 600px; + margin: 0 auto; +`; + +const AboutCard = styled.div` + background: rgba(255, 255, 255, 0.95); + border-radius: 20px; + padding: 40px; + box-shadow: 0 8px 32px rgba(168, 230, 207, 0.3); + backdrop-filter: blur(10px); + border: 1px solid rgba(168, 230, 207, 0.2); + margin-bottom: 24px; +`; + +const AppIcon = styled.div` + width: 100px; + height: 100px; + display: flex; + align-items: center; + justify-content: center; + margin: 0 auto 24px; + + img { + width: 100%; + height: 100%; + object-fit: contain; + border-radius: 8px; + } +`; + +const AppName = styled.h2` + font-size: 32px; + font-weight: bold; + color: #2e7d32; + text-align: center; + margin-bottom: 8px; +`; + +const AppVersion = styled.div` + text-align: center; + margin-bottom: 24px; +`; + +const VersionBadge = styled.span` + background: linear-gradient(135deg, #81c784 0%, #a5d6a7 100%); + color: white; + padding: 6px 16px; + border-radius: 20px; + font-size: 14px; + font-weight: 600; + box-shadow: 0 2px 8px rgba(129, 199, 132, 0.3); +`; + +const AppDescription = styled.p` + color: #4a4a4a; + font-size: 16px; + line-height: 1.6; + text-align: center; + margin-bottom: 32px; +`; + +const LinksSection = styled.div` + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 16px; + margin-bottom: 32px; +`; + +const LinkCard = styled.a` + background: rgba(129, 199, 132, 0.1); + border: 1px solid rgba(129, 199, 132, 0.3); + border-radius: 16px; + padding: 20px; + text-decoration: none; + color: inherit; + transition: all 0.3s ease; + display: flex; + align-items: center; + gap: 12px; + + &:hover { + transform: translateY(-2px); + box-shadow: 0 4px 16px rgba(129, 199, 132, 0.2); + background: rgba(129, 199, 132, 0.15); + border-color: #81c784; + } +`; + +const LinkIcon = styled.div` + width: 40px; + height: 40px; + background: linear-gradient(135deg, #81c784 0%, #a5d6a7 100%); + border-radius: 10px; + display: flex; + align-items: center; + justify-content: center; + color: white; + font-size: 18px; + flex-shrink: 0; +`; + +const LinkContent = styled.div` + flex: 1; +`; + +const LinkTitle = styled.div` + font-weight: 600; + color: #2e7d32; + margin-bottom: 4px; +`; + +const LinkUrl = styled.div` + font-size: 14px; + color: #666; + word-break: break-all; +`; + +const FeatureSection = styled.div` + margin-top: 32px; +`; + +const FeatureTitle = styled.h3` + font-size: 20px; + font-weight: bold; + color: #2e7d32; + margin-bottom: 16px; + display: flex; + align-items: center; + gap: 8px; +`; + +const FeatureList = styled.ul` + list-style: none; + padding: 0; + margin: 0; +`; + +const FeatureItem = styled.li` + color: #4a4a4a; + font-size: 14px; + margin-bottom: 8px; + padding-left: 20px; + position: relative; + + &:before { + content: '✓'; + position: absolute; + left: 0; + color: #10b981; + font-weight: bold; + } + + &:last-child { + margin-bottom: 0; + } +`; + +const FooterText = styled.div` + text-align: center; + color: #666; + font-size: 14px; + margin-top: 24px; + padding-top: 24px; + border-top: 1px solid rgba(129, 199, 132, 0.2); + display: flex; + align-items: center; + justify-content: center; + gap: 8px; +`; + +const AboutPage = () => { + return ( + + + + 关于我们 + + 了解万象口袋的更多信息和功能特色(,,・ω・,,) + + + + + + InfoGenie Logo + + + 万象口袋 + + + v2.2.3 + + + + 一款跨平台式聚合应用,集成了多种实用工具和娱乐功能, + 为用户提供便捷的一站式服务体验。 + + + + + + + + + Web端在线体验 + https://infogenie.shumengya.top + + + + + + + + + 最新版下载地址 + https://work.shumengya.top/#/work/InfoGenie + + + + + + + + 主要功能 + + + 聚合应用 - 提供天气预报,平台热搜,百度百科等实用工具 + 休闲游戏 - 迷你解压小游戏即点即玩 + AI工具 - AI翻译,AI写诗,文章转换功能体验 + 用户系统 - 个人中心、签到奖励等 + 跨平台 - 支持Web、Windows、Android平台使用 + 响应式设计 - 完美适配各种设备屏幕 + + + + + + 感谢您使用万象口袋,我们将持续为您提供更好的服务 + + + + + ); +}; + +export default AboutPage; \ No newline at end of file diff --git a/InfoGenie-frontend/src/pages/AiModelPage.js b/InfoGenie-frontend/src/pages/AiModelPage.js index 41cb4f81..548128aa 100755 --- a/InfoGenie-frontend/src/pages/AiModelPage.js +++ b/InfoGenie-frontend/src/pages/AiModelPage.js @@ -10,6 +10,20 @@ import api from '../utils/api'; const AiContainer = styled.div` min-height: calc(100vh - 140px); padding: 20px 0; + opacity: 0; + transform: translateY(20px); + animation: pageEnter 0.8s ease-out forwards; + + @keyframes pageEnter { + 0% { + opacity: 0; + transform: translateY(20px); + } + 100% { + opacity: 1; + transform: translateY(0); + } + } `; const Container = styled.div` @@ -25,7 +39,7 @@ const PageHeader = styled.div` const PageTitle = styled.h1` color: white; - font-size: 32px; + font-size: 44.8px; font-weight: 700; margin-bottom: 10px; text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3); @@ -35,7 +49,7 @@ const PageTitle = styled.h1` } @media (max-width: 768px) { - font-size: 24px; + font-size: 33.6px; } `; @@ -437,7 +451,7 @@ const AiModelPage = () => { 每次使用AI功能将消耗100萌芽币,无论成功与否。当萌芽币余额不足时,无法使用AI工具功能。

- 您可以通过每日签到获得300萌芽币。详细的萌芽币余额和使用记录将显示在各AI应用的右上角。 + 您可以通过每日签到获得300萌芽币。详细的萌芽币余额显示在个人中心页面。

)} diff --git a/InfoGenie-frontend/src/pages/Api60sPage.js b/InfoGenie-frontend/src/pages/Api60sPage.js index 488ad1e5..2a820b18 100755 --- a/InfoGenie-frontend/src/pages/Api60sPage.js +++ b/InfoGenie-frontend/src/pages/Api60sPage.js @@ -8,6 +8,20 @@ import { API_60S_CATEGORIES } from '../config/StaticPageConfig'; const Api60sContainer = styled.div` min-height: calc(100vh - 140px); padding: 20px 0; + opacity: 0; + transform: translateY(20px); + animation: pageEnter 0.8s ease-out forwards; + + @keyframes pageEnter { + 0% { + opacity: 0; + transform: translateY(20px); + } + 100% { + opacity: 1; + transform: translateY(0); + } + } `; const Container = styled.div` @@ -38,23 +52,89 @@ const Subtitle = styled.p` const CategorySection = styled.div` margin-bottom: 50px; + position: relative; + + &::before { + content: ''; + position: absolute; + top: -10px; + left: -20px; + right: -20px; + bottom: -20px; + background: linear-gradient(135deg, + rgba(255, 255, 255, 0.03) 0%, + rgba(255, 255, 255, 0.01) 50%, + rgba(0, 0, 0, 0.02) 100%); + border-radius: 20px; + pointer-events: none; + z-index: -1; + } `; const CategoryTitle = styled.h2` color: rgba(255, 255, 255, 0.95); font-size: 24px; font-weight: 600; - margin-bottom: 20px; + margin-bottom: 8px; display: flex; align-items: center; gap: 10px; - text-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); + text-shadow: + 0 2px 8px rgba(0, 0, 0, 0.2), + 0 1px 3px rgba(0, 0, 0, 0.3); + position: relative; + padding: 8px 0; + + &::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 60px; + height: 2px; + background: linear-gradient(90deg, + rgba(255, 255, 255, 0.6) 0%, + rgba(255, 255, 255, 0.2) 100%); + border-radius: 1px; + } +`; + +const CategoryDescription = styled.p` + color: rgba(255, 255, 255, 0.9); + font-size: 17px; + margin: 0 0 20px 0; + line-height: 1.4; + font-weight: 400; + text-shadow: 0 1px 4px rgba(0, 0, 0, 0.2); `; const CategoryGrid = styled.div` display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; + position: relative; + padding: 8px; + border-radius: 12px; + background: linear-gradient(135deg, + rgba(255, 255, 255, 0.02) 0%, + rgba(255, 255, 255, 0.01) 50%, + rgba(0, 0, 0, 0.01) 100%); + + &::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + border-radius: 12px; + background: linear-gradient(135deg, + rgba(255, 255, 255, 0.05) 0%, + transparent 50%, + rgba(0, 0, 0, 0.02) 100%); + pointer-events: none; + z-index: -1; + } @media (max-width: 1200px) { grid-template-columns: repeat(4, 1fr); @@ -69,24 +149,29 @@ const CategoryGrid = styled.div` @media (max-width: 600px) { grid-template-columns: repeat(2, 1fr); gap: 12px; + padding: 6px; } `; const ApiCard = styled.div` - background: rgba(255, 255, 255, 0.98); + background: linear-gradient(145deg, rgba(255, 255, 255, 0.98), rgba(248, 250, 252, 0.95)); border-radius: 16px; padding: 20px 16px; text-decoration: none; color: inherit; - transition: all 0.2s ease; - border: none; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + border: 1px solid rgba(255, 255, 255, 0.2); position: relative; overflow: hidden; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + box-shadow: + 0 2px 8px rgba(0, 0, 0, 0.1), + 0 1px 3px rgba(0, 0, 0, 0.08), + inset 0 1px 0 rgba(255, 255, 255, 0.6); cursor: pointer; min-height: 90px; display: flex; align-items: center; + backdrop-filter: blur(10px); @media (max-width: 768px) { padding: 16px 12px; @@ -101,16 +186,42 @@ const ApiCard = styled.div` right: 0; height: 3px; background: ${props => props.color || 'linear-gradient(135deg, #81c784 0%, #a5d6a7 100%)'}; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + } + + &::after { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(135deg, + rgba(255, 255, 255, 0.1) 0%, + rgba(255, 255, 255, 0.05) 50%, + rgba(0, 0, 0, 0.02) 100%); + pointer-events: none; + border-radius: 16px; } &:hover { - transform: translateY(-2px); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + transform: translateY(-3px) scale(1.02); + box-shadow: + 0 8px 25px rgba(0, 0, 0, 0.15), + 0 4px 12px rgba(0, 0, 0, 0.1), + inset 0 1px 0 rgba(255, 255, 255, 0.8), + 0 0 0 1px rgba(255, 255, 255, 0.3); + border-color: rgba(255, 255, 255, 0.4); + background: linear-gradient(145deg, rgba(255, 255, 255, 1), rgba(250, 252, 255, 0.98)); } &:active { - transform: translateY(0); - box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); + transform: translateY(-1px) scale(1.01); + box-shadow: + 0 4px 12px rgba(0, 0, 0, 0.12), + 0 2px 6px rgba(0, 0, 0, 0.08), + inset 0 2px 4px rgba(0, 0, 0, 0.06); + background: linear-gradient(145deg, rgba(245, 248, 250, 0.98), rgba(240, 245, 248, 0.95)); } `; @@ -126,6 +237,23 @@ const CardIcon = styled.div` color: ${props => props.color || '#66bb6a'}; margin-right: 10px; flex-shrink: 0; + position: relative; + padding: 4px; + border-radius: 6px; + background: linear-gradient(135deg, + rgba(255, 255, 255, 0.1) 0%, + rgba(255, 255, 255, 0.05) 100%); + box-shadow: + 0 1px 3px rgba(0, 0, 0, 0.1), + inset 0 1px 0 rgba(255, 255, 255, 0.2); + transition: all 0.2s ease; + + ${ApiCard}:hover & { + transform: scale(1.1); + box-shadow: + 0 2px 6px rgba(0, 0, 0, 0.15), + inset 0 1px 0 rgba(255, 255, 255, 0.3); + } `; const CardTitle = styled.h3` @@ -135,10 +263,17 @@ const CardTitle = styled.h3` margin: 0; flex: 1; line-height: 1.3; + text-shadow: 0 1px 2px rgba(255, 255, 255, 0.8); + transition: all 0.2s ease; @media (max-width: 768px) { font-size: 14px; } + + ${ApiCard}:hover & { + color: #1b5e20; + text-shadow: 0 1px 3px rgba(255, 255, 255, 0.9); + } `; const ExternalIcon = styled.div` @@ -146,6 +281,16 @@ const ExternalIcon = styled.div` color: #81c784; opacity: 0.7; flex-shrink: 0; + transition: all 0.2s ease; + padding: 2px; + border-radius: 4px; + + ${ApiCard}:hover & { + opacity: 1; + color: #4caf50; + background: rgba(255, 255, 255, 0.2); + transform: scale(1.1); + } `; @@ -222,6 +367,17 @@ const Api60sPage = () => { const [loading, setLoading] = useState(true); const [embeddedApi, setEmbeddedApi] = useState(null); + // 获取分类描述文字 + const getCategoryDescription = (categoryTitle) => { + const descriptions = { + '热搜榜单': '实时追踪各大平台热门话题,掌握最新网络动态和流行趋势', + '日更资讯': '每日精选优质内容,提供最新资讯和实用信息', + '实用功能': '集成多种便民工具,让生活和工作更加便捷高效', + '娱乐消遣': '轻松有趣的娱乐内容,为您的闲暇时光增添乐趣' + }; + return descriptions[categoryTitle] || ''; + }; + // 从配置文件获取60s API数据 const scanApiModules = async () => { try { @@ -299,6 +455,9 @@ const Api60sPage = () => { {category.icon} {category.title} + + {getCategoryDescription(category.title)} + {category.apis.map((api, apiIndex) => ( { { + // 确保iframe获得焦点以接收键盘事件 + e.target.focus(); + }} /> diff --git a/InfoGenie-frontend/src/pages/UserProfilePage.js b/InfoGenie-frontend/src/pages/UserProfilePage.js index 532dd248..58e8fa56 100755 --- a/InfoGenie-frontend/src/pages/UserProfilePage.js +++ b/InfoGenie-frontend/src/pages/UserProfilePage.js @@ -9,6 +9,20 @@ const ProfileContainer = styled.div` min-height: calc(100vh - 140px); padding: 20px 0; background: linear-gradient(135deg, rgba(74, 222, 128, 0.05) 0%, rgba(34, 197, 94, 0.05) 100%); + opacity: 0; + transform: translateY(20px); + animation: pageEnter 0.8s ease-out forwards; + + @keyframes pageEnter { + 0% { + opacity: 0; + transform: translateY(20px); + } + 100% { + opacity: 1; + transform: translateY(0); + } + } `; const Container = styled.div` @@ -24,13 +38,13 @@ const PageHeader = styled.div` const PageTitle = styled.h1` color: white; - font-size: 32px; + font-size: 44.8px; font-weight: 700; margin-bottom: 10px; text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3); @media (max-width: 768px) { - font-size: 24px; + font-size: 33.6px; } `; diff --git a/InfoGenie-frontend/src/styles/global.css b/InfoGenie-frontend/src/styles/global.css index 0decbff0..ffdca73a 100755 --- a/InfoGenie-frontend/src/styles/global.css +++ b/InfoGenie-frontend/src/styles/global.css @@ -317,16 +317,36 @@ .mb-5 { margin-bottom: 20px; } .mb-6 { margin-bottom: 24px; } -.pt-1 { padding-top: 4px; } -.pt-2 { padding-top: 8px; } -.pt-3 { padding-top: 12px; } -.pt-4 { padding-top: 16px; } -.pt-5 { padding-top: 20px; } -.pt-6 { padding-top: 24px; } +/* 粒子效果样式优化 */ +.click-particle { + will-change: transform, opacity; + animation-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94); + filter: blur(0.5px); +} -.pb-1 { padding-bottom: 4px; } -.pb-2 { padding-bottom: 8px; } -.pb-3 { padding-bottom: 12px; } -.pb-4 { padding-bottom: 16px; } -.pb-5 { padding-bottom: 20px; } -.pb-6 { padding-bottom: 24px; } +.click-ripple { + will-change: transform, opacity; + animation-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94); +} + +/* 为可点击元素添加更好的视觉反馈 */ +button, .btn, a, [role="button"] { + position: relative; + overflow: hidden; +} + +/* 优化粒子效果在不同背景下的显示 */ +@media (prefers-reduced-motion: reduce) { + .click-particle, + .click-ripple { + animation-duration: 0.3s; + } +} + +/* 高性能动画优化 */ +.click-particle, +.click-ripple { + transform: translateZ(0); + backface-visibility: hidden; + perspective: 1000px; +} diff --git a/InfoGenie-frontend/酷安热度榜/soc.py b/InfoGenie-frontend/酷安热度榜/soc.py deleted file mode 100755 index a0b20c26..00000000 --- a/InfoGenie-frontend/酷安热度榜/soc.py +++ /dev/null @@ -1,27 +0,0 @@ -import requests - -url = "https://api.coolapk.com/v6/page/dataList?url=%23%2Ftopic%2FtagList%3FfilterId%3D9%26keywords%3D%E6%89%8B%E6%9C%BA%E5%A4%84%E7%90%86%E5%99%A8%26ratingUI%3D1&title=SoC%E6%A6%9C&page=1&firstItem=132485" - -headers = { - 'User-Agent': "Dalvik/2.1.0 (Linux; U; Android 13; 23049RAD8C Build/TKQ1.221114.001) (#Build; Redmi; 23049RAD8C; TKQ1.221114.001 test-keys; 13) +CoolMarket/14.0.0-2401171-universal", - 'Connection': "Keep-Alive", - 'Accept-Encoding': "gzip", - 'X-Requested-With': "XMLHttpRequest", - 'X-Sdk-Int': "33", - 'X-Sdk-Locale': "zh-CN", - 'X-App-Id': "com.coolapk.market", - 'X-App-Token': "v3JDJ5JDEwJE5qaGpOemMyTUdRdllUWm1PVEZqWU8wemJjdWhNRHFEYm5URi84TG5yLnRnYkVjTVlWd2JD", - 'X-App-Version': "14.0.0", - 'X-App-Code': "2401171", - 'X-Api-Version': "14", - 'X-App-Device': "0UzMjlTZ1MWZyYDNlVTM3AyOzlXZr1CdzVGdgEDMw4CNxETMyIjLxE1SUByODhDRBJVO0AzMyAyOp1GZlJFI7kWbvFWaYByOgsDI7AyOhV2TqNXYVdWR3cXQ6hjZYNTWORkY5IXajZzbOl0bfpkaIVFR", - 'X-Dark-Mode': "1", - 'X-App-Channel': "yyb", - 'X-App-Mode': "universal", - 'X-App-Supported': "2401171", - 'Cookie': "ddid=763cdbda-df79-485a-b4ac-92df073f1df5" -} - -response = requests.get(url, headers=headers) - -print(response.text) \ No newline at end of file diff --git a/InfoGenie-frontend/酷安热度榜/性价比排行榜.py b/InfoGenie-frontend/酷安热度榜/性价比排行榜.py deleted file mode 100755 index 562bd7e7..00000000 --- a/InfoGenie-frontend/酷安热度榜/性价比排行榜.py +++ /dev/null @@ -1,27 +0,0 @@ -import requests - -url = "https://api.coolapk.com/v6/page/dataList?url=%23%2Fproduct%2FproductList%3Ftype%3Dcategory%26id%3D1000%26sortField%3Dv4_score_item_6_owner_average_score%26limitField%3Dv4_score_item_6_owner_total_count-200%3Brank_status-0-0%26ratingUI%3D1%26withConfigCard%3D1%26configCardExtraData%3D%257B%2522withRanking%2522%253A1%257D%26rightStyle%3Dtext%26rightBottomText%3D%E6%80%A7%E4%BB%B7%E6%AF%94%E5%88%86%26rightTopField%3Dv4_score_item_6_owner_average_score&title=%E6%80%A7%E4%BB%B7%E6%AF%94%E6%A6%9C&page=1&firstItem=4068" - -headers = { - 'User-Agent': "Dalvik/2.1.0 (Linux; U; Android 13; 23049RAD8C Build/TKQ1.221114.001) (#Build; Redmi; 23049RAD8C; TKQ1.221114.001 test-keys; 13) +CoolMarket/14.0.0-2401171-universal", - 'Connection': "Keep-Alive", - 'Accept-Encoding': "gzip", - 'X-Requested-With': "XMLHttpRequest", - 'X-Sdk-Int': "33", - 'X-Sdk-Locale': "zh-CN", - 'X-App-Id': "com.coolapk.market", - 'X-App-Token': "v3JDJ5JDEwJE5qaGpOemMxWldVdk9USmtaR1kzTXU3U3lLanVDVnJIR3RoMUdoNzhVT1dKNFlpdmxGL3l5", - 'X-App-Version': "14.0.0", - 'X-App-Code': "2401171", - 'X-Api-Version': "14", - 'X-App-Device': "0UzMjlTZ1MWZyYDNlVTM3AyOzlXZr1CdzVGdgEDMw4CNxETMyIjLxE1SUByODhDRBJVO0AzMyAyOp1GZlJFI7kWbvFWaYByOgsDI7AyOhV2TqNXYVdWR3cXQ6hjZYNTWORkY5IXajZzbOl0bfpkaIVFR", - 'X-Dark-Mode': "1", - 'X-App-Channel': "yyb", - 'X-App-Mode': "universal", - 'X-App-Supported': "2401171", - 'Cookie': "ddid=763cdbda-df79-485a-b4ac-92df073f1df5" -} - -response = requests.get(url, headers=headers) - -print(response.text) \ No newline at end of file diff --git a/InfoGenie-frontend/酷安热度榜/抓取酷安热度版.py b/InfoGenie-frontend/酷安热度榜/抓取酷安热度版.py deleted file mode 100755 index 448647c2..00000000 --- a/InfoGenie-frontend/酷安热度榜/抓取酷安热度版.py +++ /dev/null @@ -1,27 +0,0 @@ -import requests - -url = "https://api.coolapk.com/v6/page/dataList?url=%23%2Fproduct%2FhotProductList%3FhotType%3Dday%26withConfigCard%3D1%26configCardExtraData%3D%257B%2522withRanking%2522%253A1%257D&title=%E7%83%AD%E5%BA%A6%E6%A6%9C&page=1&firstItem=4283" - -headers = { - 'User-Agent': "Dalvik/2.1.0 (Linux; U; Android 13; 23049RAD8C Build/TKQ1.221114.001) (#Build; Redmi; 23049RAD8C; TKQ1.221114.001 test-keys; 13) +CoolMarket/14.0.0-2401171-universal", - 'Connection': "Keep-Alive", - 'Accept-Encoding': "gzip", - 'X-Requested-With': "XMLHttpRequest", - 'X-Sdk-Int': "33", - 'X-Sdk-Locale': "zh-CN", - 'X-App-Id': "com.coolapk.market", - 'X-App-Token': "v3JDJ5JDEwJE5qaGpObVJpTkRZdk1EVTVORGxpTi5XNDFxTUdXQjVsRzB1NWdEY1pXdmJjQUMyWEFnRE1X", - 'X-App-Version': "14.0.0", - 'X-App-Code': "2401171", - 'X-Api-Version': "14", - 'X-App-Device': "0UzMjlTZ1MWZyYDNlVTM3AyOzlXZr1CdzVGdgEDMw4CNxETMyIjLxE1SUByODhDRBJVO0AzMyAyOp1GZlJFI7kWbvFWaYByOgsDI7AyOhV2TqNXYVdWR3cXQ6hjZYNTWORkY5IXajZzbOl0bfpkaIVFR", - 'X-Dark-Mode': "1", - 'X-App-Channel': "yyb", - 'X-App-Mode': "universal", - 'X-App-Supported': "2401171", - 'Cookie': "ddid=f8600b13-4ac2-4207-8541-9cec299202ac" -} - -response = requests.get(url, headers=headers) - -print(response.text) \ No newline at end of file diff --git a/InfoGenie-frontend/酷安热度榜/热度排行榜.py b/InfoGenie-frontend/酷安热度榜/热度排行榜.py deleted file mode 100755 index 4732a30b..00000000 --- a/InfoGenie-frontend/酷安热度榜/热度排行榜.py +++ /dev/null @@ -1,27 +0,0 @@ -import requests - -url = "https://api.coolapk.com/v6/page/dataList?url=%23%2Fproduct%2FhotProductList%3FhotType%3Dday%26withConfigCard%3D1%26configCardExtraData%3D%257B%2522withRanking%2522%253A1%257D&title=%E7%83%AD%E5%BA%A6%E6%A6%9C&page=1&firstItem=4283" - -headers = { - 'User-Agent': "Dalvik/2.1.0 (Linux; U; Android 13; 23049RAD8C Build/TKQ1.221114.001) (#Build; Redmi; 23049RAD8C; TKQ1.221114.001 test-keys; 13) +CoolMarket/14.0.0-2401171-universal", - 'Connection': "Keep-Alive", - 'Accept-Encoding': "gzip", - 'X-Requested-With': "XMLHttpRequest", - 'X-Sdk-Int': "33", - 'X-Sdk-Locale': "zh-CN", - 'X-App-Id': "com.coolapk.market", - 'X-App-Token': "v3JDJ5JDEwJE5qaGpOemMxTkRJdk1ERmpNemszT094SE5UZEpybXZXbjQ5bU03NlVBS1pTRi9nRzRxb0NL", - 'X-App-Version': "14.0.0", - 'X-App-Code': "2401171", - 'X-Api-Version': "14", - 'X-App-Device': "0UzMjlTZ1MWZyYDNlVTM3AyOzlXZr1CdzVGdgEDMw4CNxETMyIjLxE1SUByODhDRBJVO0AzMyAyOp1GZlJFI7kWbvFWaYByOgsDI7AyOhV2TqNXYVdWR3cXQ6hjZYNTWORkY5IXajZzbOl0bfpkaIVFR", - 'X-Dark-Mode': "1", - 'X-App-Channel': "yyb", - 'X-App-Mode': "universal", - 'X-App-Supported': "2401171", - 'Cookie': "ddid=763cdbda-df79-485a-b4ac-92df073f1df5" -} - -response = requests.get(url, headers=headers) - -print(response.text) \ No newline at end of file diff --git a/InfoGenie-frontend/酷安热度榜/系统排行榜.py b/InfoGenie-frontend/酷安热度榜/系统排行榜.py deleted file mode 100755 index cab58195..00000000 --- a/InfoGenie-frontend/酷安热度榜/系统排行榜.py +++ /dev/null @@ -1,27 +0,0 @@ -import requests - -url = "https://api.coolapk.com/v6/page/dataList?url=%23%2Ftopic%2FtagList%3FfilterId%3D3%26keywords%3DROM%26ratingUI%3D1&title=%E7%B3%BB%E7%BB%9F%E6%A6%9C&page=1&firstItem=128126" - -headers = { - 'User-Agent': "Dalvik/2.1.0 (Linux; U; Android 13; 23049RAD8C Build/TKQ1.221114.001) (#Build; Redmi; 23049RAD8C; TKQ1.221114.001 test-keys; 13) +CoolMarket/14.0.0-2401171-universal", - 'Connection': "Keep-Alive", - 'Accept-Encoding': "gzip", - 'X-Requested-With': "XMLHttpRequest", - 'X-Sdk-Int': "33", - 'X-Sdk-Locale': "zh-CN", - 'X-App-Id': "com.coolapk.market", - 'X-App-Token': "v3JDJ5JDEwJE5qaGpOemMxWXpndk9EUmtOekpoTnVlQUczTHV1dUh3QTN2ZVdWUlVWcmNiaE02aVRyS1pH", - 'X-App-Version': "14.0.0", - 'X-App-Code': "2401171", - 'X-Api-Version': "14", - 'X-App-Device': "0UzMjlTZ1MWZyYDNlVTM3AyOzlXZr1CdzVGdgEDMw4CNxETMyIjLxE1SUByODhDRBJVO0AzMyAyOp1GZlJFI7kWbvFWaYByOgsDI7AyOhV2TqNXYVdWR3cXQ6hjZYNTWORkY5IXajZzbOl0bfpkaIVFR", - 'X-Dark-Mode': "1", - 'X-App-Channel': "yyb", - 'X-App-Mode': "universal", - 'X-App-Supported': "2401171", - 'Cookie': "ddid=763cdbda-df79-485a-b4ac-92df073f1df5" -} - -response = requests.get(url, headers=headers) - -print(response.text) \ No newline at end of file