新增市場情報 queue writer run package
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s

This commit is contained in:
OoO
2026-05-19 11:01:02 +08:00
parent ac5d1a2d81
commit 98a0ca7af9
10 changed files with 714 additions and 52 deletions

View File

@@ -600,6 +600,9 @@
<button class="market-intel-icon-button" type="button" title="產生 queue writer operator drill" data-market-intel-sample-candidate-queue-operator-drill>
<i class="fas fa-list-check" aria-hidden="true"></i>
</button>
<button class="market-intel-icon-button" type="button" title="產生 queue writer run package" data-market-intel-sample-candidate-queue-run-package>
<i class="fas fa-box-archive" aria-hidden="true"></i>
</button>
</div>
</div>
@@ -932,6 +935,7 @@
const sampleCandidateQueuePreflight = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-preflight]') : null;
const sampleCandidateQueuePostwriteSmoke = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-postwrite-smoke]') : null;
const sampleCandidateQueueOperatorDrill = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-operator-drill]') : null;
const sampleCandidateQueueRunPackage = sampleReviewRoot ? sampleReviewRoot.querySelector('[data-market-intel-sample-candidate-queue-run-package]') : null;
const sampleReviewEndpoint = "{{ url_for('market_intel.market_intel_manual_sample_review') }}";
const sampleReviewEvaluateEndpoint = "{{ url_for('market_intel.market_intel_manual_sample_review_evaluate') }}";
const sampleCandidateHandoffEndpoint = "{{ url_for('market_intel.market_intel_manual_sample_candidate_handoff') }}";
@@ -942,6 +946,7 @@
const sampleCandidateQueuePreflightEndpoint = "{{ url_for('market_intel.market_intel_manual_sample_candidate_queue_writer_preflight') }}";
const sampleCandidateQueuePostwriteSmokeEndpoint = "{{ url_for('market_intel.market_intel_manual_sample_candidate_queue_writer_postwrite_smoke') }}";
const sampleCandidateQueueOperatorDrillEndpoint = "{{ url_for('market_intel.market_intel_manual_sample_candidate_queue_writer_operator_drill') }}";
const sampleCandidateQueueRunPackageEndpoint = "{{ url_for('market_intel.market_intel_manual_sample_candidate_queue_writer_run_package') }}";
const schedulerMeta = schedulerRoot ? schedulerRoot.querySelector('[data-market-intel-scheduler-meta]') : null;
const schedulerBody = schedulerRoot ? schedulerRoot.querySelector('[data-market-intel-scheduler-body]') : null;
const schedulerRefresh = schedulerRoot ? schedulerRoot.querySelector('[data-market-intel-scheduler-refresh]') : null;
@@ -2528,6 +2533,97 @@
}
};
const renderCandidateQueueRunPackage = data => {
const blockers = (data.blocked_reasons || []).join(' / ');
const manifest = data.payload_manifest || {};
const artifacts = data.required_artifacts || [];
const commands = data.command_bundle || [];
const signoff = data.operator_signoff || [];
sampleReviewMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
`ready=${data.package_ready ? 'yes' : 'no'}`,
`payloads=${manifest.payload_count || 0}`,
`api_file=${data.api_writes_file ? 'yes' : 'no'}`,
`db_write=${data.database_write_executed ? 'yes' : 'no'}`
].map(item => `<span class="market-intel-pill">${escapeHtml(item)}</span>`).join('');
sampleReviewBody.innerHTML = `
<div class="market-intel-empty mb-3">此卡只整理正式 CLI 小流量寫入前的證據包與命令包API/UI 不產檔、不讀 token、不執行 CLI、不寫 DB。${blockers ? `阻擋:${escapeHtml(blockers)}` : ''}</div>
<div class="market-intel-empty mb-3">manifest=${escapeHtml((manifest.manifest_hash || '').slice(0, 16) || 'none')} / dedupe=${escapeHtml((manifest.dedupe_keys || []).join(', ') || 'none')}</div>
<div class="market-intel-deploy-grid">
<div>
<p class="market-intel-deploy-section-title">REQUIRED ARTIFACTS</p>
<div class="market-intel-operation-list">${
artifacts.map(item => `
<article class="market-intel-operation">
<strong>${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.label)}</small>
<small>${escapeHtml(item.path_shape)}</small>
<small>created_by_api=${item.created_by_api ? 'yes' : 'no'}</small>
</article>
`).join('') || '<div class="market-intel-empty">尚未提供 artifacts。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">COMMAND BUNDLE</p>
<div class="market-intel-operation-list">${
commands.map(item => `
<article class="market-intel-operation">
<strong>${escapeHtml(item.step)}. ${escapeHtml(item.key)}</strong>
<small>${escapeHtml(item.command_shape)}</small>
<small>db_write=${item.executes_database ? 'yes' : 'no'}</small>
</article>
`).join('') || '<div class="market-intel-empty">尚未提供 commands。</div>'
}</div>
</div>
<div>
<p class="market-intel-deploy-section-title">OPERATOR SIGNOFF</p>
<div class="market-intel-check-list">${
signoff.map((item, index) => `
<div class="market-intel-check">
<div>
<strong>${escapeHtml(`signoff_${index + 1}`)}</strong>
<small>${escapeHtml(item)}</small>
</div>
<span>REQUIRED</span>
</div>
`).join('') || '<div class="market-intel-empty">尚未提供 signoff。</div>'
}</div>
</div>
</div>
`;
};
const loadCandidateQueueRunPackage = async () => {
if (!sampleReviewMeta || !sampleReviewBody || !sampleReviewInput) return;
let parsed;
try {
parsed = JSON.parse(sampleReviewInput.value || '{}');
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">json_error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">JSON 格式錯誤:${escapeHtml(error.message)}</div>`;
return;
}
sampleReviewBody.innerHTML = '<div class="market-intel-empty">產生 queue writer run package 中...</div>';
try {
const response = await fetch(sampleCandidateQueueRunPackageEndpoint, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify({ sample_result: parsed })
});
const data = await response.json();
if (!response.ok && !data.mode) throw new Error(`HTTP ${response.status}`);
renderCandidateQueueRunPackage(data);
} catch (error) {
sampleReviewMeta.innerHTML = '<span class="market-intel-pill">error</span>';
sampleReviewBody.innerHTML = `<div class="market-intel-empty">queue writer run package 產生失敗:${escapeHtml(error.message)}</div>`;
}
};
const renderSchedulerMeta = data => {
schedulerMeta.innerHTML = [
`mode=${data.mode || 'unknown'}`,
@@ -4046,6 +4142,9 @@
if (sampleCandidateQueueOperatorDrill) {
sampleCandidateQueueOperatorDrill.addEventListener('click', loadCandidateQueueOperatorDrill);
}
if (sampleCandidateQueueRunPackage) {
sampleCandidateQueueRunPackage.addEventListener('click', loadCandidateQueueRunPackage);
}
if (schedulerRefresh) {
schedulerRefresh.addEventListener('click', loadScheduler);
}