From ffbd494b7bec8d2ce85119c4621363facbcbd8b0 Mon Sep 17 00:00:00 2001 From: YueL1331 <358700404@qq.com> Date: Fri, 9 Jan 2026 12:48:50 +0800 Subject: [PATCH] =?UTF-8?q?=E6=89=93=E5=8C=85=E4=B8=8A=E4=BC=A0=E7=9A=842.?= =?UTF-8?q?0=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 2.1版本/app.py | 149 ------------- 2_1banben/app.py | 202 ++++++++++++++++++ {2.1版本 => 2_1banben}/config.py | 0 {2.1版本 => 2_1banben}/extensions.py | 0 {2.1版本 => 2_1banben}/models.py | 0 {2.1版本 => 2_1banben}/routes/__init__.py | 0 {2.1版本 => 2_1banben}/routes/api.py | 0 {2.1版本 => 2_1banben}/routes/web.py | 0 {2.1版本 => 2_1banben}/services/__init__.py | 0 {2.1版本 => 2_1banben}/services/core.py | 0 .../services/crawler_106.py | 0 .../services/crawler_82.py | 0 zhandianxinxi/光谱数据监控/.gitignore | 2 +- zhandianxinxi/光谱数据监控/src/App.vue | 49 +++-- 14 files changed, 240 insertions(+), 162 deletions(-) delete mode 100644 2.1版本/app.py create mode 100644 2_1banben/app.py rename {2.1版本 => 2_1banben}/config.py (100%) rename {2.1版本 => 2_1banben}/extensions.py (100%) rename {2.1版本 => 2_1banben}/models.py (100%) rename {2.1版本 => 2_1banben}/routes/__init__.py (100%) rename {2.1版本 => 2_1banben}/routes/api.py (100%) rename {2.1版本 => 2_1banben}/routes/web.py (100%) rename {2.1版本 => 2_1banben}/services/__init__.py (100%) rename {2.1版本 => 2_1banben}/services/core.py (100%) rename {2.1版本 => 2_1banben}/services/crawler_106.py (100%) rename {2.1版本 => 2_1banben}/services/crawler_82.py (100%) diff --git a/2.1版本/app.py b/2.1版本/app.py deleted file mode 100644 index 398a7e0..0000000 --- a/2.1版本/app.py +++ /dev/null @@ -1,149 +0,0 @@ -import os -import sys -import json -from datetime import datetime -from flask import Flask -from flask_apscheduler import APScheduler # ✅ 新增:定时任务控制器 -from extensions import db, cors -from models import Device, DeviceHistory, MaintenanceLog -from routes.api import api_bp - -# 尝试导入爬虫核心逻辑,以便定时任务调用 -try: - from services.core import execute_monitor_task -except ImportError: - execute_monitor_task = None - -# 解决 Windows 下控制台输出乱码问题 -sys.stdout.reconfigure(encoding='utf-8') - -# 初始化调度器 -scheduler = APScheduler() - - -def auto_monitor_job(app): - """定时任务执行逻辑""" - with app.app_context(): - print(f"⏰ [定时任务] 启动时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") - - if not execute_monitor_task: - print("❌ 错误: 找不到 services.core.execute_monitor_task 模块") - return - - try: - # 1. 执行爬取任务 - task_result = execute_monitor_task() - if not task_result: - print("⚠️ [定时任务] 爬虫未返回数据,跳过更新") - return - - scraped_list = task_result.get('device_list', []) - current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") - - # 2. 这里的逻辑需要和 api.py 保持高度一致(复用更新逻辑) - # 为了防止代码重复,建议以后将此逻辑封装在 services 里的一个独立函数中 - from routes.api import calculate_offset - - count = 0 - for item in scraped_list: - d_name = item.get('name') - if not d_name: continue - - device = Device.query.filter_by(name=d_name).first() - if not device: - device = Device(name=d_name, source=item.get('source'), install_site="") - db.session.add(device) - db.session.flush() - - # 更新动态字段 - device.status = item.get('status') - device.current_value = item.get('value') - device.latest_time = item.get('target_time') - device.check_time = current_time - device.json_data = json.dumps(item.get('raw_json', {}), ensure_ascii=False) - device.offset = calculate_offset(item.get('target_time')) - - # 记录历史 - db.session.add(DeviceHistory( - device_id=device.id, - status=device.status, - result_data=device.current_value, - data_time=item.get('target_time'), - json_data=device.json_data - )) - count += 1 - - db.session.commit() - print(f"✅ [定时任务] 成功自动更新 {count} 台设备数据") - - except Exception as e: - db.session.rollback() - print(f"❌ [定时任务] 运行出错: {str(e)}") - - -def create_app(): - app = Flask(__name__) - - # 1. 配置路径与数据库 - basedir = os.path.abspath(os.path.dirname(__file__)) - instance_path = os.path.join(basedir, 'instance') - if not os.path.exists(instance_path): - os.makedirs(instance_path) - - db_path = os.path.join(instance_path, 'devices.db') - app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{db_path}' - app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False - app.config['JSON_AS_ASCII'] = False - - # 定时任务配置 - app.config['SCHEDULER_API_ENABLED'] = True - app.config['SCHEDULER_TIMEZONE'] = "Asia/Shanghai" # 设置时区 - - # 2. 初始化插件 - cors.init_app(app) - db.init_app(app) - - # 3. 初始化并启动调度器 - scheduler.init_app(app) - - # 4. 注册定时任务:每天 10:00 运行 - # 如果你想测试是否生效,可以暂时把 hour=10 改为每隔一分钟运行一次:trigger='interval', minutes=1 - scheduler.add_job( - id='daily_crawl_task', - func=auto_monitor_job, - args=[app], - trigger='cron', - hour=10, - minute=0 - ) - - scheduler.start() - - # 5. 注册蓝图 - app.register_blueprint(api_bp) - - # 6. 初始化数据库表 - with app.app_context(): - db.create_all() - - return app - - -app = create_app() - - -@app.shell_context_processor -def make_shell_context(): - return { - 'db': db, - 'Device': Device, - 'DeviceHistory': DeviceHistory, - 'MaintenanceLog': MaintenanceLog - } - - -if __name__ == '__main__': - print("🚀 服务正在启动: http://127.0.0.1:5000") - print("⏰ 定时任务已就绪:每天 10:00 自动执行爬取") - # 注意:在生产环境中使用 debug=True 会导致调度器运行两次,建议生产环境设为 False - app.run(debug=False, host='0.0.0.0', port=5000) \ No newline at end of file diff --git a/2_1banben/app.py b/2_1banben/app.py new file mode 100644 index 0000000..228d884 --- /dev/null +++ b/2_1banben/app.py @@ -0,0 +1,202 @@ +import os +import sys +import json +import logging +import mimetypes +from datetime import datetime +from flask import Flask, send_from_directory, jsonify +from flask_cors import CORS +from flask_apscheduler import APScheduler + +# ============================================================================== +# ✅ 1. 核心模块引用 +# ============================================================================== +try: + # 数据库实例 (在根目录 extensions.py 中) + from extensions import db + + # 数据模型 (在根目录 models.py 中) + from models import Device, DeviceHistory, MaintenanceLog + + # 核心业务逻辑 (在 services/core.py 中) + from services.core import execute_monitor_task + + # 路由蓝图 (在 routes/api.py 中) + try: + from routes.api import api_bp as device_bp + except ImportError: + from routes.api import device_bp + + # 工具函数 (在 routes/api.py 中) + from routes.api import calculate_offset + +except ImportError as e: + print(f"❌ 严重错误: 模块导入失败。请检查文件名和变量名。详细信息: {e}") + print(f"系统路径: {sys.path}") + sys.exit(1) + + +# ============================================================================== +# 2. 路径计算模块 (兼容 PyInstaller 打包) +# ============================================================================== +def get_base_path(): + """获取运行时基准路径,兼容开发环境和打包环境""" + if getattr(sys, 'frozen', False): + if hasattr(sys, '_MEIPASS'): + return sys._MEIPASS # --onefile 模式 + else: + return os.path.dirname(os.path.abspath(sys.executable)) # --onedir 模式 + else: + return os.path.abspath(os.path.dirname(__file__)) + + +BASE_DIR = get_base_path() +STATIC_FOLDER = os.path.join(BASE_DIR, 'web_dist') +INSTANCE_FOLDER = os.path.join(BASE_DIR, 'instance') +DB_PATH = os.path.join(INSTANCE_FOLDER, 'devices.db') + +# 修复 Windows 下注册表 MIME 类型缺失导致网页白屏的问题 +mimetypes.add_type('application/javascript', '.js') +mimetypes.add_type('text/css', '.css') + +print(f"🚀 运行环境: {'Packaged' if getattr(sys, 'frozen', False) else 'Dev'}") +print(f"📂 基准路径: {BASE_DIR}") +print(f"💾 数据库路径: {DB_PATH}") + + +# ============================================================================== +# 3. 定时任务逻辑 +# ============================================================================== +def auto_monitor_job(app): + """定时任务具体执行逻辑""" + with app.app_context(): + print(f"⏰ [定时任务] 启动时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") + + if not execute_monitor_task: + print("❌ 错误: 无法加载爬虫核心模块 (execute_monitor_task is Missing)") + return + + try: + # 执行爬取 + task_result = execute_monitor_task() + if not task_result: + print("⚠️ [定时任务] 爬虫未获取到数据") + return + + scraped_list = task_result.get('device_list', []) + current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + + count = 0 + for item in scraped_list: + d_name = item.get('name') + if not d_name: continue + + # 查找或创建设备 + device = Device.query.filter_by(name=d_name).first() + if not device: + device = Device(name=d_name, source=item.get('source'), install_site="") + db.session.add(device) + db.session.flush() + + # 更新字段 + device.status = item.get('status') + device.current_value = item.get('value') + device.latest_time = item.get('target_time') + device.check_time = current_time + device.json_data = json.dumps(item.get('raw_json', {}), ensure_ascii=False) + device.offset = calculate_offset(item.get('target_time')) + + # 写入历史 + db.session.add(DeviceHistory( + device_id=device.id, + status=device.status, + result_data=device.current_value, + data_time=item.get('target_time'), + json_data=device.json_data + )) + count += 1 + + db.session.commit() + print(f"✅ [定时任务] 成功更新 {count} 台设备状态") + + except Exception as e: + db.session.rollback() + print(f"❌ [定时任务] 异常: {str(e)}") + + +# ============================================================================== +# 4. Flask 应用工厂 +# ============================================================================== +def create_app(): + # 🔴 关键修复:移除了 static_url_path='' + # 这样 Flask 就不会强制拦截所有根路径请求,让下面的 serve_static 有机会处理 /dashboard + app = Flask(__name__, static_folder=STATIC_FOLDER) + + CORS(app) + + # 确保 instance 目录存在 + if not os.path.exists(INSTANCE_FOLDER): + os.makedirs(INSTANCE_FOLDER, exist_ok=True) + + app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{DB_PATH}' + app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False + app.config['SCHEDULER_API_ENABLED'] = True + + # 初始化数据库 + db.init_app(app) + + # 初始化定时任务 + scheduler = APScheduler() + scheduler.init_app(app) + scheduler.start() + + # 添加定时任务 (每天 10:00) + scheduler.add_job( + id='daily_monitor_task', + func=auto_monitor_job, + args=[app], + trigger='cron', + hour=10, + minute=0 + ) + + # 注册蓝图 + app.register_blueprint(device_bp) + + # ------------------------------------------------- + # 前端路由支持 (Vue History Mode) + # ------------------------------------------------- + @app.route('/') + def serve_index(): + if not os.path.exists(os.path.join(app.static_folder, 'index.html')): + return "❌ 错误: 前端文件丢失 (web_dist/index.html)", 404 + return send_from_directory(app.static_folder, 'index.html') + + @app.route('/') + def serve_static(path): + # 1. 优先尝试直接返回实际存在的文件 (js, css, img等) + file_path = os.path.join(app.static_folder, path) + if os.path.exists(file_path): + return send_from_directory(app.static_folder, path) + + # 2. 如果是 API 请求但没找到对应接口,返回 404 JSON (不返回 HTML) + if path.startswith('api') or path.startswith('static'): + return jsonify({'code': 404, 'message': 'Not Found'}), 404 + + # 3. 关键逻辑: + # 访问 /dashboard 等前端路由时,文件系统中并没有 dashboard 这个文件 + # 所以会走到这里,返回 index.html,让 Vue 及其 Router 接管页面渲染 + return send_from_directory(app.static_folder, 'index.html') + + with app.app_context(): + db.create_all() + + return app + + +if __name__ == '__main__': + app = create_app() + # 生产环境/打包环境通常设为 False + debug_mode = not getattr(sys, 'frozen', False) + print("🚀 服务启动中...") + app.run(host='0.0.0.0', port=5000, debug=debug_mode, use_reloader=False) \ No newline at end of file diff --git a/2.1版本/config.py b/2_1banben/config.py similarity index 100% rename from 2.1版本/config.py rename to 2_1banben/config.py diff --git a/2.1版本/extensions.py b/2_1banben/extensions.py similarity index 100% rename from 2.1版本/extensions.py rename to 2_1banben/extensions.py diff --git a/2.1版本/models.py b/2_1banben/models.py similarity index 100% rename from 2.1版本/models.py rename to 2_1banben/models.py diff --git a/2.1版本/routes/__init__.py b/2_1banben/routes/__init__.py similarity index 100% rename from 2.1版本/routes/__init__.py rename to 2_1banben/routes/__init__.py diff --git a/2.1版本/routes/api.py b/2_1banben/routes/api.py similarity index 100% rename from 2.1版本/routes/api.py rename to 2_1banben/routes/api.py diff --git a/2.1版本/routes/web.py b/2_1banben/routes/web.py similarity index 100% rename from 2.1版本/routes/web.py rename to 2_1banben/routes/web.py diff --git a/2.1版本/services/__init__.py b/2_1banben/services/__init__.py similarity index 100% rename from 2.1版本/services/__init__.py rename to 2_1banben/services/__init__.py diff --git a/2.1版本/services/core.py b/2_1banben/services/core.py similarity index 100% rename from 2.1版本/services/core.py rename to 2_1banben/services/core.py diff --git a/2.1版本/services/crawler_106.py b/2_1banben/services/crawler_106.py similarity index 100% rename from 2.1版本/services/crawler_106.py rename to 2_1banben/services/crawler_106.py diff --git a/2.1版本/services/crawler_82.py b/2_1banben/services/crawler_82.py similarity index 100% rename from 2.1版本/services/crawler_82.py rename to 2_1banben/services/crawler_82.py diff --git a/zhandianxinxi/光谱数据监控/.gitignore b/zhandianxinxi/光谱数据监控/.gitignore index a547bf3..fd95c33 100644 --- a/zhandianxinxi/光谱数据监控/.gitignore +++ b/zhandianxinxi/光谱数据监控/.gitignore @@ -8,7 +8,7 @@ pnpm-debug.log* lerna-debug.log* node_modules -dist +web_dist dist-ssr *.local diff --git a/zhandianxinxi/光谱数据监控/src/App.vue b/zhandianxinxi/光谱数据监控/src/App.vue index 9ba6e9f..08cdc29 100644 --- a/zhandianxinxi/光谱数据监控/src/App.vue +++ b/zhandianxinxi/光谱数据监控/src/App.vue @@ -1,34 +1,59 @@ -