feat: add ppt file view/download actions in observability audit page
All checks were successful
CD Pipeline / deploy (push) Successful in 58s

This commit is contained in:
OoO
2026-05-15 14:11:04 +08:00
parent 34b1fdf829
commit 40d4d01007
2 changed files with 57 additions and 3 deletions

View File

@@ -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/<path:filename>')
@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():

View File

@@ -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 @@
<div class="table-responsive">
<table class="table table-sm mb-0">
<thead class="table-light">
<tr><th>檔名</th><th class="text-end">KB</th><th>修改時間</th><th>狀態</th></tr>
<tr><th>檔名</th><th class="text-end">KB</th><th>修改時間</th><th>狀態</th><th>操作</th></tr>
</thead>
<tbody>
{% for f in files %}
@@ -275,9 +285,19 @@
<td class="text-end">{{ f.size_kb }}</td>
<td><small>{{ f.mtime }}</small></td>
<td><small class="text-muted">22:00 排程掃描</small></td>
<td>
<div class="ppt-file-actions">
<a class="btn btn-outline-primary btn-sm" href="{{ url_for('admin_observability.ppt_audit_file', filename=f.name) }}" target="_blank" rel="noopener">
<i class="fas fa-file-powerpoint me-1"></i>開啟
</a>
<a class="btn btn-outline-secondary btn-sm" href="{{ url_for('admin_observability.ppt_audit_file', filename=f.name, action='download') }}">
<i class="fas fa-download me-1"></i>下載
</a>
</div>
</td>
</tr>
{% else %}
<tr><td colspan="4" class="text-center text-muted">本月無 {{ selected_report_type.label }} 簡報</td></tr>
<tr><td colspan="5" class="text-center text-muted">本月無 {{ selected_report_type.label }} 簡報</td></tr>
{% endfor %}
</tbody>
</table>