Files
ewoooc/templates/components/_ewoooc_shell.html
OoO 849e189b60
All checks were successful
CD Pipeline / deploy (push) Successful in 2m37s
feat(p45): UI/UX 升級 ewoooc_base.html + sidebar AI 觀測 7 項 + 新增總覽頁
統帥質疑:「那六頁的視覺方格 UI/UX 搞好了嗎?還有新增頁面嗎?」
回答:沒有,從 Phase 38 開始一直推遲。本 commit 補做。

I-1: 6 頁 base.html → ewoooc_base.html
- host_health / ai_calls_dashboard / budget / promotion_review /
  quality_trend / ppt_audit_history 全改
- {% extends "base.html" %} → {% extends "ewoooc_base.html" %}
- {% block content %} → {% block ewooo_content %}
- 自動繼承:sidebar 240px / topbar 64px / fonts (Inter+JetBrains+Noto Sans TC)
  / ewoooc-tokens.css / ewoooc-shell.css / search box / 米色背景

I-2: _ewoooc_shell.html 加「AI 觀測」nav group
- 7 個項目:觀測台總覽 / 主機健康 / AI 呼叫 / 預算控管 /
  RAG 晉升審核 / 反饋趨勢 / PPT 視覺審核
- 對應 active_page='obs_*',正確高亮
- 編號 07-13(系統管理改 14)

I-3: 新增頁面 /observability/ + /observability/overview
- routes/admin_observability_routes.py::observability_overview
- 單頁聚合 8 表跨 JOIN 的 KPI:
  • 三主機 24h 在線率(host_health_probes,per host card)
  • AI 呼叫 24h(ai_calls:total/tokens/cost/error rate/RAG hit/cache hit)
  • 當月成本累計
  • 預算告警(ratio ≥ alert_pct 自動列表)
  • AIOps 7d(incidents + heal_logs:自癒成功率)
  • MCP 24h(mcp_calls:tool 呼叫 + cache 率 + cost)
  • RAG 學習 30d(learning_episodes:待審 + 晉升率)
  • PPT 視覺審核 7d(ppt_audit_results:通過率)
  • 6 大子頁入口卡(含一行說明)
- 對應 Phase 44 daily Telegram summary 的 web 版本
- 全部失敗安全(個別 query 失敗只跳過該卡,不擋整頁)

升級對應:
- UI 框架:base.html → ewoooc_base.html (sidebar + topbar + token css 已生效)
- 設計憲法:8 卡片 + 8 表跨 JOIN 全景 + 一頁式總覽
- 入口:sidebar 7 項 + 觀測台首頁
- 資料表覆蓋:4 表(Phase 38)→ 8 表(Phase 45)

注意:完整 design token 重塑(Bootstrap class → --momo-* token / 焦糖橘)
留待後續 phase;本 commit 重點是「框架升級 + 新總覽頁」。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 19:34:18 +08:00

