feat: add ppt file view/download actions in observability audit page
All checks were successful
CD Pipeline / deploy (push) Successful in 58s
All checks were successful
CD Pipeline / deploy (push) Successful in 58s
This commit is contained in:
@@ -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():
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user