feat: backfill growth momo matches
All checks were successful
CD Pipeline / deploy (push) Successful in 1m9s

This commit is contained in:
OoO
2026-06-18 16:02:02 +08:00
parent 6d6f3b473f
commit 9ca8d4e43c
9 changed files with 421 additions and 4 deletions

View File

@@ -272,6 +272,40 @@
box-shadow: inset 3px 0 0 var(--momo-success);
}
.growth-task.is-loading {
opacity: 0.78;
}
.growth-backfill-status {
margin-top: 9px;
padding: 8px 10px;
color: var(--momo-text-secondary);
background: color-mix(in srgb, var(--momo-bg-paper) 72%, transparent);
border: 1px solid var(--momo-border-light);
border-radius: 8px;
font-size: 11px;
font-weight: 900;
line-height: 1.35;
}
.growth-backfill-status.is-success {
color: var(--momo-success);
border-color: rgba(48, 133, 94, 0.24);
background: rgba(235, 248, 241, 0.72);
}
.growth-backfill-status.is-warning {
color: var(--momo-warning-text);
border-color: rgba(210, 158, 58, 0.34);
background: rgba(255, 248, 231, 0.72);
}
.growth-backfill-status.is-danger {
color: var(--momo-danger);
border-color: rgba(188, 75, 49, 0.32);
background: rgba(255, 244, 239, 0.72);
}
.growth-strategy-grid {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));

View File

@@ -280,6 +280,84 @@ let priceChartInstance = null;
button.addEventListener('click', () => runDashboardTask(button.dataset.dashboardTask));
});
function getPchomeGrowthBackfillElements() {
return {
triggers: Array.from(document.querySelectorAll('[data-pchome-growth-backfill-trigger]')),
status: document.querySelector('[data-pchome-growth-backfill-status]'),
endpoint: '/api/ai/pchome-growth/backfill-momo-candidates'
};
}
function setGrowthBackfillStatus(message, tone) {
const elements = getPchomeGrowthBackfillElements();
if (!elements.status) return;
elements.status.textContent = message;
elements.status.classList.remove('is-success', 'is-warning', 'is-danger');
if (tone) {
elements.status.classList.add(`is-${tone}`);
}
}
function setGrowthBackfillBusy(isBusy) {
const elements = getPchomeGrowthBackfillElements();
elements.triggers.forEach(trigger => {
trigger.disabled = isBusy;
trigger.classList.toggle('is-loading', isBusy);
});
}
function renderGrowthBackfillResult(data) {
const payload = data && data.data ? data.data : {};
const sync = payload.external_offer_sync || {};
const written = Number(sync.written_count || 0);
const autoCount = Number(payload.auto_compare_count || 0);
const reviewCount = Number(payload.review_count || 0);
const candidateCount = Number(payload.candidate_count || 0);
const scanned = Number(payload.scanned_products || 0);
const tone = written > 0 ? 'success' : (candidateCount > 0 ? 'warning' : 'danger');
const message = (
`掃描 ${formatBackfillCount(scanned)} 個高業績品`
+ ` · 候選 ${formatBackfillCount(candidateCount)}`
+ ` · 可自動 ${formatBackfillCount(autoCount)}`
+ ` · 寫入 ${formatBackfillCount(written)}`
+ ` · 待覆核 ${formatBackfillCount(reviewCount)}`
);
setGrowthBackfillStatus(message, tone);
if (written > 0) {
setTimeout(() => window.location.reload(), 1200);
}
}
function backfillPchomeGrowthMomoCandidates(activeTrigger) {
const elements = getPchomeGrowthBackfillElements();
if (!elements.triggers.length) return;
const trigger = activeTrigger && activeTrigger.dataset ? activeTrigger : elements.triggers[0];
const limit = Number(trigger.dataset.limit || 12);
setGrowthBackfillBusy(true);
setGrowthBackfillStatus(`正在補 ${formatBackfillCount(limit)} 個高業績商品的 MOMO 對應`, '');
fetch(elements.endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCSRFToken()
},
body: JSON.stringify({ limit })
})
.then(response => response.json().then(data => ({ ok: response.ok, data })))
.then(({ ok, data }) => {
if (!ok || !data.success) {
throw new Error(data.error || data.message || 'MOMO 對應補抓失敗');
}
renderGrowthBackfillResult(data);
})
.catch(error => {
setGrowthBackfillStatus(error.message || 'MOMO 對應補抓失敗', 'danger');
})
.finally(() => {
setGrowthBackfillBusy(false);
});
}
let pchomeBackfillPollTimer = null;
const DEFAULT_PCHOME_BACKFILL_LABEL = '補強 60 筆';
const DEFAULT_PCHOME_REFRESH_STALE_LABEL = '刷新過期 120 筆';
@@ -529,6 +607,10 @@ let priceChartInstance = null;
window.backfillPchomeMatches = backfillPchomeMatches;
window.refreshStalePchomeMatches = refreshStalePchomeMatches;
window.backfillPchomeGrowthMomoCandidates = backfillPchomeGrowthMomoCandidates;
document.querySelectorAll('[data-pchome-growth-backfill-trigger]').forEach(button => {
button.addEventListener('click', () => backfillPchomeGrowthMomoCandidates(button));
});
document.querySelectorAll('[data-pchome-backfill-trigger]').forEach(button => {
button.addEventListener('click', () => backfillPchomeMatches(button));
});