Appearance
网站服务典型场景
发货车辆信息登记列表

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>发货车辆信息登记列表</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', // 主色调:深蓝色(代表专业、可靠)
secondary: '#3B82F6', // 辅助色:浅蓝色
success: '#10B981', // 成功色:绿色
warning: '#F59E0B', // 警告色:黄色
danger: '#EF4444', // 危险色:红色
neutral: '#6B7280', // 中性色:灰色
},
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">
<!-- 页面头部 -->
<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">发货车辆信息登记列表</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>刷新数据</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>导出Excel</span>
</button>
</div>
</div>
</header>
<!-- 筛选区域 -->
<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">
<!-- 车牌号筛选 -->
<div>
<label for="plateNumber" class="block text-sm font-medium text-gray-700 mb-1">车牌号</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="请输入车牌号(可选)"
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">请输入有效车牌号</p>
</div>
</div>
<!-- 发货日期筛选 -->
<div>
<label for="shipDateRange" class="block text-sm font-medium text-gray-700 mb-1">发货日期范围</label>
<div class="flex space-x-2">
<input type="date" id="startDate" placeholder="开始日期"
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">至</span>
<input type="date" id="endDate" placeholder="结束日期"
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">结束日期不能早于开始日期</p>
</div>
</div>
<!-- 筛选按钮 -->
<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>筛选</span>
</button>
</div>
</div>
</div>
</section>
<!-- 数据统计概览 -->
<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">
<!-- 总车辆数 -->
<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">总车辆数</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">截至当前统计</p>
</div>
<!-- 今日发货数 -->
<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">今日发货数</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">今日新增</p>
</div>
<!-- 待发货数 -->
<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">待发货数</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">待处理订单</p>
</div>
<!-- 异常车辆数 -->
<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">异常车辆数</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">需人工处理</p>
</div>
</div>
</section>
<!-- 列表展示区域 -->
<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">序号</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">车牌号</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">司机姓名</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">发货日期</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">车辆状态</th>
<th scope="col" class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">操作</th>
</tr>
</thead>
<tbody id="vehicleTableBody" class="bg-white divide-y divide-gray-200">
<!-- 初始状态:请筛选数据 -->
<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">请填写筛选条件后点击筛选按钮查询数据</p>
</div>
</td>
</tr>
<!-- 数据加载中 -->
<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">正在加载数据...</p>
</div>
</td>
</tr>
<!-- 无数据提示 -->
<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">暂无符合条件的发货车辆信息</p>
</div>
</td>
</tr>
<!-- 接口错误提示 -->
<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">数据加载失败</p>
<button id="retryBtn" class="px-4 py-2 bg-secondary text-white rounded-md hover:bg-secondary/90 transition-colors">
重试
</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- 分页控件 -->
<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>
上一页
</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>
下一页
</button>
</div>
<div class="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
<div>
<p class="text-sm text-gray-700">
显示第 <span id="currentPageText">1</span> 页,共 <span id="totalPagesText">0</span> 页,总计 <span id="totalItemsText">0</span> 条记录
</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">上一页</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">下一页</span>
<i class="fa fa-chevron-right h-5 w-5"></i>
</button>
</nav>
</div>
</div>
</div>
</div>
</section>
<!-- 查看详情弹窗 -->
<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">车辆发货详情</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">序号</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">车牌号</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">司机姓名</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">发货日期</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">车辆状态</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">
关闭
</button>
</div>
</div>
</div>
<!-- 页脚 -->
<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 发货车辆管理系统 版权所有</p>
<div class="flex space-x-4">
<a href="#" class="text-sm text-gray-500 hover:text-primary transition-colors">帮助中心</a>
<a href="#" class="text-sm text-gray-500 hover:text-primary transition-colors">联系我们</a>
<a href="#" class="text-sm text-gray-500 hover:text-primary transition-colors">系统说明</a>
</div>
</div>
</div>
</footer>
<script>
// 全局变量
let vehicleData = []; // 车辆数据列表
let currentPage = 1; // 当前页码
let pageSize = 10; // 每页条数
let totalItems = 0; // 总记录数
let totalPages = 0; // 总页数
// 接口配置参数(请根据实际情况修改tableId和apiKey)
const API_CONFIG = {
url: 'https://next.informat.cn/web0/webapi/table_record_list',
apiKey: 'ojw76e1htyb2p3e37gcay', // 示例apiKey,实际请使用真实密钥
tableId: 'shipPlan', // 示例tableId,实际请使用发货车辆数据表的标识符
// 字段映射:确保与数据表中的字段ID一致
fieldMap: {
seq: 'seq', // 序号字段ID
plateNumber: 'plateNumber', // 车牌号字段ID
name: 'name', // 司机姓名字段ID
shipDate: 'shipDate', // 发货日期字段ID
state: 'state',
state_name: 'state_name' // 车辆状态字段ID
}
};
// DOM元素
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');
// 初始化页面
document.addEventListener('DOMContentLoaded', () => {
// 绑定事件
bindEvents();
fetchVehicleData();
});
// 绑定事件
function bindEvents() {
// 刷新按钮
refreshBtn.addEventListener('click', () => {
// 重置筛选条件
plateNumberInput.value = '';
startDateInput.value = '';
endDateInput.value = '';
// 隐藏其他状态,显示初始状态
hideAllStates();
initialRow.classList.remove('hidden');
paginationContainer.classList.add('hidden');
// 重置统计数据
resetStatistics();
});
// 导出按钮
exportBtn.addEventListener('click', exportToExcel);
// 搜索按钮
searchBtn.addEventListener('click', () => {
currentPage = 1; // 重置到第一页
// 先校验筛选条件
if (validateFilterConditions()) {
fetchVehicleData();
}
});
// 车牌号输入框事件:输入时清除错误提示
plateNumberInput.addEventListener('input', () => {
plateNumberInput.classList.remove('input-error');
plateNumberError.style.display = 'none';
});
// 日期输入框事件:输入时清除错误提示
startDateInput.addEventListener('input', () => {
dateRangeError.style.display = 'none';
});
endDateInput.addEventListener('input', () => {
dateRangeError.style.display = 'none';
});
// 分页按钮
prevPageBtn.addEventListener('click', goToPrevPage);
nextPageBtn.addEventListener('click', goToNextPage);
prevPageMobileBtn.addEventListener('click', goToPrevPage);
nextPageMobileBtn.addEventListener('click', goToNextPage);
// 详情弹窗关闭按钮
closeModalBtn.addEventListener('click', closeDetailModal);
closeDetailBtn.addEventListener('click', closeDetailModal);
// 点击弹窗外部关闭
detailModal.addEventListener('click', (e) => {
if (e.target === detailModal) {
closeDetailModal();
}
});
// 重试按钮
retryBtn.addEventListener('click', () => {
if (validateFilterConditions()) {
fetchVehicleData();
}
});
}
// 校验筛选条件
function validateFilterConditions() {
let isValid = true;
// 车牌号校验(可选,若填写则校验格式)
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;
}
// 日期范围校验(若都填写则结束日期不能早于开始日期)
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;
}
// 构建接口请求参数
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' // 按发货日期降序排列
}
]
};
// 车牌号筛选(模糊查询)
const plateNumber = plateNumberInput.value.trim();
if (plateNumber) {
params.filter.conditionList.push({
fieldId: API_CONFIG.fieldMap.plateNumber,
opt: 'eq',
value: `${plateNumber}`
});
}
// 发货日期范围筛选
const startDate = startDateInput.value;
const endDate = endDateInput.value;
if (startDate ) {
// 转换为时间戳(毫秒)
const startTimestamp = new Date(startDate).getTime();
// 大于等于开始时间
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);
// 小于等于结束时间
params.filter.conditionList.push({
fieldId: API_CONFIG.fieldMap.shipDate,
opt: 'le',
value: endTimestamp
});
}
return params;
}
// 从真实接口获取车辆数据
async function fetchVehicleData() {
// const plateNumber = plateNumberInput.value.trim();
// // 校验车牌号是否为空
// if (!plateNumber) {
// plateNumberInput.classList.add('input-error');
// plateNumberError.style.display = 'block';
// // 滚动到错误位置(移动端友好)
// plateNumberInput.scrollIntoView({ behavior: 'smooth', block: 'center' });
// return;
// }
// 隐藏所有状态行
hideAllStates();
// 显示加载状态
showLoading();
try {
// 构建请求参数
const requestParams = buildRequestParams();
// 发送POST请求
const response = await fetch(API_CONFIG.url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify(requestParams)
});
// 检查响应状态
if (!response.ok) {
throw new Error(`接口请求失败:${response.status} ${response.statusText}`);
}
// 解析响应数据
const result = await response.json();
// 检查接口返回状态
if (result.code !== 0) {
throw new Error(`接口返回错误:${result.message || '未知错误'}`);
}
// 处理数据(适配接口返回格式)
const { recordList = [], count = 0 } = result.data || {};
vehicleData = formatVehicleData(recordList);
totalItems = count;
totalPages = Math.ceil(totalItems / pageSize);
// 更新表格
updateVehicleTable(vehicleData);
// 更新分页信息
updatePaginationInfo();
// 更新统计信息
updateStatistics(vehicleData);
// 隐藏加载状态
hideLoading();
// 显示空数据提示(如果需要)
if (vehicleData.length === 0) {
showEmptyState();
} else {
// 显示分页控件
paginationContainer.classList.remove('hidden');
}
} catch (error) {
console.error('获取车辆数据失败:', error);
hideLoading();
showErrorState(error.message);
}
}
// 格式化车辆数据(适配页面展示)
function formatVehicleData(rawData) {
return rawData.map(item => {
// 映射字段,确保字段名统一
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] || '未知',
state: item[API_CONFIG.fieldMap.state] || '未知'
};
}).filter(item => {
// 过滤无效数据
return item.plateNumber || item.name;
});
}
// 更新车辆表格
function updateVehicleTable(data) {
// 清空表格(保留所有状态行)
const rows = vehicleTableBody.querySelectorAll('tr:not(#initialRow):not(#loadingRow):not(#emptyRow):not(#errorRow)');
rows.forEach(row => row.remove());
// 分页处理
const startIndex = (currentPage - 1) * pageSize;
const endIndex = Math.min(startIndex + pageSize, data.length);
const pageData = data.slice(startIndex, endIndex);
// 添加数据行
pageData.forEach(item => {
const row = document.createElement('tr');
row.className = 'hover:bg-gray-50 transition-colors';
// 处理日期格式
const shipDate = item.shipDate ? new Date(item.shipDate) : new Date();
const formattedDate = shipDate.toLocaleDateString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit'
});
// 处理状态样式
let statusClass = '';
switch (item.state) {
case 'hasIn':
statusClass = 'text-success';
break;
case 'notIn':
statusClass = 'text-warning';
break;
case '异常':
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}">
查看
</button>
</td>
`;
vehicleTableBody.appendChild(row);
// 绑定查看详情事件
const viewDetailBtn = row.querySelector('.view-detail');
viewDetailBtn.addEventListener('click', () => {
showDetailModal(item);
});
});
}
// 更新分页信息
function updatePaginationInfo() {
currentPageText.textContent = currentPage;
totalPagesText.textContent = totalPages;
totalItemsText.textContent = totalItems;
// 更新分页按钮状态
prevPageBtn.disabled = currentPage === 1;
nextPageBtn.disabled = currentPage === totalPages || totalPages === 0;
prevPageMobileBtn.disabled = currentPage === 1;
nextPageMobileBtn.disabled = currentPage === totalPages || totalPages === 0;
}
// 更新统计信息
function updateStatistics(data) {
// 总车辆数
totalVehiclesEl.textContent = data.length;
// 今日发货数(状态为已发货且日期为今日)
const today = new Date();
const todayOnly = new Date(today.getFullYear(), today.getMonth(), today.getDate()).getTime();
const todayShipments = data.filter(item => {
if (item.state !== '已发货' || !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;
// 待发货数
const pendingShipments = data.filter(item => item.status === '待发货').length;
pendingShipmentsEl.textContent = pendingShipments;
// 异常车辆数
const abnormalVehicles = data.filter(item => item.status === '异常').length;
abnormalVehiclesEl.textContent = abnormalVehicles;
}
// 重置统计信息
function resetStatistics() {
totalVehiclesEl.textContent = '0';
todayShipmentsEl.textContent = '0';
pendingShipmentsEl.textContent = '0';
abnormalVehiclesEl.textContent = '0';
}
// 显示详情弹窗
function showDetailModal(item) {
// 处理日期格式
const shipDate = item.shipDate ? new Date(item.shipDate) : new Date();
const formattedDate = shipDate.toLocaleDateString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
});
// 处理状态样式
let statusClass = '';
switch (item.status) {
case '已发货':
statusClass = 'text-success';
break;
case '待发货':
statusClass = 'text-warning';
break;
case '异常':
statusClass = 'text-danger';
break;
default:
statusClass = 'text-neutral';
}
// 填充数据
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}`;
// 显示弹窗
detailModal.classList.remove('hidden');
// 禁止背景滚动
document.body.style.overflow = 'hidden';
}
// 关闭详情弹窗
function closeDetailModal() {
detailModal.classList.add('hidden');
// 恢复背景滚动
document.body.style.overflow = '';
}
// 上一页
function goToPrevPage() {
if (currentPage > 1) {
currentPage--;
fetchVehicleData();
// 滚动到表格顶部
vehicleTableBody.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}
// 下一页
function goToNextPage() {
if (currentPage < totalPages) {
currentPage++;
fetchVehicleData();
// 滚动到表格顶部
vehicleTableBody.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}
// 导出Excel
function exportToExcel() {
if (vehicleData.length === 0) {
alert('暂无数据可导出');
return;
}
// 准备导出数据
const exportData = vehicleData.map(item => {
const shipDate = item.shipDate ? new Date(item.shipDate) : new Date();
const formattedDate = shipDate.toLocaleDateString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit'
});
return {
'序号': item.seq || '-',
'车牌号': item.plateNumber || '-',
'司机姓名': item.name || '-',
'发货日期': formattedDate,
'车辆状态': item.state_name
};
});
// 创建工作簿和工作表
const worksheet = XLSX.utils.json_to_sheet(exportData);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, '发货车辆信息');
// 设置列宽
const wscols = [
{wch: 8}, // 序号
{wch: 12}, // 车牌号
{wch: 12}, // 司机姓名
{wch: 16}, // 发货日期
{wch: 12} // 发货状态
];
worksheet['!cols'] = wscols;
// 导出文件
const today = new Date().toLocaleDateString('zh-CN').replace(/\//g, '-');
XLSX.writeFile(workbook, `发货车辆信息_${today}.xlsx`);
}
// 隐藏所有状态行
function hideAllStates() {
initialRow.classList.add('hidden');
loadingRow.classList.add('hidden');
emptyRow.classList.add('hidden');
errorRow.classList.add('hidden');
}
// 显示加载状态
function showLoading() {
loadingRow.classList.remove('hidden');
}
// 隐藏加载状态
function hideLoading() {
loadingRow.classList.add('hidden');
}
// 显示空数据状态
function showEmptyState(message = '暂无符合条件的发货车辆信息') {
emptyRow.querySelector('p').textContent = message;
emptyRow.classList.remove('hidden');
paginationContainer.classList.add('hidden');
}
// 显示错误状态
function showErrorState(message = '数据加载失败,请稍后重试') {
errorMessage.textContent = message;
errorRow.classList.remove('hidden');
paginationContainer.classList.add('hidden');
}
</script>
</body>
</html>
