diff --git a/config.py b/config.py index d3d8673..b3a4e85 100644 --- a/config.py +++ b/config.py @@ -414,7 +414,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '') # ========================================== # 系統版本與路徑 # ========================================== -SYSTEM_VERSION = "V10.793" +SYSTEM_VERSION = "V10.794" LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log') public_url = PUBLIC_URL # 用於模板顯示 diff --git a/tests/test_pchome_same_item_reconciliation.py b/tests/test_pchome_same_item_reconciliation.py index aa0987c..50848ed 100644 --- a/tests/test_pchome_same_item_reconciliation.py +++ b/tests/test_pchome_same_item_reconciliation.py @@ -317,6 +317,7 @@ def test_dashboard_exposes_count_and_revenue_coverage_without_a_text_wall(): from pathlib import Path template = Path("templates/dashboard_v2.html").read_text(encoding="utf-8") + css = Path("web/static/css/page-dashboard-v2.css").read_text(encoding="utf-8") assert "業績比價覆蓋" in template assert "growth.comparison_revenue_coverage_rate | default(0)" in template @@ -324,6 +325,11 @@ def test_dashboard_exposes_count_and_revenue_coverage_without_a_text_wall(): assert "growth.comparison_ready_sales_7d" in template assert "growth.comparison_total_sales_7d" in template assert "growth.mapped_count" in template + assert ".growth-mapping-backlog {" in css + assert ".growth-mapping-backlog-grid {" in css + assert ".growth-automation-panel {" in css + assert ".growth-automation-steps {" in css + assert ".growth-automation-step {" in css def test_same_item_reconciliation_route_returns_durable_readback(monkeypatch): diff --git a/web/static/css/page-dashboard-v2.css b/web/static/css/page-dashboard-v2.css index a9aef71..277035e 100644 --- a/web/static/css/page-dashboard-v2.css +++ b/web/static/css/page-dashboard-v2.css @@ -163,6 +163,205 @@ background: color-mix(in srgb, var(--momo-ink) 42%, var(--momo-border-light)); } + .growth-mapping-backlog, + .growth-automation-panel { + display: grid; + gap: 12px; + min-width: 0; + padding: 13px 14px; + background: var(--momo-bg-surface); + border: 1px solid var(--momo-border-light); + border-radius: 8px; + box-shadow: var(--momo-shadow-soft); + } + + .growth-mapping-backlog { + grid-template-columns: minmax(190px, 0.42fr) minmax(0, 1.58fr); + align-items: center; + } + + .growth-mapping-backlog-head { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + gap: 3px 10px; + align-items: baseline; + min-width: 0; + } + + .growth-mapping-backlog-head strong { + color: var(--momo-text-primary); + font-size: 1.45rem; + font-weight: 900; + line-height: 1; + } + + .growth-mapping-backlog-head em { + grid-column: 1 / -1; + color: var(--momo-text-secondary); + font-size: 11px; + font-style: normal; + font-weight: 800; + } + + .growth-mapping-backlog-grid { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + min-width: 0; + } + + .growth-mapping-metric { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + gap: 3px 8px; + min-width: 0; + padding: 3px 12px; + border-left: 1px solid var(--momo-border-light); + } + + .growth-mapping-metric span, + .growth-automation-status span, + .growth-automation-step span { + min-width: 0; + overflow: hidden; + color: var(--momo-text-tertiary); + font-size: 10px; + font-weight: 900; + text-overflow: ellipsis; + white-space: nowrap; + } + + .growth-mapping-metric strong { + color: var(--momo-text-primary); + font-size: 1rem; + font-weight: 900; + line-height: 1; + } + + .growth-mapping-metric em { + grid-column: 1 / -1; + min-width: 0; + overflow: hidden; + color: var(--momo-text-secondary); + font-size: 10px; + font-style: normal; + font-weight: 800; + text-overflow: ellipsis; + white-space: nowrap; + } + + .growth-mapping-metric.is-needs { + border-left-color: var(--momo-danger); + } + + .growth-mapping-metric.is-review { + border-left-color: var(--momo-warning); + } + + .growth-mapping-metric.is-ready { + border-left-color: var(--momo-success); + } + + .growth-mapping-metric.is-auto { + border-left-color: var(--momo-warm-caramel); + } + + .growth-automation-panel { + grid-template-columns: minmax(230px, 0.52fr) minmax(0, 1.48fr); + } + + .growth-automation-panel > .growth-panel-head { + grid-column: 1 / -1; + margin-bottom: 0; + } + + .growth-automation-status { + grid-row: 2 / span 2; + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + gap: 5px 10px; + align-content: start; + min-width: 0; + padding: 10px 12px; + background: color-mix(in srgb, var(--momo-bg-paper) 76%, transparent); + border-left: 3px solid var(--momo-border-strong); + } + + .growth-automation-status strong { + color: var(--momo-text-primary); + font-size: 12px; + font-weight: 900; + } + + .growth-automation-status em { + grid-column: 1 / -1; + color: var(--momo-text-secondary); + font-size: 10px; + font-style: normal; + font-weight: 800; + line-height: 1.4; + } + + .growth-automation-status.is-success { + border-left-color: var(--momo-success); + } + + .growth-automation-status.is-warning { + border-left-color: var(--momo-warning); + } + + .growth-automation-status.is-danger { + border-left-color: var(--momo-danger); + } + + .growth-automation-steps { + grid-column: 2; + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 6px; + min-width: 0; + } + + .growth-automation-step { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + gap: 3px 8px; + min-width: 0; + padding: 7px 9px; + background: color-mix(in srgb, var(--momo-bg-paper) 72%, transparent); + border-left: 2px solid var(--momo-border-strong); + } + + .growth-automation-step strong { + color: var(--momo-text-primary); + font-size: 0.92rem; + font-weight: 900; + line-height: 1; + } + + .growth-automation-step em { + grid-column: 1 / -1; + min-width: 0; + overflow: hidden; + color: var(--momo-text-secondary); + font-size: 9px; + font-style: normal; + font-weight: 800; + text-overflow: ellipsis; + white-space: nowrap; + } + + .growth-automation-step.is-success { + border-left-color: var(--momo-success); + } + + .growth-automation-step.is-warning { + border-left-color: var(--momo-warning); + } + + .growth-automation-step.is-danger { + border-left-color: var(--momo-danger); + } + .growth-command-grid { display: grid; grid-template-columns: minmax(320px, 0.92fr) minmax(0, 1.35fr); @@ -2096,6 +2295,20 @@ } @media (max-width: 980px) { + .growth-mapping-backlog, + .growth-automation-panel { + grid-template-columns: 1fr; + } + + .growth-automation-status { + grid-column: 1; + grid-row: auto; + } + + .growth-automation-steps { + grid-column: 1; + } + .growth-command-head { align-items: stretch; flex-direction: column; @@ -2149,6 +2362,16 @@ } @media (max-width: 640px) { + .growth-mapping-backlog, + .growth-automation-panel { + padding: 12px; + } + + .growth-mapping-backlog-grid, + .growth-automation-steps { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + .growth-command-kpis, .growth-strategy-grid, .dashboard-kpi-grid,