fix: rename crawler UI to product monitoring
All checks were successful
CD Pipeline / deploy (push) Successful in 1m9s
All checks were successful
CD Pipeline / deploy (push) Successful in 1m9s
This commit is contained in:
@@ -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 # 用於模板顯示
|
||||
|
||||
|
||||
@@ -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 可保留以降低部署風險。 |
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
6. 外部促銷活動、折扣、價格壓力與平台活動訊號,必須被整理成「PChome 現況對比」與「業績提升解法」,不能只顯示外部事件本身。
|
||||
7. 商品型頁面必須把商品身份放在主要視覺區:商品圖、平台商品 ID、商品名稱、售價、賣場連結、可信度與下一步不得分散到難以掃描的位置。
|
||||
8. 外部主流平台來源治理不得只看 PChome / MOMO;Shopee、Lazada、Amazon、Google Merchant / Shopping、TikTok Shop、LINE 購物、Rakuten、Yahoo 購物、露天、品牌官網 / Shopify、Meta Commerce、Coupang 等來源至少要有待接入契約。未接合法穩定來源前只能標示待接入,不得假裝已監控。
|
||||
9. 前台頁首、導覽、CTA 與提示不得把「爬蟲」當使用者主語;應使用「商品監控、資料擷取、監控來源、價格來源」等營運語言。內部 route / key 可維持相容,但不得外露成主要文案。
|
||||
|
||||
## 每次 UI/UX 修改的驗收
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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') }}">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 #}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -255,7 +255,7 @@ let priceChartInstance = null;
|
||||
|
||||
const dashboardTaskMap = {
|
||||
crawler: {
|
||||
confirmText: '確定要手動執行全站爬蟲嗎?可能需要一段時間。',
|
||||
confirmText: '確定要手動執行全站商品監控嗎?可能需要一段時間。',
|
||||
url: '/api/run_task'
|
||||
},
|
||||
notification: {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user