const PageSettings = { _el: null, init() { this._el = document.getElementById('page-settings'); }, async render() { const cfg = await API.getConfig(); const games = await API.getGames(); this._el.innerHTML = this._template(cfg, games); this._bindEvents(); }, _bindEvents() { document.getElementById('settings-telemetry-port')?.addEventListener('change', async (e) => { await API.updateConfig({ telemetry_port: parseInt(e.target.value) || 20777 }); Toast.show('遥测端口已更新,重启监听后生效', 'info'); }); document.getElementById('settings-server-port')?.addEventListener('change', async (e) => { Toast.show('服务器端口修改后需要重启程序', 'warning'); }); document.getElementById('settings-restart-telemetry')?.addEventListener('click', async () => { await API.stopTelemetry(); await API.startTelemetry(); Toast.show('遥测监听已重启', 'success'); }); document.getElementById('btn-import-plugin')?.addEventListener('click', () => this._importPlugin()); document.getElementById('btn-reload-plugins')?.addEventListener('click', async () => { await API.reloadGamePlugins(); Toast.show('插件已重新加载', 'success'); this.render(); }); document.getElementById('settings-game-list')?.addEventListener('click', async (e) => { const exportBtn = e.target.closest('.btn-export-plugin'); const removeBtn = e.target.closest('.btn-remove-plugin'); if (exportBtn) { const pluginId = exportBtn.dataset.pluginId; const data = await API.exportGamePlugin(pluginId); if (data) { this._downloadJson(`plugin_${pluginId}.json`, data); Toast.show('插件已导出', 'success'); } } if (removeBtn) { const pluginId = removeBtn.dataset.pluginId; if (confirm('确定移除这个游戏插件?')) { await API.removeGamePlugin(pluginId); Toast.show('插件已移除', 'info'); this.render(); } } }); }, async _importPlugin() { const input = document.createElement('input'); input.type = 'file'; input.accept = '.json'; input.onchange = async (e) => { const file = e.target.files[0]; if (!file) return; try { const text = await file.text(); const data = JSON.parse(text); if (data.type === 'game_plugin') { await API.installGamePlugin(data); Toast.show('插件安装成功', 'success'); this.render(); } else { Toast.show('无效的插件文件格式', 'error'); } } catch (err) { Toast.show('文件解析失败: ' + err.message, 'error'); } }; input.click(); }, _downloadJson(filename, data) { const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; a.click(); URL.revokeObjectURL(url); }, _gamePluginListHtml(games) { if (!games || games.length === 0) { return '
暂无游戏插件
'; } return games.map(g => `manifest.json 和 parser.py 的文件夹manifest.json 定义游戏元信息,parser.py 实现 get_parser() 函数get_parser() 返回对象需实现 game_id() 和 parse(data, addr) 方法games/user/ 目录安装