feat: add public h5 dashboard and publish traceability
This commit is contained in:
@@ -154,7 +154,10 @@
|
||||
}
|
||||
if (!response.ok || !payload.ok) {
|
||||
const error = payload?.error || {};
|
||||
throw new Error(I18N?.errorMessage(error.code, error.message) || error.message || "请求未完成");
|
||||
const requestError = new Error(I18N?.errorMessage(error.code, error.message) || error.message || "请求未完成");
|
||||
requestError.code = error.code || "";
|
||||
requestError.status = response.status;
|
||||
throw requestError;
|
||||
}
|
||||
return returnEnvelope ? payload : payload.data;
|
||||
}
|
||||
@@ -516,7 +519,7 @@
|
||||
const lines = [
|
||||
`$ arr trace --job ${job.job_id || state.selectedJobId || "-"}`,
|
||||
`trace_version=${traceConsoleValue(trace.trace_version)} status=${traceConsoleValue(job.status)} active=${Boolean(job.active)} current_stage=${traceConsoleValue(job.current_stage)}`,
|
||||
`attempt_no=${traceConsoleValue(job.attempt_no)} remote_run_id=${traceConsoleValue(job.remote_run_id)} delivery_mode=${traceConsoleValue(job.delivery_mode)}`,
|
||||
`attempt_no=${traceConsoleValue(job.attempt_no)} execution_scope=${traceConsoleValue(job.execution_scope || "unknown")} processor_mode=${traceConsoleValue(job.processor_mode || "unknown")} remote_dispatch=${traceConsoleValue(job.remote_dispatch || "unknown")} remote_run_id=${traceConsoleValue(job.remote_run_id)} delivery_mode=${traceConsoleValue(job.delivery_mode)}`,
|
||||
`created_at=${traceConsoleValue(job.created_at)} updated_at=${traceConsoleValue(job.updated_at)} finished_at=${traceConsoleValue(job.finished_at)}`,
|
||||
`evidence=${JSON.stringify(trace.evidence || {})}`,
|
||||
"--------------------------------------------------------------------------------",
|
||||
@@ -986,6 +989,52 @@
|
||||
node.hidden = !message;
|
||||
}
|
||||
|
||||
function setCompanySourceStatus(message = "") {
|
||||
const node = $("#company-source-status");
|
||||
node.textContent = I18N?.text(message) || message;
|
||||
node.hidden = !message;
|
||||
}
|
||||
|
||||
function companySourceFilename(source) {
|
||||
const filename = String(source?.filename || "").trim();
|
||||
return filename || (I18N?.t("company.source_file_missing") || "未记录文件名");
|
||||
}
|
||||
|
||||
function companySourceMeta(source) {
|
||||
const batchId = Number(source?.source_batch_id);
|
||||
const rows = Number(source?.source_rows);
|
||||
const rooms = Number(source?.room_quantity);
|
||||
const batch = Number.isInteger(batchId) && batchId > 0 ? formatInteger(batchId) : "—";
|
||||
const rowCount = Number.isInteger(rows) && rows >= 0 ? formatInteger(rows) : "—";
|
||||
const roomCount = Number.isInteger(rooms) && rooms >= 0 ? formatInteger(rooms) : "—";
|
||||
const activated = source?.activated_at ? formatDate(source.activated_at, true) : (I18N?.t("company.review_no_record") || "暂无");
|
||||
return I18N?.t("company.source_meta", { batch, rows: rowCount, rooms: roomCount, activated })
|
||||
|| `批次 #${batch} · ${rowCount} 条记录 · ${roomCount} 间 · 启用于 ${activated}`;
|
||||
}
|
||||
|
||||
function companyJobSourceMeta(source) {
|
||||
const batchId = Number(source?.source_batch_id);
|
||||
const batch = Number.isInteger(batchId) && batchId > 0 ? formatInteger(batchId) : "—";
|
||||
const activated = source?.activated_at ? formatDate(source.activated_at, true) : (I18N?.t("company.review_no_record") || "暂无");
|
||||
return I18N?.t("company.job_source_meta", { batch, activated })
|
||||
|| `批次 #${batch} · 启用于 ${activated}`;
|
||||
}
|
||||
|
||||
function renderCompanySource(source) {
|
||||
const panel = $("#company-source-current");
|
||||
if (!panel) return;
|
||||
if (!source) {
|
||||
panel.hidden = true;
|
||||
$("#company-source-current-filename").textContent = "";
|
||||
$("#company-source-current-meta").textContent = "";
|
||||
return;
|
||||
}
|
||||
panel.hidden = false;
|
||||
$("#company-source-current-filename").textContent = companySourceFilename(source);
|
||||
$("#company-source-current-filename").title = companySourceFilename(source);
|
||||
$("#company-source-current-meta").textContent = companySourceMeta(source);
|
||||
}
|
||||
|
||||
function updateCompanySourceUploadControls() {
|
||||
const busy = state.companySourceUploading || state.companyReviewMutating || isCompanyReportActive();
|
||||
const enabled = state.companySourceUploadReady && !busy;
|
||||
@@ -1104,6 +1153,7 @@
|
||||
|
||||
function selectCompanySourceFile(file) {
|
||||
setCompanySourceError();
|
||||
setCompanySourceStatus();
|
||||
state.companySourceFile = null;
|
||||
if (file) {
|
||||
if (!file.name.toLowerCase().endsWith(".xlsx")) {
|
||||
@@ -1125,14 +1175,17 @@
|
||||
async function loadCompanySource(showErrors = false) {
|
||||
if (!state.companySourceUploadReady) {
|
||||
state.companySource = null;
|
||||
renderCompanySource(null);
|
||||
updateCompanyReportControls();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
state.companySource = await api("/api/company-reports/source");
|
||||
renderCompanySource(state.companySource);
|
||||
setCompanySourceError();
|
||||
} catch (error) {
|
||||
state.companySource = null;
|
||||
renderCompanySource(null);
|
||||
setCompanySourceError(I18N?.t("company.source_error") || "当前 Excel 数据源暂时无法读取");
|
||||
if (showErrors) showToast(error.message, true);
|
||||
}
|
||||
@@ -1172,6 +1225,7 @@
|
||||
if (!state.companySourceFile || !state.companySourceUploadReady || state.companySourceUploading) return;
|
||||
state.companySourceUploading = true;
|
||||
setCompanySourceError();
|
||||
setCompanySourceStatus();
|
||||
updateCompanySourceUploadControls();
|
||||
updateCompanyReportControls();
|
||||
try {
|
||||
@@ -1195,6 +1249,17 @@
|
||||
? (I18N?.t("company.extract_pending", { count: formatInteger(pending) }) || `提取完成,${formatInteger(pending)} 条需要人工确认`)
|
||||
: (I18N?.t("company.extract_done") || "提取完成,可以确认并启用"));
|
||||
} catch (error) {
|
||||
if (error.code === "BOOKING_EXCEL_SOURCE_ALREADY_ACTIVATED") {
|
||||
const message = I18N?.t("company.source_already_active") || "这份 Excel 已是当前启用来源;请在下方按月份查看或生成对应报表";
|
||||
state.companySourceFile = null;
|
||||
$("#company-excel-file").value = "";
|
||||
$("#company-selected-file").textContent = I18N?.t("upload.file_not_selected") || "尚未选择文件";
|
||||
setCompanySourceError();
|
||||
setCompanySourceStatus(message);
|
||||
await Promise.all([loadCompanySource(true), loadCompanyReportHistory(true)]);
|
||||
showToast(message);
|
||||
return;
|
||||
}
|
||||
setCompanySourceError(error.message || I18N?.t("company.file_extract_failed") || "Excel 文件未能完成提取");
|
||||
showToast(error.message || I18N?.t("company.file_extract_failed") || "Excel 文件未能完成提取", true);
|
||||
} finally {
|
||||
@@ -1407,6 +1472,8 @@
|
||||
state.companyReviewMutating = false;
|
||||
clearCompanyReviewSelection();
|
||||
renderCompanyDraft(null);
|
||||
renderCompanySource(source);
|
||||
setCompanySourceStatus();
|
||||
updateCompanyReportControls();
|
||||
showToast(I18N?.t("company.review_activated") || "人工核对完成,Booking 数据源已启用");
|
||||
} catch (error) {
|
||||
@@ -1695,6 +1762,16 @@
|
||||
$("#company-report-job-as-of").textContent = job.as_of_date ? formatDate(job.as_of_date) : (I18N?.t("company.review_no_record") || "暂无");
|
||||
$("#company-report-job-duration").textContent = formatDurationSeconds(job.duration_seconds);
|
||||
$("#company-report-warning-count").textContent = I18N?.t("company.report_warning_count", { count: formatInteger(companyWarningCount(job)) }) || `${companyWarningCount(job)} 项`;
|
||||
const source = job?.source;
|
||||
const sourcePanel = $("#company-report-job-source");
|
||||
sourcePanel.classList.toggle("is-missing", !source);
|
||||
$("#company-report-job-source-file").textContent = source
|
||||
? companySourceFilename(source)
|
||||
: (I18N?.t("company.job_source_missing") || "历史任务未记录来源");
|
||||
$("#company-report-job-source-file").title = source ? companySourceFilename(source) : "";
|
||||
$("#company-report-job-source-meta").textContent = source
|
||||
? companyJobSourceMeta(source)
|
||||
: (I18N?.t("company.review_no_record") || "暂无");
|
||||
$("#company-result-month-end-header").textContent = companyPeriodRange(job.report_month, "21-month-end");
|
||||
renderCompanyResultRows(job);
|
||||
localStorage.setItem("arr:last-company-report-job", job.job_id);
|
||||
@@ -1706,18 +1783,24 @@
|
||||
state.companyReportJobs = jobs;
|
||||
const body = $("#company-history-rows");
|
||||
if (!jobs.length) {
|
||||
body.innerHTML = `<tr><td class="empty-cell" colspan="7">${historyEmptyMarkup("company", "history.company_empty", "暂无公司渠道明细任务")}</td></tr>`;
|
||||
body.innerHTML = `<tr><td class="empty-cell" colspan="8">${historyEmptyMarkup("company", "history.company_empty", "暂无公司渠道明细任务")}</td></tr>`;
|
||||
return;
|
||||
}
|
||||
body.innerHTML = jobs.map((job) => `<tr>
|
||||
body.innerHTML = jobs.map((job) => {
|
||||
const source = job?.source;
|
||||
const sourceFilename = source ? companySourceFilename(source) : (I18N?.t("company.job_source_missing") || "历史任务未记录来源");
|
||||
const sourceMeta = source ? companyJobSourceMeta(source) : (I18N?.t("company.review_no_record") || "暂无");
|
||||
return `<tr>
|
||||
<td>${formatDate(job.created_at, true)}</td>
|
||||
<td><strong>${escapeHtml(job.report_month ? monthLabel(job.report_month) : (I18N?.t("company.review_no_record") || "暂无"))}</strong></td>
|
||||
<td>${escapeHtml(companyCutoffLabel(job))}</td>
|
||||
<td><span class="status-chip ${companyStateStyle(job.state)}">${escapeHtml(companyStateLabel(job.state))}</span></td>
|
||||
<td>${companySuccessCount(job)} / 5</td>
|
||||
<td>${companyWarningCount(job)}</td>
|
||||
<td><div class="company-history-source"><strong title="${escapeHtml(sourceFilename)}">${escapeHtml(sourceFilename)}</strong><small>${escapeHtml(sourceMeta)}</small></div></td>
|
||||
<td><button class="company-detail-button" type="button" data-company-job-id="${escapeHtml(job.job_id)}">${escapeHtml(I18N?.t("common.view") || "查看")}</button></td>
|
||||
</tr>`).join("");
|
||||
</tr>`;
|
||||
}).join("");
|
||||
$$('[data-company-job-id]', body).forEach((button) => button.addEventListener("click", () => loadCompanyReportJob(button.dataset.companyJobId, true)));
|
||||
}
|
||||
|
||||
@@ -1754,7 +1837,7 @@
|
||||
if (target) await loadCompanyReportJob(target.job_id);
|
||||
}
|
||||
} catch (error) {
|
||||
$("#company-history-rows").innerHTML = `<tr><td class="empty-cell" colspan="7">${escapeHtml(I18N?.t("company.draft_error") || "任务记录暂时无法读取")}</td></tr>`;
|
||||
$("#company-history-rows").innerHTML = `<tr><td class="empty-cell" colspan="8">${escapeHtml(I18N?.t("company.draft_error") || "任务记录暂时无法读取")}</td></tr>`;
|
||||
if (restore) showToast(error.message, true);
|
||||
} finally {
|
||||
state.companyHistoryLoading = false;
|
||||
@@ -1888,6 +1971,7 @@
|
||||
renderPagination("monthly", state.monthlyTotal, state.monthlyOffset, state.monthlyLoading);
|
||||
if (state.analytics) renderAnalytics(state.analytics);
|
||||
else resetAnalytics(I18N?.t("bi.empty") || "暂无渠道与房型数据");
|
||||
renderCompanySource(state.companySource);
|
||||
if (state.companySourceDraft?.summary) renderCompanyDraft(state.companySourceDraft);
|
||||
else renderCompanyDraft(null);
|
||||
renderPagination("company", state.companyReportsTotal, state.companyReportsOffset, state.companyHistoryLoading);
|
||||
|
||||
Reference in New Issue
Block a user