fix: align stockout pages with supply risk UX
All checks were successful
CD Pipeline / deploy (push) Successful in 1m3s

This commit is contained in:
ogt
2026-06-26 19:03:15 +08:00
parent e76e05510c
commit fbce41cf02
7 changed files with 54 additions and 35 deletions

View File

@@ -402,7 +402,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '')
# ==========================================
# 系統版本與路徑
# ==========================================
SYSTEM_VERSION = "V10.716"
SYSTEM_VERSION = "V10.717"
LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log')
public_url = PUBLIC_URL # 用於模板顯示

View File

@@ -2,7 +2,7 @@
> **最後更新**: 2026-06-26 (台北時間)
> **狀態**: 🟢 四 AI Agent 自動化閉環已落地LLM 路由紅線升級為 Ollama-first 三主機級聯PChome 後台業績匯入韌性已補強產品定位正名為「PChome 業績成長自動化作戰系統」外部市場來源正規化層、自動同步、作戰清單與價格參考表優先讀取、CSV 備援預檢、前台操作入口、高可見頁面繁中化守門、比價/作戰 UI 工作台化、跨平台來源治理與商品身份 UI 契約已建立GCP embedding 熔斷延後處理、110 proxy rescue 與 direct host health skip 已建立
> **適用版本**: V10.716
> **適用版本**: V10.717
---
@@ -801,3 +801,4 @@ POSTGRES_HOST=momo-db
| 2026-06-26 | AI 銷售建議商品區塊必須商品身份優先 | V10.714 起 `/ai_recommend` 熱銷商品參考改為商品卡,後端 bestseller API 回傳平台、商品 ID、賣場連結與圖片欄位前端必須顯示縮圖、平台、商品 ID、價格與開賣場操作缺圖/缺連結需顯示待補狀態,並把商品 ID / URL 帶入銷售建議上下文。 |
| 2026-06-26 | AI 銷售建議前端不得保留 raw content 路徑 | V10.715 起 `/ai_recommend` 只使用已整理的外部訊號摘要與可用線索;搜尋或商品洞察結果若未整理成結構,前端只顯示可理解的待整理狀態,不再把 raw content 當上下文或 fallback 分支保留。 |
| 2026-06-26 | 首頁覆核候選必須標示為待確認商品 | V10.716 起首頁 PChome 覆核區不再使用「PChome 候選」作為可見主語統一改為「PChome 待確認商品」與「開 PChome 待確認商品」,避免使用者把未確認同款誤認為正式比價結果。 |
| 2026-06-26 | 供貨風險頁不得使用資料表或英文模組名作為主語 | V10.717 起缺貨清單與補貨通知頁統一使用「供貨風險、缺貨處理清單、補貨通知紀錄」等營運語言不再顯示「缺貨資料表、缺貨資料、Vendor Stockout」等資料庫或英文模組感文案。 |

View File

@@ -14,11 +14,11 @@
<section class="stockout-import-header">
<div>
<div class="stockout-import-eyebrow momo-mono">
<i class="fas fa-file-import"></i>STOCKOUT IMPORT
<i class="fas fa-file-import"></i>供貨風險匯入
</div>
<h1 class="stockout-import-title">Excel 匯入</h1>
<p class="stockout-import-subtitle">
補齊缺貨資料,先保住主推商品供貨。
補齊缺貨清單,先保住主推商品供貨。
</p>
<div class="stockout-import-actions is-header">
<a class="stockout-action" href="{{ url_for('vendor.index') }}">
@@ -30,8 +30,8 @@
</div>
</div>
<aside class="stockout-import-note">
<div class="stockout-import-note-label momo-mono">資料原則</div>
<div class="stockout-import-note-value">只匯入使用者上傳的正式 Excel不預填任何資料列</div>
<div class="stockout-import-note-label momo-mono">匯入原則</div>
<div class="stockout-import-note-value">只匯入正式 Excel不預填示範品項</div>
</aside>
</section>
@@ -54,9 +54,9 @@
<aside class="stockout-import-side">
<div class="stockout-import-card">
<div class="stockout-card-label momo-mono">必要資料</div>
<div class="stockout-card-label momo-mono">必要內容</div>
<div class="stockout-card-title">來源供應商編號、來源供應商名稱、商品ID、商品名稱</div>
<div class="stockout-card-meta momo-mono">缺少必要資料時,會先停止匯入並提示需補內容</div>
<div class="stockout-card-meta momo-mono">缺少必要內容時,會先停止匯入並提示需補項目</div>
</div>
<div class="stockout-import-card">
<div class="stockout-card-label momo-mono">匯入範本</div>

View File

