366 lines
17 KiB
HTML
366 lines
17 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>工作人员仪表板 - 车管家4S店车辆维保管理系统</title>
|
|
<link href="/lib/bootstrap.min.css" rel="stylesheet">
|
|
<link href="/lib/bootstrap-icons.css" rel="stylesheet">
|
|
<link rel="stylesheet" href="../css/style.css">
|
|
</head>
|
|
<body>
|
|
<div class="dashboard-wrapper">
|
|
<nav class="sidebar">
|
|
<div class="sidebar-header">
|
|
<i class="bi bi-car-front-fill fs-1 d-block mb-2"></i>
|
|
<h5 class="mb-1">车管家系统</h5>
|
|
<small>工作人员控制台</small>
|
|
</div>
|
|
<div class="mt-4">
|
|
<a class="menu-item active" onclick="showSection('overview')">
|
|
<i class="bi bi-speedometer2"></i>
|
|
<span>工作概览</span>
|
|
</a>
|
|
<a class="menu-item" onclick="showSection('myorders')">
|
|
<i class="bi bi-clipboard-data"></i>
|
|
<span>我的工单</span>
|
|
</a>
|
|
<a class="menu-item" onclick="showSection('search-vehicle')">
|
|
<i class="bi bi-search"></i>
|
|
<span>车辆查询</span>
|
|
</a>
|
|
<a class="menu-item" onclick="showSection('search-parts')">
|
|
<i class="bi bi-box-seam"></i>
|
|
<span>配件查询</span>
|
|
</a>
|
|
</div>
|
|
</nav>
|
|
|
|
<main class="main-content">
|
|
<div class="top-navbar">
|
|
<div class="d-flex align-items-center">
|
|
<h5 class="mb-0 me-3">
|
|
<i class="bi bi-speedometer2"></i> 工作人员仪表板
|
|
</h5>
|
|
</div>
|
|
<div class="d-flex align-items-center gap-3">
|
|
<div class="dropdown">
|
|
<button class="btn btn-outline-light dropdown-toggle" type="button" data-bs-toggle="dropdown">
|
|
<i class="bi bi-person-circle"></i>
|
|
<span id="userName">工作人员</span>
|
|
</button>
|
|
<ul class="dropdown-menu dropdown-menu-end">
|
|
<li><h6 class="dropdown-header">当前角色</h6></li>
|
|
<li><span class="dropdown-item" id="userRole"></span></li>
|
|
<li><hr class="dropdown-divider"></li>
|
|
<li><a class="dropdown-item" href="#" onclick="Utils.logout()">
|
|
<i class="bi bi-box-arrow-right"></i> 退出登录
|
|
</a></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 工作概览 -->
|
|
<div id="overview-section" class="content-section">
|
|
<div class="row g-4 mb-4">
|
|
<div class="col-md-4">
|
|
<div class="stat-card">
|
|
<div class="stat-icon blue">
|
|
<i class="bi bi-clipboard-data-fill"></i>
|
|
</div>
|
|
<div class="stat-value" id="myOrdersCount">0</div>
|
|
<div class="stat-label">我的工单</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="stat-card">
|
|
<div class="stat-icon orange">
|
|
<i class="bi bi-hourglass-split"></i>
|
|
</div>
|
|
<div class="stat-value" id="inProgressCount">0</div>
|
|
<div class="stat-label">进行中</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="stat-card">
|
|
<div class="stat-icon green">
|
|
<i class="bi bi-check-circle-fill"></i>
|
|
</div>
|
|
<div class="stat-value" id="completedCount">0</div>
|
|
<div class="stat-label">已完成</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="content-card">
|
|
<div class="card-header">
|
|
<h6 class="mb-0"><i class="bi bi-clock-history"></i> 待处理工单</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="table-responsive">
|
|
<table class="table table-custom">
|
|
<thead>
|
|
<tr>
|
|
<th>工单编号</th>
|
|
<th>服务类型</th>
|
|
<th>车牌号</th>
|
|
<th>状态</th>
|
|
<th>预约时间</th>
|
|
<th>操作</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="pendingOrdersTableBody">
|
|
<tr>
|
|
<td colspan="6" class="text-center text-muted py-4">
|
|
<div class="spinner-border spinner-border-sm me-2"></div>
|
|
加载中...
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 我的工单 -->
|
|
<div id="myorders-section" class="content-section" style="display: none;">
|
|
<div class="content-card">
|
|
<div class="card-header">
|
|
<h6 class="mb-0"><i class="bi bi-clipboard-data"></i> 我的工单列表</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="table-responsive">
|
|
<table class="table table-custom">
|
|
<thead>
|
|
<tr>
|
|
<th>工单编号</th>
|
|
<th>服务类型</th>
|
|
<th>车牌号</th>
|
|
<th>客户姓名</th>
|
|
<th>状态</th>
|
|
<th>创建时间</th>
|
|
<th>操作</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="myOrdersTableBody">
|
|
<tr>
|
|
<td colspan="7" class="text-center text-muted py-4">加载中...</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 车辆查询 -->
|
|
<div id="search-vehicle-section" class="content-section" style="display: none;">
|
|
<div class="content-card">
|
|
<div class="card-header">
|
|
<h6 class="mb-0"><i class="bi bi-search"></i> 车辆信息查询</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="mb-4">
|
|
<div class="input-group">
|
|
<span class="input-group-text"><i class="bi bi-car-front"></i></span>
|
|
<input type="text" class="form-control" id="searchVehiclePlate" placeholder="请输入车牌号查询...">
|
|
<button class="btn btn-primary" onclick="searchVehicle()">
|
|
<i class="bi bi-search"></i> 查询
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div id="vehicleSearchResult">
|
|
<div class="empty-state">
|
|
<i class="bi bi-car-front"></i>
|
|
<p>请输入车牌号进行查询</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 配件查询 -->
|
|
<div id="search-parts-section" class="content-section" style="display: none;">
|
|
<div class="content-card">
|
|
<div class="card-header">
|
|
<h6 class="mb-0"><i class="bi bi-box-seam"></i> 配件库存查询</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="mb-4">
|
|
<div class="input-group">
|
|
<span class="input-group-text"><i class="bi bi-search"></i></span>
|
|
<input type="text" class="form-control" id="searchPartKeyword" placeholder="请输入配件名称或编号...">
|
|
<button class="btn btn-primary" onclick="searchParts()">
|
|
<i class="bi bi-search"></i> 搜索
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div id="partsSearchResult">
|
|
<div class="empty-state">
|
|
<i class="bi bi-box-seam"></i>
|
|
<p>请输入关键词搜索配件</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
|
|
<!-- Toast 通知 -->
|
|
<div class="toast-container position-fixed top-0 end-0 p-3">
|
|
<div id="liveToast" class="toast" role="alert">
|
|
<div class="toast-header">
|
|
<i class="bi bi-bell me-2" id="toastIcon"></i>
|
|
<strong class="me-auto" id="toastTitle">提示</strong>
|
|
<button type="button" class="btn-close" data-bs-dismiss="toast"></button>
|
|
</div>
|
|
<div class="toast-body" id="toastMessage"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Loading 遮罩 -->
|
|
<div id="loadingOverlay" class="loading-overlay d-none">
|
|
<div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;">
|
|
<span class="visually-hidden">Loading...</span>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="/lib/bootstrap.bundle.min.js"></script>
|
|
<script src="../js/config.js"></script>
|
|
<script src="../js/api.js"></script>
|
|
<script>
|
|
// 车辆查询
|
|
async function searchVehicle() {
|
|
const plate = document.getElementById('searchVehiclePlate').value.trim();
|
|
if (!plate) {
|
|
Utils.showToast('请输入车牌号', 'warning');
|
|
return;
|
|
}
|
|
|
|
Utils.loading(true);
|
|
try {
|
|
const response = await http.get(API.VEHICLE_PLATE(plate));
|
|
const resultDiv = document.getElementById('vehicleSearchResult');
|
|
|
|
if (response.code === 200 && response.data) {
|
|
const v = response.data;
|
|
resultDiv.innerHTML = `
|
|
<div class="card border-primary mb-3">
|
|
<div class="card-header bg-primary text-white">
|
|
<i class="bi bi-car-front"></i> 车辆信息
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<p class="mb-2"><strong>车牌号:</strong> <span class="badge bg-primary fs-6">${v.licensePlate}</span></p>
|
|
<p class="mb-2"><strong>品牌型号:</strong> ${v.brand} ${v.model}</p>
|
|
<p class="mb-2"><strong>颜色:</strong> ${v.color || '-'}</p>
|
|
<p class="mb-2"><strong>车架号:</strong> ${v.vin || '-'}</p>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<p class="mb-2"><strong>当前里程:</strong> ${v.mileage || 0} 公里</p>
|
|
<p class="mb-2"><strong>上次保养:</strong> ${Utils.formatDate(v.lastMaintenanceDate)}</p>
|
|
<p class="mb-2"><strong>下次保养:</strong> ${Utils.formatDate(v.nextMaintenanceDate)}</p>
|
|
<p class="mb-0"><strong>车辆状态:</strong> ${Utils.getStatusBadge(v.status)}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
} else {
|
|
resultDiv.innerHTML = `
|
|
<div class="alert alert-warning">
|
|
<i class="bi bi-exclamation-triangle"></i> 未找到该车辆
|
|
</div>
|
|
`;
|
|
}
|
|
} catch (error) {
|
|
console.error('查询失败:', error);
|
|
Utils.showToast('查询失败', 'error');
|
|
} finally {
|
|
Utils.loading(false);
|
|
}
|
|
}
|
|
|
|
// 配件搜索
|
|
async function searchParts() {
|
|
const keyword = document.getElementById('searchPartKeyword').value.trim();
|
|
if (!keyword) {
|
|
Utils.showToast('请输入搜索关键词', 'warning');
|
|
return;
|
|
}
|
|
|
|
Utils.loading(true);
|
|
try {
|
|
const response = await http.get(API.PARTS);
|
|
const resultDiv = document.getElementById('partsSearchResult');
|
|
|
|
if (response.code === 200 && response.data) {
|
|
const filtered = response.data.filter(p =>
|
|
p.partName.toLowerCase().includes(keyword.toLowerCase()) ||
|
|
p.partNo.toLowerCase().includes(keyword.toLowerCase())
|
|
);
|
|
|
|
if (filtered.length === 0) {
|
|
resultDiv.innerHTML = `
|
|
<div class="alert alert-info">
|
|
<i class="bi bi-info-circle"></i> 未找到匹配的配件
|
|
</div>
|
|
`;
|
|
return;
|
|
}
|
|
|
|
resultDiv.innerHTML = `
|
|
<div class="table-responsive">
|
|
<table class="table table-custom">
|
|
<thead>
|
|
<tr>
|
|
<th>配件编号</th>
|
|
<th>配件名称</th>
|
|
<th>类别</th>
|
|
<th>库存数量</th>
|
|
<th>单价</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
${filtered.map(p => `
|
|
<tr>
|
|
<td>${p.partNo}</td>
|
|
<td>${p.partName}</td>
|
|
<td>${p.category || '-'}</td>
|
|
<td>
|
|
${p.stockQuantity} ${p.unit}
|
|
${p.stockQuantity <= p.minStock ? '<span class="badge bg-danger ms-2">库存预警</span>' : ''}
|
|
</td>
|
|
<td>${Utils.formatMoney(p.unitPrice)}</td>
|
|
</tr>
|
|
`).join('')}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
`;
|
|
}
|
|
} catch (error) {
|
|
console.error('搜索失败:', error);
|
|
Utils.showToast('搜索失败', 'error');
|
|
} finally {
|
|
Utils.loading(false);
|
|
}
|
|
}
|
|
|
|
// 回车搜索
|
|
document.getElementById('searchVehiclePlate')?.addEventListener('keypress', function(e) {
|
|
if (e.key === 'Enter') searchVehicle();
|
|
});
|
|
|
|
document.getElementById('searchPartKeyword')?.addEventListener('keypress', function(e) {
|
|
if (e.key === 'Enter') searchParts();
|
|
});
|
|
</script>
|
|
<script src="../js/app.js"></script>
|
|
</body>
|
|
</html>
|