'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');
if (!entities.length) {
tbody.innerHTML = '
| 本地湖为空 —— 取数机先「同步数据」,其他电脑点右上「从云端拉取」 |
';
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} 行` : '未推送';
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)} |
`;
}).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;
}
}
window.shanLakeInit = function () {
if (!inited) {
inited = true;
$('btnLakeRefresh').addEventListener('click', loadLake);
$('btnLakePull').addEventListener('click', pullAll);
}
loadLake();
};
})();