@@ -47,7 +47,7 @@
<div class="stockout-kpi">
<div class="stockout-kpi-label momo-mono">已發送</div>
<div class="stockout-kpi-value momo-mono is-success">{{ stats.sent | number_format }}</div>
<div class="stockout-kpi-sub momo-mono">通知完成記錄</div>
<div class="stockout-kpi-sub momo-mono">已完成通知</div>
</div>
<div class="stockout-kpi">
<div class="stockout-kpi-label momo-mono">失敗</div>
@@ -106,10 +106,10 @@
href="{{ url_for('vendor.list_page', status='duplicate', q=search_query, batch=current_batch, sort=current_sort, page_size=page_size) }}">重複</a>
</nav>
<section class="stockout-table-card" aria-label="缺貨資料表">
<section class="stockout-table-card" aria-label="缺貨處理清單">
<div class="stockout-table-head">
<div>
<span class="stockout-table-title">缺貨資料</span>
<span class="stockout-table-title">供貨風險清單</span>
<span class="stockout-table-meta momo-mono">第 {{ current_page }} / {{ total_pages }} 頁</span>
</div>
<span class="stockout-table-meta momo-mono">{{ total_items | number_format }} 筆</span>
@@ -169,7 +169,7 @@
</div>
{% else %}
<div class="stockout-empty momo-mono">
目前沒有符合條件的缺貨資料;請調整篩選條件,或先匯入真實缺貨清單。
目前沒有符合條件的缺貨項目;請調整篩選條件,或先匯入真實缺貨清單。
</div>
{% endif %}

View File

