Files
sincos.cc-website/website/static/admin.html
T
admin d4ffec7f18 feat: 全站改版为科技首页风格,重构导航与产品页面
- 品牌更名 Easy Data Collection
- 导航重构:前沿技术研究 / 工具开发 / 资源中心 / License / 博客(含下拉菜单)
- 新增前沿技术研究聚合页、工具开发产品页与 6 个产品独立介绍页
- License 申请 / 查询下载 / 资源包合并为 License 中心,旧路径保留兼容
- 首页与全站样式升级为科技产品风(Apple/Wise 式)
- 博客构建脚本同步更新(新导航 + 新首页)
2026-09-29 10:52:30 +08:00

234 lines
9.4 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>管理后台 - ResLib License</title>
<link rel="stylesheet" href="/static/css/style.css">
<link rel="icon" href="/static/img/logo.svg" type="image/svg+xml">
<style>
.filters { display: flex; gap: 8px; flex-wrap: wrap; margin: 18px 0; }
.filter-btn {
padding: 6px 16px; border-radius: 20px; border: 1px solid var(--line);
background: #fff; color: var(--ink-light); font-size: 0.85rem; cursor: pointer; font-family: inherit;
}
.filter-btn.active { background: var(--blue); color: #fff; border-color: var(--blue); }
.empty { text-align: center; color: var(--ink-light); padding: 40px 0; }
.modal-mask {
position: fixed; inset: 0; background: rgba(15, 30, 50, 0.5);
display: none; align-items: center; justify-content: center; z-index: 200; padding: 20px;
}
.modal-mask.show { display: flex; }
.modal {
background: #fff; border-radius: 10px; width: 100%; max-width: 560px;
max-height: 90vh; overflow: auto; padding: 26px;
}
.modal h3 { color: var(--blue-dark); margin-bottom: 14px; }
.kv { display: grid; grid-template-columns: 110px 1fr; gap: 8px 12px; font-size: 0.92rem; margin-bottom: 16px; }
.kv dt { color: var(--ink-light); }
.kv dd { word-break: break-all; }
.lic-preview {
background: #0d2b4a; color: #7cc0ff; font-family: Consolas, monospace;
border-radius: 6px; padding: 12px 14px; font-size: 0.85rem; margin: 12px 0; letter-spacing: 0.05em;
}
.modal-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 18px; flex-wrap: wrap; }
.deny-reason { width: 100%; margin-top: 10px; display: none; }
.deny-reason.show { display: block; }
</style>
</head>
<body>
<header class="site-header">
<div class="container header-inner">
<a class="brand" href="/admin">
<img src="/static/img/logo.svg" alt="ResLib">
<span class="brand-name">ResLib License 管理后台</span>
</a>
<div>
<a href="/license/" class="btn btn-ghost btn-sm" style="margin-right:8px;">License 中心</a>
<a href="/admin/logout" class="btn btn-danger btn-sm">退出</a>
</div>
</div>
</header>
<main class="section" style="padding-top: 30px;">
<div class="container">
<div class="filters" id="filters">
<button class="filter-btn active" data-f="all">全部</button>
<button class="filter-btn" data-f="pending">待审核</button>
<button class="filter-btn" data-f="approved">已批准</button>
<button class="filter-btn" data-f="denied">已拒绝</button>
<button id="refresh" class="filter-btn" style="margin-left:auto; border-color: var(--blue); color: var(--blue);">刷新</button>
</div>
<div class="table-wrap">
<table class="admin" id="table">
<thead>
<tr>
<th>申请编号</th><th>提交时间</th><th>公司</th><th>联系人</th><th>邮箱</th>
<th>MAC</th><th>状态</th><th>操作</th>
</tr>
</thead>
<tbody id="tbody"></tbody>
</table>
</div>
<div class="empty" id="empty" style="display:none;">暂无申请记录</div>
</div>
</main>
<div class="modal-mask" id="mask">
<div class="modal">
<h3 id="m-title">申请详情</h3>
<dl class="kv" id="m-body"></dl>
<div id="m-lic"></div>
<div class="deny-reason" id="deny-box">
<label style="font-size:0.85rem; font-weight:600;">拒绝原因(可选):</label>
<input type="text" id="deny-reason-input" style="width:100%; margin-top:6px; padding:9px 12px; border:1px solid #cfdcea; border-radius:6px;">
</div>
<div class="modal-actions">
<button class="btn btn-ghost btn-sm" id="m-close">关闭</button>
<button class="btn btn-danger btn-sm" id="m-deny" style="display:none;">拒绝</button>
<button class="btn btn-primary btn-sm" id="m-approve" style="display:none;">批准并生成 License</button>
</div>
</div>
</div>
<script>
(function () {
var tbody = document.getElementById("tbody");
var empty = document.getElementById("empty");
var filter = "all";
var items = [];
var current = null;
function badge(s) {
if (s === "approved") return '<span class="badge badge-approved">已批准</span>';
if (s === "denied") return '<span class="badge badge-denied">已拒绝</span>';
return '<span class="badge badge-pending">待审核</span>';
}
async function load() {
try {
var resp = await fetch("/api/admin/list");
if (resp.status === 401) { window.location.href = "/admin/login"; return; }
items = await resp.json();
render();
} catch (e) {
alert("加载失败:" + e.message);
}
}
function render() {
var list = filter === "all" ? items : items.filter(function (i) { return i.status === filter; });
tbody.innerHTML = "";
empty.style.display = list.length ? "none" : "block";
list.forEach(function (i) {
var tr = document.createElement("tr");
tr.innerHTML =
'<td class="mono">' + i.id + "</td>" +
"<td>" + i.created + "</td>" +
"<td>" + esc(i.company) + "</td>" +
"<td>" + esc(i.contact) + "</td>" +
"<td>" + esc(i.email) + "</td>" +
'<td class="mono">' + esc(i.mac) + "</td>" +
"<td>" + badge(i.status) + "</td>" +
'<td class="actions"><button class="btn btn-ghost btn-sm" data-view="' + i.id + '">详情</button></td>';
tbody.appendChild(tr);
});
}
function esc(s) {
return String(s == null ? "" : s).replace(/[&<>"']/g, function (c) {
return { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" }[c];
});
}
function showDetail(id) {
current = items.find(function (i) { return i.id === id; });
if (!current) return;
document.getElementById("m-body").innerHTML =
"<dt>申请编号</dt><dd class='mono'>" + current.id + "</dd>" +
"<dt>提交时间</dt><dd>" + current.created + "</dd>" +
"<dt>状态</dt><dd>" + badge(current.status) + "</dd>" +
"<dt>MAC 地址</dt><dd class='mono'>" + esc(current.mac) + "</dd>" +
"<dt>公司</dt><dd>" + esc(current.company) + "</dd>" +
"<dt>联系人</dt><dd>" + esc(current.contact) + "</dd>" +
"<dt>邮箱</dt><dd>" + esc(current.email) + "</dd>" +
"<dt>Creo 版本</dt><dd>" + esc(current.creo) + "</dd>" +
"<dt>授权套数</dt><dd>" + esc(current.seats) + "</dd>" +
"<dt>备注</dt><dd>" + esc(current.notes) || "(无)" + "</dd>" +
(current.reason ? "<dt>拒绝原因</dt><dd>" + esc(current.reason) + "</dd>" : "");
var licBox = document.getElementById("m-lic");
licBox.innerHTML = "";
if (current.status === "approved") {
licBox.innerHTML =
"<b style='font-size:0.88rem;'>已生成授权文件:</b>" +
"<div class='lic-preview' id='lic-content'></div>" +
"<a class='btn btn-primary btn-sm' href='/api/license/" + encodeURIComponent(current.id) + "' download>下载 res_center.lic</a>";
fetch("/api/license/" + encodeURIComponent(current.id)).then(function (r) { return r.text(); }).then(function (t) {
var el = document.getElementById("lic-content");
if (el) el.textContent = t.trim();
}).catch(function () {});
}
document.getElementById("m-approve").style.display =
current.status === "pending" ? "" : "none";
document.getElementById("m-deny").style.display =
current.status === "pending" ? "" : "none";
document.getElementById("deny-box").classList.remove("show");
document.getElementById("deny-reason-input").value = "";
document.getElementById("mask").classList.add("show");
}
document.getElementById("filters").addEventListener("click", function (e) {
var b = e.target.closest(".filter-btn");
if (!b || b.id === "refresh") return;
document.querySelectorAll(".filter-btn").forEach(function (x) { x.classList.remove("active"); });
b.classList.add("active");
filter = b.dataset.f;
render();
});
document.getElementById("refresh").addEventListener("click", load);
tbody.addEventListener("click", function (e) {
var b = e.target.closest("[data-view]");
if (b) showDetail(b.dataset.view);
});
document.getElementById("m-close").addEventListener("click", function () {
document.getElementById("mask").classList.remove("show");
});
document.getElementById("mask").addEventListener("click", function (e) {
if (e.target === this) this.classList.remove("show");
});
document.getElementById("m-approve").addEventListener("click", async function () {
if (!confirm("确认批准该申请并生成 License?")) return;
var resp = await fetch("/api/admin/approve/" + encodeURIComponent(current.id), { method: "POST" });
if (resp.ok) { closeAndReload(); } else { alert("操作失败"); }
});
document.getElementById("m-deny").addEventListener("click", async function () {
if (!confirm("确认拒绝该申请?")) return;
var reason = document.getElementById("deny-reason-input").value;
var resp = await fetch("/api/admin/deny/" + encodeURIComponent(current.id), {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: "reason=" + encodeURIComponent(reason)
});
if (resp.ok) { closeAndReload(); } else { alert("操作失败"); }
});
function closeAndReload() {
document.getElementById("mask").classList.remove("show");
load();
}
load();
})();
</script>
</body>
</html>