This commit is contained in:
@@ -2683,6 +2683,113 @@ def _build_ppt_pipeline_view(files, auto_generation, audit_stats, generation_run
|
||||
}
|
||||
|
||||
|
||||
def _build_ppt_operator_summary(files, auto_generation, pipeline_view, vision_status, audit_stats, generation_runs):
|
||||
"""Build first-screen operator copy that prioritizes deck work over raw pipeline states."""
|
||||
files = files or []
|
||||
auto_generation = auto_generation or {}
|
||||
pipeline_view = pipeline_view or {}
|
||||
vision_status = vision_status or {}
|
||||
audit_stats = audit_stats or {}
|
||||
generation_runs = generation_runs or []
|
||||
|
||||
latest_preview = next(
|
||||
(
|
||||
item for item in files
|
||||
if item.get('file_exists') and item.get('is_valid_ppt') and item.get('name')
|
||||
),
|
||||
None,
|
||||
)
|
||||
issue_count = int(audit_stats.get('total_issues') or 0) if audit_stats else 0
|
||||
missing_count = int(auto_generation.get('missing_count') or 0)
|
||||
valid_preview_count = int(pipeline_view.get('valid_preview_count') or 0)
|
||||
cached_preview_count = int(pipeline_view.get('cached_preview_count') or 0)
|
||||
audit_total = int(pipeline_view.get('audit_total') or 0)
|
||||
run_error_count = int(pipeline_view.get('run_error_count') or 0)
|
||||
broken_file_count = int(pipeline_view.get('broken_file_count') or 0)
|
||||
blockers = vision_status.get('blockers') or []
|
||||
|
||||
if run_error_count or broken_file_count:
|
||||
status = 'error'
|
||||
headline = '先處理異常,再放行簡報'
|
||||
message = f'目前有 {run_error_count} 筆產出失敗、{broken_file_count} 份檔案不可預覽,建議先看 Action Queue。'
|
||||
primary_action = '查看待處理'
|
||||
primary_anchor = '#ppt-action-queue'
|
||||
elif missing_count:
|
||||
status = 'partial'
|
||||
headline = '定期簡報尚未全數補齊'
|
||||
message = f'本期還有 {missing_count} 類定義簡報缺漏,可手動補齊或等待排程寫入 DB。'
|
||||
primary_action = '補齊缺漏'
|
||||
primary_anchor = '#ppt-production-center'
|
||||
elif not vision_status.get('ready'):
|
||||
status = 'partial'
|
||||
headline = '簡報可管理,視覺 QA 待啟用'
|
||||
message = 'PPT 產出與預覽入口仍可用;視覺模型、LibreOffice 或模型檔需補齊後才會自動審核。'
|
||||
primary_action = '查看就緒檢查'
|
||||
primary_anchor = '#ppt-runtime-diagnostic'
|
||||
elif issue_count:
|
||||
status = 'partial'
|
||||
headline = '有視覺問題待回放'
|
||||
message = f'本期視覺 QA 發現 {issue_count} 個問題,請從問題追蹤或審核歷史回放檢查。'
|
||||
primary_action = '查看問題'
|
||||
primary_anchor = '#ppt-issue-board'
|
||||
else:
|
||||
status = 'ready' if valid_preview_count else 'planned'
|
||||
headline = '簡報工作台待命'
|
||||
message = '最新簡報、PDF 預覽、DB 寫入與視覺 QA 都集中在同一頁追蹤。'
|
||||
primary_action = '查看簡報'
|
||||
primary_anchor = '#ppt-deck-workbench'
|
||||
|
||||
latest_run = generation_runs[0] if generation_runs else {}
|
||||
latest_deck_label = latest_preview.get('name') if latest_preview else '尚無可預覽 PPTX'
|
||||
latest_deck_meta = (
|
||||
f"{latest_preview.get('mtime') or '時間未知'} · "
|
||||
f"{latest_preview.get('size_kb') if latest_preview.get('size_kb') is not None else '—'} KB · "
|
||||
f"{'PDF 已快取' if latest_preview and latest_preview.get('preview_cache_ready') else '首次開啟轉檔'}"
|
||||
if latest_preview else
|
||||
'請先補齊本期簡報或切換月份 / 報表類型'
|
||||
)
|
||||
|
||||
return {
|
||||
'status': status,
|
||||
'headline': headline,
|
||||
'message': message,
|
||||
'primary_action': primary_action,
|
||||
'primary_anchor': primary_anchor,
|
||||
'latest_deck': latest_preview or {},
|
||||
'latest_deck_label': latest_deck_label,
|
||||
'latest_deck_meta': latest_deck_meta,
|
||||
'latest_run_label': latest_run.get('report_label') or latest_run.get('report_type') or '尚無 DB run',
|
||||
'latest_run_meta': latest_run.get('started_at') or '等待下一次排程寫入',
|
||||
'blocker_text': ';'.join(blockers[:2]) if blockers else '',
|
||||
'signals': [
|
||||
{
|
||||
'label': '可預覽簡報',
|
||||
'value': valid_preview_count,
|
||||
'meta': f'{cached_preview_count} 份 PDF 快取',
|
||||
'status': 'ready' if valid_preview_count else 'planned',
|
||||
},
|
||||
{
|
||||
'label': '待補齊定義',
|
||||
'value': missing_count,
|
||||
'meta': f"{auto_generation.get('ready_count', 0)}/{auto_generation.get('total', 0)} 已覆蓋",
|
||||
'status': 'ready' if missing_count == 0 and auto_generation.get('total') else 'partial',
|
||||
},
|
||||
{
|
||||
'label': '視覺 QA',
|
||||
'value': audit_total if audit_total else '待跑',
|
||||
'meta': '已就緒' if vision_status.get('ready') else 'runtime 待確認',
|
||||
'status': 'ready' if vision_status.get('ready') and not issue_count else 'partial',
|
||||
},
|
||||
{
|
||||
'label': '視覺問題',
|
||||
'value': issue_count,
|
||||
'meta': '需回放' if issue_count else '目前無待處理',
|
||||
'status': 'partial' if issue_count else 'ready',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def _enrich_ppt_coverage_items(auto_generation_items, files, generation_runs, audit_records):
|
||||
"""Join coverage rows with file, DB run, preview and QA state for the UI matrix."""
|
||||
files = files or []
|
||||
@@ -3312,6 +3419,14 @@ def ppt_audit_history():
|
||||
vision_status=vision_status,
|
||||
audit_records=audit_records,
|
||||
)
|
||||
operator_summary = _build_ppt_operator_summary(
|
||||
files=files,
|
||||
auto_generation=auto_generation,
|
||||
pipeline_view=pipeline_view,
|
||||
vision_status=vision_status,
|
||||
audit_stats=audit_30d_stats,
|
||||
generation_runs=generation_runs,
|
||||
)
|
||||
vision_audit_filenames = [
|
||||
item.get('name')
|
||||
for item in files
|
||||
@@ -3348,6 +3463,7 @@ def ppt_audit_history():
|
||||
auto_generation_missing_report_types=auto_generation.get('missing_report_types', []),
|
||||
generation_runs=generation_runs,
|
||||
pipeline_view=pipeline_view,
|
||||
operator_summary=operator_summary,
|
||||
vision_audit_filenames=vision_audit_filenames,
|
||||
issue_items=issue_items,
|
||||
issue_digest=issue_digest,
|
||||
|
||||
Reference in New Issue
Block a user