fix: rename crawler UI to product monitoring
All checks were successful
CD Pipeline / deploy (push) Successful in 1m9s

This commit is contained in:
ogt
2026-06-26 18:08:14 +08:00
parent cb14c74b88
commit d2d798933a
15 changed files with 63 additions and 44 deletions

View File

@@ -402,7 +402,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '')
# ==========================================
# 系統版本與路徑
# ==========================================
SYSTEM_VERSION = "V10.710"
SYSTEM_VERSION = "V10.711"
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.710
> **適用版本**: V10.711
---
@@ -795,3 +795,4 @@ POSTGRES_HOST=momo-db
| 2026-06-26 | Telegram 告警不得因非支援 HTML 送出失敗 | V10.709 起 Telegram HTML 發送前只保留 Bot API 支援的 `<b>``<i>``<code>``<pre>``<a href="">` 等白名單標籤;`<httpconnection(...)>`、原始錯誤物件或其他未知標籤會轉成可讀文字,避免營運告警因 parse error 400 消失。 |
| 2026-06-26 | 部署前備份入口必須備到專案根目錄 | V10.709 起根目錄 `backup_system.py``scripts/tools/backup_system.py` 共用同一套備份流程,預設打包專案根目錄並排除 `.env`、Google token、`.git`、runtime volume 與既有 backups避免只備到 `scripts/tools` 或把敏感 runtime 檔案包入備份。 |
| 2026-06-26 | 低頻頁也不得藏工程 scaffold 或 raw fallback | V10.710 起市場情報停用頁移除舊 preview scaffold 註解只保留營運可讀狀態與下一步PChome 爬蟲匯出操作改為下載商品清單AI 建議頁若外部訊號未整理成結構,不再直接顯示 raw content而是提示重新整理或補商品線索。 |
| 2026-06-26 | 前台不得用爬蟲當使用者主語 | V10.711 起 PChome、設定、舊入口、market intel 與任務確認文字統一使用「商品監控 / 資料擷取 / 監控來源」不再把「爬蟲」當頁首、導覽、CTA 或提示主語;內部 route/key 可保留以降低部署風險。 |

View File

@@ -14,6 +14,7 @@
6. 外部促銷活動、折扣、價格壓力與平台活動訊號必須被整理成「PChome 現況對比」與「業績提升解法」,不能只顯示外部事件本身。
7. 商品型頁面必須把商品身份放在主要視覺區:商品圖、平台商品 ID、商品名稱、售價、賣場連結、可信度與下一步不得分散到難以掃描的位置。
8. 外部主流平台來源治理不得只看 PChome / MOMOShopee、Lazada、Amazon、Google Merchant / Shopping、TikTok Shop、LINE 購物、Rakuten、Yahoo 購物、露天、品牌官網 / Shopify、Meta Commerce、Coupang 等來源至少要有待接入契約。未接合法穩定來源前只能標示待接入,不得假裝已監控。
9. 前台頁首、導覽、CTA 與提示不得把「爬蟲」當使用者主語;應使用「商品監控、資料擷取、監控來源、價格來源」等營運語言。內部 route / key 可維持相容,但不得外露成主要文案。
## 每次 UI/UX 修改的驗收

View File

@@ -191,7 +191,7 @@
</nav>
<div class="momo-status-card">
<div class="momo-status-title">爬蟲狀態</div>
<div class="momo-status-title">商品監控狀態</div>
<div class="momo-status-active">
<span class="momo-live-dot"></span>
<span>{{ _status_label }}</span>

View File

@@ -330,12 +330,12 @@
<li><hr class="dropdown-divider"></li>
<li>
<a class="dropdown-item" href="/settings">
<i class="fas fa-robot me-2"></i>爬蟲管理
<i class="fas fa-robot me-2"></i>商品監控
</a>
</li>
<li>
<a class="dropdown-item" href="/crawler_management">
<i class="fas fa-spider me-2"></i>爬蟲設定
<i class="fas fa-spider me-2"></i>監控設定
</a>
</li>
<li><hr class="dropdown-divider"></li>

View File

