xq-admin-page
Version:
基于Bootstrap5的表格列表,主要有后台管理的列表与搜索、添加、编辑、删除、导出等功能,同时列表支持自定义排序、分页大小等。
731 lines (707 loc) • 23.7 kB
JavaScript
/*!
* xq-admin-page v1.0.10 (https://xqkeji.cn/demo/xq-admin-page)
* Author xqkeji.cn
* LICENSE SSPL-1.0
* Copyright 2024 xqkeji.cn
*/
'use strict';
const xqUtil = require('xq-util');
const xqConfirm = require('xq-confirm');
const xqMask = require('xq-mask');
const sortable = require('xq-html5sortable');
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
const xqConfirm__default = /*#__PURE__*/_interopDefaultCompat(xqConfirm);
const sortable__default = /*#__PURE__*/_interopDefaultCompat(sortable);
const DEFAULT_OPTIONS = {
tableClass: ".xq-table",
orderClass: ".xq-order",
orderAscClass: ".xq-order-asc",
orderDescClass: ".xq-order-desc",
dragClass: ".xq-drag",
checkAllClass: ".xq-table .xq-check-all",
addBtnClass: ".xq-table .xq-add",
editBtnClass: ".xq-edit",
viewBtnClass: ".xq-view",
deleteBtnClass: ".xq-delete",
exportBtnClass: ".xq-export",
copyBtnClass: ".xq-copy",
batchBtnClass: ".xq-batch",
backPageClass: ".xq-backpage",
authTableClass: ".xq-auth-table",
authCheckTableClass: ".xq-auth-check-table",
authCheckRowClass: ".xq-auth-check-row",
captchaClass: ".xq-captcha",
pageSizeId: "#xq-page-size"
};
let tablelistOptions = {};
const setOption = (options = {}) => {
tablelistOptions = Object.assign({}, DEFAULT_OPTIONS);
if (options) {
for (const option in options) {
if (Object.hasOwn(tablelistOptions, option)) {
treegridOptions[option] = options[option];
}
}
}
};
const getOption = (key) => {
if (key in tablelistOptions) {
return tablelistOptions[key];
}
const tableClass = tablelistOptions["tableClass"];
const table = document.querySelector(tableClass);
if (table.hasAttribute(key)) {
return String(table.getAttribute(key));
}
return "";
};
let table;
const getTable = () => {
if (table) {
return table;
} else {
const tableClass = getOption("tableClass");
const container = document.querySelector(tableClass);
table = container;
return table;
}
};
const bindAdd = () => {
const addBtnClass = getOption("addBtnClass");
const add_btn = document.querySelector(addBtnClass);
if (add_btn) {
add_btn.addEventListener("click", (event) => {
const target = event.currentTarget;
const table = xqUtil.parents(target, "table")[0];
const pid = table.getAttribute("pid");
let url = target.getAttribute("xq-url");
if (!url) {
url = window.location.href;
if (url.includes(".html") || url.includes("localhost")) {
url = url.slice(0, Math.max(0, url.lastIndexOf("/")));
url += "/add.html";
} else {
if (pid) {
url = url.replace("/" + pid, "");
}
url = url.slice(0, Math.max(0, url.lastIndexOf("/")));
url += pid ? "/add/" + pid : "/add";
}
}
window.location.href = url;
});
}
};
const bindEdit = (element) => {
const editBtnClass = getOption("editBtnClass");
const edit_btn = element.querySelector(editBtnClass);
if (edit_btn) {
edit_btn.addEventListener("click", (event) => {
const target = event.currentTarget;
const table = getTable();
const pid = table?.getAttribute("pid");
let id = element.getAttribute("id");
id = id.replace("xq_", "");
if (id) {
let url = target.getAttribute("xq-url");
if (!url) {
url = window.location.href;
if (url.includes(".html") || url.endsWith("/")) {
url = url.slice(0, Math.max(0, url.lastIndexOf("/")));
url = url + "/edit.html?id=" + id;
} else {
if (pid) {
url = url.replace("/" + pid, "");
}
url = url.slice(0, Math.max(0, url.lastIndexOf("/")));
url = url + "/edit/" + id;
}
}
window.location.href = url;
} else {
xqConfirm__default({
content: "\u627E\u4E0D\u5230tr\u7684id\u5C5E\u6027\uFF01"
});
}
});
}
};
const bindView = (element) => {
const viewBtnClass = getOption("viewBtnClass");
const view_btn = element.querySelector(viewBtnClass);
if (view_btn) {
view_btn.addEventListener("click", (event) => {
const target = event.currentTarget;
const table = getTable();
const pid = table?.getAttribute("pid");
let id = element.getAttribute("id");
id = id.replace("xq_", "");
if (id) {
let url = target.getAttribute("xq-url");
if (!url) {
url = window.location.href;
if (url.includes(".html") || url.endsWith("/")) {
url = url.slice(0, Math.max(0, url.lastIndexOf("/")));
url = url + "/view.html?id=" + id;
} else {
if (pid) {
url = url.replace("/" + pid, "");
}
url = url.slice(0, Math.max(0, url.lastIndexOf("/")));
url = url + "/view/" + id;
}
}
window.location.href = url;
} else {
xqConfirm__default({
content: "\u627E\u4E0D\u5230tr\u7684id\u5C5E\u6027\uFF01"
});
}
});
}
};
const copy = (text) => {
const el = document.createElement("input");
el.setAttribute("value", text);
document.body.append(el);
el.select();
document.execCommand("copy");
el.remove();
};
const bindCopy = (element) => {
const copyBtnClass = getOption("copyBtnClass");
const copy_btn = element.querySelector(copyBtnClass);
if (copy_btn) {
copy_btn.addEventListener("click", () => {
let id = element.getAttribute("id");
id = id.replace("xq_", "");
if (id) {
copy(id);
xqConfirm__default({
content: "\u5DF2\u7ECF\u5C06id\u590D\u5236\u5230\u7C98\u8D34\u677F"
});
}
});
}
};
const bindDelete = (element) => {
const deleteBtnClass = getOption("deleteBtnClass");
const delete_btn = element.querySelector(deleteBtnClass);
if (delete_btn) {
delete_btn.addEventListener("click", (event) => {
const target = event.currentTarget;
const table = getTable();
const pid = table?.getAttribute("pid");
let id = element.getAttribute("id");
id = id.replace("xq_", "");
if (id) {
let url = target.getAttribute("xq-url");
if (!url) {
url = window.location.href;
if (pid) {
url = url.replace("/" + pid, "");
}
url = url.slice(0, Math.max(0, url.lastIndexOf("/")));
url += "/delete";
}
xqConfirm__default({
content: "\u786E\u5B9A\u8981\u5220\u9664\u5417\uFF1F",
confirm() {
fetch(url, {
body: JSON.stringify({ id }),
headers: {
"content-type": "application/json"
},
method: "POST"
}).then(async (response) => {
return response.json();
}).then((data) => {
xqConfirm__default({
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access
content: data.message,
confirm() {
if (data.code === 200) {
window.location.reload();
}
}
});
});
}
});
} else {
xqConfirm__default({
content: "\u627E\u4E0D\u5230tr\u7684id\u5C5E\u6027\uFF01"
});
}
});
}
};
const bindChange = (element) => {
const table = getTable();
let id = element.getAttribute("id");
id = id?.replace("xq_", "");
const textes = element.querySelectorAll("input,select");
for (const text of textes) {
const elementId = text.getAttribute("id");
if (elementId !== "id" && elementId !== "check_all") {
text.addEventListener("change", (event) => {
const targetElement = event.currentTarget;
let value = null;
value = targetElement.type === "checkbox" ? targetElement.checked : targetElement.value;
const target_id = targetElement.getAttribute("id");
const field = target_id?.slice(0, Math.max(0, target_id.indexOf("_")));
const pid = table?.getAttribute("pid");
let xq_url = table?.getAttribute("xq-url");
const data = { id, field, value };
if (!xq_url) {
let url = window.location.href;
if (pid) {
url = url.replace("/" + pid, "");
}
url = url.slice(0, Math.max(0, url.lastIndexOf("/")));
url += "/change";
xq_url = url;
} else {
xq_url += "/change";
}
fetch(xq_url, {
body: JSON.stringify(data),
headers: {
"content-type": "application/json"
},
method: "POST"
}).then(async (response) => {
return response.json();
}).then((data2) => {
console.log(data2);
});
});
}
}
};
const bindBatch = () => {
const batchBtnClass = getOption("batchBtnClass");
const batch_btns = document.querySelectorAll(batchBtnClass);
if (batch_btns) {
for (const batch_btn of batch_btns) {
batch_btn.addEventListener("click", (event) => {
const target = event.currentTarget;
const table = xqUtil.parents(target, "table")[0];
const pid = table.getAttribute("pid");
const formObject = xqUtil.parents(target, "form")[0];
const action = target.getAttribute("name");
if (action) {
let url = target.getAttribute("xq-url");
if (!url) {
url = window.location.href;
if (pid) {
url = url.replace("/" + pid, "");
}
url = url.slice(0, Math.max(0, url.lastIndexOf("/")));
url = url + "/" + action;
}
const formData = xqUtil.jsonFormData(formObject);
const jsonData = JSON.stringify(formData);
if (jsonData !== "{}") {
xqConfirm__default({
content: "\u786E\u5B9A\u8981\u8FDB\u884C\u6279\u91CF\u64CD\u4F5C\u5417\uFF1F",
confirm() {
xqMask.xqMask();
fetch(url, {
body: jsonData,
headers: {
"content-type": "application/json"
},
method: "POST"
}).then(async (response) => {
return response.json();
}).then((data) => {
xqMask.xqUnMask();
xqConfirm__default({
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access
content: data.message,
confirm() {
if (data.code === 200) {
window.location.reload();
}
}
});
});
}
});
} else {
xqConfirm__default({
content: "\u6CA1\u6709\u9009\u62E9\u64CD\u4F5C\u6570\u636E."
});
}
}
});
}
}
};
const bindDrag = () => {
const dragClass = getOption("dragClass");
const dragger_table = document.querySelector(dragClass);
if (dragger_table) {
let tbody = dragger_table.querySelector("tbody");
if (tbody) {
const firstTr = tbody.querySelector("tbody>tr:first-child");
const firstId = firstTr.getAttribute("id");
const firstTd = firstTr.querySelector("td:first-child");
firstTd?.classList.add("xq-move");
tbody.setAttribute("id", "tbody_" + firstId);
const trs = tbody.querySelectorAll("tbody>tr:not(:first-child)");
for (const tr of trs) {
const td = tr.querySelector("td:first-child");
td?.classList.add("xq-move");
const innerbody = document.createElement("tbody");
innerbody.append(tr);
const trId = tr.getAttribute("id");
innerbody.setAttribute("id", "tbody_" + trId);
tbody.after(innerbody);
tbody = innerbody;
}
}
sortable__default(dragClass, {
items: "tbody",
handle: ".xq-move",
placeholder: '<tbody><tr><td colspan="99"> </td></tr><tbody>'
});
dragger_table.addEventListener("sortstop", () => {
const rows = [];
let rowIndex = 0;
const tbodies = dragger_table.querySelectorAll("tbody");
for (const tbody2 of tbodies) {
rowIndex++;
const tr = tbody2.querySelector("tr:first-child");
const trId = tr?.getAttribute("id");
const row = { id: trId, ordernum: rowIndex };
rows.push(row);
}
const pid = dragger_table.getAttribute("pid");
let url = dragger_table.getAttribute("xq-url");
if (!url) {
url = window.location.href;
if (pid) {
url = url.replace("/" + pid, "");
}
url = url.slice(0, Math.max(0, url.lastIndexOf("/")));
url += "/b-order";
}
fetch(url, {
body: JSON.stringify(rows),
headers: {
"content-type": "application/json"
},
method: "POST"
}).then(async (response) => {
return response.json();
}).then((data) => {
if (data.code === 200) ;
});
});
}
};
const bindCheckAll = () => {
const checkAllClass = getOption("checkAllClass");
const check_all = document.querySelector(checkAllClass);
if (check_all) {
check_all.addEventListener("click", (event) => {
const target = event.currentTarget;
const { checked } = target;
const table = getTable();
const checks = table?.querySelectorAll("tr > td:first-child > input[type=checkbox]");
for (const check of checks) {
if (check === target) {
continue;
}
if (checked) {
check.checked = true;
} else {
check.checked = false;
}
}
});
}
};
const bindBack = () => {
let referrer;
let backpage;
let topReferrer;
const backPageClass = getOption("backPageClass");
const els = document.querySelectorAll(backPageClass);
if (els) {
referrer = document.referrer;
topReferrer = null;
if (window.top !== window) {
try {
topReferrer = window.top?.location.href;
} catch (e) {
}
}
if (referrer && referrer !== document.location.href && referrer !== topReferrer) {
sessionStorage.setItem(document.location.href, referrer);
backpage = referrer;
} else {
const item = sessionStorage.getItem(document.location.href);
if (item) {
backpage = item.toString();
}
}
for (const el of els) {
el.addEventListener("click", (event) => {
event.preventDefault();
if (backpage) {
document.location.href = backpage;
} else {
xqConfirm__default({
content: "\u7CFB\u7EDF\u65E0\u6CD5\u81EA\u52A8\u8FD4\u56DE\u4E0A\u4E00\u4E2A\u9875\u9762."
});
}
});
}
}
};
const bindAuth = () => {
const authTableClass = getOption("authTableClass");
const auth_tables = document.querySelectorAll(authTableClass);
if (auth_tables) {
for (const auth_table of auth_tables) {
const authCheckTableClass = getOption("authCheckTableClass");
const check_table = auth_table.querySelector(authCheckTableClass);
if (check_table) {
const table_check_all = check_table.querySelector("input[type=checkbox]");
if (table_check_all) {
table_check_all.addEventListener("click", (event) => {
const target = event.currentTarget;
const { checked } = target;
const other_checks = auth_table.querySelectorAll("input[type=checkbox]:not(" + authCheckTableClass + ">input[type=checkbox])");
for (const other_check of other_checks) {
if (checked) {
other_check.checked = true;
} else {
other_check.checked = false;
}
}
});
}
}
const authCheckRowClass = getOption("authCheckRowClass");
const check_rows = auth_table.querySelectorAll(authCheckRowClass);
for (const check_row of check_rows) {
const row_check_all = check_row.querySelector("input[type=checkbox]");
if (row_check_all) {
row_check_all.addEventListener("click", (event) => {
const target = event.currentTarget;
const { checked } = target;
const next_td = xqUtil.next(check_row, "td")[0];
const next_td_checks = next_td.querySelectorAll("input[type=checkbox]");
for (const next_td_check of next_td_checks) {
if (checked) {
next_td_check.checked = true;
} else {
next_td_check.checked = false;
}
}
});
}
}
}
}
};
const bindFileinput = () => {
const fileinputs = document.querySelectorAll(".xq-fileinput");
if (fileinputs && typeof jQuery !== void 0) {
let config;
for (const fileinput of fileinputs) {
config = fileinput.hasAttribute("xq-config") ? fileinput.getAttribute("xq-config") : "{}";
$(fileinput).fileinput(JSON.parse(config)).on("filedeleted", (event) => {
const target = event.currentTarget;
updateFileInputValue(target);
}).on("fileuploaded", (event) => {
const target = event.currentTarget;
updateFileInputValue(target);
}).on("filesorted", (event) => {
const target = event.currentTarget;
updateFileInputValue(target);
});
updateFileInputValue(fileinput);
}
}
};
const updateFileInputValue = (fileinput) => {
const fileinput_id = fileinput.getAttribute("id");
const fileinput_value_id = fileinput_id.replace("-xq-fileinput", "");
const fileinput_value = document.querySelector("#" + fileinput_value_id);
const fileinput_preview = $(fileinput).fileinput("getPreview");
fileinput_value?.setAttribute("value", JSON.stringify(fileinput_preview));
const fileCount = $(fileinput).fileinput("getFilesCount", true);
const configStr = fileinput.getAttribute("xq-config");
const config = JSON.parse(configStr);
if (config !== null && "required" in config) {
if (fileCount > 0) {
fileinput.removeAttribute("required");
} else {
fileinput.setAttribute("required", "true");
}
if ("content" in fileinput_preview) {
const { content } = fileinput_preview;
if (content.length === 0) {
fileinput.setCustomValidity("\u9700\u8981\u81F3\u5C11\u4E0A\u4F20\u4E00\u4E2A\u6587\u4EF6");
} else {
fileinput.setCustomValidity("");
}
}
}
};
const bindCaptcha = () => {
const captchaClass = getOption("captchaClass");
const captcha = document.querySelector(captchaClass);
if (captcha) {
captcha.addEventListener("click", (event) => {
const target = event.currentTarget;
let src = target.getAttribute("src");
if (src.includes("?")) {
src = src.slice(0, Math.max(0, src.lastIndexOf("?")));
src = src + "?xq-r=" + Math.random().toString();
} else {
src = src + "?xq-r=" + Math.random().toString();
}
target.setAttribute("src", src);
});
}
};
const bindOrder = () => {
const table = getTable();
const thead = table.querySelector("thead");
const orderClass = getOption("orderClass");
const orderAscClass = getOption("orderAscClass");
const orderDescClass = getOption("orderDescClass");
const orderClassStr = orderClass.slice(1);
const orderAscClassStr = orderAscClass.slice(1);
const orderDescClassStr = orderDescClass.slice(1);
const thes = thead.querySelectorAll(orderClass);
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.has("orderby")) {
const field = urlParams.get("orderby");
const ordertype = urlParams.get("ordertype") ?? 1;
const thsort = thead?.querySelector('th[field="' + field + '"]');
if (thsort) {
thsort.classList.remove(orderClassStr);
if (ordertype == 1) {
thsort.classList.add(orderAscClassStr);
} else {
thsort.classList.add(orderDescClassStr);
}
}
}
for (const th of thes) {
th.addEventListener("click", (event) => {
let field = th.getAttribute("field");
let type = 0;
if (th.classList.contains(orderClassStr)) {
th.classList.remove(orderClassStr);
th.classList.add(orderAscClassStr);
type = 1;
} else if (th.classList.contains(orderAscClassStr)) {
th.classList.remove(orderAscClassStr);
th.classList.add(orderDescClassStr);
type = 2;
} else if (th.classList.contains(orderDescClassStr)) {
th.classList.remove(orderDescClassStr);
th.classList.add(orderAscClassStr);
type = 1;
}
let url = window.location.href;
url = xqUtil.setUrlParam(url, "orderby", field);
switch (type) {
case 1:
url = xqUtil.setUrlParam(url, "ordertype", 1);
break;
case 2:
url = xqUtil.setUrlParam(url, "ordertype", 2);
break;
default:
url = xqUtil.setUrlParam(url, "ordertype", 1);
break;
}
window.location.href = url;
});
}
};
const bindPageSize = () => {
const pageSizeId = getOption("pageSizeId");
const pageSize = document.querySelector(pageSizeId);
if (pageSize) {
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.has("page-size")) {
const param = urlParams.get("page-size");
pageSize.value = param ?? "10";
}
pageSize.addEventListener("change", (event) => {
const target = event.currentTarget;
const size = target.value;
let url = window.location.href;
url = xqUtil.setUrlParam(url, "page-size", size);
window.location.href = url;
});
}
};
const bindExport = () => {
const table = getTable();
const exportBtnClass = getOption("exportBtnClass");
const export_btn = table.querySelector(exportBtnClass);
if (export_btn) {
export_btn.addEventListener("click", () => {
const url = new URL(window.location.href);
let actionUrl = url.origin + url.pathname;
actionUrl = actionUrl.slice(0, Math.max(0, actionUrl.lastIndexOf("/")));
actionUrl = actionUrl + "/export";
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.size > 0) {
actionUrl = actionUrl + "?" + urlParams.toString();
}
const id = "xq-export-form";
let export_form = document.querySelector("#" + id);
if (export_form) {
export_form.setAttribute("action", actionUrl);
} else {
const export_form_str = '<form action="' + actionUrl + '" method="post" style="display: none;" id="' + id + '"></form>';
xqUtil.append(document.body, export_form_str);
export_form = document.querySelector("#" + id);
}
export_form.submit();
});
}
};
const init = () => {
const table = getTable();
if (table) {
bindOrder();
bindPageSize();
const tres = table.querySelectorAll("tr");
for (const tr of tres) {
bindView(tr);
bindEdit(tr);
bindDelete(tr);
bindChange(tr);
bindCopy(tr);
}
bindCheckAll();
bindAdd();
bindBatch();
bindExport();
bindDrag();
}
bindBack();
bindAuth();
bindFileinput();
bindCaptcha();
};
const xqTableList = (options = {}) => {
setOption(options);
init();
};
xqUtil.domReady(() => {
xqTableList();
});