/* ---- 联系人导入三段式(upload→confirm→result/failures 轮询;id 加 cimp 前缀避让客户导入 tab) ---- */ let cimpTaskId = null, cimpPollTimer = null; function openCimp() { cimpTaskId = null; clearInterval(cimpPollTimer); $('cimpStep1').style.display = ''; $('cimpStep2').style.display = 'none'; $('cimpStep3').style.display = 'none'; $('cimpFile').value = ''; $('cimpCustName').textContent = custName(); $('cimpOverlay').classList.add('show'); } function cimpClose() { $('cimpOverlay').classList.remove('show'); clearInterval(cimpPollTimer); } async function cimpTemplateDownload() { try { const blob = await apiDownload('/api/customer/contact/import/template', 'GET'); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = '联系人导入模板-V1.xlsx'; a.click(); URL.revokeObjectURL(a.href); } catch (err) { toast('模板下载失败(' + err.code + '):' + err.message, 'err'); } } function cimpReupload() { $('cimpStep1').style.display = ''; $('cimpStep2').style.display = 'none'; } async function cimpUpload() { const file = $('cimpFile').files[0]; if (!file) { toast('请先选择 .xlsx 文件', 'err'); return; } const fd = new FormData(); fd.append('customerId', D.id); fd.append('file', file); fd.append('importMode', $('cimpMode').value); fd.append('duplicateStrategy', $('cimpStrategy').value); $('cimpUploadBtn').disabled = true; try { const p = await api('/api/customer/contact/import/upload', { method: 'POST', body: fd }); cimpTaskId = p.taskId; $('cimpPreviewHead').textContent = '预检完成(任务 ' + p.taskId + ' 待确认):共 ' + p.totalCount + ' 行,预计新增 ' + p.insertCount + '、更新 ' + p.updateCount + '、失败 ' + p.failCount + '、疑似重复 ' + p.suspectCount; $('cimpPreviewTbody').innerHTML = (p.rows || []).map(r => '' + r.rowNum + '' + esc(r.identity || '') + '' + esc(r.verdict || '') + '' + esc(r.reason || '--') + '').join('') || '无明细(全部可入库)'; $('cimpStep1').style.display = 'none'; $('cimpStep2').style.display = ''; } catch (err) { toast('预检失败(' + err.code + '):' + err.message, 'err'); // 67023 守门/模板版本/行数超限 } finally { $('cimpUploadBtn').disabled = false; } } async function cimpConfirmTask() { if (!cimpTaskId) return; try { await api('/api/customer/contact/import/confirm?taskId=' + encodeURIComponent(cimpTaskId), { method: 'POST' }); $('cimpStep2').style.display = 'none'; $('cimpStep3').style.display = ''; $('cimpResultHead').textContent = '导入执行中…'; $('cimpFailTbody').innerHTML = ''; pollCimpResult(); } catch (err) { toast('确认失败(' + err.code + '):' + err.message, 'err'); // 67024 重复确认/状态不允许 } } function pollCimpResult() { clearInterval(cimpPollTimer); const tick = async () => { try { const r = await api('/api/customer/contact/import/result?taskId=' + encodeURIComponent(cimpTaskId)); if (r.status === 1) { $('cimpResultHead').textContent = '导入执行中…(总 ' + r.totalCount + ' 行)'; return; } clearInterval(cimpPollTimer); const statusTxt = r.status === 2 ? '已完成' : (r.status === 3 ? '已失败:' + (r.failReason || '--') : '状态 ' + r.status); $('cimpResultHead').textContent = statusTxt + ':新增 ' + r.insertCount + '、更新 ' + r.updateCount + '、未变化 ' + r.unchangedCount + '、失败 ' + r.failCount + '、疑似重复 ' + r.suspectCount; const fails = await api('/api/customer/contact/import/failures?taskId=' + encodeURIComponent(cimpTaskId)).catch(() => []); $('cimpFailTbody').innerHTML = (fails || []).map(f => '' + f.rowNum + '' + esc(f.name || '') + '' + esc(f.phone || '--') + '' + esc(f.failReason || '') + '').join('') || '无失败/疑似明细'; if (D.sub === 'contacts') { await Promise.all([loadContacts(), loadGraph()]); layoutGraph(); renderContactsAll(); } } catch (err) { clearInterval(cimpPollTimer); toast('结果查询失败(' + err.code + '):' + err.message, 'err'); } }; tick(); cimpPollTimer = setInterval(tick, 1000); } function cimpDone() { $('cimpOverlay').classList.remove('show'); clearInterval(cimpPollTimer); } /* ---- 批量导出(POST /export 全量导出该客户 xlsx;电话列脱敏口径) ---- */ async function exportContacts() { try { const blob = await apiDownload('/api/customer/contact/export?customerId=' + D.id, 'POST'); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = '联系人导出.xlsx'; a.click(); URL.revokeObjectURL(a.href); addLog('数据', opName() + ' 导出联系人(xlsx 全量,电话恒脱敏)'); toast('导出已提交(全量,电话恒脱敏)', 'ok'); } catch (err) { toast('导出失败(' + err.code + '):' + err.message, 'err'); } }