v1.2.5 管理后台表格点击表头排序:任意字段升序/降序切换(▲▼指示),后端字段白名单校验防注入

This commit is contained in:
2026-08-17 23:16:05 +08:00
parent 437e707893
commit 0a3b075644
3 changed files with 33 additions and 6 deletions
+19 -4
View File
@@ -4,7 +4,7 @@ const $$ = (s) => [...document.querySelectorAll(s)];
const esc = (s) => String(s ?? "").replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" }[c]));
let TOKEN = localStorage.getItem("nba_admin_token") || "";
let CUR = { table: "", page: 1, q: "" };
let CUR = { table: "", page: 1, q: "", sort: "id", order: "desc" };
let LOOKUPS = {}; // teams/players/leagues/sports → {id: name}
/* 字段中文名 */
@@ -79,7 +79,7 @@ function switchPage(p) {
$("#page-config").classList.toggle("hidden", p !== "config");
if (p === "stats") loadStats();
else if (p === "config") loadConfig();
else { CUR = { table: p, page: 1, q: "" }; $("#tbl-search").value = ""; loadTable(); }
else { CUR = { table: p, page: 1, q: "", sort: "id", order: "desc" }; $("#tbl-search").value = ""; loadTable(); }
}
/* ================= 仪表盘 ================= */
@@ -108,11 +108,15 @@ async function loadLookups() {
async function loadTable() {
$("#table-title").textContent = TITLE_CN[CUR.table] || CUR.table;
const d = await api(`/api/admin/${CUR.table}?page=${CUR.page}&size=20&q=${encodeURIComponent(CUR.q)}`);
const d = await api(`/api/admin/${CUR.table}?page=${CUR.page}&size=20&q=${encodeURIComponent(CUR.q)}&sort=${encodeURIComponent(CUR.sort)}&order=${CUR.order}`);
const cols = d.columns.filter((c) => c.name !== "created_at");
const rows = d.rows;
if (!Object.keys(LOOKUPS).length) await loadLookups().catch(() => {});
const thead = `<tr>${cols.map((c) => `<th>${esc(FIELD_CN[CUR.table]?.[c.name] || c.name)}</th>`).join("")}<th>操作</th></tr>`;
const thead = `<tr>${cols.map((c) => {
const active = CUR.sort === c.name;
const arrow = active ? (CUR.order === "asc" ? " ▲" : " ▼") : "";
return `<th class="sortable ${active ? "sort-active" : ""}" data-sort="${c.name}" title="点击排序">${esc(FIELD_CN[CUR.table]?.[c.name] || c.name)}${arrow}</th>`;
}).join("")}<th>操作</th></tr>`;
const tbody = rows.map((r) => {
const tds = cols.map((c) => {
let v = r[c.name];
@@ -141,6 +145,17 @@ $("#tbl-search-btn").addEventListener("click", () => { CUR.q = $("#tbl-search").
$("#tbl-search").addEventListener("keydown", (e) => { if (e.key === "Enter") $("#tbl-search-btn").click(); });
$("#tbl-add").addEventListener("click", () => openEdit(CUR.table, null));
/* 表头点击排序:首次点击升序,再点切降序,循环 */
$("#tbl-wrap").addEventListener("click", (e) => {
const th = e.target.closest("th[data-sort]");
if (!th) return;
const f = th.dataset.sort;
if (CUR.sort === f) CUR.order = CUR.order === "asc" ? "desc" : "asc";
else { CUR.sort = f; CUR.order = "asc"; }
CUR.page = 1;
loadTable();
});
/* ================= 编辑弹窗 ================= */
let EDIT = { table: "", id: null };