'use strict'; // 数据中台页:本地湖全景 + 云端同步(推送/拉取) // 读取 GET /api/reports/lake;推送逐主体执行(POST /api/reports/aitable/push)。 (function () { const $ = (id) => document.getElementById(id); let inited = false; let loading = false; function fmtDate(ymd) { const s = String(ymd || ''); return /^\d{8}$/.test(s) ? `${s.slice(0, 4)}-${s.slice(4, 6)}-${s.slice(6, 8)}` : (s || '–'); } function fmtTime(iso) { if (!iso) return '–'; const d = new Date(iso); return Number.isNaN(d.getTime()) ? String(iso) : `${d.getMonth() + 1}/${d.getDate()} ${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`; } function esc(value) { const div = document.createElement('div'); div.textContent = String(value ?? ''); return div.innerHTML; } function setBadge(id, text, cls) { const badge = $(id); if (!badge) return; badge.textContent = text; badge.className = 'badge ' + (cls || 'badge-info'); } function renderKpis(data) { $('lakeEntityCount').textContent = data.entities.length; $('lakeRowCount').textContent = data.totalRows; $('lakeCoverage').textContent = data.coverage ? `${fmtDate(data.coverage.from)} ~ ${fmtDate(data.coverage.to)}` : '–'; const lastSyncs = data.entities.map((e) => e.lastSync && e.lastSync.at).filter(Boolean).sort(); $('lakeLastSync').textContent = lastSyncs.length ? fmtTime(lastSyncs[lastSyncs.length - 1]) : '–'; $('lakeRowsBadge').textContent = `${data.entities.length} 主体`; } function renderEntities(entities) { const tbody = $('lakeEntityRows'); // 空湖:与明细 tab 同款 .empty-hint 空态(图标+标题+引导文案),表格整体隐藏 $('lakeEntityTable').hidden = !entities.length; $('lakeEmpty').hidden = !!entities.length; if (!entities.length) return; tbody.innerHTML = entities.map((e) => { const cov = e.coverage ? `${fmtDate(e.coverage.from)} ~ ${fmtDate(e.coverage.to)}` : '–'; const sync = e.lastSync ? `${fmtTime(e.lastSync.at)}(${fmtDate(e.lastSync.from)}~${fmtDate(e.lastSync.to)})${e.lastSync.ok ? '' : ' ⚠'}` : '–'; const push = e.lastPush ? `${fmtTime(e.lastPush.at)} / ${e.lastPush.pushedRows || 0} 行` : '未推送'; const pending = typeof e.pending === 'number' && e.pending > 0 ? `待推 ${e.pending} 行` : ''; return ` ${esc(e.name || e.key)} ${e.shopCount || 0} / ${e.chainCount || 0} ${e.rows} ${e.byScope.company || 0} ${e.byScope.chain || 0} ${e.byScope.shop || 0} ${e.byScope.summary || 0} ${cov} ${esc(sync)} ${esc(push)} ${pending} `; }).join(''); } async function loadLake() { if (loading) return; loading = true; try { const res = await fetch('/api/reports/lake'); const data = await res.json(); if (!res.ok) throw new Error(data.error || `HTTP ${res.status}`); renderKpis(data); renderEntities(data.entities); if (!data.aitable.enabled) setBadge('lakeSyncBadge', '云端同步未启用(系统设置)', 'badge-info'); else if (!data.aitable.operatorConfigured) setBadge('lakeSyncBadge', '云端配置不完整', 'badge-fail'); else setBadge('lakeSyncBadge', '云端就绪', 'badge-ok'); } catch (error) { setBadge('lakeSyncBadge', `加载失败:${error.message}`, 'badge-fail'); } finally { loading = false; } } // 推送动作在数据采集页(取数机的动作);中台只负责看数与从云端拉取 async function pullAll() { const btn = $('btnLakePull'); btn.disabled = true; try { await window.shanAitableAction('pull', 'lakeSyncBadge', {}); await loadLake(); } catch { /* 徽标已由 aitableAction 写入 */ } finally { btn.disabled = false; } } // 页内 tab:湖全景 / 明细数据(明细区首次激活时才初始化报表浏览,懒加载) function activateLakeTab(tab) { const tabs = $('lakeTabs'); if (!tabs) return; tabs.querySelectorAll('button').forEach((b) => b.classList.toggle('active', b.dataset.tab === tab)); $('lakeTabOverview').hidden = tab !== 'overview'; $('lakeTabDetail').hidden = tab !== 'detail'; if (tab === 'overview') loadLake(); else if (window.shanReportsInit) window.shanReportsInit(); } window.shanLakeInit = function () { if (!inited) { inited = true; $('btnLakeRefresh').addEventListener('click', loadLake); $('btnLakePull').addEventListener('click', pullAll); $('lakeTabs').addEventListener('click', (event) => { const btn = event.target.closest('button[data-tab]'); if (btn) activateLakeTab(btn.dataset.tab); }); // 「?」弹窗:与采集页连接帮助同款交互(点按钮开合,点外部关闭) const helpBtn = $('btnLakeHelp'); const helpPop = $('lakeHelpPopover'); if (helpBtn && helpPop) { helpBtn.addEventListener('click', (event) => { event.stopPropagation(); helpPop.hidden = !helpPop.hidden; helpBtn.classList.toggle('active', !helpPop.hidden); helpBtn.setAttribute('aria-expanded', String(!helpPop.hidden)); }); document.addEventListener('click', (event) => { if (!helpPop.hidden && !event.target.closest('.conn-help-wrap')) { helpPop.hidden = true; helpBtn.classList.remove('active'); helpBtn.setAttribute('aria-expanded', 'false'); } }); } } activateLakeTab('overview'); }; // 供问数「应用到报表」等外部入口直接落到明细 tab window.shanLakeShowDetail = function () { activateLakeTab('detail'); }; })();