export function validateSitePayload(payload, site) { const data = payload?.data; if (!data || data.site !== site || !Array.isArray(data.list)) throw new Error('库区数据不匹配'); if (data.list.some(row => row.site !== site)) throw new Error('仓库归属不匹配'); return data; } export async function fetchSiteData(site, fetcher = fetch) { const path = `/api/index/granaryList?site=${encodeURIComponent(site)}`; const endpoints = [path, `https://grain.gynhc.com${path}`]; for (const url of endpoints) { try { const response = await fetcher(url, { cache: 'no-store', signal: AbortSignal.timeout(8000) }); if (!response.ok) continue; return validateSitePayload(await response.json(), site); } catch (_) { /* Try the configured service if this origin is unavailable. */ } } throw new Error('暂时无法读取库区数据'); } export function showSiteDataState(site, state, count, hasDemo = false) { const wrapper = document.getElementById('screen-wrapper'); if (!wrapper) return; let badge = document.getElementById('site-data-state'); if (!badge) { badge = document.createElement('div'); badge.id = 'site-data-state'; badge.setAttribute('role', 'status'); badge.style.cssText = 'position:absolute;top:83px;left:50%;transform:translateX(-50%);z-index:100;padding:5px 14px;border:1px solid #35536a;border-radius:4px;background:#0b1828;color:#bcd4e8;font-size:13px;pointer-events:none;white-space:nowrap'; wrapper.appendChild(badge); } const name = site === 'xishui' ? '习水库' : '遵义中心库'; badge.dataset.state = state; badge.hidden = state === 'live'; badge.textContent = state === 'live' ? `${name} · 后台数据 · ${count} 座仓储设施${hasDemo ? ' · 含 DEMO 演示化验,非实测' : ''}` : state === 'empty' ? `${name} · 暂无仓库资料` : `${name} · 数据连接失败,请稍后重试`; let empty = document.getElementById('site-empty-state'); if (!empty) { empty = document.createElement('div'); empty.id = 'site-empty-state'; empty.style.cssText = 'position:absolute;inset:120px 0 50px;z-index:99;display:none;align-items:center;justify-content:center;background:rgba(6,16,29,.97);color:#bcd4e8;font-size:24px'; wrapper.appendChild(empty); } empty.style.display = state === 'live' ? 'none' : 'flex'; empty.textContent = state === 'empty' ? '当前库区暂无仓库资料,请在后台录入' : '暂时无法读取库区数据,请检查网络后刷新'; }