baoxiang/admin_config.html

134 lines
6.5 KiB
HTML
Raw Normal View History

2025-12-16 18:06:50 +08:00
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>系统配置管理</title>
<style>
body { font-family: sans-serif; background: #f5f5f5; padding: 20px; }
.container { max-width: 1400px; margin: 0 auto; }
.header { background: white; padding: 20px; border-radius: 8px; margin-bottom: 20px; }
.summary-cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; margin-bottom: 20px; }
.summary-card { background: white; padding: 20px; border-radius: 8px; }
.number { font-size: 32px; font-weight: bold; color: #333; }
.tab { padding: 10px 20px; background: white; border: none; border-radius: 6px; cursor: pointer; margin-right: 10px; }
.tab.active { background: #007bff; color: white; }
.config-section { display: none; background: white; padding: 20px; border-radius: 8px; }
.config-section.active { display: block; }
.config-item { padding: 15px; border-bottom: 1px solid #eee; display: flex; align-items: center; }
.config-info { flex: 1; }
.config-key { color: #007bff; margin-bottom: 5px; }
.config-value { width: 200px; margin-right: 10px; }
.config-value input { width: 100%; padding: 5px; border: 1px solid #ddd; border-radius: 4px; }
.btn { padding: 6px 12px; border: none; border-radius: 4px; cursor: pointer; }
.btn-save { background: #28a745; color: white; }
.notification { position: fixed; top: 20px; right: 20px; padding: 15px; background: #28a745; color: white; border-radius: 4px; display: none; }
.notification.show { display: block; }
.notification.error { background: #dc3545; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>系统配置管理</h1>
<p>管理游戏经济、游戏逻辑和系统运维配置</p>
</div>
<div class="summary-cards">
<div class="summary-card"><h3>总配置数</h3><div class="number" id="totalConfigs">-</div></div>
<div class="summary-card"><h3>可编辑配置</h3><div class="number" id="editableConfigs">-</div></div>
<div class="summary-card"><h3>公开配置</h3><div class="number" id="publicConfigs">-</div></div>
</div>
<div style="margin-bottom: 20px;">
<button class="tab active" data-category="GAME_ECONOMY">游戏经济配置</button>
<button class="tab" data-category="GAME_LOGIC">游戏逻辑配置</button>
<button class="tab" data-category="SYSTEM_OPERATIONS">系统运维配置</button>
</div>
<div id="configSections"><div>正在加载配置...</div></div>
</div>
<div class="notification" id="notification"></div>
<script>
function showNotification(msg, isError=false) {
const n = document.getElementById("notification");
n.textContent = msg;
n.className = "notification " + (isError ? "error" : "");
n.classList.add("show");
setTimeout(()=>n.classList.remove("show"), 3000);
}
async function loadConfigGroups() {
try {
const response = await fetch("/api/system/configs/groups", {
headers: { "Authorization": "Bearer " + localStorage.getItem("token") }
});
if (!response.ok) throw new Error("加载配置失败");
const groups = await response.json();
renderConfigSections(groups);
} catch (error) {
showNotification("加载配置失败: " + error.message, true);
}
}
function renderConfigSections(groups) {
const container = document.getElementById("configSections");
container.innerHTML = "";
groups.forEach(group => {
const section = document.createElement("div");
section.className = "config-section";
section.id = "section-" + group.category;
if (group.category === "GAME_ECONOMY") section.classList.add("active");
let itemsHtml = "";
group.configs.forEach(config => {
itemsHtml += `
<div class="config-item">
<div class="config-info">
<div class="config-key">${config.config_key}</div>
<div>${config.description || "无描述"}</div>
</div>
<div class="config-value">
<input type="text" id="input-${config.id}" value="${config.config_value}" ${!config.is_editable ? "disabled" : ""}>
</div>
<button class="btn btn-save" onclick="saveConfig('${config.config_key}', '${config.id}')" ${!config.is_editable ? "disabled" : ""}>保存</button>
</div>`;
});
section.innerHTML = `<h3>${group.category_name}</h3>${itemsHtml}`;
container.appendChild(section);
});
}
async function saveConfig(key, id) {
const input = document.getElementById("input-" + id);
const value = input.value.trim();
try {
const response = await fetch("/api/system/configs/" + key, {
method: "PUT",
headers: { "Content-Type": "application/json", "Authorization": "Bearer " + localStorage.getItem("token") },
body: JSON.stringify({ config_value: value })
});
if (!response.ok) throw new Error("保存失败");
showNotification("保存成功");
} catch (error) {
showNotification("保存失败: " + error.message, true);
}
}
document.querySelectorAll(".tab").forEach(tab => {
tab.addEventListener("click", () => {
document.querySelectorAll(".tab").forEach(t => t.classList.remove("active"));
tab.classList.add("active");
document.querySelectorAll(".config-section").forEach(s => s.classList.remove("active"));
document.getElementById("section-" + tab.dataset.category).classList.add("active");
});
});
document.addEventListener("DOMContentLoaded", () => {
if (!localStorage.getItem("token")) { showNotification("请先登录", true); return; }
loadConfigGroups();
});
</script>
</body>
</html>