Spaces:
Sleeping
Sleeping
| const fileInput = document.getElementById("file-input"); | |
| const statusText = document.getElementById("status-text"); | |
| const statusDetail = document.getElementById("status-detail"); | |
| const progressFill = document.getElementById("progress-fill"); | |
| const progressPercent = document.getElementById("progress-percent"); | |
| const progressLabel = document.getElementById("progress-label"); | |
| const sguidCount = document.getElementById("sguid-count"); | |
| const skuidCount = document.getElementById("skuid-count"); | |
| const productLineCount = document.getElementById("product-line-count"); | |
| const outputPath = document.getElementById("output-path"); | |
| const statToday = document.getElementById("stat-today"); | |
| const statMonth = document.getElementById("stat-month"); | |
| const statSevenDays = document.getElementById("stat-seven-days"); | |
| const resultActions = document.getElementById("sgu-result-actions"); | |
| const downloadBtn = document.getElementById("sgu-download-btn"); | |
| let currentTaskId = null; | |
| let currentResult = null; | |
| let pollingTimer = null; | |
| let progressTimer = null; | |
| async function refreshStats() { | |
| const response = await fetch("/api/stats"); | |
| if (!response.ok) { | |
| throw new Error("统计信息刷新失败"); | |
| } | |
| const data = await response.json(); | |
| statToday.textContent = data.today ?? 0; | |
| statMonth.textContent = data.month ?? 0; | |
| statSevenDays.textContent = data.seven_days ?? 0; | |
| } | |
| function setProgress(value, label) { | |
| const safeValue = Math.max(0, Math.min(100, Math.round(value))); | |
| progressFill.style.width = `${safeValue}%`; | |
| progressPercent.textContent = `${safeValue}%`; | |
| progressLabel.textContent = label; | |
| } | |
| function startProgressSimulation() { | |
| let current = Math.max(18, Number.parseInt(progressPercent.textContent, 10) || 0); | |
| setProgress(current, "文件已上传,准备开始分析..."); | |
| progressTimer = window.setInterval(() => { | |
| if (current < 72) { | |
| current += current < 42 ? 7 : 4; | |
| setProgress(current, "正在汇总数据,请稍候..."); | |
| return; | |
| } | |
| if (current < 90) { | |
| current += 1; | |
| setProgress(current, "正在生成结果文件..."); | |
| } | |
| }, 500); | |
| } | |
| function stopProgressSimulation() { | |
| if (progressTimer) { | |
| window.clearInterval(progressTimer); | |
| progressTimer = null; | |
| } | |
| } | |
| function resetView() { | |
| if (pollingTimer) { | |
| window.clearTimeout(pollingTimer); | |
| pollingTimer = null; | |
| } | |
| stopProgressSimulation(); | |
| currentTaskId = null; | |
| currentResult = null; | |
| resultActions.classList.add("hidden"); | |
| sguidCount.textContent = "0"; | |
| skuidCount.textContent = "0"; | |
| productLineCount.textContent = "0"; | |
| outputPath.textContent = "尚未生成"; | |
| } | |
| function renderCompletedResult(result) { | |
| currentResult = result; | |
| const counts = result.counts || {}; | |
| sguidCount.textContent = counts.SGUID ?? 0; | |
| skuidCount.textContent = counts.SKUID ?? 0; | |
| productLineCount.textContent = counts.PRODUCT_LINE ?? 0; | |
| outputPath.textContent = result.output_file || result.output_filename || "尚未生成"; | |
| resultActions.classList.remove("hidden"); | |
| if (result.result_type === "success") { | |
| statusText.textContent = "已处理成功"; | |
| statusDetail.textContent = `结果文件 ${result.output_filename} 已生成,请点击下方按钮下载。`; | |
| setProgress(100, "处理完成,结果文件已生成"); | |
| return; | |
| } | |
| statusText.textContent = "已生成错误说明"; | |
| statusDetail.textContent = `系统已生成错误说明文件 ${result.output_filename},请点击下方按钮下载查看。`; | |
| setProgress(100, "处理完成,错误说明文件已生成"); | |
| } | |
| async function pollStatus() { | |
| if (!currentTaskId) { | |
| return; | |
| } | |
| const response = await fetch(`/api/process/status/${currentTaskId}`); | |
| const payload = await response.json(); | |
| if (!response.ok) { | |
| throw new Error(payload.error || "任务状态获取失败"); | |
| } | |
| if (payload.status === "processing") { | |
| pollingTimer = window.setTimeout(pollStatus, 1000); | |
| return; | |
| } | |
| if (payload.status === "completed") { | |
| renderCompletedResult(payload.result || {}); | |
| await refreshStats(); | |
| return; | |
| } | |
| if (payload.status === "error") { | |
| throw new Error(payload.result?.error || "处理失败,请稍后重试。"); | |
| } | |
| pollingTimer = window.setTimeout(pollStatus, 1000); | |
| } | |
| async function uploadFile(file) { | |
| const formData = new FormData(); | |
| formData.append("file", file); | |
| resetView(); | |
| fileInput.disabled = true; | |
| setProgress(6, "正在上传文件..."); | |
| statusText.textContent = "处理中,请稍候..."; | |
| statusDetail.textContent = `正在处理文件:${file.name}`; | |
| outputPath.textContent = "服务器保存中..."; | |
| const response = await fetch("/api/process", { | |
| method: "POST", | |
| body: formData, | |
| }); | |
| const payload = await response.json(); | |
| if (!response.ok || payload.success === false) { | |
| throw new Error(payload.error || "上传失败"); | |
| } | |
| currentTaskId = payload.task_id; | |
| setProgress(22, "文件上传成功,正在排队分析..."); | |
| startProgressSimulation(); | |
| await pollStatus(); | |
| } | |
| fileInput.addEventListener("change", async (event) => { | |
| const [file] = event.target.files; | |
| if (!file) { | |
| return; | |
| } | |
| try { | |
| await uploadFile(file); | |
| } catch (error) { | |
| stopProgressSimulation(); | |
| statusText.textContent = "处理失败"; | |
| statusDetail.textContent = error.message; | |
| outputPath.textContent = "服务器未生成文件"; | |
| setProgress(100, "处理失败"); | |
| } finally { | |
| stopProgressSimulation(); | |
| fileInput.disabled = false; | |
| fileInput.value = ""; | |
| } | |
| }); | |
| downloadBtn.addEventListener("click", () => { | |
| if (!currentResult?.output_filename) { | |
| return; | |
| } | |
| window.open(`/api/process/download/${currentResult.output_filename}`, "_blank"); | |
| }); | |
| window.addEventListener("beforeunload", () => { | |
| if (pollingTimer) { | |
| clearTimeout(pollingTimer); | |
| } | |
| stopProgressSimulation(); | |
| }); | |
| setProgress(0, "等待上传文件"); | |
| refreshStats().catch(() => { | |
| statToday.textContent = "0"; | |
| statMonth.textContent = "0"; | |
| statSevenDays.textContent = "0"; | |
| }); | |