增加了一些功能

This commit is contained in:
2026-06-19 23:08:26 +08:00
parent 6dd576158c
commit aedc199777
9 changed files with 502 additions and 10 deletions
+118
View File
@@ -0,0 +1,118 @@
package admin
import (
"Embalming_Girl_Server/db"
"encoding/json"
"fmt"
"net/http"
)
const AdminPassword = "admin123"
func Register(mux *http.ServeMux, getStats func() map[string]interface{}) {
mux.HandleFunc("/admin", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
fmt.Fprint(w, adminHTML)
})
mux.HandleFunc("/api/admin/login", func(w http.ResponseWriter, r *http.Request) {
var req struct {
Password string `json:"password"`
}
json.NewDecoder(r.Body).Decode(&req)
if req.Password != AdminPassword {
json.NewEncoder(w).Encode(map[string]interface{}{"ok": false})
return
}
json.NewEncoder(w).Encode(map[string]interface{}{"ok": true})
})
mux.HandleFunc("/api/admin/stats", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(getStats())
})
mux.HandleFunc("/api/admin/users", func(w http.ResponseWriter, r *http.Request) {
rows, err := db.DB.Query("SELECT id, username, nickname, bio, avatar, created_at, last_login FROM users ORDER BY id DESC")
if err != nil {
json.NewEncoder(w).Encode([]int{})
return
}
defer rows.Close()
var users []map[string]interface{}
for rows.Next() {
var id int64
var username, nickname, bio, avatar string
var created, login interface{}
rows.Scan(&id, &username, &nickname, &bio, &avatar, &created, &login)
users = append(users, map[string]interface{}{
"id": id, "username": username, "nickname": nickname,
"bio": bio, "avatar": avatar, "created_at": created, "last_login": login,
})
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(users)
})
mux.HandleFunc("/api/admin/delete_user", func(w http.ResponseWriter, r *http.Request) {
var req struct {
ID int64 `json:"id"`
}
json.NewDecoder(r.Body).Decode(&req)
db.DB.Exec("DELETE FROM sessions WHERE user_id=?", req.ID)
db.DB.Exec("DELETE FROM users WHERE id=?", req.ID)
json.NewEncoder(w).Encode(map[string]interface{}{"ok": true})
})
}
const adminHTML = `<!DOCTYPE html><html><head><meta charset="utf-8"><title>管理面板</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{background:#1a1f2e;color:#e0e0e0;font-family:system-ui;padding:20px}
h1{color:#5eb3e6;margin-bottom:20px;text-align:center}
.card{background:#252b3d;border-radius:12px;padding:20px;margin-bottom:16px}
.card h2{color:#d4c5a3;margin-bottom:12px;font-size:18px}
.stats{display:flex;gap:16px;flex-wrap:wrap}
.stat{background:#1a1f2e;border-radius:8px;padding:16px;text-align:center;min-width:120px}
.stat .num{font-size:28px;color:#5eb3e6;font-weight:bold}
.stat .label{font-size:12px;color:#8a8f9d;margin-top:4px}
table{width:100%;border-collapse:collapse;margin-top:8px}
th,td{padding:8px 12px;text-align:left;border-bottom:1px solid #2a3040}
th{color:#8a8f9d;font-size:12px}
.btn{padding:4px 12px;border:none;border-radius:4px;cursor:pointer;font-size:12px}
.btn-danger{background:#d94f5c;color:white}
.btn-danger:hover{background:#c0392b}
#loginBox{max-width:300px;margin:100px auto;text-align:center}
#loginBox input{width:100%;padding:10px;margin:8px 0;border-radius:6px;border:1px solid #3a3f4e;background:#1a1f2e;color:white}
#loginBox button{width:100%;padding:10px;background:#5eb3e6;border:none;border-radius:6px;color:white;cursor:pointer;font-size:14px}
#main{display:none}
</style></head><body>
<div id="loginBox"><h1>管理面板</h1><input id="pw" type="password" placeholder="管理密码">
<button onclick="doLogin()">登录</button></div>
<div id="main"><h1>Embalming Girl 管理面板</h1>
<div class="card"><h2>服务器状态</h2><div class="stats" id="stats"></div></div>
<div class="card"><h2>注册用户</h2><table><thead><tr><th>ID</th><th>用户名</th><th>昵称</th><th>头像</th><th>简介</th><th>注册时间</th><th>操作</th></tr></thead><tbody id="users"></tbody></table></div>
</div>
<script>
async function doLogin(){
let r=await fetch('/api/admin/login',{method:'POST',body:JSON.stringify({password:document.getElementById('pw').value})});
let d=await r.json();
if(d.ok){document.getElementById('loginBox').style.display='none';document.getElementById('main').style.display='block';loadData();}
else alert('密码错误');
}
async function loadData(){
let s=await(await fetch('/api/admin/stats')).json();
document.getElementById('stats').innerHTML=
'<div class="stat"><div class="num">'+s.total_users+'</div><div class="label">注册用户</div></div>'+
'<div class="stat"><div class="num">'+s.active_rooms+'</div><div class="label">活跃房间</div></div>'+
'<div class="stat"><div class="num">'+s.online_clients+'</div><div class="label">在线连接</div></div>';
let u=await(await fetch('/api/admin/users')).json();
let h='';(u||[]).forEach(x=>{
h+='<tr><td>'+x.id+'</td><td>'+x.username+'</td><td>'+x.nickname+'</td><td>'+
(x.avatar||'-')+'</td><td>'+(x.bio||'-')+'</td><td>'+(x.created_at||'-')+'</td>'+
'<td><button class="btn btn-danger" onclick="delUser('+x.id+')">删除</button></td></tr>';
});
document.getElementById('users').innerHTML=h||'<tr><td colspan="7">暂无用户</td></tr>';
}
async function delUser(id){
if(!confirm('确定删除此用户?'))return;
await fetch('/api/admin/delete_user',{method:'POST',body:JSON.stringify({id})});
loadData();
}
</script></body></html>`