feat: add dual-store actions to price comparison

This commit is contained in:
ogt
2026-06-25 18:52:59 +08:00
parent 49ff083512
commit 45da965702
4 changed files with 41 additions and 6 deletions

View File

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

View File

@@ -770,3 +770,4 @@ POSTGRES_HOST=momo-db
| 2026-06-25 | 全頁價格方向統一為 PChome 成長視角 | V10.691 起 AI Intelligence、Daily Sales、Growth Analysis、Dashboard、Telegram 與 AI 報告 prompt 不再使用「PChome 價格壓力 / MOMO 價格優勢 / MOMO 更便宜 / PChome 有優勢」等易混淆詞統一為「PChome 價格優勢」與「MOMO 低價壓力」。 |
| 2026-06-25 | 候選比較卡與價格語意必須有測試防線 | V10.692 起 `tests/test_pchome_revenue_growth_service.py` 鎖定 `/ai_intelligence` 模板必須提供 PChome/MOMO 雙賣場連結、雙開賣場操作與白話候選理由,且不得再出現 `variant_selection_review``focused_exact_identity``source_code``momo_reference` 或反向價格詞。 |
| 2026-06-25 | 成長報表不得把比價內部指標整排丟給使用者 | V10.693 起 `/growth_analysis` 的比價品質區改為「PChome 價格作戰可用度」:只呈現可直接決策、同款覆蓋、價格需刷新、待補/待確認四個訊號,並依資料狀態給下一步建議與今日作戰入口;測試禁止回到「比價資料品質、高信心門檻、未知新鮮度、人工否決」這類工程化列表。 |
| 2026-06-25 | 比價頁每筆結果也必須能雙開賣場 | V10.694 起 `/price_comparison` 的結果列在 PChome/MOMO 連結都存在時提供「雙開賣場」操作Excel 與手動輸入提示改成白話作戰語言,不再顯示「格式說明、欄位、商品名稱,價格」這類工程化提示;`tests/test_frontend_v2_assets.py` 鎖定此行為。 |

View File

@@ -956,7 +956,7 @@
</div>
<div class="price-note">
<i class="fas fa-info-circle me-1"></i>
Excel 需包含「商品名稱」和「售價」欄位。可選包含「商品編號」和「連結」
Excel 至少要有商品名稱與售價;有賣場連結時會一起帶入雙開比對
</div>
</div>
<div class="modal-footer">
@@ -979,9 +979,8 @@
</div>
<div class="modal-body">
<div class="price-note py-2">
<i class="fas fa-info-circle me-1"></i>
<strong>格式說明:</strong> 每行一筆商品,用<strong>逗號</strong><strong>Tab</strong> 分隔<br>
<code>商品名稱,價格</code><code>商品名稱,價格,商品連結(選填)</code>
<i class="fas fa-bullseye me-1"></i>
貼上 MOMO 商品、售價與賣場連結;系統會整理成可比價清單。
</div>
<div class="mb-3">
<label class="form-label">商品資料</label>
@@ -1314,7 +1313,7 @@ La Roche-Posay 安得利防曬液 50ml,920
parts = line.split('\t');
}
if (parts.length < 2) {
showToast(`${i + 1}格式錯誤,請使用「商品名稱,價格」,例如:理膚寶水 B5修復霜,680`, 'warning');
showToast(`${i + 1}缺商品名稱或售價,請補齊後再加入比價清單`, 'warning');
return;
}
@@ -1699,10 +1698,20 @@ La Roche-Posay 安得利防曬液 50ml,920
// 處理 URL (可能是 url 或 product_url)
const pchomeUrl = toSafeUrl(m.pchome?.url || m.pchome?.product_url || '');
const momoUrl = toSafeUrl(m.momo?.url || m.momo?.product_url || '');
const dualOpenButton = pchomeUrl && momoUrl
? `<button type="button"
class="btn btn-sm btn-outline-primary mt-2"
data-pchome-url="${escapeHtml(pchomeUrl)}"
data-momo-url="${escapeHtml(momoUrl)}"
onclick="openComparisonStores(this)">
<i class="fas fa-up-right-from-square me-1"></i>雙開賣場
</button>`
: '';
row.innerHTML = `
<td>
${actionBadge}
${dualOpenButton}
</td>
<td>
<div class="d-flex align-items-start">
@@ -1757,6 +1766,22 @@ La Roche-Posay 安得利防曬液 50ml,920
document.getElementById('resultSection').style.display = 'block';
}
function openComparisonStores(button) {
const pchomeUrl = toSafeUrl(button?.dataset?.pchomeUrl || '');
const momoUrl = toSafeUrl(button?.dataset?.momoUrl || '');
const opened = [];
if (pchomeUrl) opened.push(window.open(pchomeUrl, `pchome_compare_${Date.now()}`));
if (momoUrl) opened.push(window.open(momoUrl, `momo_compare_${Date.now()}`));
for (const win of opened) {
if (win) {
try { win.opener = null; } catch (_) {}
}
}
if (opened.some((win) => !win)) {
showToast('瀏覽器擋住了其中一個視窗;請用商品旁的 PChome / MOMO 按鈕分別開啟。', 'warning');
}
}
function getResultActionBadge(match) {
if (match.cheaper_at === 'momo') {
return '<span class="price-action-pill is-urgent">檢查售價</span>';

View File

@@ -572,10 +572,19 @@ def test_price_comparison_page_is_action_oriented_and_plain_chinese():
assert "主推曝光" in template
assert "PChome 貴" in template
assert "PChome 便宜" in template
assert "雙開賣場" in template
assert "openComparisonStores" in template
assert "data-pchome-url" in template
assert "data-momo-url" in template
assert "Excel 至少要有商品名稱與售價" in template
assert "貼上 MOMO 商品、售價與賣場連結" in template
assert "resetComparisonResult" in template
assert "showToast" in template
assert "text.textContent = message" in template
assert "toast.innerHTML" not in template
assert "格式說明" not in template
assert "商品名稱,價格" not in template
assert "欄位" not in template
assert "Step 1" not in template
assert "Step 2" not in template
assert "Step 3" not in template