'use strict'; (function () { const ICON_DOWNLOAD = ''; function esc(value) { const div = document.createElement('div'); div.textContent = String(value ?? ''); return div.innerHTML; } const state = { initialized: false, loading: false, root: '', items: [], filter: 'all', keyword: '', }; const FILTER_LABELS = { logo: 'LOGO', banner: '海报', signage: '招牌', sticker: '贴纸', dish: '菜品', other: '其他', }; function formatBytes(size) { if (!Number.isFinite(size) || size <= 0) return '—'; if (size < 1024 * 1024) return `${Math.round(size / 1024)} KB`; return `${(size / 1024 / 1024).toFixed(1)} MB`; } function formatTime(value) { if (!value) return ''; const date = new Date(value); const pad = (n) => String(n).padStart(2, '0'); return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`; } function getFilteredItems() { const keyword = state.keyword.trim().toLowerCase(); return state.items.filter((item) => { if (state.filter !== 'all' && item.kind !== state.filter) return false; if (!keyword) return true; return `${item.shopName} ${item.name} ${item.fileName}`.toLowerCase().includes(keyword); }); } function renderSummary() { const summary = document.getElementById('historySummary'); const filtered = getFilteredItems(); if (state.loading) { summary.textContent = '正在加载历史作品…'; return; } summary.textContent = state.items.length ? `共 ${state.items.length} 件作品 · 当前显示 ${filtered.length} 件` : '暂无历史作品'; } function renderGallery() { const gallery = document.getElementById('historyGallery'); const items = getFilteredItems(); gallery.classList.toggle('empty', items.length === 0); if (!items.length) { gallery.innerHTML = `

${state.loading ? '正在加载作品' : '暂无匹配的历史作品'}

${state.loading ? '请稍候' : '生成完成的作品会自动出现在这里'}
`; return; } gallery.innerHTML = ''; items.forEach((item) => { const card = document.createElement('figure'); card.className = 'creation-card'; card.dataset.kind = item.kind; const frame = document.createElement('div'); frame.className = 'creation-frame'; if (item.kind === 'sticker') frame.classList.add('transparent-bg'); const image = document.createElement('img'); image.src = item.url; image.alt = `${item.shopName} ${item.name}`; image.loading = 'lazy'; frame.appendChild(image); window.shanHoverZoom(frame, image.src, item.kind === 'sticker'); const kind = document.createElement('span'); kind.className = 'creation-kind'; kind.textContent = FILTER_LABELS[item.kind] || '其他'; frame.appendChild(kind); const download = document.createElement('a'); download.className = 'result-download-icon'; download.href = item.url; download.download = ''; download.title = '下载原图'; download.setAttribute('aria-label', '下载原图'); download.innerHTML = ICON_DOWNLOAD; frame.appendChild(download); const caption = document.createElement('figcaption'); const title = document.createElement('div'); title.className = 'creation-title'; title.title = item.name; title.textContent = item.name; const shop = document.createElement('div'); shop.className = 'creation-shop'; shop.title = item.shopName; shop.textContent = item.shopName; const meta = document.createElement('div'); meta.className = 'creation-meta'; meta.textContent = `${formatTime(item.modifiedAt)} · ${formatBytes(item.fileSizeBytes)}`; caption.append(title, shop, meta); card.append(frame, caption); gallery.appendChild(card); }); } function render() { renderSummary(); renderGallery(); } async function loadHistory() { if (state.loading) return; state.loading = true; render(); try { const rootResponse = await fetch('/api/default-root'); const rootData = await rootResponse.json(); state.root = rootData.root; const response = await fetch(`/api/creations?root=${encodeURIComponent(state.root)}&limit=600`); const data = await response.json(); if (!response.ok) throw new Error(data.error || '历史作品加载失败'); state.items = data.items || []; } catch (error) { state.items = []; renderGallery(); document.getElementById('historySummary').textContent = error.message; } finally { state.loading = false; render(); } } function bindEvents() { document.getElementById('btnRefreshHistory').addEventListener('click', loadHistory); document.getElementById('historySearch').addEventListener('input', (event) => { state.keyword = event.target.value; render(); }); document.getElementById('historyFilters').addEventListener('click', (event) => { const button = event.target.closest('[data-filter]'); if (!button) return; state.filter = button.dataset.filter; document.querySelectorAll('#historyFilters .history-filter').forEach((item) => { item.classList.toggle('active', item === button); }); render(); }); } window.shanHistoryInit = function () { if (!state.initialized) { state.initialized = true; bindEvents(); } loadHistory(); }; })();