- 52 JS files (backend + public/js): header with Copyright (C) 2026 Sea Network Technology Studio Author: CangLan <admin@sea-studio.top> + AGPLv3 notice - idempotent (skips if header present), all syntax-checked
112 lines
5.8 KiB
JavaScript
112 lines
5.8 KiB
JavaScript
/*
|
||
* MC Report System
|
||
* Copyright (C) 2026 Sea Network Technology Studio
|
||
* Author: CangLan <admin@sea-studio.top>
|
||
*
|
||
* This program is free software: you can redistribute it and/or modify
|
||
* it under the terms of the GNU Affero General Public License as published
|
||
* by the Free Software Foundation, either version 3 of the License, or
|
||
* (at your option) any later version.
|
||
*
|
||
* This program is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* GNU Affero General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU Affero General Public License
|
||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||
*/
|
||
|
||
const ServersPage = {
|
||
async render() { return '<div class="loading"><i class="fas fa-spinner"></i></div>'; },
|
||
|
||
async mount() {
|
||
document.getElementById('page-title').textContent = '服务器管理';
|
||
document.getElementById('page-actions').innerHTML = Auth.isOwner()
|
||
? '<button class="btn btn-p btn-sm" id="btn-add-srv"><i class="fas fa-plus"></i> 添加</button>'
|
||
: '';
|
||
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
|
||
? '<div class="empty"><i class="fas fa-server"></i><p>暂无服务器分组</p></div>'
|
||
: Object.entries(grouped).map(([group, servers]) => `
|
||
<div class="card">
|
||
<div class="card-h"><i class="fas fa-folder"></i> ${U.esc(group)} <span class="ts tm">${servers.length} 个子服</span></div>
|
||
<div class="card-b">
|
||
<div style="display:flex;flex-wrap:wrap;gap:8px">
|
||
${servers.map(s => `
|
||
<div style="display:flex;align-items:center;gap:6px;background:var(--g1);padding:6px 12px;border-radius:var(--r);font-size:13px">
|
||
<i class="fas fa-server ts tm"></i> ${U.esc(s.server_name)}
|
||
${s.alias ? `<span class="badge bg-admin" title="外部别名">${U.esc(s.alias)}</span>` : ''}
|
||
${Auth.isOwner() ? `<button class="btn btn-o btn-sm" style="padding:2px 6px;font-size:10px" onclick="ServersPage.showEdit(${s.id})"><i class="fas fa-edit"></i></button><button class="btn btn-d btn-sm" style="padding:2px 6px;font-size:10px" onclick="ServersPage.del(${s.id})"><i class="fas fa-times"></i></button>` : ''}
|
||
</div>
|
||
`).join('')}
|
||
</div>
|
||
</div>
|
||
</div>`).join('');
|
||
} catch (e) { ct.innerHTML = `<div class="alert alert-e">${e.message}</div>`; }
|
||
},
|
||
|
||
showAdd() {
|
||
U.modal('添加服务器', `
|
||
<form id="add-srv-form">
|
||
<div class="grid-2"><div class="form-group"><label>分组名 *</label><input id="as-group" required placeholder="如:网易服务器"></div>
|
||
<div class="form-group"><label>子服名 *</label><input id="as-server" required placeholder="如:生存服"></div></div>
|
||
<div class="form-group"><label>外部别名(可选)</label><input id="as-alias" placeholder="如:survival —— 供外部API按别名拉取该子服数据"><span class="help">外部 API 可用别名或「分组/子服名」定位此服务器</span></div>
|
||
<div class="modal-f"><button type="button" class="btn btn-o" data-action="App:closeModal">取消</button><button type="submit" class="btn btn-p">添加</button></div>
|
||
</form>
|
||
`);
|
||
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,
|
||
alias: document.getElementById('as-alias').value.trim(),
|
||
});
|
||
App.closeModal(); this.load();
|
||
} catch(ex){alert(ex.message);}
|
||
};
|
||
},
|
||
|
||
async showEdit(id) {
|
||
try {
|
||
const groups = await API.get('/polls/groups');
|
||
const s = groups.find(x => x.id === id);
|
||
if (!s) return alert('未找到');
|
||
U.modal('编辑服务器', `
|
||
<form id="edit-srv-form">
|
||
<div class="grid-2"><div class="form-group"><label>分组名 *</label><input id="es-group" required value="${U.esc(s.group_name)}"></div>
|
||
<div class="form-group"><label>子服名 *</label><input id="es-server" required value="${U.esc(s.server_name)}"></div></div>
|
||
<div class="form-group"><label>外部别名(可选)</label><input id="es-alias" value="${U.esc(s.alias||'')}" placeholder="如:survival"><span class="help">外部 API 可用别名或「分组/子服名」定位此服务器</span></div>
|
||
<div class="modal-f"><button type="button" class="btn btn-o" data-action="App:closeModal">取消</button><button type="submit" class="btn btn-p">保存</button></div>
|
||
</form>
|
||
`);
|
||
document.getElementById('edit-srv-form').onsubmit = async e => {
|
||
e.preventDefault();
|
||
try {
|
||
await API.put(`/polls/groups/${id}`, {
|
||
group_name: document.getElementById('es-group').value,
|
||
server_name: document.getElementById('es-server').value,
|
||
alias: document.getElementById('es-alias').value.trim(),
|
||
});
|
||
App.closeModal(); this.load();
|
||
} catch(ex){alert(ex.message);}
|
||
};
|
||
} 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);} }
|
||
};
|