Fix PPT auto generation and analytics fallbacks
Some checks failed
CD Pipeline / deploy (push) Failing after 26s
Some checks failed
CD Pipeline / deploy (push) Failing after 26s
This commit is contained in:
@@ -2,159 +2,11 @@
|
||||
|
||||
{% block title %}PPT 視覺 QA 產線{% endblock %}
|
||||
|
||||
{% block ewooo_content %}
|
||||
<style>
|
||||
.ppt-hero, .ppt-panel, .ppt-table-shell {
|
||||
border: 1px solid var(--obs-line);
|
||||
border-radius: 26px;
|
||||
background: var(--obs-card);
|
||||
box-shadow: 0 16px 38px rgba(70, 46, 28, .08);
|
||||
}
|
||||
.ppt-hero {
|
||||
padding: 1.4rem;
|
||||
background: radial-gradient(circle at 12% 14%, rgba(201,100,66,.18), transparent 24rem),
|
||||
radial-gradient(circle at 88% 8%, rgba(79,111,143,.14), transparent 22rem),
|
||||
linear-gradient(135deg, rgba(255,248,239,.98), rgba(255,255,255,.74));
|
||||
}
|
||||
.ppt-kicker {
|
||||
color: var(--obs-accent);
|
||||
font-size: .76rem;
|
||||
letter-spacing: .13em;
|
||||
text-transform: uppercase;
|
||||
font-weight: 850;
|
||||
}
|
||||
.ppt-title {
|
||||
margin: .45rem 0 .25rem;
|
||||
font-family: var(--momo-font-display, "Inter", "Noto Sans TC", system-ui, sans-serif);
|
||||
font-size: var(--obs-title-size);
|
||||
letter-spacing: 0;
|
||||
line-height: .98;
|
||||
}
|
||||
.ppt-subtitle {
|
||||
color: var(--obs-muted);
|
||||
max-width: 860px;
|
||||
line-height: 1.7;
|
||||
}
|
||||
.ppt-command {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0,1fr));
|
||||
gap: .75rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.ppt-signal {
|
||||
padding: .95rem;
|
||||
border: 1px solid var(--obs-line);
|
||||
border-radius: 20px;
|
||||
background: rgba(255,255,255,.62);
|
||||
}
|
||||
.ppt-label {
|
||||
color: var(--obs-muted);
|
||||
font-size: .72rem;
|
||||
letter-spacing: .1em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.ppt-value {
|
||||
display: block;
|
||||
margin-top: .28rem;
|
||||
font-size: var(--obs-value-size);
|
||||
font-weight: 880;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
.ppt-toolbar {
|
||||
margin-top: 1rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: .75rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.ppt-type-tabs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: .45rem;
|
||||
}
|
||||
.ppt-type-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: .35rem;
|
||||
}
|
||||
.ppt-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0,1.2fr) minmax(330px,.8fr);
|
||||
gap: 1rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.ppt-stack { display: grid; gap: 1rem; }
|
||||
.ppt-panel-head, .ppt-table-title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
gap: 1rem;
|
||||
padding: 1.05rem 1.1rem .25rem;
|
||||
}
|
||||
.ppt-panel-title, .ppt-table-title h3 {
|
||||
margin: .15rem 0 0;
|
||||
font-size: 1.1rem;
|
||||
font-weight: 850;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
.ppt-panel-body {
|
||||
padding: 1rem 1.1rem 1.1rem;
|
||||
}
|
||||
.ppt-table-shell {
|
||||
overflow: hidden;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.ppt-table-shell .table {
|
||||
min-width: 760px;
|
||||
}
|
||||
.ppt-mini-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0,1fr));
|
||||
gap: .7rem;
|
||||
}
|
||||
.ppt-mini {
|
||||
padding: .85rem;
|
||||
border: 1px solid var(--obs-line);
|
||||
border-radius: 18px;
|
||||
background: rgba(255,255,255,.58);
|
||||
}
|
||||
.ppt-mini strong {
|
||||
display: block;
|
||||
margin-top: .24rem;
|
||||
font-size: 1.35rem;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
.fix-card {
|
||||
padding: .85rem;
|
||||
border: 1px solid var(--obs-line);
|
||||
border-radius: 18px;
|
||||
background: rgba(255,255,255,.58);
|
||||
margin-bottom: .7rem;
|
||||
}
|
||||
.status-good { color: var(--obs-green); }
|
||||
.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; }
|
||||
}
|
||||
@media(max-width:720px) {
|
||||
.ppt-command { grid-template-columns: 1fr; }
|
||||
}
|
||||
</style>
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/page-ppt-audit-history.css') }}">
|
||||
{% endblock %}
|
||||
|
||||
{% block ewooo_content %}
|
||||
{% import "admin/_observability_labels.html" as obs_label %}
|
||||
{% set report_is_daily = report_type == 'daily' %}
|
||||
|
||||
@@ -188,6 +40,13 @@
|
||||
</span>
|
||||
<small class="text-muted">視覺問題數</small>
|
||||
</div>
|
||||
<div class="ppt-signal">
|
||||
<div class="ppt-label">定義覆蓋</div>
|
||||
<span class="ppt-value {% if auto_generation.missing_count == 0 and auto_generation.total > 0 %}status-good{% elif auto_generation.missing_count > 0 %}status-warn{% else %}status-blue{% endif %}">
|
||||
{{ auto_generation.ready_count }}/{{ auto_generation.total }}
|
||||
</span>
|
||||
<small class="text-muted">自動簡報產線</small>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% if error %}<div class="alert alert-warning mt-3"><strong><i class="fas fa-triangle-exclamation me-1"></i></strong>{{ error }}</div>{% endif %}
|
||||
@@ -214,6 +73,40 @@
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
<section class="ppt-panel mt-3"
|
||||
data-ppt-auto-generation
|
||||
data-auto-start="{{ 'true' if auto_generation.can_auto_start else 'false' }}"
|
||||
data-report-types="{{ auto_generation_missing_report_types | join(',') }}">
|
||||
<div class="ppt-panel-head">
|
||||
<div>
|
||||
<div class="ppt-label">自動產生定義</div>
|
||||
<h2 class="ppt-panel-title">簡報產線覆蓋狀態</h2>
|
||||
</div>
|
||||
<button class="btn btn-sm btn-outline-primary" type="button" data-ppt-generate-missing {% if not auto_generation.enabled or auto_generation.missing_count == 0 %}disabled{% endif %}>
|
||||
<i class="fas fa-wand-magic-sparkles me-1" aria-hidden="true"></i>補齊缺漏簡報
|
||||
</button>
|
||||
</div>
|
||||
<div class="ppt-panel-body">
|
||||
<div class="ppt-auto-grid">
|
||||
{% for item in auto_generation_items %}
|
||||
<div class="ppt-mini">
|
||||
<span class="ppt-label">{{ item.label }}</span>
|
||||
<strong class="{% if item.ready %}status-good{% else %}status-warn{% endif %}">
|
||||
{{ '已產生' if item.ready else '待補齊' }}
|
||||
</strong>
|
||||
<small class="text-muted">{{ item.count }} 筆{% if item.sources %} · {{ item.sources|join(' + ') }}{% endif %}</small>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="ppt-auto-status small text-muted mt-3" data-ppt-auto-status>
|
||||
{% if auto_generation.enabled %}
|
||||
每日 20:30 會自動補齊定義簡報;目前缺漏 {{ auto_generation.missing_count }} 類。
|
||||
{% else %}
|
||||
PPT_AUTO_GENERATION_ENABLED=false,已停用自動補齊。
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="ppt-grid">
|
||||
<div class="ppt-stack">
|
||||
<article class="ppt-table-shell">
|
||||
@@ -245,7 +138,17 @@
|
||||
<td class="text-end">{{ "%.2f"|format(r.confidence) }}</td>
|
||||
<td class="text-end">{{ r.duration_ms }}</td>
|
||||
<td><small class="text-muted">{{ (r.error_msg or '')[:80] }}</small></td>
|
||||
<td>{% if r.audit_status in ('failed','error') %}<button class="btn btn-sm btn-outline-warning" onclick="triggerAiderHeal({{ r.pptx_filename|tojson }}, {{ (r.error_msg or '')|tojson }})"><i class="fas fa-wrench me-1"></i>AiderHeal</button>{% endif %}</td>
|
||||
<td>
|
||||
{% if r.audit_status in ('failed','error') %}
|
||||
<button class="btn btn-sm btn-outline-warning"
|
||||
type="button"
|
||||
data-ppt-aider-heal
|
||||
data-ppt-filename="{{ r.pptx_filename }}"
|
||||
data-ppt-error="{{ r.error_msg or '' }}">
|
||||
<i class="fas fa-wrench me-1"></i>AiderHeal
|
||||
</button>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr><td colspan="8" class="text-center text-muted">目前無 daily 審核歷史;請確認 {{ report_month }} 是否已完成 22:00 排程。</td></tr>
|
||||
|
||||
@@ -1,57 +1,5 @@
|
||||
{# 分析報表第二層分頁:保留頁面內容與圖表邏輯,只提供一致的報表切換入口。 #}
|
||||
{% set _analysis_active = active_page|default('') %}
|
||||
<style>
|
||||
.analysis-report-tabs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin: 0 0 18px;
|
||||
padding: 8px;
|
||||
border: 1px solid var(--momo-border-light, rgba(42, 37, 32, 0.16));
|
||||
border-radius: 8px;
|
||||
background: var(--momo-bg-elevated, #fdfaf2);
|
||||
box-shadow: var(--momo-shadow-md, 0 0 0 1px rgba(42, 37, 32, 0.10));
|
||||
}
|
||||
.analysis-report-tabs-spacer {
|
||||
flex: 1 1 auto;
|
||||
min-width: 8px;
|
||||
}
|
||||
.analysis-report-tab {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 7px;
|
||||
min-height: 34px;
|
||||
padding: 0 12px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 7px;
|
||||
color: var(--momo-text-secondary, #645c52);
|
||||
text-decoration: none;
|
||||
font-family: var(--momo-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif);
|
||||
font-size: var(--momo-text-body-sm, 13px);
|
||||
font-weight: 700;
|
||||
transition: background-color 160ms ease, border-color 160ms ease, color 160ms ease;
|
||||
}
|
||||
.analysis-report-tab:hover {
|
||||
border-color: var(--momo-border-light, rgba(42, 37, 32, 0.16));
|
||||
background: var(--momo-bg-surface, #faf7f0);
|
||||
color: var(--momo-text-primary, #2a2520);
|
||||
}
|
||||
.analysis-report-tab.is-active {
|
||||
border-color: var(--momo-page-accent-dark, #a95846);
|
||||
background: var(--momo-page-accent, #c89043);
|
||||
color: var(--momo-page-inverse, #fff8ef);
|
||||
}
|
||||
.analysis-report-tab.is-external {
|
||||
border-color: var(--momo-border-light, rgba(42, 37, 32, 0.16));
|
||||
background: var(--momo-bg-surface, #faf6ec);
|
||||
font-family: var(--momo-font-family-mono, "SF Mono", Menlo, Consolas, monospace);
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
.analysis-report-tab i {
|
||||
color: currentColor !important;
|
||||
}
|
||||
</style>
|
||||
<nav class="analysis-report-tabs" aria-label="分析報表分頁">
|
||||
<a class="analysis-report-tab {% if _analysis_active == 'sales' %}is-active{% endif %}"
|
||||
{% if _analysis_active == 'sales' %}aria-current="page"{% endif %}
|
||||
@@ -77,12 +25,12 @@
|
||||
<span class="analysis-report-tabs-spacer" aria-hidden="true"></span>
|
||||
{% endif %}
|
||||
{% if metabase_url %}
|
||||
<a class="analysis-report-tab is-external" href="{{ metabase_url }}" target="_blank" rel="noopener">
|
||||
<a class="analysis-report-tab is-external {% if _analysis_active == 'metabase' %}is-active{% endif %}" href="{{ metabase_url }}">
|
||||
<i class="fas fa-chart-pie"></i>Metabase <i class="fas fa-up-right-from-square"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if grist_url %}
|
||||
<a class="analysis-report-tab is-external" href="{{ grist_url }}" target="_blank" rel="noopener">
|
||||
<a class="analysis-report-tab is-external {% if _analysis_active == 'grist' %}is-active{% endif %}" href="{{ grist_url }}">
|
||||
<i class="fas fa-table"></i>Grist <i class="fas fa-up-right-from-square"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
@@ -82,12 +82,12 @@
|
||||
<i class="fas fa-table"></i><span>月份總表</span><span class="momo-nav-code">04</span>
|
||||
</a>
|
||||
{% if metabase_url %}
|
||||
<a class="momo-nav-sublink" href="{{ metabase_url }}" target="_blank" rel="noopener">
|
||||
<a class="momo-nav-sublink {% if _active_page == 'metabase' %}is-active{% endif %}" href="{{ metabase_url }}">
|
||||
<i class="fas fa-chart-pie"></i><span>自訂圖表</span><span class="momo-nav-code">外部</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if grist_url %}
|
||||
<a class="momo-nav-sublink" href="{{ grist_url }}" target="_blank" rel="noopener">
|
||||
<a class="momo-nav-sublink {% if _active_page == 'grist' %}is-active{% endif %}" href="{{ grist_url }}">
|
||||
<i class="fas fa-table-cells"></i><span>資料協作</span><span class="momo-nav-code">外部</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
@@ -201,17 +201,15 @@
|
||||
{% if metabase_url %}
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="{{ metabase_url }}" target="_blank">
|
||||
<a class="dropdown-item" href="{{ metabase_url }}">
|
||||
<i class="fas fa-chart-pie me-2"></i>自訂圖表 (Metabase)
|
||||
<i class="fas fa-external-link-alt ms-1 small text-muted"></i>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if grist_url %}
|
||||
<li>
|
||||
<a class="dropdown-item" href="{{ grist_url }}" target="_blank">
|
||||
<a class="dropdown-item" href="{{ grist_url }}">
|
||||
<i class="fas fa-table me-2"></i>資料協作 (Grist)
|
||||
<i class="fas fa-external-link-alt ms-1 small text-muted"></i>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
@@ -51,6 +51,25 @@
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro chart_snapshot(labels, values, mode='currency', limit=12) %}
|
||||
{% set total = labels|length %}
|
||||
<div class="chart-fallback-list">
|
||||
{% for label in labels %}
|
||||
{% if loop.index > total - limit %}
|
||||
{% set val = values[loop.index0]|default(0) %}
|
||||
<span class="chart-fallback-item">
|
||||
<b>{{ label }}</b>
|
||||
<strong>
|
||||
{% if mode == 'pct' %}{{ "{:+.1f}%".format(val) }}
|
||||
{% elif mode == 'number' %}{{ "{:,.0f}".format(val) }}
|
||||
{% else %}${{ "{:,.0f}".format(val) }}{% endif %}
|
||||
</strong>
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% block ewooo_content %}
|
||||
<div
|
||||
class="daily-sales-page"
|
||||
@@ -262,13 +281,13 @@
|
||||
<div class="col-lg-8">
|
||||
<div class="card chart-card">
|
||||
<div class="card-header"><i class="fas fa-chart-area"></i> 每日業績趨勢(近 30 天)</div>
|
||||
<div class="card-body"><div class="chart-container"><canvas id="trendChart"></canvas></div></div>
|
||||
<div class="card-body"><div class="chart-container has-html-chart"><canvas id="trendChart"></canvas>{{ chart_snapshot(chart_data.labels, chart_data.revenue, 'currency') }}</div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="card chart-card">
|
||||
<div class="card-header"><i class="fas fa-percentage"></i> 日成長率 (DoD %)</div>
|
||||
<div class="card-body"><div class="chart-container"><canvas id="dodChart"></canvas></div></div>
|
||||
<div class="card-body"><div class="chart-container has-html-chart"><canvas id="dodChart"></canvas>{{ chart_snapshot(chart_data.labels, chart_data.dod_revenue, 'pct') }}</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -278,7 +297,7 @@
|
||||
<div class="col-lg-8">
|
||||
<div class="card chart-card">
|
||||
<div class="card-header"><i class="fas fa-chart-bar"></i> 週成長對比 (WoW)</div>
|
||||
<div class="card-body"><div class="chart-container"><canvas id="wowChart"></canvas></div></div>
|
||||
<div class="card-body"><div class="chart-container has-html-chart"><canvas id="wowChart"></canvas>{{ chart_snapshot(chart_data.labels, chart_data.wow_revenue, 'pct') }}</div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
@@ -289,8 +308,9 @@
|
||||
<i class="fas fa-hand-pointer"></i> 左右滑動查看完整圖表
|
||||
</div>
|
||||
<div class="chart-responsive">
|
||||
<div class="chart-container" id="top10ChartContainer">
|
||||
<div class="chart-container has-html-chart" id="top10ChartContainer">
|
||||
<canvas id="top10Chart"></canvas>
|
||||
{{ chart_snapshot(chart_data.top10_labels, chart_data.top10_values, 'currency', 10) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -314,7 +334,7 @@
|
||||
<div class="col-lg-6 mb-4">
|
||||
<h6 class="marketing-subhead"><i class="fas fa-tags"></i> 折扣活動 Top 10</h6>
|
||||
{% if marketing_data.discount %}
|
||||
<div class="chart-container chart-container--md"><canvas id="discountChart"></canvas></div>
|
||||
<div class="chart-container chart-container--md has-html-chart"><canvas id="discountChart"></canvas>{{ chart_snapshot(marketing_data.discount['labels'], marketing_data.discount['values'], 'currency', 10) }}</div>
|
||||
{% else %}
|
||||
<div class="chart-empty"><i class="fas fa-info-circle"></i><p>暫無折扣活動數據</p></div>
|
||||
{% endif %}
|
||||
@@ -322,7 +342,7 @@
|
||||
<div class="col-lg-6 mb-4">
|
||||
<h6 class="marketing-subhead"><i class="fas fa-ticket-alt"></i> 折價券活動 Top 10</h6>
|
||||
{% if marketing_data.coupon %}
|
||||
<div class="chart-container chart-container--md"><canvas id="couponChart"></canvas></div>
|
||||
<div class="chart-container chart-container--md has-html-chart"><canvas id="couponChart"></canvas>{{ chart_snapshot(marketing_data.coupon['labels'], marketing_data.coupon['values'], 'currency', 10) }}</div>
|
||||
{% else %}
|
||||
<div class="chart-empty"><i class="fas fa-info-circle"></i><p>暫無折價券活動數據</p></div>
|
||||
{% endif %}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/ewoooc-tokens-v2-alias.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/ewoooc-shell.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/ewoooc-dotmatrix.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/analysis-report-tabs.css') }}">
|
||||
{% if active_page|default('') in [
|
||||
'obs_overview', 'obs_agent_orchestration', 'obs_business_intel',
|
||||
'obs_host_health', 'obs_ai_calls', 'obs_budget',
|
||||
@@ -49,7 +50,7 @@
|
||||
{# 群組映射 — Jinja 計算 [data-page-group] #}
|
||||
{% set _page = active_page|default('') %}
|
||||
{% set _group_monitor = ['dashboard', 'edm', 'campaigns'] %}
|
||||
{% set _group_analytics = ['sales', 'daily_sales', 'monthly', 'growth'] %}
|
||||
{% set _group_analytics = ['sales', 'daily_sales', 'monthly', 'growth', 'metabase', 'grist'] %}
|
||||
{% set _group_ops = ['vendor_stockout', 'auto_import', 'market_intel'] %}
|
||||
{% set _group_ai = ['ai_recommend', 'ai_history', 'ai_intelligence',
|
||||
'pchome_crawler', 'price_comparison', 'trends',
|
||||
|
||||
33
templates/external_tool_status.html
Normal file
33
templates/external_tool_status.html
Normal file
@@ -0,0 +1,33 @@
|
||||
{% extends "ewoooc_base.html" %}
|
||||
{% block title %}{{ tool.title }} - EwoooC{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/page-external-tools.css') }}">
|
||||
{% endblock %}
|
||||
|
||||
{% block ewooo_content %}
|
||||
<main class="external-tool-page" data-screen-label="{{ tool.key }}">
|
||||
<section class="external-tool-hero">
|
||||
<div>
|
||||
<div class="external-tool-eyebrow">
|
||||
<i class="fas fa-link" aria-hidden="true"></i>
|
||||
{{ tool.eyebrow }}
|
||||
</div>
|
||||
<h1>{{ tool.title }}</h1>
|
||||
<p>{{ tool.summary }}</p>
|
||||
</div>
|
||||
<span class="external-tool-status">{{ tool.status_label }}</span>
|
||||
</section>
|
||||
|
||||
<section class="external-tool-panel">
|
||||
<div class="external-tool-panel__body">
|
||||
<span class="external-tool-kicker">路由狀態</span>
|
||||
<h2>入口已由 momo-pro 接管</h2>
|
||||
<p>{{ tool.detail }}</p>
|
||||
</div>
|
||||
<a class="btn btn-primary" href="{{ tool.primary_href }}">
|
||||
<i class="fas fa-arrow-left" aria-hidden="true"></i>{{ tool.primary_label }}
|
||||
</a>
|
||||
</section>
|
||||
</main>
|
||||
{% endblock %}
|
||||
@@ -6,9 +6,23 @@
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/page-growth-bem.css') }}">
|
||||
{% endblock %}
|
||||
|
||||
{% macro ga_chart_snapshot(labels, values, mode='currency') %}
|
||||
<div class="ga-chart-snapshot">
|
||||
{% for label in labels %}
|
||||
{% set val = values[loop.index0]|default(0) %}
|
||||
<span class="ga-chart-snapshot__item">
|
||||
<b>{{ label }}</b>
|
||||
<strong>
|
||||
{% if mode == 'pct' %}{{ "{:+.1f}%".format(val) }}
|
||||
{% else %}${{ "{:,.0f}".format(val) }}{% endif %}
|
||||
</strong>
|
||||
</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% block ewooo_content %}
|
||||
<div class="momo-app" data-page-group="analytics">
|
||||
<div class="growth-analysis-page">
|
||||
<div class="growth-analysis-page" data-page-group="analytics">
|
||||
{% include 'components/_analysis_report_tabs.html' %}
|
||||
|
||||
{# ── Page head ──────────────────────────────────── #}
|
||||
@@ -67,8 +81,9 @@
|
||||
<header class="ga-chart-card__head">
|
||||
<span class="ga-chart-card__title"><i class="fas fa-chart-bar"></i> 月營收與年增率 (Revenue & YoY)</span>
|
||||
</header>
|
||||
<div class="ga-chart-card__body" style="--ga-chart-h: 350px;">
|
||||
<div class="ga-chart-card__body ga-chart-card__body--lg has-html-chart">
|
||||
<canvas id="revenueChart"></canvas>
|
||||
{{ ga_chart_snapshot(chart_data.labels, chart_data.revenue, 'currency') }}
|
||||
</div>
|
||||
</article>
|
||||
|
||||
@@ -76,8 +91,9 @@
|
||||
<header class="ga-chart-card__head">
|
||||
<span class="ga-chart-card__title"><i class="fas fa-percentage"></i> 月增率分析 (MoM)</span>
|
||||
</header>
|
||||
<div class="ga-chart-card__body" style="--ga-chart-h: 350px;">
|
||||
<div class="ga-chart-card__body ga-chart-card__body--lg has-html-chart">
|
||||
<canvas id="momChart"></canvas>
|
||||
{{ ga_chart_snapshot(chart_data.labels, chart_data.mom, 'pct') }}
|
||||
</div>
|
||||
</article>
|
||||
</section>
|
||||
@@ -88,8 +104,9 @@
|
||||
<header class="ga-chart-card__head">
|
||||
<span class="ga-chart-card__title"><i class="fas fa-wallet"></i> 平均單價趨勢</span>
|
||||
</header>
|
||||
<div class="ga-chart-card__body" style="--ga-chart-h: 300px;">
|
||||
<div class="ga-chart-card__body ga-chart-card__body--md has-html-chart">
|
||||
<canvas id="aovChart"></canvas>
|
||||
{{ ga_chart_snapshot(chart_data.labels, chart_data.aov, 'currency') }}
|
||||
</div>
|
||||
</article>
|
||||
|
||||
@@ -97,12 +114,12 @@
|
||||
<header class="ga-chart-card__head">
|
||||
<span class="ga-chart-card__title"><i class="fas fa-hand-holding-usd"></i> 獲利能力分析 (Gross Margin %)</span>
|
||||
</header>
|
||||
<div class="ga-chart-card__body" style="--ga-chart-h: 300px;">
|
||||
<div class="ga-chart-card__body ga-chart-card__body--md has-html-chart">
|
||||
<canvas id="marginChart"></canvas>
|
||||
{{ ga_chart_snapshot(chart_data.labels, chart_data.margin_rate, 'pct') }}
|
||||
</div>
|
||||
</article>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user