AI works here

This commit is contained in:
2026-04-30 12:48:29 -04:00
parent 92024c8a64
commit 6f4519894b
16 changed files with 1793 additions and 303 deletions
+50 -3
View File
@@ -145,6 +145,17 @@ function createRouter(getActiveInstance) {
}
});
router.get('/api/maps', async (req, res) => {
if (!dbAvailable()) return res.status(503).json({ error: 'Storage database not initialized' });
try {
const maps = await database.getAllMaps();
res.json({ maps });
} catch (error) {
console.error('API Error /api/maps:', error);
res.status(500).json({ error: error.message });
}
});
router.get('/api/special-items', async (req, res) => {
if (!dbAvailable()) return res.status(503).json({ error: 'Storage database not initialized' });
try {
@@ -323,6 +334,7 @@ const webUI = {
<div class="tab active" onclick="switchStorageSubTab('inventory')">Inventory</div>
<div class="tab" onclick="switchStorageSubTab('map')">Storage Map</div>
<div class="tab" onclick="switchStorageSubTab('special')">Special Items</div>
<div class="tab" onclick="switchStorageSubTab('maps')">Maps</div>
<div class="tab" onclick="switchStorageSubTab('withdraw')">Withdraw</div>
</div>
<div id="stab-inventory" class="stab-content active" style="margin-top:16px">
@@ -353,6 +365,12 @@ const webUI = {
<div id="specialItems"><div style="padding:20px;color:#6b7280;text-align:center">Click tab to load...</div></div>
</div>
</div>
<div id="stab-maps" class="stab-content" style="margin-top:16px">
<div class="panel">
<h3>Filled Maps</h3>
<div id="mapsGrid"><div style="padding:20px;color:#6b7280;text-align:center">Click tab to load...</div></div>
</div>
</div>
<div id="stab-withdraw" class="stab-content" style="margin-top:16px">
<div class="panel">
<h3>Request Withdrawal</h3>
@@ -455,6 +473,11 @@ const webUI = {
.special-card .sp-withdraw button{background:#2563eb;color:#fff;border:none;padding:6px 12px;border-radius:4px;cursor:pointer;font-size:.8em}
.special-card .sp-withdraw button:hover{background:#1d4ed8}
.special-card .sp-status{font-size:.8em;margin-top:4px;min-height:16px}
.maps-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:12px}
.map-card{background:#111827;border:1px solid #374151;border-radius:8px;padding:8px;text-align:center;transition:border-color .2s}
.map-card:hover{border-color:#60a5fa}
.map-card img{width:128px;height:128px;image-rendering:pixelated;border-radius:4px}
.map-card .map-label{font-size:.8em;color:#9ca3af;margin-top:6px}
.stab-content{display:none}
.stab-content.active{display:block}
.storage-sub-tabs{display:flex;border-bottom:1px solid #374151}
@@ -462,7 +485,7 @@ const webUI = {
`,
js: `
let allItems=[], mapData=[], sortKey='total_count', sortDir=-1;
let specialLoaded=false, storageSubTab='inventory';
let specialLoaded=false, mapsLoaded=false, storageSubTab='inventory';
function onStorageTabActive() {
if (allItems.length === 0) { loadStats(); loadInventory(); loadPlayers(); }
@@ -474,12 +497,13 @@ function switchStorageSubTab(name) {
document.querySelectorAll('.stab-content').forEach(t => t.classList.remove('active'));
const el = document.getElementById('stab-'+name);
if (el) el.classList.add('active');
const subNames=['inventory','map','special','withdraw'];
const subNames=['inventory','map','special','maps','withdraw'];
const tabs = document.querySelectorAll('.storage-sub-tabs .tab');
const idx = subNames.indexOf(name);
if (idx >= 0 && tabs[idx]) tabs[idx].classList.add('active');
if (name === 'map' && mapData.length === 0) loadMap();
if (name === 'special' && !specialLoaded) loadSpecialItems();
if (name === 'maps' && !mapsLoaded) loadMaps();
}
async function loadStats() {
@@ -875,7 +899,30 @@ async function loadPlayers(){
try{const r=await fetch('/api/players');if(!r.ok)return;const d=await r.json();playerNames=(d.players||[]).map(p=>p.player_name)}catch(e){}
}
function storageLoadAll(){loadStats();loadInventory();loadPlayers();if(storageSubTab==='map')loadMap();if(storageSubTab==='special')loadSpecialItems()}
async function loadMaps() {
const container = document.getElementById('mapsGrid');
container.innerHTML = '<div style="padding:20px;color:#6b7280;text-align:center">Loading...</div>';
try {
const r = await fetch('/api/maps');
const d = await r.json();
const maps = d.maps || [];
mapsLoaded = true;
if (maps.length === 0) {
container.innerHTML = '<div style="padding:20px;color:#6b7280;text-align:center">No maps captured yet</div>';
return;
}
container.innerHTML = '<div class="maps-grid">' + maps.map(m =>
'<div class="map-card">' +
'<img src="data:image/png;base64,' + m.image_data + '" alt="Map #' + m.map_id + '">' +
'<div class="map-label">Map #' + m.map_id + '</div>' +
'</div>'
).join('') + '</div>';
} catch(e) {
container.innerHTML = '<div style="padding:20px;color:#ef4444">Failed to load maps</div>';
}
}
function storageLoadAll(){loadStats();loadInventory();loadPlayers();if(storageSubTab==='map')loadMap();if(storageSubTab==='special')loadSpecialItems();if(storageSubTab==='maps')loadMaps()}
`,
};