fix: replace _upload with publish modal (file picker + local list)

This commit is contained in:
2026-07-27 10:14:14 +08:00
parent 2960d132ef
commit 3ea3f10100
+51 -15
View File
@@ -220,22 +220,58 @@ const PageMarket = {
},
_upload() {
const input = document.createElement('input'); input.type = 'file'; input.accept = this._tab === 'scenes' ? '.tss' : '.tsd';
const endpoint = this._tab === 'scenes' ? '/api/market/scenes/upload' : '/api/market/upload';
input.onchange = async (e) => {
const file = e.target.files[0]; if (!file) return;
const fd = new FormData(); fd.append('file', file);
fd.append('name', file.name.replace('.tsd',''));
fd.append('category', 'community');
fd.append('author', 'TurboSu User');
fd.append('token', this._marketToken);
try {
const res = await fetch('/api/market/upload', { method: 'POST', body: fd });
if (!this._marketToken) { Toast.show('请先登录', 'error'); return; }
const overlay = document.createElement('div'); overlay.className = 'modal-overlay';
overlay.innerHTML = '<div class="modal" style="min-width:480px;max-width:520px;padding:24px"><h3 style="font-size:18px;font-weight:600;margin-bottom:4px">发布作品</h3><p style="font-size:12px;color:var(--text-secondary);margin-bottom:18px">选择要发布的仪表盘或场景</p><button id="pub-file-btn" class="btn btn-primary btn-sm" style="width:100%;margin-bottom:10px">📁 选择文件 (.tsd / .tss)</button><div style="font-size:13px;color:var(--text-tertiary);margin:10px 0;text-align:center">— 或从本地选择 —</div><div id="pub-local-list" style="max-height:300px;overflow-y:auto">加载中...</div></div>';
document.body.appendChild(overlay);
overlay.addEventListener('click', (e) => { if (e.target === overlay) overlay.remove(); });
overlay.querySelector('#pub-file-btn').addEventListener('click', () => {
const input = document.createElement('input'); input.type = 'file'; input.accept = '.tsd,.tss';
input.onchange = async (e) => {
const file = e.target.files[0]; if (!file) return;
const isTss = file.name.endsWith('.tss');
const fd = new FormData(); fd.append('file', file); fd.append('token', this._marketToken);
const res = await fetch(isTss ? '/api/market/scenes/upload' : '/api/market/upload', { method: 'POST', body: fd });
const data = await res.json();
Toast.show(data.error ? '上传失败: ' + data.error : '上传成功', data.error ? 'error' : 'success');
if (!data.error) this._loadItems();
} catch (e) { Toast.show('上传失败', 'error'); }
}; input.click();
Toast.show(data.error ? '失败: '+data.error : '发布成功', data.error ? 'error' : 'success');
if (!data.error) { overlay.remove(); this._loadItems(); }
}; input.click();
});
this._loadLocalItems(overlay);
},
async _loadLocalItems(overlay) {
const list = overlay.querySelector('#pub-local-list');
try {
const dashRes = await fetch('/api/dashboards?category=all');
const dashes = (await dashRes.json()) || [];
const sceneRes = await fetch('/api/scenes');
const scenes = (await sceneRes.json()) || [];
const upD = dashes.filter(d => !d.is_builtin && !(d.id||'').match(/^[a-f0-9]{6}__/));
const upS = Array.isArray(scenes) ? scenes.filter(s => !s.is_builtin && !(s.id||'').match(/^[a-f0-9]{6}__/)) : [];
let h = '';
if (upD.length) {
h += '<div style="font-weight:600;font-size:13px;color:var(--text-secondary);margin-bottom:6px">本地仪表盘</div>';
h += upD.map(d => '<div class="glass-card" style="padding:10px 14px;margin-bottom:4px;display:flex;align-items:center;justify-content:space-between;gap:8px"><div><span style="font-weight:500">'+(d.icon||'📊')+' '+d.name+'</span></div><button class="btn btn-sm btn-primary pub-dash-btn" data-id="'+d.id+'">发布</button></div>').join('');
}
if (upS.length) {
h += '<div style="font-weight:600;font-size:13px;color:var(--text-secondary);margin:14px 0 6px">本地场景</div>';
h += upS.map(s => '<div class="glass-card" style="padding:10px 14px;margin-bottom:4px;display:flex;align-items:center;justify-content:space-between;gap:8px"><div><span style="font-weight:500">🎬 '+s.name+'</span></div><button class="btn btn-sm btn-primary pub-scene-btn" data-id="'+s.id+'">发布</button></div>').join('');
}
list.innerHTML = h || '<p style="color:var(--text-tertiary);font-size:12px;padding:10px">没有可发布的内容</p>';
list.querySelectorAll('.pub-dash-btn').forEach(btn => btn.addEventListener('click', async () => {
const r = await fetch('/api/market/publish-local', {method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({id:btn.dataset.id,type:'dashboard',token:this._marketToken})});
const d = await r.json();
Toast.show(d.error?'失败:'+d.error:'发布成功',d.error?'error':'success');
if(!d.error){overlay.remove();this._loadItems();}
}));
list.querySelectorAll('.pub-scene-btn').forEach(btn => btn.addEventListener('click', async () => {
const r = await fetch('/api/market/publish-local', {method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({id:btn.dataset.id,type:'scene',token:this._marketToken})});
const d = await r.json();
Toast.show(d.error?'失败:'+d.error:'发布成功',d.error?'error':'success');
if(!d.error){overlay.remove();this._loadItems();}
}));
} catch(e) { list.innerHTML = '<p style="color:var(--text-tertiary);padding:10px">加载失败</p>'; }
},
_showLogin() {