Allow independent dates while ARR field reviews are pending

This commit is contained in:
Wyndham ARR committed 2026-10-08 17:27:56 +08:00
1 parent fe8735aac2
commit fb07580c0c
15 files changed
+316 -16

No files matched your search

+76 -7
View File
@@ -24,6 +24,7 @@
arrDownloadStorageKey: "",
arrDownloadUsername: "",
arrDownloadContextId: "",
arrDownloadPendingReviews: [],
arrDataReview: null,
arrDataReviewRequestId: "",
arrDataReviewLoading: false,
@@ -31,6 +32,7 @@
arrDataReviewDisconnected: false,
arrDataReviewFinalizing: false,
arrDataReviewDrafts: {},
arrDataReviewDraftsByRequest: {},
arrDataReviewMessage: "",
arrDataReviewMessageError: false,
companySourceFile: null,
@@ -322,6 +324,53 @@
return state.arrDownloadTask?.status === "needs_data_review";
}
function selectedARRDateNeedsDataReview() {
return arrDownloadNeedsDataReview() && $("#arr-download-date").value === state.arrDownloadTask.report_date;
}
function rememberARRPendingReview(task) {
state.arrDownloadPendingReviews = state.arrDownloadPendingReviews.filter((item) => item.request_id !== task.request_id);
if (task.status === "needs_data_review") state.arrDownloadPendingReviews.push(task);
state.arrDownloadPendingReviews.sort((a, b) => b.report_date.localeCompare(a.report_date) || a.request_id.localeCompare(b.request_id));
}
function renderARRPendingReviews() {
const panel = $("#arr-download-pending");
panel.hidden = !state.arrDownloadPendingReviews.length;
$("#arr-download-pending-title").textContent = I18N.t("arr_download.pending_dates");
const locked = state.arrDownloadBusy || state.arrDownloadLoading || state.arrDataReviewLoading || state.arrDataReviewMutating
|| state.arrDataReviewFinalizing || arrDownloadActive() || arrDownloadNeedsReconciliation();
$("#arr-download-pending-list").innerHTML = state.arrDownloadPendingReviews.map((task) =>
`<button type="button" data-arr-pending-review="${escapeHtml(task.request_id)}" aria-pressed="${state.arrDownloadTask?.request_id === task.request_id}" ${locked ? "disabled" : ""}>${escapeHtml(task.report_date)} · ${escapeHtml(I18N.t("arr_download.pending_date"))}</button>`).join("");
}
async function selectARRPendingReview(requestId) {
if (!state.arrDownloadPendingReviews.some((task) => task.request_id === requestId)
|| state.arrDownloadBusy || state.arrDownloadLoading || state.arrDataReviewLoading || state.arrDataReviewMutating
|| state.arrDataReviewFinalizing || arrDownloadActive() || arrDownloadNeedsReconciliation()) return;
const contextId = state.arrDownloadContextId;
state.arrDownloadBusy = true;
renderARRDownload();
try {
const task = await api(`/api/arr-downloads/${encodeURIComponent(requestId)}`);
if (state.arrDownloadContextId !== contextId) return;
state.arrDownloadDateEdited = false;
$("#arr-download-date").value = task.report_date;
await acceptARRDownloadTask(task, { sync: false });
if (arrDownloadNeedsDataReview()) {
$("#arr-data-review-panel").scrollIntoView({ behavior: "smooth", block: "start" });
$("#arr-data-review-panel").focus({ preventScroll: true });
}
} catch (error) {
showToast(error.message, true);
} finally {
state.arrDownloadBusy = false;
renderARRDataReview();
renderARRDownload();
scheduleARRDownloadPoll();
}
}
function handleARRDownloadDateChange() {
state.arrDownloadDateEdited = true;
// Choosing the next report date must not abandon a running or uncertain request.
@@ -347,6 +396,7 @@
$("#arr-date-toggle").setAttribute("aria-label", I18N.t("arr_download.choose_date"));
$("#arr-download-help").textContent = I18N.t(locked ? "arr_download.submitting"
: arrDownloadActive() ? "arr_download.date_next"
: arrDownloadNeedsDataReview() ? "arr_download.date_independent"
: reconciling ? "arr_download.date_resume" : "arr_download.help",
{ date: state.arrDownloadIntent?.report_date });
if (locked) closeARRCalendar();
@@ -358,7 +408,7 @@
if (state.arrDownloadBusy) label = "arr_download.submitting";
else if (arrDownloadActive()) label = "arr_download.running";
else if (pending || state.arrDownloadDisconnected) label = "arr_download.check";
else if (arrDownloadNeedsDataReview()) label = "arr_download.complete_data";
else if (selectedARRDateNeedsDataReview()) label = "arr_download.complete_data";
else if (arrDownloadCanResume() || task?.status === "not_received") label = "arr_download.retry_date";
button.textContent = I18N.t(label, { date: task?.report_date });
button.setAttribute("aria-busy", String(state.arrDownloadBusy || arrDownloadActive()));
@@ -375,6 +425,7 @@
$("#arr-download-review").hidden = task?.status !== "needs_review" || !task.job_id;
$("#arr-download-data-review").hidden = !arrDownloadNeedsDataReview();
$("#arr-download-data-review").disabled = locked;
renderARRPendingReviews();
}
function clearARRDownloadPoll() {
@@ -394,6 +445,7 @@
async function acceptARRDownloadTask(task, { sync = true } = {}) {
state.arrDownloadTask = task;
rememberARRPendingReview(task);
state.arrDownloadDisconnected = false;
rememberARRIntent({ request_id: task.request_id, report_date: task.report_date });
if (!state.arrDownloadDateEdited) $("#arr-download-date").value = task.report_date;
@@ -465,8 +517,13 @@
state.arrDownloadTask = null;
state.arrDownloadDisconnected = false;
state.arrDownloadSynced = "";
resetARRDataReview();
state.arrDownloadPendingReviews = [];
resetARRDataReview({ clearDrafts: true });
}
state.arrDownloadPendingReviews = Array.isArray(config.pending_data_reviews)
? config.pending_data_reviews.filter((task) => task.status === "needs_data_review"
&& /^[0-9a-f]{32}$/.test(task.request_id) && validARRDate(task.report_date)) : [];
if (state.arrDownloadTask) rememberARRPendingReview(state.arrDownloadTask);
if (!state.arrDownloadRestored) {
state.arrDownloadRestored = true;
let saved;
@@ -505,7 +562,7 @@
await loadARRDownloadTask();
return;
}
if (arrDownloadNeedsDataReview()) {
if (selectedARRDateNeedsDataReview()) {
await loadARRDataReview(state.arrDownloadTask.request_id, { scroll: true });
return;
}
@@ -522,6 +579,7 @@
}
rememberARRIntent(intent); // Persist before the HTTP call, including a lost response.
state.arrDownloadTask = null;
resetARRDataReview();
state.arrDownloadBusy = true;
clearARRDownloadPoll();
renderARRDownload();
@@ -553,7 +611,11 @@
}
}
function resetARRDataReview() {
function resetARRDataReview({ clearDrafts = false } = {}) {
if (clearDrafts) state.arrDataReviewDraftsByRequest = {};
else if (state.arrDataReviewRequestId) {
state.arrDataReviewDraftsByRequest[state.arrDataReviewRequestId] = { ...state.arrDataReviewDrafts };
}
state.arrDataReview = null;
state.arrDataReviewRequestId = "";
state.arrDataReviewLoading = false;
@@ -572,7 +634,8 @@
}
function arrDataReviewCanFinalize(review = state.arrDataReview) {
return Boolean(review && review.status === "editing" && review.can_finalize && Number(review.pending_count) === 0
return Boolean(arrDownloadNeedsDataReview() && state.arrDownloadTask.request_id === state.arrDataReviewRequestId
&& !state.arrDownloadBusy && review && review.status === "editing" && review.can_finalize && Number(review.pending_count) === 0
&& Array.isArray(review.items) && review.items.every((item) => item.confirmed)
&& !Object.keys(state.arrDataReviewDrafts).length && !state.arrDataReviewLoading && !state.arrDataReviewMutating
&& !state.arrDataReviewDisconnected && !state.arrDataReviewFinalizing);
@@ -589,7 +652,8 @@
function renderARRDataReview() {
const panel = $("#arr-data-review-panel");
const review = state.arrDataReview;
panel.hidden = !state.arrDataReviewRequestId || !arrDownloadNeedsDataReview();
panel.hidden = !state.arrDataReviewRequestId || !arrDownloadNeedsDataReview()
|| state.arrDownloadTask.request_id !== state.arrDataReviewRequestId;
if (panel.hidden) return;
const busy = state.arrDataReviewLoading || state.arrDataReviewMutating;
const editable = review?.status === "editing" && !busy && !state.arrDataReviewDisconnected && !state.arrDataReviewFinalizing;
@@ -637,6 +701,7 @@
if (state.arrDataReviewRequestId !== requestId) {
resetARRDataReview();
state.arrDataReviewRequestId = requestId;
state.arrDataReviewDrafts = { ...state.arrDataReviewDraftsByRequest[requestId] };
}
const contextId = state.arrDownloadContextId;
state.arrDataReviewLoading = true;
@@ -3172,7 +3237,7 @@
});
$("#upload-button").addEventListener("click", handleUpload);
$("#arr-download-form").addEventListener("submit", submitARRDownload);
$("#arr-download-date").addEventListener("input", () => { state.arrDownloadDateEdited = true; });
$("#arr-download-date").addEventListener("input", handleARRDownloadDateChange);
$("#arr-download-date").addEventListener("change", handleARRDownloadDateChange);
$("#arr-download-review").addEventListener("click", async () => {
const jobId = state.arrDownloadTask?.job_id;
@@ -3180,6 +3245,10 @@
try { await openDailyPriceReview(jobId, true); } catch (error) { showToast(error.message, true); }
});
$("#arr-download-data-review").addEventListener("click", () => loadARRDataReview(state.arrDownloadTask?.request_id, { scroll: true }));
$("#arr-download-pending-list").addEventListener("click", (event) => {
const button = event.target.closest("[data-arr-pending-review]");
if (button) selectARRPendingReview(button.dataset.arrPendingReview);
});
$("#arr-data-review-refresh").addEventListener("click", () => loadARRDataReview());
$("#arr-data-review-finalize").addEventListener("click", finalizeARRDataReview);
$("#arr-data-review-body").addEventListener("input", (event) => {
+3
View File
@@ -124,6 +124,9 @@
"arr_download.needs_review": ["等待人工价格复核", "Awaiting price review", "รอตรวจสอบราคาด้วยตนเอง"],
"arr_download.needs_data_review": ["等待人工完善报表字段", "Awaiting source field review", "รอตรวจสอบข้อมูลรายงานด้วยตนเอง"],
"arr_download.complete_data": ["完善报表字段", "Complete report fields", "กรอกข้อมูลรายงานให้ครบ"],
"arr_download.date_independent": ["可选其他日期下载,当前待完善内容会保留。", "Choose another date to download; this review will be kept.", "เลือกวันอื่นเพื่อดาวน์โหลดได้ ข้อมูลที่รอตรวจสอบจะยังคงอยู่"],
"arr_download.pending_dates": ["待完善日期", "Dates awaiting field review", "วันที่รอตรวจสอบข้อมูล"],
"arr_download.pending_date": ["待完善", "Complete fields", "รอตรวจสอบ"],
"arr_download.source_failed": ["到店数据获取未完成,请继续原任务重试。", "Arrival data could not be fetched. Resume the original task to retry.", "ยังดึงข้อมูลผู้เข้าพักไม่สำเร็จ โปรดดำเนินงานเดิมต่อเพื่อลองอีกครั้ง"],
"arr_download.source_interrupted": ["到店数据获取中断,请继续原任务。", "Arrival data fetch was interrupted. Resume the original task.", "การดึงข้อมูลผู้เข้าพักขัดจังหวะ โปรดดำเนินงานเดิมต่อ"],
"arr_download.failed": ["任务未完成,请查看任务日志", "Task failed. Check the task log.", "งานไม่สำเร็จ โปรดดูบันทึกงาน"],
+4
View File
@@ -74,6 +74,10 @@
<span class="arr-download-indicator" aria-hidden="true"></span>
<span id="arr-download-status">正在连接下载服务…</span>
</div>
<div class="arr-download-pending" id="arr-download-pending" hidden>
<span id="arr-download-pending-title">待完善日期</span>
<div id="arr-download-pending-list"></div>
</div>
<div class="arr-download-actions">
<button class="arr-download-review" id="arr-download-data-review" type="button" hidden>完善报表字段</button>
<button class="arr-download-review" id="arr-download-review" type="button" hidden>查看价格复核</button>
+7
View File
@@ -201,6 +201,13 @@ button { color: inherit; }
.arr-download-actions .primary-button { min-height: 34px; margin: 0; padding: 0 12px; border-radius: 8px; font-size: 11px; }
.arr-download-review { padding: 4px 0; border: 0; color: var(--blue-dark); background: transparent; font-size: 11px; font-weight: 650; cursor: pointer; text-decoration: underline; text-underline-offset: 3px; }
.arr-download-review:hover { color: var(--blue); }
.arr-download-pending { margin: 10px 0 12px; }
.arr-download-pending[hidden] { display: none; }
.arr-download-pending > span { display: block; margin-bottom: 5px; color: var(--muted); font-size: 11px; }
#arr-download-pending-list { display: flex; flex-wrap: wrap; gap: 6px; max-height: 110px; overflow-y: auto; }
#arr-download-pending-list button { padding: 5px 8px; border: 1px solid var(--line); border-radius: 6px; color: var(--blue-dark); background: #fff; font: inherit; font-size: 11px; cursor: pointer; }
#arr-download-pending-list button[aria-pressed="true"] { border-color: var(--blue); background: #f0f4ff; }
#arr-download-pending-list button:disabled { opacity: .55; cursor: default; }
.arr-data-review-panel { margin: 20px 0; border-color: #e6d4b5; overflow: hidden; }
.arr-data-review-panel[hidden] { display: none; }
.arr-data-review-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; padding: 20px; background: #fffcf5; }