134 lines
6.5 KiB
HTML
134 lines
6.5 KiB
HTML
|
|
<!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>
|