141 lines
8.0 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{#
EwoooC Frontend V2 shell.
使用方式:
{% include 'components/_ewoooc_shell.html' %}
呼叫頁需提供 active_page未提供時會以空字串處理。
#}
{% set _active_page = active_page|default('') %}
{% set _scheduler = scheduler_stats|default({}) %}
{% set _momo_runs = _scheduler.get('momo_task', []) if _scheduler is mapping else [] %}
{% set _latest_run = _momo_runs[0] if _momo_runs else {} %}
{% set _has_scheduler_data = _latest_run is mapping and _latest_run %}
{% set _last_run = _latest_run.get('last_run', '--') if _has_scheduler_data else '--' %}
{% set _scanned = _latest_run.get('scanned_count', _latest_run.get('total_products', '--')) if _latest_run is mapping else '--' %}
{% set _added = _latest_run.get('new_records', _latest_run.get('added', '--')) if _latest_run is mapping else '--' %}
{% set _run_status = _latest_run.get('status', '') if _has_scheduler_data else '' %}
{% set _status_label = '尚無紀錄' if not _has_scheduler_data else ('最近成功' if _run_status in ['Success', 'success', 'SUCCESS'] else (_run_status or '已有紀錄')) %}
{% set _next_run = next_run|default(None) %}
{% set _session_username = session.get('username') if session is defined else None %}
{% set _session_role = session.get('role') if session is defined else None %}
{% set _is_logged_in = session.get('logged_in') if session is defined else false %}
<aside class="momo-sidebar" aria-label="主選單">
<a class="momo-sidebar-logo" href="/">
<span class="momo-logo-mark" aria-hidden="true">
<span></span><span></span><span></span>
<span></span><span></span><span></span>
<span></span><span></span><span></span>
</span>
<span class="momo-brand-word">
<span class="momo-brand-name momo-display">EwoooC</span>
<span class="momo-brand-subtitle momo-label">價格監控 V2</span>
</span>
</a>
<nav class="momo-nav momo-scroll">
<div class="momo-nav-group">
<div class="momo-nav-group-title momo-label">監控</div>
<a class="momo-nav-link {% if _active_page == 'dashboard' %}is-active{% endif %}" href="/">
<span class="momo-nav-icon"><i class="fas fa-border-all"></i></span>
<span class="momo-nav-label">商品看板</span>
<span class="momo-nav-code momo-mono">01</span>
</a>
<a class="momo-nav-link {% if _active_page in ['edm', 'campaigns'] %}is-active{% endif %}" href="/edm">
<span class="momo-nav-icon"><i class="fas fa-bullhorn"></i></span>
<span class="momo-nav-label">活動看板</span>
<span class="momo-nav-code momo-mono">02</span>
</a>
<a class="momo-nav-link {% if _active_page in ['sales', 'daily_sales', 'monthly', 'growth'] %}is-active{% endif %}" href="/sales_analysis">
<span class="momo-nav-icon"><i class="fas fa-chart-line"></i></span>
<span class="momo-nav-label">分析報表</span>
<span class="momo-nav-code momo-mono">03</span>
</a>
</div>
<div class="momo-nav-group">
<div class="momo-nav-group-title momo-label">營運</div>
<a class="momo-nav-link {% if _active_page == 'vendor_stockout' %}is-active{% endif %}" href="/vendor-stockout">
<span class="momo-nav-icon"><i class="fas fa-box-open"></i></span>
<span class="momo-nav-label">廠商缺貨</span>
<span class="momo-nav-code momo-mono">04</span>
</a>
<a class="momo-nav-link {% if _active_page in ['ai_recommend', 'ai_history', 'ai_intelligence'] %}is-active{% endif %}" href="/ai_recommend">
<span class="momo-nav-icon"><i class="fas fa-wand-magic-sparkles"></i></span>
<span class="momo-nav-label">AI 助手</span>
<span class="momo-nav-code momo-mono">05</span>
</a>
<a class="momo-nav-link {% if _active_page == 'auto_import' %}is-active{% endif %}" href="/auto_import">
<span class="momo-nav-icon"><i class="fas fa-download"></i></span>
<span class="momo-nav-label">雲端匯入</span>
<span class="momo-nav-code momo-mono">06</span>
</a>
</div>
<div class="momo-nav-group">
<div class="momo-nav-group-title momo-label">AI 觀測</div>
<a class="momo-nav-link {% if _active_page == 'obs_overview' %}is-active{% endif %}" href="/observability/overview">
<span class="momo-nav-icon"><i class="fas fa-satellite-dish"></i></span>
<span class="momo-nav-label">觀測台總覽</span>
<span class="momo-nav-code momo-mono">07</span>
</a>
<a class="momo-nav-link {% if _active_page == 'obs_host_health' %}is-active{% endif %}" href="/observability/host_health">
<span class="momo-nav-icon"><i class="fas fa-heartbeat"></i></span>
<span class="momo-nav-label">主機健康</span>
<span class="momo-nav-code momo-mono">08</span>
</a>
<a class="momo-nav-link {% if _active_page == 'obs_ai_calls' %}is-active{% endif %}" href="/observability/ai_calls">
<span class="momo-nav-icon"><i class="fas fa-chart-bar"></i></span>
<span class="momo-nav-label">AI 呼叫</span>
<span class="momo-nav-code momo-mono">09</span>
</a>
<a class="momo-nav-link {% if _active_page == 'obs_budget' %}is-active{% endif %}" href="/observability/budget">
<span class="momo-nav-icon"><i class="fas fa-wallet"></i></span>
<span class="momo-nav-label">預算控管</span>
<span class="momo-nav-code momo-mono">10</span>
</a>
<a class="momo-nav-link {% if _active_page == 'obs_promotion_review' %}is-active{% endif %}" href="/observability/promotion_review">
<span class="momo-nav-icon"><i class="fas fa-brain"></i></span>
<span class="momo-nav-label">RAG 晉升審核</span>
<span class="momo-nav-code momo-mono">11</span>
</a>
<a class="momo-nav-link {% if _active_page == 'obs_quality_trend' %}is-active{% endif %}" href="/observability/quality_trend">
<span class="momo-nav-icon"><i class="fas fa-comments"></i></span>
<span class="momo-nav-label">反饋趨勢</span>
<span class="momo-nav-code momo-mono">12</span>
</a>
<a class="momo-nav-link {% if _active_page == 'obs_ppt_audit' %}is-active{% endif %}" href="/observability/ppt_audit_history">
<span class="momo-nav-icon"><i class="fas fa-search"></i></span>
<span class="momo-nav-label">PPT 視覺審核</span>
<span class="momo-nav-code momo-mono">13</span>
</a>
</div>
<div class="momo-nav-group">
<div class="momo-nav-group-title momo-label">系統</div>
<a class="momo-nav-link {% if _active_page in ['settings', 'system_settings', 'logs', 'crawler', 'user_management', 'ai_automation_smoke'] %}is-active{% endif %}" href="/settings">
<span class="momo-nav-icon"><i class="fas fa-gear"></i></span>
<span class="momo-nav-label">系統管理</span>
<span class="momo-nav-code momo-mono">14</span>
</a>
</div>
</nav>
<div class="momo-status-card">
<div class="momo-status-title momo-label">爬蟲狀態</div>
<div class="momo-status-active momo-mono">
<span class="momo-live-dot"></span>
<span>{{ _status_label }}</span>
</div>
<div class="momo-status-meta momo-mono">
上次執行 {{ _last_run }}<br>
掃描筆數 {{ _scanned }}<br>
新增筆數 {% if _added == '--' %}--{% else %}+{{ _added }}{% endif %}
</div>
</div>
</aside>
<div class="momo-shell-backdrop" data-momo-sidebar-close></div>