diff --git a/routes/admin_observability_routes.py b/routes/admin_observability_routes.py index 92dadaa..027ee4c 100644 --- a/routes/admin_observability_routes.py +++ b/routes/admin_observability_routes.py @@ -19,7 +19,7 @@ Operation Ollama-First v5.0 / Phase 27 — Admin Observability Dashboard import logging from datetime import datetime, timedelta -from flask import Blueprint, render_template, request, jsonify +from flask import Blueprint, render_template, request, jsonify, send_file from sqlalchemy import text as sa_text from auth import login_required, get_current_user @@ -1836,6 +1836,40 @@ def ppt_audit_trigger_aider_heal(): return jsonify({'ok': False, 'error': f'{type(e).__name__}: {str(e)[:200]}'}), 500 +@admin_observability_bp.route('/ppt_audit_file/') +@login_required +def ppt_audit_file(filename: str): + """提供觀測台簡報檔案預覽/下載。 + + - action=view 開啟預覽(預設) + - action=download 直接下載 + """ + action = (request.args.get('action', 'view') or 'view').strip().lower() + try: + import os + from utils.security import safe_join + + reports_dir = os.environ.get('REPORTS_DIR', '/app/data/reports') + safe_path = safe_join(reports_dir, filename) + + if not safe_path.exists() or not safe_path.is_file(): + return '檔案不存在', 404 + + if safe_path.suffix.lower() != '.pptx': + return '不支援的檔案格式', 400 + + return send_file( + str(safe_path), + mimetype='application/vnd.openxmlformats-officedocument.presentationml.presentation', + as_attachment=(action == 'download'), + download_name=safe_path.name, + ) + except ValueError: + return '非法路徑', 400 + except Exception as e: + return f'{type(e).__name__}: {str(e)[:200]}', 500 + + @admin_observability_bp.route('/api/health_indicator') @login_required def health_indicator_api(): diff --git a/templates/admin/ppt_audit_history.html b/templates/admin/ppt_audit_history.html index 110a634..b53ffc8 100644 --- a/templates/admin/ppt_audit_history.html +++ b/templates/admin/ppt_audit_history.html @@ -136,6 +136,16 @@ .status-warn { color: var(--obs-amber); } .status-bad { color: var(--obs-red); } .status-blue { color: var(--obs-blue); } + .ppt-file-actions { + display: flex; + gap: .4rem; + flex-wrap: wrap; + } + .ppt-file-actions .btn { + display: inline-flex; + align-items: center; + gap: .3rem; + } @media(max-width:1100px) { .ppt-command, .ppt-mini-grid { grid-template-columns: repeat(2,minmax(0,1fr)); } .ppt-grid { grid-template-columns: 1fr; } @@ -266,7 +276,7 @@
- + {% for f in files %} @@ -275,9 +285,19 @@ + {% else %} - + {% endfor %}
檔名KB修改時間狀態
檔名KB修改時間狀態操作
{{ f.size_kb }} {{ f.mtime }} 22:00 排程掃描 + +
本月無 {{ selected_report_type.label }} 簡報
本月無 {{ selected_report_type.label }} 簡報