const $ = (id) => document.getElementById(id); const msg = (t) => $("msg").textContent = typeof t === 'string' ? t : JSON.stringify(t, null, 2); const tokenKey = 'asset_tracker_token'; let categories = []; function token(){ return localStorage.getItem(tokenKey) || ''; } async function api(path, method='GET', body){ const headers = {}; if(token()) headers['Authorization'] = `Bearer ${token()}`; if(body) headers['Content-Type'] = 'application/json'; const res = await fetch(path, { method, headers, body: body ? JSON.stringify(body) : undefined }); const data = await res.json().catch(() => ({})); if(!res.ok) throw new Error(data.error || `${res.status}`); return data; } async function doLogin(){ try{ const data = await api('/api/v1/auth/login', 'POST', { username: $('username').value.trim(), password: $('password').value }); localStorage.setItem(tokenKey, data.access_token); $('login-section').classList.add('hidden'); $('app-section').classList.remove('hidden'); await reloadAll(); msg('登录成功'); }catch(e){ msg(`登录失败: ${e.message}`); } } async function loadCategories(){ const data = await api('/api/v1/categories'); categories = data.data || []; $('category-list').innerHTML = categories.map(c => `
  • #${c.id} ${c.name} (${c.type})
  • `).join('') || '
  • 暂无分类
  • '; $('asset-category').innerHTML = categories.map(c => ``).join(''); } async function addCategory(){ try{ await api('/api/v1/categories', 'POST', { name: $('cat-name').value.trim(), type: $('cat-type').value }); $('cat-name').value=''; await loadCategories(); msg('分类创建成功'); }catch(e){ msg(`分类创建失败: ${e.message}`); } } function toRFC3339(localVal){ if(!localVal) return ''; const d = new Date(localVal); return d.toISOString(); } async function addAsset(){ try{ await api('/api/v1/assets', 'POST', { name: $('asset-name').value.trim(), category_id: Number($('asset-category').value), quantity: Number($('asset-quantity').value || 0), unit_price: Number($('asset-price').value || 0), currency: $('asset-currency').value.trim().toUpperCase(), expiry_date: toRFC3339($('asset-expiry').value) }); $('asset-name').value=''; await loadAssets(); await loadDashboard(); msg('资产创建成功'); }catch(e){ msg(`资产创建失败: ${e.message}`); } } async function loadAssets(){ const data = await api('/api/v1/assets?page=1&page_size=100'); const rows = data.data || []; const map = new Map(categories.map(c => [c.id, c.name])); $('asset-tbody').innerHTML = rows.map(a => ` ${a.id} ${a.name} ${map.get(a.category_id) || a.category_id} ${a.total_value} ${a.currency} ${a.status} ${a.expiry_date || '-'} `).join('') || '暂无资产'; $('asset-cards').innerHTML = rows.map(a => `
    #${a.id} ${a.name}${a.status}
    分类${map.get(a.category_id) || a.category_id}
    金额${a.total_value} ${a.currency}
    到期${a.expiry_date || '-'}
    `).join('') || '
    暂无资产
    '; } async function delAsset(id){ try{ await api(`/api/v1/assets/${id}`, 'DELETE'); await loadAssets(); await loadDashboard(); msg(`已删除资产 #${id}`); }catch(e){ msg(`删除失败: ${e.message}`); } } window.delAsset = delAsset; async function loadDashboard(){ const d = await api('/api/v1/dashboard/summary'); const byCat = (d.by_category || []).map(x => `${x.category_name}: ${x.total_value}`).join('
    ') || '无'; $('dashboard').innerHTML = `
    总资产
    ${d.total_assets_value}
    分类占比
    ${byCat}
    30天到期
    ${(d.expiring_in_30_days || []).length} 条
    `; } async function reloadAll(){ await loadCategories(); await loadAssets(); await loadDashboard(); } $('login-btn').addEventListener('click', doLogin); $('add-cat').addEventListener('click', addCategory); $('add-asset').addEventListener('click', addAsset); $('refresh-dashboard').addEventListener('click', loadDashboard); (async function init(){ if(token()){ $('login-section').classList.add('hidden'); $('app-section').classList.remove('hidden'); try{ await reloadAll(); }catch(e){ msg(`自动加载失败: ${e.message}`); } } })();