188 lines
7.2 KiB
JavaScript
188 lines
7.2 KiB
JavaScript
const PageScene = {
|
|
_el: null,
|
|
_currentGameId: null,
|
|
_currentGameName: '',
|
|
_editorSceneId: null,
|
|
_editorData: null,
|
|
|
|
init() {
|
|
this._el = document.getElementById('page-scene');
|
|
},
|
|
|
|
async render() {
|
|
const cfg = await API.getConfig();
|
|
this._currentGameId = cfg.selected_game_id;
|
|
|
|
if (this._currentGameId) {
|
|
const games = await API.getGames();
|
|
const game = games.find(g => g.id === this._currentGameId);
|
|
this._currentGameName = game ? game.name : this._currentGameId;
|
|
}
|
|
|
|
this._el.innerHTML = this._template();
|
|
await this._loadScenes();
|
|
this._bindEvents();
|
|
},
|
|
|
|
async _loadScenes() {
|
|
const grid = document.getElementById('scene-grid');
|
|
if (!grid) return;
|
|
|
|
try {
|
|
const scenes = await API.getScenes(this._currentGameId);
|
|
if (!scenes || scenes.length === 0) {
|
|
grid.innerHTML = `
|
|
<div class="empty-state" style="grid-column:1/-1;">
|
|
<svg viewBox="0 0 24 24" width="64" height="64"><path d="M3 3h8v8H3zm10 0h8v8h-8zM3 13h8v8H3zm10 0h8v8h-8z" fill="currentColor"/></svg>
|
|
<h4>暂无场景</h4>
|
|
<p>点击"新建场景"创建你的第一个场景布局</p>
|
|
</div>`;
|
|
return;
|
|
}
|
|
|
|
grid.innerHTML = scenes.map(s => this._sceneCardHtml(s)).join('');
|
|
} catch (e) {
|
|
console.error('Failed to load scenes:', e);
|
|
}
|
|
},
|
|
|
|
_bindEvents() {
|
|
document.getElementById('btn-new-scene')?.addEventListener('click', () => this._showEditor());
|
|
|
|
const grid = document.getElementById('scene-grid');
|
|
if (grid) {
|
|
grid.addEventListener('click', (e) => {
|
|
const card = e.target.closest('[data-scene-id]');
|
|
if (!card) return;
|
|
const action = card.dataset.action;
|
|
const sceneId = card.dataset.sceneId;
|
|
|
|
if (action === 'render') {
|
|
this._renderScene(sceneId);
|
|
} else if (action === 'edit') {
|
|
e.stopPropagation();
|
|
this._showEditor(sceneId);
|
|
} else if (action === 'delete') {
|
|
e.stopPropagation();
|
|
this._deleteScene(sceneId);
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
async _showEditor(sceneId) {
|
|
let scene = null;
|
|
if (sceneId) {
|
|
scene = await API.getScene(sceneId);
|
|
if (!scene) return;
|
|
}
|
|
|
|
this._editorSceneId = sceneId;
|
|
const modal = document.createElement('div');
|
|
modal.className = 'modal-overlay';
|
|
modal.innerHTML = this._editorTemplate(scene);
|
|
document.body.appendChild(modal);
|
|
|
|
modal.querySelector('.modal-overlay, .modal-actions .btn-secondary')
|
|
?.addEventListener('click', (e) => {
|
|
if (e.target === modal || e.target.matches('.btn-secondary')) {
|
|
modal.remove();
|
|
}
|
|
});
|
|
|
|
modal.querySelector('.btn-primary')?.addEventListener('click', async () => {
|
|
const name = modal.querySelector('#edit-scene-name').value || 'New Scene';
|
|
const desc = modal.querySelector('#edit-scene-desc').value || '';
|
|
const gameId = this._currentGameId || '';
|
|
|
|
const data = { name, description: desc, game_id: gameId };
|
|
if (this._editorSceneId) {
|
|
await API.updateScene(this._editorSceneId, data);
|
|
} else {
|
|
await API.createScene(data);
|
|
}
|
|
modal.remove();
|
|
Toast.show('场景保存成功', 'success');
|
|
this.render();
|
|
});
|
|
},
|
|
|
|
async _renderScene(sceneId) {
|
|
const url = `${location.origin}/scene/${sceneId}`;
|
|
window.open(url, '_blank');
|
|
navigator.clipboard.writeText(url).then(() => {
|
|
Toast.show('场景链接已复制,可在局域网设备访问', 'success');
|
|
}).catch(() => {});
|
|
},
|
|
|
|
async _deleteScene(sceneId) {
|
|
if (!confirm('确定删除此场景?')) return;
|
|
await API.deleteScene(sceneId);
|
|
Toast.show('场景已删除', 'info');
|
|
this._loadScenes();
|
|
},
|
|
|
|
_sceneCardHtml(scene) {
|
|
const canvasCount = (scene.canvases || []).length;
|
|
return `
|
|
<div class="glass-card scene-card" data-scene-id="${scene.id}" data-action="render">
|
|
<div class="scene-card-name">${scene.name}</div>
|
|
<div class="scene-card-game" style="margin-bottom:6px;">${this._currentGameName || '未关联游戏'}</div>
|
|
<div class="scene-card-meta">
|
|
<span>${canvasCount} 个画布</span>
|
|
<span>${scene.updated_at ? new Date(scene.updated_at).toLocaleDateString() : ''}</span>
|
|
</div>
|
|
<div class="scene-canvas-list">
|
|
${(scene.canvases || []).map(c => `<span class="scene-canvas-badge">${c.label || c.width + 'x' + c.height}</span>`).join('')}
|
|
</div>
|
|
<div style="margin-top:12px;display:flex;gap:6px;">
|
|
<button class="btn btn-sm btn-primary" data-scene-id="${scene.id}" data-action="render">渲染</button>
|
|
<button class="btn btn-sm btn-secondary" data-scene-id="${scene.id}" data-action="edit">编辑</button>
|
|
<button class="btn btn-sm btn-danger" data-scene-id="${scene.id}" data-action="delete">删除</button>
|
|
</div>
|
|
</div>`;
|
|
},
|
|
|
|
_editorTemplate(scene) {
|
|
const name = scene ? scene.name : '';
|
|
const desc = scene ? scene.description : '';
|
|
return `
|
|
<div class="modal">
|
|
<h3>${scene ? '编辑场景' : '新建场景'}</h3>
|
|
<div class="form-group">
|
|
<label>场景名称</label>
|
|
<input id="edit-scene-name" type="text" value="${name}" placeholder="输入场景名称">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>描述</label>
|
|
<textarea id="edit-scene-desc" placeholder="场景描述(可选)">${desc}</textarea>
|
|
</div>
|
|
<p style="font-size:12px;color:var(--text-tertiary);margin-top:8px;">
|
|
提示:保存后可在场景编辑器中添加仪表盘、调整布局和画布比例。
|
|
</p>
|
|
<div class="modal-actions">
|
|
<button class="btn btn-secondary">取消</button>
|
|
<button class="btn btn-primary">保存</button>
|
|
</div>
|
|
</div>`;
|
|
},
|
|
|
|
_template() {
|
|
return `
|
|
<div class="scene-header animated">
|
|
<div>
|
|
<h2>场景管理</h2>
|
|
<p style="color:var(--text-secondary);font-size:14px;margin-top:4px;">
|
|
${this._currentGameId ? `当前游戏: ${this._currentGameName}` : '请先在侧边栏选择一个游戏'}
|
|
</p>
|
|
</div>
|
|
<button id="btn-new-scene" class="btn btn-primary" ${!this._currentGameId ? 'disabled' : ''}>
|
|
+ 新建场景
|
|
</button>
|
|
</div>
|
|
<div id="scene-grid" class="scene-grid animated"></div>`;
|
|
}
|
|
};
|
|
|
|
window.PageScene = PageScene;
|