@@ -1,9 +1,9 @@
{% set active_page = 'settings' %}
{% set legacy_bridge_title = '爬蟲管理已整併' %}
{% set legacy_bridge_title = '商品監控已整併' %}
{% set legacy_bridge_kicker = '系統治理' %}
{% set legacy_bridge_icon = 'fas fa-gear' %}
{% set legacy_bridge_heading = '爬蟲管理已移到系統管理' %}
{% set legacy_bridge_body = '到系統管理確認爬蟲與排程,讓比價與業績判斷保持新鮮。' %}
{% set legacy_bridge_heading = '商品監控已移到系統管理' %}
{% set legacy_bridge_body = '到系統管理確認商品監控與排程,讓比價與業績判斷保持新鮮。' %}
{% set legacy_bridge_target = '/settings' %}
{% set legacy_bridge_cta = '開啟系統管理' %}
{% set legacy_bridge_secondary_target = '/logs' %}
@@ -11,7 +11,7 @@
{% set legacy_bridge_meta = '已整併到系統管理' %}
{% 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-legacy-bridge.css') }}">

View File

@@ -157,7 +157,7 @@
<p class="market-intel-kicker">市場情報</p>
<h1 class="market-intel-title">市場情報入口</h1>
<p class="market-intel-copy">
市場情報尚未進入正式決策先用比價覆核、PChome 爬蟲與 AI 觀測台守住商品判斷。
市場情報尚未進入正式決策先用比價覆核、PChome 商品監控與 AI 觀測台守住商品判斷。
</p>
</div>
</header>
@@ -202,7 +202,7 @@
<p>先處理候選同款、單位價與低信心候選。</p>
</article>
<article class="market-intel-flow-item">
<h3>PChome 爬蟲</h3>
<h3>PChome 商品監控</h3>
<p>先檢查搜尋、候選取得與資料新鮮度。</p>
</article>
<article class="market-intel-flow-item">
@@ -217,7 +217,7 @@
</a>
<a class="market-intel-action" href="/pchome_crawler">
<i class="fas fa-magnifying-glass-chart" aria-hidden="true"></i>
<span>PChome 爬蟲</span>
<span>PChome 商品監控</span>
</a>
<a class="market-intel-action" href="/observability/overview">
<i class="fas fa-satellite-dish" aria-hidden="true"></i>

View File

@@ -1,6 +1,6 @@
{% extends "ewoooc_base.html" %}
{% block title %}PChome 爬蟲 - EwoooC{% endblock %}
{% block title %}PChome 商品監控 - EwoooC{% endblock %}
{% block extra_css %}
<style>
@@ -126,16 +126,16 @@
{% block content %}
<div class="container-fluid py-4 pchome-tool-page">
<header class="pchome-tool-head mb-4">
<h2><i class="fas fa-spider me-2"></i>PChome 24h 爬蟲</h2>
<h2><i class="fas fa-magnifying-glass-chart me-2"></i>PChome 24h 商品監控</h2>
<p class="text-muted">補齊 PChome 商品資料,支援同款與價差判斷。</p>
</header>
<!-- 爬取方式選擇 -->
<!-- 資料取得方式選擇 -->
<div class="row mb-4">
<div class="col-lg-6">
<div class="card">
<div class="card-header pchome-card-head">
<i class="fas fa-folder-open me-2"></i>館別爬取
<i class="fas fa-folder-open me-2"></i>館別商品整理
</div>
<div class="card-body">
<div class="mb-3">
@@ -151,7 +151,7 @@
</select>
</div>
<button class="btn btn-primary" id="crawlRegionBtn" disabled>
<i class="fas fa-download me-1"></i>開始爬取
<i class="fas fa-download me-1"></i>開始整理
</button>
</div>
</div>
@@ -187,7 +187,7 @@
<div class="col">
<div class="card">
<div class="card-header pchome-card-head">
<i class="fas fa-link me-2"></i>自訂 URL 爬取
<i class="fas fa-link me-2"></i>自訂賣場整理
</div>
<div class="card-body">
<div class="row align-items-end">
@@ -198,7 +198,7 @@
</div>
<div class="col-lg-3">
<button class="btn btn-primary w-100" id="crawlCustomBtn">
<i class="fas fa-download me-1"></i>
<i class="fas fa-download me-1"></i>得商品
</button>
</div>
</div>
@@ -207,7 +207,7 @@
</div>
</div>
<!-- 爬取進度 -->
<!-- 資料整理進度 -->
<div class="row mb-4" id="progressSection" style="display: none;">
<div class="col">
<div class="card">
@@ -329,7 +329,7 @@
document.getElementById('crawlRegionBtn').disabled = !this.value;
});
// 館別爬取
// 館別商品整理
document.getElementById('crawlRegionBtn').addEventListener('click', crawlRegion);
// 搜尋
@@ -338,7 +338,7 @@
if (e.key === 'Enter') searchProducts();
});
// 自訂 URL 爬取
// 自訂賣場整理
document.getElementById('crawlCustomBtn').addEventListener('click', crawlCustomUrl);
// 匯出
@@ -351,7 +351,7 @@
if (!regionCode) return;
const regionName = regionsData[regionCode]?.name || regionCode;
showProgress(`正在爬取 ${regionName}...`, '取得商品列表中');
showProgress(`正在整理 ${regionName} 商品...`, '取得商品列表中');
try {
const response = await fetch('/api/pchome/crawl/region', {
@@ -366,13 +366,13 @@
if (data.success) {
currentProducts = data.data.products;
showResults(currentProducts);
showToast(`成功爬取 ${currentProducts.length} 個商品`, 'success');
showToast(`已整理 ${currentProducts.length} 個商品`, 'success');
} else {
showToast(data.message, 'danger');
}
} catch (error) {
hideProgress();
showToast('爬取失敗: ' + error.message, 'danger');
showToast('商品整理失敗: ' + error.message, 'danger');
}
}
@@ -421,7 +421,7 @@
return;
}
showProgress(`爬取 URL...`, url);
showProgress(`正在取得賣場資料...`, url);
try {
const response = await fetch('/api/pchome/crawl/custom', {
@@ -436,13 +436,13 @@
if (data.success) {
currentProducts = data.data.products;
showResults(currentProducts);
showToast(`成功爬取 ${currentProducts.length} 個商品`, 'success');
showToast(`已整理 ${currentProducts.length} 個商品`, 'success');
} else {
showToast(data.message, 'danger');
}
} catch (error) {
hideProgress();
showToast('爬取失敗: ' + error.message, 'danger');
showToast('商品整理失敗: ' + error.message, 'danger');
}
}

View File

@@ -10,7 +10,7 @@
#}
{% extends "ewoooc_base.html" %}
{% block title %}爬蟲管理 · EwoooC{% endblock %}
{% block title %}商品監控 · EwoooC{% endblock %}
{% set active_page = 'settings' %}
@@ -21,7 +21,7 @@
{% block ewooo_content %}
<header class="page-header">
<div>
<h1><i class="fas fa-robot me-2"></i>爬蟲管理中心</h1>
<h1><i class="fas fa-robot me-2"></i>商品監控中心</h1>
<p class="text-muted mb-0">守住比價資料新鮮度,支援 PChome 業績判斷。</p>
</div>
<button class="refresh-btn" onclick="refreshData()">
@@ -44,11 +44,11 @@
<div class="stat-card total">
<div class="stat-icon"><i class="fas fa-layer-group"></i></div>
<div class="stat-number" id="total-count">0</div>
<div class="stat-label">爬蟲總</div>
<div class="stat-label">監控來源</div>
</div>
</div>
{# 爬蟲卡片 (JS 動態插入) #}
{# 商品監控卡片 (JS 動態插入) #}
<div id="crawlers-container"></div>
{# 操作重點 #}
@@ -57,7 +57,7 @@
<ul>
<li>優先確保 PChome / MOMO 比價來源保持啟用。</li>
<li>資料過舊時先調整頻率,再重啟排程器讓設定生效。</li>
<li>修改分類後,下一輪爬蟲會自動使用新設定。</li>
<li>修改分類後,下一輪資料擷取會自動使用新設定。</li>
</ul>
</div>
@@ -65,7 +65,7 @@
{# 分類設定 #}
<div class="section-header">
<h5><i class="fas fa-list-alt me-2"></i>爬蟲網址設定</h5>
<h5><i class="fas fa-list-alt me-2"></i>監控來源設定</h5>
<button class="btn btn-primary" onclick="prepareAddModal()">
<i class="fas fa-plus me-2"></i>新增分類
</button>
@@ -124,7 +124,7 @@
<div class="alert alert-info mb-5">
<i class="fas fa-lightbulb me-2"></i>
<strong>比價來源同步:</strong> 新增或修改分類後,下一次爬蟲會使用最新清單補齊 MOMO 參考來源。
<strong>比價來源同步:</strong> 新增或修改分類後,下一次資料擷取會使用最新清單補齊 MOMO 參考來源。
</div>
{# Toast / Loading / Modal #}

View File

@@ -169,7 +169,7 @@ def test_market_intel_disabled_page_stays_lightweight_and_action_oriented():
assert template_path.stat().st_size < 40000
assert "市場情報入口" in template
assert "比價覆核" in template
assert "PChome 爬蟲" in template
assert "PChome 商品監控" in template
assert "AI 觀測台" in template
assert "system_version" not in template
assert "V10." not in template
@@ -189,19 +189,36 @@ def test_market_intel_disabled_page_stays_lightweight_and_action_oriented():
def test_growth_workflow_pages_hide_raw_export_and_fallback_content():
pchome_crawler = (ROOT / "templates/pchome_crawler.html").read_text(encoding="utf-8")
market_intel = (ROOT / "templates/market_intel/disabled.html").read_text(encoding="utf-8")
settings = (ROOT / "templates/settings.html").read_text(encoding="utf-8")
navbar = (ROOT / "templates/components/_navbar.html").read_text(encoding="utf-8")
shell = (ROOT / "templates/components/_ewoooc_shell.html").read_text(encoding="utf-8")
dashboard_js = (ROOT / "web/static/js/page-dashboard-v2.js").read_text(encoding="utf-8")
ai_recommend_js = (ROOT / "web/static/js/page-ai-recommend.js").read_text(encoding="utf-8")
assert "PChome 商品監控" in pchome_crawler
assert "商品清單" in pchome_crawler
assert "下載完整清單" in pchome_crawler
assert "匯出 JSON" not in pchome_crawler
assert "PChome 爬蟲" not in pchome_crawler
assert "爬蟲" not in pchome_crawler
assert "資料狀態" in market_intel
assert "PChome 商品監控" in market_intel
assert "來源規格" in market_intel
assert "手動整理" in market_intel
assert "DATA STATUS" not in market_intel
assert "Adapter" not in market_intel
assert "手動 Fetch" not in market_intel
assert "API 不執行推版" not in market_intel
assert "PChome 爬蟲" not in market_intel
assert "商品監控中心" in settings
assert "監控來源設定" in settings
assert "商品監控" in navbar
assert "商品監控狀態" in shell
assert "全站商品監控" in dashboard_js
for source in (settings, navbar, shell, dashboard_js):
assert "爬蟲" not in source
assert "外部訊號已取得,但尚未整理成可直接判斷的摘要" in ai_recommend_js
assert "商品判斷尚未整理成可執行摘要" in ai_recommend_js

View File

@@ -877,7 +877,7 @@ def test_market_intel_preview_template_uses_safe_fetch_false_endpoint():
assert "市場情報入口" in template
assert "比價覆核" in template
assert "PChome 爬蟲" in template
assert "PChome 商品監控" in template
assert "AI 觀測台" in template
assert "市場情報尚未進入正式決策" in template
assert "資料狀態" in template

View File

@@ -255,7 +255,7 @@ let priceChartInstance = null;
const dashboardTaskMap = {
crawler: {
confirmText: '確定要手動執行全站爬蟲嗎?可能需要一段時間。',
confirmText: '確定要手動執行全站商品監控嗎?可能需要一段時間。',
url: '/api/run_task'
},
notification: {

View File

@@ -21,7 +21,7 @@ function getCSRFToken() {
}
function triggerTask() {
if (confirm('確定要手動執行全站爬蟲嗎?(可能需要一段時間)')) {
if (confirm('確定要手動執行全站商品監控嗎?(可能需要一段時間)')) {
fetch('/api/run_task', { method: 'POST', headers: { 'X-CSRFToken': getCSRFToken() } })
.then(r => r.json()).then(d => alert(d.message)).catch(e => alert('錯誤: ' + e));
}

View File

@@ -269,11 +269,11 @@ let campaignPriceChartInstance = null;
const campaignTaskMap = {
edm: {
confirmText: '確定要手動執行 EDM 爬蟲嗎?',
confirmText: '確定要手動執行 EDM 商品監控嗎?',
url: '/api/run_edm_task'
},
festival: {
confirmText: '確定要手動執行節慶活動爬蟲嗎?',
confirmText: '確定要手動執行節慶活動監控嗎?',
url: '/api/run_festival_task'
},
notification: {

View File

@@ -1,5 +1,5 @@
/* ═══════════════════════════════════════════════════════════
* page-settings.js — 爬蟲管理中心
* page-settings.js — 商品監控中心
* 從原 settings.html L1230-L1648 抽出
* 邏輯與原版一致
* ═══════════════════════════════════════════════════════════ */
@@ -51,7 +51,7 @@ async function loadCrawlers() {
showToast('載入失敗: ' + result.message, 'error');
}
} catch (e) {
showToast('載入爬蟲配置時發生錯誤', 'error');
showToast('載入商品監控設定時發生錯誤', 'error');
console.error(e);
}
}
@@ -174,7 +174,7 @@ async function refreshData() {
setTimeout(() => {
btn.classList.remove('spinning');
btn.disabled = false;
showToast('已刷新爬蟲狀態', 'success');
showToast('已刷新商品監控狀態', 'success');
}, 600);
}