@@ -1,5 +1,5 @@
{% extends "ewoooc_base.html" %}
{% block title %}郵件發送記- EwoooC{% endblock %}
{% block title %}補貨通知紀· EwoooC{% endblock %}
{% block extra_css %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/page-vendor-tools.css') }}">
{% endblock %}
@@ -8,8 +8,8 @@
<section class="vendor-tools-page" data-vendor-tool="email">
<header class="vendor-tools-header">
<div>
<span class="vendor-tools-kicker"><i class="fas fa-boxes-stacked"></i> Vendor Stockout</span>
<h1>郵件發送記</h1>
<span class="vendor-tools-kicker"><i class="fas fa-boxes-stacked"></i>供貨風險</span>
<h1>補貨通知紀</h1>
<p>先處理失敗通知,讓補貨協調不中斷。</p>
</div>
<div class="vendor-tools-nav" aria-label="廠商缺貨工具導覽">
@@ -27,10 +27,10 @@
<!-- 標題 -->
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="mb-0">
<i class="fas fa-paper-plane text-primary me-3"></i>郵件發送記
<i class="fas fa-paper-plane text-primary me-3"></i>補貨通知紀
</h2>
<a href="/vendor-stockout" class="btn btn-outline-secondary">
<i class="fas fa-home me-2"></i>返回主頁
<i class="fas fa-home me-2"></i>返回總覽
</a>
</div>
@@ -41,7 +41,7 @@
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<div>
<div class="text-muted small">發送</div>
<div class="text-muted small">通知總數</div>
<h3 class="mb-0" id="statTotal">0</h3>
</div>
<div class="fs-1 text-primary">
@@ -56,7 +56,7 @@
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<div>
<div class="text-muted small">成功</div>
<div class="text-muted small">已送達</div>
<h3 class="mb-0 text-success" id="statSuccess">0</h3>
</div>
<div class="fs-1 text-success">
@@ -132,20 +132,20 @@
</div>
</div>
<!-- 資料表格 -->
<!-- 通知清單 -->
<div class="table-container">
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>ID</th>
<th>批次編號</th>
<th>紀錄</th>
<th>批次</th>
<th>廠商</th>
<th>收件者</th>
<th>主旨</th>
<th>商品數</th>
<th>狀態</th>
<th>發送時間</th>
<th>通知時間</th>
</tr>
</thead>
<tbody id="tableBody">
@@ -161,7 +161,7 @@
<!-- 分頁 -->
<div class="d-flex justify-content-between align-items-center mt-3">
<div class="text-muted">
<span id="totalCount">0</span>記錄
<span id="totalCount">0</span>通知
</div>
<nav>
<ul class="pagination mb-0" id="pagination"></ul>

View File

@@ -1,5 +1,5 @@
{% extends "ewoooc_base.html" %}
{% block title %}廠商管理 - EwoooC{% endblock %}
{% block title %}供應商窗口 · EwoooC{% endblock %}
{% block extra_css %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/page-vendor-tools.css') }}">
{% endblock %}
@@ -8,16 +8,16 @@
<section class="vendor-tools-page" data-vendor-tool="management">
<header class="vendor-tools-header">
<div>
<span class="vendor-tools-kicker"><i class="fas fa-boxes-stacked"></i> Vendor Stockout</span>
<h1>廠商管理</h1>
<p>維護供應商與收件人,讓缺貨補救能快速送達。</p>
<span class="vendor-tools-kicker"><i class="fas fa-boxes-stacked"></i>供貨風險</span>
<h1>供應商窗口</h1>
<p>維護正確窗口,讓缺貨補救能快速送達。</p>
</div>
<div class="vendor-tools-nav" aria-label="廠商缺貨工具導覽">
<a href="/vendor-stockout/" ><i class="fas fa-table-columns"></i>總覽</a>
<a href="/vendor-stockout/list" ><i class="fas fa-list-check"></i>缺貨清單</a>
<a href="/vendor-stockout/import" ><i class="fas fa-file-arrow-up"></i>匯入</a>
<a href="/vendor-stockout/vendor-management" class="is-active" aria-current="page"><i class="fas fa-building"></i>廠商</a>
<a href="/vendor-stockout/send-email" ><i class="fas fa-paper-plane"></i>郵件記錄</a>
<a href="/vendor-stockout/send-email" ><i class="fas fa-paper-plane"></i>補貨通知</a>
<a href="/vendor-stockout/history" ><i class="fas fa-clock-rotate-left"></i>歷史</a>
</div>
</header>
@@ -25,7 +25,7 @@
<div class="vendor-tools-body">
<div class="container-fluid" style="padding: 2rem;">
<h2 class="mb-4">
<i class="fas fa-building me-2" style="color: var(--momo-page-accent-dark);"></i>廠商管理
<i class="fas fa-building me-2" style="color: var(--momo-page-accent-dark);"></i>供應商窗口
</h2>
<!-- 分頁標籤 -->
@@ -33,7 +33,7 @@
<ul class="nav nav-tabs" id="vendorTabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="list-tab" data-bs-toggle="tab" data-bs-target="#list" type="button">
<i class="fas fa-list me-2"></i>商清單
<i class="fas fa-list me-2"></i>供應商清單
</button>
</li>
<li class="nav-item" role="presentation">
@@ -52,7 +52,7 @@
<div class="col-md-4">
<div class="stats-card">
<div class="stats-number text-primary" style="font-size: 2rem; font-weight: bold;" id="totalVendors">0</div>
<div class="stats-label text-muted">總廠商數</div>
<div class="stats-label text-muted">供應商數</div>
</div>
</div>
<div class="col-md-4">
@@ -74,8 +74,8 @@
<div class="card-body">
<div class="row align-items-end">
<div class="col-md-4">
<label class="form-label">搜尋</label>
<input type="text" class="form-control" id="searchVendor" placeholder="輸入商代碼或名稱">
<label class="form-label">搜尋供應</label>
<input type="text" class="form-control" id="searchVendor" placeholder="輸入供應商代碼或名稱">
</div>
<div class="col-md-3">
<button class="btn btn-success" id="searchBtn">

View File

@@ -706,6 +706,9 @@ def test_utility_pages_keep_operator_copy_professional():
vendor_import_js = (ROOT / "web/static/js/page-vendor-import.js").read_text(encoding="utf-8")
stockout_index = (ROOT / "templates/vendor_stockout_index_v2.html").read_text(encoding="utf-8")
stockout_history = (ROOT / "templates/vendor_stockout_history_v2.html").read_text(encoding="utf-8")
stockout_list = (ROOT / "templates/vendor_stockout_list_v2.html").read_text(encoding="utf-8")
stockout_send_email = (ROOT / "templates/vendor_stockout_send_email_v2.html").read_text(encoding="utf-8")
stockout_vendor_management = (ROOT / "templates/vendor_stockout_vendor_management_v2.html").read_text(encoding="utf-8")
ai_calls = (ROOT / "templates/admin/ai_calls_dashboard.html").read_text(encoding="utf-8")
observability_labels = (ROOT / "templates/admin/_observability_labels.html").read_text(encoding="utf-8")
host_health = (ROOT / "templates/admin/host_health.html").read_text(encoding="utf-8")
@@ -724,6 +727,9 @@ def test_utility_pages_keep_operator_copy_professional():
vendor_import_js,
stockout_index,
stockout_history,
stockout_list,
stockout_send_email,
stockout_vendor_management,
ai_calls,
observability_labels,
host_health,
@@ -741,8 +747,20 @@ def test_utility_pages_keep_operator_copy_professional():
assert "送出後更新日報、成長分析與今日作戰清單" in auto_import
assert "等待系統更新任務狀態;若重複停在異常" in auto_import
assert "return raw ||" not in auto_import
assert "缺少必要資料時,會先停止匯入" in stockout_import
assert "供貨風險匯入" in stockout_import
assert "缺少必要內容時,會先停止匯入" in stockout_import
assert "缺貨資料" not in stockout_import
assert "STOCKOUT IMPORT" not in stockout_import
assert "先選擇供應商缺貨 Excel 檔。" in vendor_import_js
assert "供貨風險清單" in stockout_list
assert "缺貨處理清單" in stockout_list
assert "缺貨資料表" not in stockout_list
assert "補貨通知紀錄" in stockout_send_email
assert "供貨風險" in stockout_send_email
assert "Vendor Stockout" not in stockout_send_email
assert "供應商窗口" in stockout_vendor_management
assert "維護正確窗口" in stockout_vendor_management
assert "Vendor Stockout" not in stockout_vendor_management
assert "使用情境" in ai_calls
assert "全部使用情境" in ai_calls
assert "情境 × 知識命中矩陣" in ai_calls