From abf747e3afdc1c9e4f0201e9325c17e868582e59 Mon Sep 17 00:00:00 2001 From: canglan Date: Thu, 16 Jul 2026 03:56:09 +0800 Subject: [PATCH] feat: dedicated server groups management page in sidebar --- public/index.html | 1 + public/js/app.js | 3 ++ public/js/pages/servers.js | 56 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 public/js/pages/servers.js diff --git a/public/index.html b/public/index.html index acb5f3c..8e8fdec 100644 --- a/public/index.html +++ b/public/index.html @@ -70,6 +70,7 @@ + diff --git a/public/js/app.js b/public/js/app.js index 2d3c989..3be7918 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -11,6 +11,7 @@ const App = { { id: 'export', label: '数据导出', icon: 'fa-download', roles: ['owner'] }, { id: 'polls', label: '投票', icon: 'fa-poll', roles: ['owner','admin','player'] }, { id: 'features', label: '更新内容', icon: 'fa-lightbulb', roles: ['owner','admin','player'] }, + { id: 'servers', label: '服务器管理', icon: 'fa-server', roles: ['owner','admin'] }, ], async init() { @@ -93,6 +94,7 @@ const App = { case 'export': this.renderMain('数据导出', ExportPage, param); break; case 'polls': this.renderMain('投票', PollsPage, param); break; case 'features': this.renderMain('更新内容', FeaturesPage, param); break; + case 'servers': this.renderMain('服务器管理', ServersPage, param); break; default: this.renderMain('控制台', Dashboard, param); } }, @@ -170,6 +172,7 @@ window.SettingsPage = SettingsPage; window.ExportPage = ExportPage; window.PollsPage = PollsPage; window.FeaturesPage = FeaturesPage; +window.ServersPage = ServersPage; window.LoginPage = LoginPage; window.RegisterPage = RegisterPage; window.HomePage = HomePage; diff --git a/public/js/pages/servers.js b/public/js/pages/servers.js new file mode 100644 index 0000000..0822587 --- /dev/null +++ b/public/js/pages/servers.js @@ -0,0 +1,56 @@ +const ServersPage = { + async render() { return '
'; }, + + async mount() { + document.getElementById('page-title').textContent = '服务器管理'; + document.getElementById('page-actions').innerHTML = Auth.isOwner() + ? '' + : ''; + document.getElementById('btn-add-srv').onclick = () => this.showAdd(); + await this.load(); + }, + + async load() { + const ct = document.getElementById('page-content'); + try { + const groups = await API.get('/polls/groups'); + const grouped = {}; + for (const g of groups) { + if (!grouped[g.group_name]) grouped[g.group_name] = []; + grouped[g.group_name].push(g); + } + ct.innerHTML = Object.keys(grouped).length === 0 + ? '

暂无服务器分组

' + : Object.entries(grouped).map(([group, servers]) => ` +
+
${U.esc(group)} ${servers.length} 个子服
+
+
+ ${servers.map(s => ` +
+ ${U.esc(s.server_name)} + ${Auth.isOwner() ? `` : ''} +
+ `).join('')} +
+
+
`).join(''); + } catch (e) { ct.innerHTML = `
${e.message}
`; } + }, + + showAdd() { + U.modal('添加服务器', ` +
+
+
+ +
+ `); + document.getElementById('add-srv-form').onsubmit = async e => { + e.preventDefault(); + try { await API.post('/polls/groups', { group_name: document.getElementById('as-group').value, server_name: document.getElementById('as-server').value }); App.closeModal(); this.load(); } catch(ex){alert(ex.message);} + }; + }, + + async del(id) { if (!await U.confirm('确认删除?')) return; try { await API.req('DELETE', '/polls/groups/'+id); this.load(); } catch(ex){alert(ex.message);} } +};