| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645 |
- /**
- * TcsTable - 通用表格组件
- * 提供表格数据生成、渲染、分页和筛选功能
- */
- class TcsTable {
- /**
- * 构造函数
- * @param {Object} options - 表格配置选项
- * @param {Array} data - 表格数据
- */
- constructor(options, data) {
- this.options = Object.assign(
- {
- tableId: "data-table", // 表格元素ID
- paginationInfoId: "pagination-info", // 分页信息元素ID
- paginationControlsId: "pagination-controls", // 分页控件元素ID
- pageSizeId: "current-page-size", // 每页显示条数元素ID
- pageSizeItemClass: "page-size-item", // 每页显示条数选项类名
- defaultPageSize: 10, // 默认每页显示条数
- maxVisiblePages: 5, // 最大可见页码数
- columns: [], // 列配置
- },
- options
- );
- this.data = data || []; // 原始数据
- this.filteredData = [...this.data]; // 筛选后的数据
- this.currentPage = 1; // 当前页码
- this.itemsPerPage = this.options.defaultPageSize; // 每页显示条数
- // 注册内置的表头渲染器
- this.headerRenderers = {
- // 复选框表头渲染器
- checkbox: (column, th) => {
- th.innerHTML = '<input class="form-check-input m-0 align-middle" type="checkbox" id="select-all" aria-label="全选">';
-
- // 绑定全选事件
- setTimeout(() => {
- const selectAll = document.getElementById('select-all');
- if (selectAll) {
- selectAll.addEventListener('change', () => {
- const checkboxes = document.querySelectorAll('.row-checkbox');
- checkboxes.forEach(checkbox => {
- checkbox.checked = selectAll.checked;
- });
- });
-
- // 监听表格体中的复选框变化,更新全选框状态
- document.addEventListener('change', (e) => {
- if (e.target && e.target.classList.contains('row-checkbox')) {
- this.updateSelectAllCheckboxState();
- }
- });
- }
- }, 0);
-
- return th;
- },
-
- // 可以添加更多内置渲染器...
- };
-
- // 允许用户注册自定义渲染器
- if (options.headerRenderers) {
- Object.assign(this.headerRenderers, options.headerRenderers);
- }
- // 初始化表格
- this.init();
- }
- /**
- * 初始化表格
- */
- init() {
- // 初始化表头
- this.initTableHeader();
-
- // 渲染表格
- this.renderTable();
- // 绑定分页事件
- this.bindPaginationEvents();
- // 绑定每页显示条数事件
- this.bindPageSizeEvents();
- }
- /**
- * 初始化表头
- */
- initTableHeader() {
- const tableHead = document.querySelector(`#${this.options.tableId} thead tr`);
- if (!tableHead) return;
-
- // 清空表头
- tableHead.innerHTML = "";
-
- // 创建表头单元格
- this.options.columns.forEach(column => {
- const th = document.createElement("th");
-
- // 添加列的自定义类名
- if (column.className) {
- th.className = column.className;
- }
-
- // 使用自定义渲染器(如果有)
- if (column.headerRenderer && this.headerRenderers[column.headerRenderer]) {
- this.headerRenderers[column.headerRenderer](column, th);
- } else {
- th.textContent = column.title;
- }
-
- tableHead.appendChild(th);
- });
- }
- /**
- * 更新全选框状态
- */
- updateSelectAllCheckboxState() {
- const selectAllCheckbox = document.getElementById('select-all');
- const checkboxes = document.querySelectorAll('.row-checkbox');
- const checkedCheckboxes = document.querySelectorAll('.row-checkbox:checked');
-
- if (selectAllCheckbox) {
- // 如果所有复选框都被选中,则全选框也被选中
- selectAllCheckbox.checked = checkboxes.length > 0 && checkboxes.length === checkedCheckboxes.length;
- // 如果部分复选框被选中,则全选框处于不确定状态
- selectAllCheckbox.indeterminate = checkedCheckboxes.length > 0 && checkboxes.length !== checkedCheckboxes.length;
- }
- }
- /**
- * 获取选中行的ID
- * @returns {Array} 选中行的ID数组
- */
- getSelectedRowIds() {
- const selectedIds = [];
- const checkedCheckboxes = document.querySelectorAll('.row-checkbox:checked');
- checkedCheckboxes.forEach(checkbox => {
- selectedIds.push(checkbox.getAttribute('data-id'));
- });
- return selectedIds;
- }
- /**
- * 渲染表格
- */
- renderTable() {
- const tableBody = document.querySelector(`#${this.options.tableId} tbody`);
- if (!tableBody) return;
- tableBody.innerHTML = ""; // 清空表格
- const totalItems = this.filteredData.length;
- const totalPages = Math.ceil(totalItems / this.itemsPerPage);
- // 计算当前页的数据范围
- const startIndex = (this.currentPage - 1) * this.itemsPerPage;
- const endIndex = Math.min(startIndex + this.itemsPerPage, totalItems);
- const currentPageData = this.filteredData.slice(startIndex, endIndex);
- // 填充表格数据
- currentPageData.forEach((rowData) => {
- const row = document.createElement("tr");
- // 遍历列配置,生成单元格
- this.options.columns.forEach((column) => {
- const cell = document.createElement("td");
-
- // 添加列的自定义类名
- if (column.className) {
- cell.className = column.className;
- }
-
- // 获取单元格值
- let value = rowData[column.field];
-
- // 如果值为空且有默认值,则使用默认值
- if ((value === undefined || value === null || value === "") && column.defaultValue !== undefined) {
- value = column.defaultValue;
- }
-
- // 如果有格式化函数,则使用格式化函数处理值
- if (column.formatter && typeof column.formatter === "function") {
- cell.innerHTML = column.formatter(value, rowData);
- } else {
- cell.textContent = value;
- }
-
- row.appendChild(cell);
- });
- tableBody.appendChild(row);
- });
- // 更新分页信息
- this.updatePagination(totalItems, totalPages);
- }
- /**
- * 更新分页信息和控件
- * @param {Number} totalItems - 总条目数
- * @param {Number} totalPages - 总页数
- */
- updatePagination(totalItems, totalPages) {
- // 更新分页信息文本
- const paginationInfo = document.getElementById(this.options.paginationInfoId);
- if (paginationInfo) {
- paginationInfo.textContent = `显示第 ${
- totalItems === 0 ? 0 : (this.currentPage - 1) * this.itemsPerPage + 1
- } 到第 ${Math.min(
- this.currentPage * this.itemsPerPage,
- totalItems
- )} 条记录,共计 ${totalItems} 条记录`;
- }
- // 更新每页显示条数
- const currentPageSize = document.getElementById(this.options.pageSizeId);
- if (currentPageSize) {
- currentPageSize.textContent = this.itemsPerPage;
- }
- // 更新分页控件
- const paginationControls = document.getElementById(
- this.options.paginationControlsId
- );
- if (!paginationControls) return;
-
- paginationControls.innerHTML = "";
- // 上一页按钮
- const prevDisabled = this.currentPage === 1 || totalItems === 0;
- const prevItem = document.createElement("li");
- prevItem.className = `page-item ${prevDisabled ? "disabled" : ""}`;
- prevItem.innerHTML = `
- <a class="page-link" href="#" data-page="${this.currentPage - 1}" ${
- prevDisabled ? 'tabindex="-1" aria-disabled="true"' : ""
- }>
- <i class="ti ti-chevron-left"></i>
- </a>
- `;
- paginationControls.appendChild(prevItem);
- // 页码按钮
- const maxVisiblePages = this.options.maxVisiblePages;
- let startPage = Math.max(
- 1,
- this.currentPage - Math.floor(maxVisiblePages / 2)
- );
- let endPage = Math.min(totalPages, startPage + maxVisiblePages - 1);
- if (endPage - startPage < maxVisiblePages - 1 && startPage > 1) {
- startPage = Math.max(1, endPage - maxVisiblePages + 1);
- }
- // 添加页码
- for (let i = 1; i <= totalPages; i++) {
- // 显示第一页、最后一页和当前页附近的页码
- if (
- i === 1 ||
- i === totalPages ||
- (i >= startPage && i <= endPage)
- ) {
- const pageItem = document.createElement("li");
- pageItem.className = `page-item ${
- i === this.currentPage ? "active" : ""
- }`;
- pageItem.innerHTML = `<a class="page-link" href="#" data-page="${i}">${i}</a>`;
- paginationControls.appendChild(pageItem);
- }
- // 添加省略号
- else if (i === startPage - 1 || i === endPage + 1) {
- const ellipsisItem = document.createElement("li");
- ellipsisItem.className = "page-item disabled";
- ellipsisItem.innerHTML = '<a class="page-link" href="#">...</a>';
- paginationControls.appendChild(ellipsisItem);
- }
- }
- // 下一页按钮
- const nextDisabled = this.currentPage === totalPages || totalItems === 0;
- const nextItem = document.createElement("li");
- nextItem.className = `page-item ${nextDisabled ? "disabled" : ""}`;
- nextItem.innerHTML = `
- <a class="page-link" href="#" data-page="${this.currentPage + 1}" ${
- nextDisabled ? 'tabindex="-1" aria-disabled="true"' : ""
- }>
- <i class="ti ti-chevron-right"></i>
- </a>
- `;
- paginationControls.appendChild(nextItem);
- }
- /**
- * 绑定分页事件
- */
- bindPaginationEvents() {
- const paginationControls = document.getElementById(
- this.options.paginationControlsId
- );
- if (!paginationControls) return;
- paginationControls.addEventListener("click", (e) => {
- e.preventDefault();
- // 检查点击的是否是分页链接
- const pageLink = e.target.closest(".page-link");
- if (!pageLink) return;
- // 检查链接是否被禁用
- if (pageLink.getAttribute("aria-disabled") === "true") return;
- // 获取目标页码
- const targetPage = parseInt(pageLink.getAttribute("data-page"));
- if (isNaN(targetPage)) return;
- // 更新当前页码
- this.currentPage = targetPage;
- // 重新渲染表格
- this.renderTable();
- });
- }
- /**
- * 绑定每页显示条数事件
- */
- bindPageSizeEvents() {
- const pageSizeItems = document.querySelectorAll(`.${this.options.pageSizeItemClass}`);
-
- pageSizeItems.forEach((item) => {
- item.addEventListener("click", (e) => {
- e.preventDefault();
-
- // 获取新的每页显示条数
- const newItemsPerPage = parseInt(item.getAttribute("data-size"));
- if (isNaN(newItemsPerPage)) return;
-
- // 更新每页显示条数
- this.itemsPerPage = newItemsPerPage;
- this.currentPage = 1; // 重置为第一页
-
- // 重新渲染表格
- this.renderTable();
- });
- });
- }
- /**
- * 筛选数据
- * @param {Function} filterFn - 筛选函数
- */
- filter(filterFn) {
- if (typeof filterFn !== "function") {
- this.filteredData = [...this.data];
- } else {
- this.filteredData = this.data.filter(filterFn);
- }
-
- this.currentPage = 1; // 重置为第一页
- this.renderTable(); // 重新渲染表格
- }
- /**
- * 搜索数据
- * @param {String} keyword - 搜索关键字
- * @param {Array} fields - 要搜索的字段
- */
- search(keyword, fields) {
- if (!keyword) {
- this.filteredData = [...this.data];
- } else {
- const lowerKeyword = keyword.toLowerCase();
-
- this.filteredData = this.data.filter((item) => {
- return fields.some((field) => {
- const value = item[field];
- if (value === undefined || value === null) return false;
-
- // 处理对象类型的值
- if (typeof value === "object" && value.text) {
- return value.text.toLowerCase().includes(lowerKeyword);
- }
-
- return String(value).toLowerCase().includes(lowerKeyword);
- });
- });
- }
-
- this.currentPage = 1; // 重置为第一页
- this.renderTable(); // 重新渲染表格
- }
- /**
- * 重置筛选
- */
- resetFilter() {
- this.filteredData = [...this.data];
- this.currentPage = 1; // 重置为第一页
- this.renderTable(); // 重新渲染表格
- }
- /**
- * 更新数据
- * @param {Array} data - 新数据
- */
- updateData(data) {
- this.data = data || [];
- this.filteredData = [...this.data];
- this.currentPage = 1; // 重置为第一页
- this.renderTable(); // 重新渲染表格
- }
- /**
- * 添加数据
- * @param {Object|Array} data - 要添加的数据
- */
- addData(data) {
- if (Array.isArray(data)) {
- this.data = [...this.data, ...data];
- } else {
- this.data.push(data);
- }
-
- this.filteredData = [...this.data];
- this.renderTable(); // 重新渲染表格
- }
- /**
- * 删除数据
- * @param {Function} predicate - 判断函数
- */
- removeData(predicate) {
- if (typeof predicate !== "function") return;
-
- this.data = this.data.filter((item) => !predicate(item));
- this.filteredData = [...this.data];
- this.renderTable(); // 重新渲染表格
- }
- /**
- * 生成模拟订单数据
- * @param {Number} count - 数据条数
- * @returns {Array} - 生成的数据
- */
- static generateOrderData(count = 100) {
- const statusOptions = [
- { text: "进行中", class: "bg-success" },
- { text: "待处理", class: "bg-warning" },
- { text: "已完成", class: "bg-info" },
- { text: "已取消", class: "bg-danger" },
- { text: "已超时", class: "bg-secondary" },
- ];
- const locations = ["A区", "B区", "C区", "D区", "E区", "F区"];
- const goods = [
- "原材料",
- "半成品",
- "成品",
- "包装材料",
- "零部件",
- "工具",
- ];
- const orders = [];
- for (let i = 1; i <= count; i++) {
- // 生成订单ID
- const id = `ORD-${String(i).padStart(3, "0")}`;
- // 生成订单时间(过去30天内的随机时间)
- const now = new Date();
- const randomDays = Math.floor(Math.random() * 30);
- const randomHours = Math.floor(Math.random() * 24);
- const randomMinutes = Math.floor(Math.random() * 60);
- const orderDate = new Date(now);
- orderDate.setDate(now.getDate() - randomDays);
- orderDate.setHours(now.getHours() - randomHours);
- orderDate.setMinutes(now.getMinutes() - randomMinutes);
- const orderTime = `${orderDate.getFullYear()}-${String(
- orderDate.getMonth() + 1
- ).padStart(2, "0")}-${String(orderDate.getDate()).padStart(
- 2,
- "0"
- )} ${String(orderDate.getHours()).padStart(2, "0")}:${String(
- orderDate.getMinutes()
- ).padStart(2, "0")}`;
- // 随机选择起点和终点
- const from = `${
- locations[Math.floor(Math.random() * locations.length)]
- }-${Math.floor(Math.random() * 20) + 1}号仓位`;
- let to;
- do {
- to = `${
- locations[Math.floor(Math.random() * locations.length)]
- }-${Math.floor(Math.random() * 20) + 1}号仓位`;
- } while (to === from); // 确保起点和终点不同
- // 随机选择货物
- const good = goods[Math.floor(Math.random() * goods.length)];
- // 生成期限(订单时间后的1-24小时)
- const deadlineDate = new Date(orderDate);
- deadlineDate.setHours(
- orderDate.getHours() + Math.floor(Math.random() * 24) + 1
- );
- const deadline = `${deadlineDate.getFullYear()}-${String(
- deadlineDate.getMonth() + 1
- ).padStart(2, "0")}-${String(deadlineDate.getDate()).padStart(
- 2,
- "0"
- )} ${String(deadlineDate.getHours()).padStart(2, "0")}:${String(
- deadlineDate.getMinutes()
- ).padStart(2, "0")}`;
- // 随机选择状态
- const status =
- statusOptions[Math.floor(Math.random() * statusOptions.length)];
- // 生成开始和结束时间
- let startTime = "";
- let endTime = "";
- if (status.text !== "待处理") {
- // 如果不是待处理状态,则有开始时间
- const startDate = new Date(orderDate);
- startDate.setMinutes(
- startDate.getMinutes() + Math.floor(Math.random() * 60)
- );
- startTime = `${startDate.getFullYear()}-${String(
- startDate.getMonth() + 1
- ).padStart(2, "0")}-${String(startDate.getDate()).padStart(
- 2,
- "0"
- )} ${String(startDate.getHours()).padStart(2, "0")}:${String(
- startDate.getMinutes()
- ).padStart(2, "0")}`;
- // 如果是已完成或已取消或已超时状态,则有结束时间
- if (
- status.text === "已完成" ||
- status.text === "已取消" ||
- status.text === "已超时"
- ) {
- const endDate = new Date(startDate);
- endDate.setMinutes(
- endDate.getMinutes() + Math.floor(Math.random() * 120)
- );
- endTime = `${endDate.getFullYear()}-${String(
- endDate.getMonth() + 1
- ).padStart(2, "0")}-${String(endDate.getDate()).padStart(
- 2,
- "0"
- )} ${String(endDate.getHours()).padStart(2, "0")}:${String(
- endDate.getMinutes()
- ).padStart(2, "0")}`;
- }
- }
- // 创建订单对象
- const order = {
- id,
- orderTime,
- from,
- to,
- good,
- deadline,
- startTime,
- endTime,
- status,
- };
- orders.push(order);
- }
- return orders;
- }
- /**
- * 生成模拟车辆数据
- * @param {Number} count - 数据条数
- * @returns {Array} - 生成的数据
- */
- static generateVehicleData(count = 100) {
- const statusOptions = [
- { text: "空闲", class: "bg-success" },
- { text: "任务中", class: "bg-warning" },
- { text: "充电中", class: "bg-info" },
- { text: "维修中", class: "bg-danger" },
- { text: "离线", class: "bg-secondary" },
- ];
- const vehicleTypes = ["AGV-小车", "AGV-叉车", "AGV-拖车", "AGV-搬运车", "AGV-牵引车"];
- const locations = ["A区", "B区", "C区", "D区", "E区", "F区"];
- const vehicles = [];
- for (let i = 1; i <= count; i++) {
- // 生成车辆ID
- const id = `AGV-${String(i).padStart(3, "0")}`;
- // 随机选择车辆类型
- const type = vehicleTypes[Math.floor(Math.random() * vehicleTypes.length)];
- // 随机生成电量 (0-100)
- const battery = Math.floor(Math.random() * 101);
- // 随机选择位置
- const location = `${
- locations[Math.floor(Math.random() * locations.length)]
- }-${Math.floor(Math.random() * 20) + 1}号位置`;
- // 随机选择状态
- const status =
- statusOptions[Math.floor(Math.random() * statusOptions.length)];
- // 随机生成运行时间 (0-10000小时)
- const runtime = Math.floor(Math.random() * 10000);
- // 创建车辆对象
- const vehicle = {
- id,
- type,
- battery,
- location,
- status,
- runtime: `${runtime}小时`,
- lastMaintenance: `${Math.floor(Math.random() * 365)}天前`,
- };
- vehicles.push(vehicle);
- }
- return vehicles;
- }
- }
- // 如果在Node.js环境中,导出模块
- if (typeof module !== 'undefined' && module.exports) {
- module.exports = TcsTable;
- }
|