82 lines
3.7 KiB
JavaScript
82 lines
3.7 KiB
JavaScript
function initializeAutoTableSorting() {
|
|
markAutoSortableHeaders(document);
|
|
document.addEventListener("click", (event) => {
|
|
const header = event.target.closest?.("th[data-auto-sort]");
|
|
if (!header || header.closest("#limitTable")) return;
|
|
const table = header.closest("table");
|
|
const body = table?.tBodies?.[0];
|
|
if (!body || body.rows.length < 2) return;
|
|
const direction = header.classList.contains("sort-asc") ? "desc" : "asc";
|
|
table.querySelectorAll("th.sort-asc, th.sort-desc").forEach((item) => {
|
|
item.classList.remove("sort-asc", "sort-desc", "sorted");
|
|
item.removeAttribute("aria-sort");
|
|
const arrow = item.querySelector(".arr");
|
|
if (arrow) arrow.textContent = "↕";
|
|
});
|
|
header.classList.add(`sort-${direction}`, "sorted");
|
|
header.setAttribute("aria-sort", direction === "asc" ? "ascending" : "descending");
|
|
const activeArrow = header.querySelector(".arr");
|
|
if (activeArrow) activeArrow.textContent = direction === "asc" ? "▲" : "▼";
|
|
const columnIndex = header.cellIndex;
|
|
const rows = [...body.rows].map((row, index) => ({ row, index }));
|
|
rows.sort((left, right) => {
|
|
const leftValue = autoSortValue(left.row.cells[columnIndex]);
|
|
const rightValue = autoSortValue(right.row.cells[columnIndex]);
|
|
let result;
|
|
if (leftValue.kind === "number" && rightValue.kind === "number") result = leftValue.value - rightValue.value;
|
|
else result = String(leftValue.value).localeCompare(String(rightValue.value), "zh-CN", { numeric: true, sensitivity: "base" });
|
|
if (result === 0) result = left.index - right.index;
|
|
return direction === "asc" ? result : -result;
|
|
});
|
|
rows.forEach(({ row }) => body.appendChild(row));
|
|
const firstHeader = [...header.parentElement.cells][0]?.textContent.trim();
|
|
if (["#", "排名"].includes(firstHeader)) {
|
|
[...body.rows].forEach((row, index) => {
|
|
if (row.cells[0]) row.cells[0].textContent = String(index + 1);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
function markAutoSortableHeaders(root) {
|
|
root.querySelectorAll?.(".data-table:not(#limitTable) thead th").forEach((header) => {
|
|
if (header.closest("#brokenTable, #downTable, #yesterdayTable, #rotationTable")) return;
|
|
if (number(header.colSpan) > 1) return;
|
|
const label = header.textContent.trim();
|
|
if (!label || ["#", "操作"].includes(label)) return;
|
|
header.dataset.autoSort = "true";
|
|
header.classList.add("sortable");
|
|
if (!header.querySelector(".arr")) header.insertAdjacentHTML("beforeend", '<span class="arr">↕</span>');
|
|
header.title = `${label}:点击排序`;
|
|
});
|
|
}
|
|
|
|
function autoSortValue(cell) {
|
|
const text = String(cell?.dataset?.sortValue || cell?.textContent || "").trim();
|
|
if (!text || text === "--" || text.includes("样本不足")) return { kind: "text", value: "\uffff" };
|
|
const boardMatch = text.match(/(\d+)\s*板/);
|
|
if (boardMatch) return { kind: "number", value: Number(boardMatch[1]) };
|
|
const normalized = text.replaceAll(",", "").replace(/[+%]/g, "");
|
|
const numericMatch = normalized.match(/^-?\d+(?:\.\d+)?/);
|
|
if (numericMatch) {
|
|
let value = Number(numericMatch[0]);
|
|
if (text.includes("亿")) value *= 10000;
|
|
return { kind: "number", value };
|
|
}
|
|
return { kind: "text", value: text };
|
|
}
|
|
|
|
|
|
function bindSharedTableEvents() {
|
|
document.querySelectorAll("[data-table-search]").forEach((input) => {
|
|
input.addEventListener("input", () => {
|
|
const query = input.value.trim().toLowerCase();
|
|
const body = document.querySelector(`#${CSS.escape(input.dataset.tableSearch)}`);
|
|
body?.querySelectorAll("tr").forEach((row) => {
|
|
row.hidden = Boolean(query) && !row.textContent.toLowerCase().includes(query);
|
|
});
|
|
});
|
|
});
|
|
initializeAutoTableSorting();
|
|
}
|