Skip to content

Website Service Typical Scenarios

Delivery Vehicle Information Registration List

Effect

html
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Delivery Vehicle Information Registration List</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet" />
    <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.8/dist/chart.umd.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js"></script>
    <script>
      tailwind.config = {
        theme: {
          extend: {
            colors: {
              primary: "#1E40AF", // Primary: dark blue (professional, reliable)
              secondary: "#3B82F6", // Secondary: light blue
              success: "#10B981", // Success: green
              warning: "#F59E0B", // Warning: yellow
              danger: "#EF4444", // Danger: red
              neutral: "#6B7280", // Neutral: gray
            },
            fontFamily: {
              sans: ["Inter", "system-ui", "sans-serif"],
            },
          },
        },
      };
    </script>
    <style type="text/tailwindcss">
      @layer utilities {
        .content-auto {
          content-visibility: auto;
        }
        .table-shadow {
          box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
        }
        .filter-card {
          box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
        }
        .input-error {
          border-color: #ef4444 !important;
          box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.1) !important;
        }
        .error-hint {
          color: #ef4444;
          font-size: 0.75rem;
          margin-top: 0.25rem;
          display: none;
        }
      }
    </style>
  </head>
  <body class="bg-gray-50 min-h-screen font-sans">
    <!-- Page Header -->
    <header class="bg-white shadow-sm sticky top-0 z-10">
      <div class="container mx-auto px-4 py-4 flex flex-col md:flex-row justify-between items-center">
        <div class="flex items-center mb-4 md:mb-0">
          <i class="fa fa-truck text-primary text-2xl mr-3"></i>
          <h1 class="text-[clamp(1.25rem,3vw,1.75rem)] font-bold text-gray-800">Delivery Vehicle Information Registration List</h1>
        </div>
        <div class="flex space-x-3">
          <button id="refreshBtn" class="flex items-center px-4 py-2 bg-white border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors">
            <i class="fa fa-refresh mr-2"></i>
            <span>Refresh Data</span>
          </button>
          <button id="exportBtn" class="flex items-center px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors">
            <i class="fa fa-download mr-2"></i>
            <span>Export Excel</span>
          </button>
        </div>
      </div>
    </header>

    <!-- Filter Area -->
    <section class="container mx-auto px-4 py-6">
      <div class="bg-white rounded-lg p-4 filter-card">
        <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
          <!-- License Plate Filter -->
          <div>
            <label for="plateNumber" class="block text-sm font-medium text-gray-700 mb-1">License Plate</label>
            <div class="relative">
              <i class="fa fa-search absolute left-3 top-1/2 -translate-y-1/2 text-gray-400"></i>
              <input type="text" id="plateNumber" placeholder="Enter license plate (optional)" class="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-primary/50 focus:border-primary outline-none transition-all" />
              <p id="plateNumberError" class="error-hint">Please enter a valid license plate</p>
            </div>
          </div>

          <!-- Shipping Date Filter -->
          <div>
            <label for="shipDateRange" class="block text-sm font-medium text-gray-700 mb-1">Shipping Date Range</label>
            <div class="flex space-x-2">
              <input type="date" id="startDate" placeholder="Start Date" class="flex-1 px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-primary/50 focus:border-primary outline-none transition-all" />
              <span class="flex items-center text-gray-500">to</span>
              <input type="date" id="endDate" placeholder="End Date" class="flex-1 px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-primary/50 focus:border-primary outline-none transition-all" />
              <p id="dateRangeError" class="error-hint absolute mt-10 text-xs">End date cannot be earlier than start date</p>
            </div>
          </div>

          <!-- Filter Button -->
          <div class="flex items-end">
            <button id="searchBtn" class="w-full px-4 py-2 bg-secondary text-white rounded-md hover:bg-secondary/90 transition-colors">
              <i class="fa fa-filter mr-2"></i>
              <span>Filter</span>
            </button>
          </div>
        </div>
      </div>
    </section>

    <!-- Data Statistics Overview -->
    <section class="container mx-auto px-4 py-4">
      <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
        <!-- Total Vehicles -->
        <div class="bg-white rounded-lg p-4 shadow-sm">
          <div class="flex items-center justify-between mb-2">
            <h3 class="text-sm font-medium text-gray-500">Total Vehicles</h3>
            <i class="fa fa-car text-primary text-xl"></i>
          </div>
          <p id="totalVehicles" class="text-2xl font-bold text-gray-800">0</p>
          <p class="text-xs text-gray-400">As of current statistics</p>
        </div>

        <!-- Today's Shipments -->
        <div class="bg-white rounded-lg p-4 shadow-sm">
          <div class="flex items-center justify-between mb-2">
            <h3 class="text-sm font-medium text-gray-500">Today's Shipments</h3>
            <i class="fa fa-calendar-check-o text-success text-xl"></i>
          </div>
          <p id="todayShipments" class="text-2xl font-bold text-gray-800">0</p>
          <p class="text-xs text-gray-400">Added today</p>
        </div>

        <!-- Pending Shipments -->
        <div class="bg-white rounded-lg p-4 shadow-sm">
          <div class="flex items-center justify-between mb-2">
            <h3 class="text-sm font-medium text-gray-500">Pending Shipments</h3>
            <i class="fa fa-clock-o text-warning text-xl"></i>
          </div>
          <p id="pendingShipments" class="text-2xl font-bold text-gray-800">0</p>
          <p class="text-xs text-gray-400">Pending orders</p>
        </div>

        <!-- Abnormal Vehicles -->
        <div class="bg-white rounded-lg p-4 shadow-sm">
          <div class="flex items-center justify-between mb-2">
            <h3 class="text-sm font-medium text-gray-500">Abnormal Vehicles</h3>
            <i class="fa fa-exclamation-triangle text-danger text-xl"></i>
          </div>
          <p id="abnormalVehicles" class="text-2xl font-bold text-gray-800">0</p>
          <p class="text-xs text-gray-400">Requires manual handling</p>
        </div>
      </div>
    </section>

    <!-- List Display Area -->
    <section class="container mx-auto px-4 py-4">
      <div class="bg-white rounded-lg table-shadow overflow-hidden">
        <div class="overflow-x-auto">
          <table class="min-w-full divide-y divide-gray-200">
            <thead class="bg-gray-50">
              <tr>
                <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">No.</th>
                <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">License Plate</th>
                <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Driver Name</th>
                <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Shipping Date</th>
                <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Vehicle Status</th>
                <th scope="col" class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
              </tr>
            </thead>
            <tbody id="vehicleTableBody" class="bg-white divide-y divide-gray-200">
              <!-- Initial state: please filter data -->
              <tr id="initialRow" class="">
                <td colspan="6" class="px-6 py-12 text-center">
                  <div class="flex flex-col items-center">
                    <i class="fa fa-filter text-gray-300 text-2xl mb-3"></i>
                    <p class="text-gray-500">Please fill in filter conditions and click the Filter button to query data</p>
                  </div>
                </td>
              </tr>
              <!-- Loading data -->
              <tr id="loadingRow" class="hidden">
                <td colspan="6" class="px-6 py-12 text-center">
                  <div class="flex flex-col items-center">
                    <i class="fa fa-spinner fa-spin text-primary text-2xl mb-3"></i>
                    <p class="text-gray-500">Loading data...</p>
                  </div>
                </td>
              </tr>
              <!-- No data hint -->
              <tr id="emptyRow" class="hidden">
                <td colspan="6" class="px-6 py-12 text-center">
                  <div class="flex flex-col items-center">
                    <i class="fa fa-folder-open-o text-gray-300 text-2xl mb-3"></i>
                    <p class="text-gray-500">No delivery vehicle information matching the criteria</p>
                  </div>
                </td>
              </tr>
              <!-- API error hint -->
              <tr id="errorRow" class="hidden">
                <td colspan="6" class="px-6 py-12 text-center">
                  <div class="flex flex-col items-center">
                    <i class="fa fa-exclamation-circle text-danger text-2xl mb-3"></i>
                    <p class="text-gray-500 mb-4" id="errorMessage">Data loading failed</p>
                    <button id="retryBtn" class="px-4 py-2 bg-secondary text-white rounded-md hover:bg-secondary/90 transition-colors">Retry</button>
                  </div>
                </td>
              </tr>
            </tbody>
          </table>
        </div>

        <!-- Pagination Controls -->
        <div class="px-6 py-4 flex items-center justify-between border-t border-gray-200 hidden" id="paginationContainer">
          <div class="flex-1 flex justify-between sm:hidden">
            <button id="prevPageMobile" class="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed" disabled>Previous</button>
            <button id="nextPageMobile" class="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed" disabled>Next</button>
          </div>
          <div class="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
            <div>
              <p class="text-sm text-gray-700">Showing page <span id="currentPageText">1</span> of <span id="totalPagesText">0</span>, total <span id="totalItemsText">0</span> records</p>
            </div>
            <div>
              <nav class="relative z-0 inline-flex rounded-md shadow-sm -space-x-px" aria-label="Pagination">
                <button id="prevPage" class="relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed" disabled>
                  <span class="sr-only">Previous</span>
                  <i class="fa fa-chevron-left h-5 w-5"></i>
                </button>
                <button id="nextPage" class="relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed" disabled>
                  <span class="sr-only">Next</span>
                  <i class="fa fa-chevron-right h-5 w-5"></i>
                </button>
              </nav>
            </div>
          </div>
        </div>
      </div>
    </section>

    <!-- View Details Modal -->
    <div id="detailModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
      <div class="bg-white rounded-lg max-w-md w-full mx-4 overflow-hidden transform transition-all">
        <div class="px-6 py-4 border-b border-gray-200">
          <div class="flex justify-between items-center">
            <h3 class="text-lg font-medium text-gray-900">Vehicle Shipping Details</h3>
            <button id="closeModal" class="text-gray-400 hover:text-gray-500">
              <i class="fa fa-times"></i>
            </button>
          </div>
        </div>
        <div class="px-6 py-4">
          <div class="space-y-4">
            <div class="grid grid-cols-3 gap-2">
              <label class="text-sm font-medium text-gray-500">No.</label>
              <p id="detailSeq" class="col-span-2 text-sm text-gray-900">-</p>
            </div>
            <div class="grid grid-cols-3 gap-2">
              <label class="text-sm font-medium text-gray-500">License Plate</label>
              <p id="detailPlateNumber" class="col-span-2 text-sm text-gray-900">-</p>
            </div>
            <div class="grid grid-cols-3 gap-2">
              <label class="text-sm font-medium text-gray-500">Driver Name</label>
              <p id="detailName" class="col-span-2 text-sm text-gray-900">-</p>
            </div>
            <div class="grid grid-cols-3 gap-2">
              <label class="text-sm font-medium text-gray-500">Shipping Date</label>
              <p id="detailShipDate" class="col-span-2 text-sm text-gray-900">-</p>
            </div>
            <div class="grid grid-cols-3 gap-2">
              <label class="text-sm font-medium text-gray-500">Vehicle Status</label>
              <p id="detailStatus" class="col-span-2 text-sm font-medium">-</p>
            </div>
          </div>
        </div>
        <div class="px-6 py-4 border-t border-gray-200 flex justify-end">
          <button id="closeDetailBtn" class="px-4 py-2 bg-gray-100 text-gray-700 rounded-md hover:bg-gray-200 transition-colors">Close</button>
        </div>
      </div>
    </div>

    <!-- Footer -->
    <footer class="bg-white border-t border-gray-200 mt-8">
      <div class="container mx-auto px-4 py-6">
        <div class="flex flex-col md:flex-row justify-between items-center">
          <p class="text-sm text-gray-500 mb-4 md:mb-0">© 2025 Delivery Vehicle Management System. All rights reserved.</p>
          <div class="flex space-x-4">
            <a href="#" class="text-sm text-gray-500 hover:text-primary transition-colors">Help Center</a>
            <a href="#" class="text-sm text-gray-500 hover:text-primary transition-colors">Contact Us</a>
            <a href="#" class="text-sm text-gray-500 hover:text-primary transition-colors">System Info</a>
          </div>
        </div>
      </div>
    </footer>

    <script>
      // Global variables
      let vehicleData = []; // Vehicle data list
      let currentPage = 1; // Current page number
      let pageSize = 10; // Items per page
      let totalItems = 0; // Total records
      let totalPages = 0; // Total pages

      // API configuration parameters (modify tableId and apiKey according to your actual setup)
      const API_CONFIG = {
        url: "https://ai.ainformat.com//web0/webapi/table_record_list",
        apiKey: "ojw76e1htyb2p3e37gcay", // Example apiKey, use your actual key in production
        tableId: "shipPlan", // Example tableId, use the actual delivery vehicle data table identifier
        // Field mapping: ensure consistency with field IDs in the data table
        fieldMap: {
          seq: "seq", // Sequence number field ID
          plateNumber: "plateNumber", // License plate field ID
          name: "name", // Driver name field ID
          shipDate: "shipDate", // Shipping date field ID
          state: "state",
          state_name: "state_name", // Vehicle status field ID
        },
      };

      // DOM elements
      const vehicleTableBody = document.getElementById("vehicleTableBody");
      const initialRow = document.getElementById("initialRow");
      const loadingRow = document.getElementById("loadingRow");
      const emptyRow = document.getElementById("emptyRow");
      const errorRow = document.getElementById("errorRow");
      const errorMessage = document.getElementById("errorMessage");
      const retryBtn = document.getElementById("retryBtn");
      const refreshBtn = document.getElementById("refreshBtn");
      const exportBtn = document.getElementById("exportBtn");
      const searchBtn = document.getElementById("searchBtn");
      const plateNumberInput = document.getElementById("plateNumber");
      const startDateInput = document.getElementById("startDate");
      const endDateInput = document.getElementById("endDate");
      const plateNumberError = document.getElementById("plateNumberError");
      const dateRangeError = document.getElementById("dateRangeError");
      const prevPageBtn = document.getElementById("prevPage");
      const nextPageBtn = document.getElementById("nextPage");
      const prevPageMobileBtn = document.getElementById("prevPageMobile");
      const nextPageMobileBtn = document.getElementById("nextPageMobile");
      const currentPageText = document.getElementById("currentPageText");
      const totalPagesText = document.getElementById("totalPagesText");
      const totalItemsText = document.getElementById("totalItemsText");
      const totalVehiclesEl = document.getElementById("totalVehicles");
      const todayShipmentsEl = document.getElementById("todayShipments");
      const pendingShipmentsEl = document.getElementById("pendingShipments");
      const abnormalVehiclesEl = document.getElementById("abnormalVehicles");
      const detailModal = document.getElementById("detailModal");
      const closeModalBtn = document.getElementById("closeModal");
      const closeDetailBtn = document.getElementById("closeDetailBtn");
      const detailSeqEl = document.getElementById("detailSeq");
      const detailPlateNumberEl = document.getElementById("detailPlateNumber");
      const detailNameEl = document.getElementById("detailName");
      const detailShipDateEl = document.getElementById("detailShipDate");
      const detailStatusEl = document.getElementById("detailStatus");
      const paginationContainer = document.getElementById("paginationContainer");

      // Initialize page
      document.addEventListener("DOMContentLoaded", () => {
        // Bind events
        bindEvents();
        fetchVehicleData();
      });

      // Bind events
      function bindEvents() {
        // Refresh button
        refreshBtn.addEventListener("click", () => {
          // Reset filter conditions
          plateNumberInput.value = "";
          startDateInput.value = "";
          endDateInput.value = "";

          // Hide other states, show initial state
          hideAllStates();
          initialRow.classList.remove("hidden");
          paginationContainer.classList.add("hidden");

          // Reset statistics
          resetStatistics();
        });

        // Export button
        exportBtn.addEventListener("click", exportToExcel);

        // Search button
        searchBtn.addEventListener("click", () => {
          currentPage = 1; // Reset to first page
          // Validate filter conditions first
          if (validateFilterConditions()) {
            fetchVehicleData();
          }
        });

        // License plate input event: clear error hint on input
        plateNumberInput.addEventListener("input", () => {
          plateNumberInput.classList.remove("input-error");
          plateNumberError.style.display = "none";
        });

        // Date input event: clear error hint on input
        startDateInput.addEventListener("input", () => {
          dateRangeError.style.display = "none";
        });
        endDateInput.addEventListener("input", () => {
          dateRangeError.style.display = "none";
        });

        // Pagination buttons
        prevPageBtn.addEventListener("click", goToPrevPage);
        nextPageBtn.addEventListener("click", goToNextPage);
        prevPageMobileBtn.addEventListener("click", goToPrevPage);
        nextPageMobileBtn.addEventListener("click", goToNextPage);

        // Detail modal close buttons
        closeModalBtn.addEventListener("click", closeDetailModal);
        closeDetailBtn.addEventListener("click", closeDetailModal);

        // Click outside modal to close
        detailModal.addEventListener("click", (e) => {
          if (e.target === detailModal) {
            closeDetailModal();
          }
        });

        // Retry button
        retryBtn.addEventListener("click", () => {
          if (validateFilterConditions()) {
            fetchVehicleData();
          }
        });
      }

      // Validate filter conditions
      function validateFilterConditions() {
        let isValid = true;

        // License plate validation (optional, validate format if filled)
        const plateNumber = plateNumberInput.value.trim();
        if (plateNumber && !/^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$/.test(plateNumber)) {
          plateNumberInput.classList.add("input-error");
          plateNumberError.style.display = "block";
          plateNumberInput.scrollIntoView({ behavior: "smooth", block: "center" });
          isValid = false;
        }

        // Date range validation (if both filled, end date cannot be earlier than start date)
        const startDate = startDateInput.value;
        const endDate = endDateInput.value;
        if (startDate && endDate && new Date(endDate) < new Date(startDate)) {
          dateRangeError.style.display = "block";
          endDateInput.scrollIntoView({ behavior: "smooth", block: "center" });
          isValid = false;
        }

        return isValid;
      }

      // Build API request parameters
      function buildRequestParams() {
        const params = {
          apiKey: API_CONFIG.apiKey,
          tableId: API_CONFIG.tableId,
          pageIndex: currentPage,
          pageSize: pageSize,
          filter: {
            conditionList: [],
          },
          orderByList: [
            {
              fieldId: API_CONFIG.fieldMap.shipDate,
              order: "desc", // Sort by shipping date descending
            },
          ],
        };

        // License plate filter (exact match)
        const plateNumber = plateNumberInput.value.trim();
        if (plateNumber) {
          params.filter.conditionList.push({
            fieldId: API_CONFIG.fieldMap.plateNumber,
            opt: "eq",
            value: `${plateNumber}`,
          });
        }

        // Shipping date range filter
        const startDate = startDateInput.value;
        const endDate = endDateInput.value;
        if (startDate) {
          // Convert to timestamp (milliseconds)
          const startTimestamp = new Date(startDate).getTime();

          // Greater than or equal to start time
          params.filter.conditionList.push({
            fieldId: API_CONFIG.fieldMap.shipDate,
            opt: "ge",
            value: startTimestamp,
          });
        }
        if (endDate) {
          const endTimestamp = new Date(endDate).setHours(23, 59, 59, 999);
          // Less than or equal to end time
          params.filter.conditionList.push({
            fieldId: API_CONFIG.fieldMap.shipDate,
            opt: "le",
            value: endTimestamp,
          });
        }

        return params;
      }

      // Fetch vehicle data from API
      async function fetchVehicleData() {
        // const plateNumber = plateNumberInput.value.trim();
        // // Validate license plate is not empty
        // if (!plateNumber) {
        //     plateNumberInput.classList.add('input-error');
        //     plateNumberError.style.display = 'block';
        //
        //     // Scroll to error position (mobile friendly)
        //     plateNumberInput.scrollIntoView({ behavior: 'smooth', block: 'center' });
        //     return;
        // }
        // Hide all state rows
        hideAllStates();

        // Show loading state
        showLoading();

        try {
          // Build request parameters
          const requestParams = buildRequestParams();

          // Send POST request
          const response = await fetch(API_CONFIG.url, {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              Accept: "application/json",
            },
            body: JSON.stringify(requestParams),
          });

          // Check response status
          if (!response.ok) {
            throw new Error(`API request failed: ${response.status} ${response.statusText}`);
          }

          // Parse response data
          const result = await response.json();

          // Check API return status
          if (result.code !== 0) {
            throw new Error(`API returned error: ${result.message || "Unknown error"}`);
          }

          // Process data (adapt to API response format)
          const { recordList = [], count = 0 } = result.data || {};
          vehicleData = formatVehicleData(recordList);
          totalItems = count;
          totalPages = Math.ceil(totalItems / pageSize);

          // Update table
          updateVehicleTable(vehicleData);

          // Update pagination info
          updatePaginationInfo();

          // Update statistics
          updateStatistics(vehicleData);

          // Hide loading state
          hideLoading();

          // Show empty data hint (if needed)
          if (vehicleData.length === 0) {
            showEmptyState();
          } else {
            // Show pagination controls
            paginationContainer.classList.remove("hidden");
          }
        } catch (error) {
          console.error("Failed to fetch vehicle data:", error);
          hideLoading();
          showErrorState(error.message);
        }
      }

      // Format vehicle data (adapt for page display)
      function formatVehicleData(rawData) {
        return rawData
          .map((item) => {
            // Map fields to ensure consistent field names
            return {
              seq: item[API_CONFIG.fieldMap.seq] || "",
              plateNumber: item[API_CONFIG.fieldMap.plateNumber] || "",
              name: item[API_CONFIG.fieldMap.name] || "",
              shipDate: item[API_CONFIG.fieldMap.shipDate] || 0,
              state_name: item[API_CONFIG.fieldMap.state_name] || "Unknown",
              state: item[API_CONFIG.fieldMap.state] || "Unknown",
            };
          })
          .filter((item) => {
            // Filter out invalid data
            return item.plateNumber || item.name;
          });
      }

      // Update vehicle table
      function updateVehicleTable(data) {
        // Clear table (keep all state rows)
        const rows = vehicleTableBody.querySelectorAll("tr:not(#initialRow):not(#loadingRow):not(#emptyRow):not(#errorRow)");
        rows.forEach((row) => row.remove());

        // Pagination handling
        const startIndex = (currentPage - 1) * pageSize;
        const endIndex = Math.min(startIndex + pageSize, data.length);
        const pageData = data.slice(startIndex, endIndex);

        // Add data rows
        pageData.forEach((item) => {
          const row = document.createElement("tr");
          row.className = "hover:bg-gray-50 transition-colors";

          // Format date
          const shipDate = item.shipDate ? new Date(item.shipDate) : new Date();
          const formattedDate = shipDate.toLocaleDateString("en-US", {
            year: "numeric",
            month: "2-digit",
            day: "2-digit",
          });

          // Handle status styling
          let statusClass = "";
          switch (item.state) {
            case "hasIn":
              statusClass = "text-success";
              break;
            case "notIn":
              statusClass = "text-warning";
              break;
            case "abnormal":
              statusClass = "text-danger";
              break;
            default:
              statusClass = "text-neutral";
          }

          row.innerHTML = `
                    <td class="px-6 py-4 whitespace-nowrap">
                        <div class="text-sm text-gray-900">${item.seq || "-"}</div>
                    </td>
                    <td class="px-6 py-4 whitespace-nowrap">
                        <div class="text-sm text-gray-900 font-medium">${item.plateNumber || "-"}</div>
                    </td>
                    <td class="px-6 py-4 whitespace-nowrap">
                        <div class="text-sm text-gray-900">${item.name || "-"}</div>
                    </td>
                    <td class="px-6 py-4 whitespace-nowrap">
                        <div class="text-sm text-gray-900">${formattedDate}</div>
                    </td>
                    <td class="px-6 py-4 whitespace-nowrap">
                        <span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full ${statusClass}">
                            ${item.state_name}
                        </span>
                    </td>
                    <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
                        <button class="view-detail text-primary hover:text-primary/80 mr-3" data-id="${item.seq}">
                            View
                        </button>
                    </td>
                `;

          vehicleTableBody.appendChild(row);

          // Bind view detail event
          const viewDetailBtn = row.querySelector(".view-detail");
          viewDetailBtn.addEventListener("click", () => {
            showDetailModal(item);
          });
        });
      }

      // Update pagination info
      function updatePaginationInfo() {
        currentPageText.textContent = currentPage;
        totalPagesText.textContent = totalPages;
        totalItemsText.textContent = totalItems;

        // Update pagination button states
        prevPageBtn.disabled = currentPage === 1;
        nextPageBtn.disabled = currentPage === totalPages || totalPages === 0;
        prevPageMobileBtn.disabled = currentPage === 1;
        nextPageMobileBtn.disabled = currentPage === totalPages || totalPages === 0;
      }

      // Update statistics
      function updateStatistics(data) {
        // Total vehicles
        totalVehiclesEl.textContent = data.length;

        // Today's shipments (status is "shipped" and date is today)
        const today = new Date();
        const todayOnly = new Date(today.getFullYear(), today.getMonth(), today.getDate()).getTime();
        const todayShipments = data.filter((item) => {
          if (item.state !== "shipped" || !item.shipDate) return false;
          const shipDateOnly = new Date(new Date(item.shipDate).getFullYear(), new Date(item.shipDate).getMonth(), new Date(item.shipDate).getDate()).getTime();
          return shipDateOnly === todayOnly;
        }).length;
        todayShipmentsEl.textContent = todayShipments;

        // Pending shipments
        const pendingShipments = data.filter((item) => item.status === "pending").length;
        pendingShipmentsEl.textContent = pendingShipments;

        // Abnormal vehicles
        const abnormalVehicles = data.filter((item) => item.status === "abnormal").length;
        abnormalVehiclesEl.textContent = abnormalVehicles;
      }

      // Reset statistics
      function resetStatistics() {
        totalVehiclesEl.textContent = "0";
        todayShipmentsEl.textContent = "0";
        pendingShipmentsEl.textContent = "0";
        abnormalVehiclesEl.textContent = "0";
      }

      // Show detail modal
      function showDetailModal(item) {
        // Format date
        const shipDate = item.shipDate ? new Date(item.shipDate) : new Date();
        const formattedDate = shipDate.toLocaleDateString("en-US", {
          year: "numeric",
          month: "2-digit",
          day: "2-digit",
          hour: "2-digit",
          minute: "2-digit",
        });

        // Handle status styling
        let statusClass = "";
        switch (item.status) {
          case "shipped":
            statusClass = "text-success";
            break;
          case "pending":
            statusClass = "text-warning";
            break;
          case "abnormal":
            statusClass = "text-danger";
            break;
          default:
            statusClass = "text-neutral";
        }

        // Populate data
        detailSeqEl.textContent = item.seq || "-";
        detailPlateNumberEl.textContent = item.plateNumber || "-";
        detailNameEl.textContent = item.name || "-";
        detailShipDateEl.textContent = formattedDate;
        detailStatusEl.textContent = item.state_name;
        detailStatusEl.className = `col-span-2 text-sm font-medium ${statusClass}`;

        // Show modal
        detailModal.classList.remove("hidden");
        // Disable background scrolling
        document.body.style.overflow = "hidden";
      }

      // Close detail modal
      function closeDetailModal() {
        detailModal.classList.add("hidden");
        // Restore background scrolling
        document.body.style.overflow = "";
      }

      // Previous page
      function goToPrevPage() {
        if (currentPage > 1) {
          currentPage--;
          fetchVehicleData();
          // Scroll to table top
          vehicleTableBody.scrollIntoView({ behavior: "smooth", block: "start" });
        }
      }

      // Next page
      function goToNextPage() {
        if (currentPage < totalPages) {
          currentPage++;
          fetchVehicleData();
          // Scroll to table top
          vehicleTableBody.scrollIntoView({ behavior: "smooth", block: "start" });
        }
      }

      // Export to Excel
      function exportToExcel() {
        if (vehicleData.length === 0) {
          alert("No data available to export");
          return;
        }

        // Prepare export data
        const exportData = vehicleData.map((item) => {
          const shipDate = item.shipDate ? new Date(item.shipDate) : new Date();
          const formattedDate = shipDate.toLocaleDateString("en-US", {
            year: "numeric",
            month: "2-digit",
            day: "2-digit",
          });

          return {
            "No.": item.seq || "-",
            "License Plate": item.plateNumber || "-",
            "Driver Name": item.name || "-",
            "Shipping Date": formattedDate,
            "Vehicle Status": item.state_name,
          };
        });

        // Create workbook and worksheet
        const worksheet = XLSX.utils.json_to_sheet(exportData);
        const workbook = XLSX.utils.book_new();
        XLSX.utils.book_append_sheet(workbook, worksheet, "Delivery Vehicles");

        // Set column widths
        const wscols = [
          { wch: 8 }, // No.
          { wch: 12 }, // License Plate
          { wch: 12 }, // Driver Name
          { wch: 16 }, // Shipping Date
          { wch: 12 }, // Vehicle Status
        ];
        worksheet["!cols"] = wscols;

        // Export file
        const today = new Date().toLocaleDateString("en-US").replace(/\//g, "-");
        XLSX.writeFile(workbook, `Delivery_Vehicles_${today}.xlsx`);
      }

      // Hide all state rows
      function hideAllStates() {
        initialRow.classList.add("hidden");
        loadingRow.classList.add("hidden");
        emptyRow.classList.add("hidden");
        errorRow.classList.add("hidden");
      }

      // Show loading state
      function showLoading() {
        loadingRow.classList.remove("hidden");
      }

      // Hide loading state
      function hideLoading() {
        loadingRow.classList.add("hidden");
      }

      // Show empty data state
      function showEmptyState(message = "No delivery vehicle information matching the criteria") {
        emptyRow.querySelector("p").textContent = message;
        emptyRow.classList.remove("hidden");
        paginationContainer.classList.add("hidden");
      }

      // Show error state
      function showErrorState(message = "Data loading failed, please try again later") {
        errorMessage.textContent = message;
        errorRow.classList.remove("hidden");
        paginationContainer.classList.add("hidden");
      }
    </script>
  </body>
</html>