This commit is contained in:
wangziqi
2026-01-07 16:18:56 +08:00
parent 7c4be0b7b4
commit ea9c94dfeb
13 changed files with 2243 additions and 148 deletions

View File

@@ -4,8 +4,8 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>管理员仪表板 - 车管家4S店车辆维保管理系统</title> <title>管理员仪表板 - 车管家4S店车辆维保管理系统</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <link href="/lib/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css" rel="stylesheet"> <link href="/lib/bootstrap-icons.css" rel="stylesheet">
<link rel="stylesheet" href="../css/style.css"> <link rel="stylesheet" href="../css/style.css">
</head> </head>
<body> <body>
@@ -56,7 +56,7 @@
</div> </div>
<div class="d-flex align-items-center gap-3"> <div class="d-flex align-items-center gap-3">
<div class="dropdown"> <div class="dropdown">
<button class="btn btn-outline-light dropdown-toggle" type="button" data-bs-toggle="dropdown"> <button class="btn btn-outline-light dropdown-toggle" style="color: black;" type="button" data-bs-toggle="dropdown">
<i class="bi bi-person-circle"></i> <i class="bi bi-person-circle"></i>
<span id="userName">管理员</span> <span id="userName">管理员</span>
</button> </button>
@@ -508,10 +508,10 @@
</div> </div>
</div> </div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> <script src="/lib/bootstrap.bundle.min.js"></script>
<script src="../js/config.js"></script> <script src="../js/config.js"></script>
<script src="../js/api.js"></script> <script src="../js/api.js"></script>
<script src="../js/admin.js"></script>
<script src="../js/app.js"></script> <script src="../js/app.js"></script>
<script src="../js/admin.js"></script>
</body> </body>
</html> </html>

View File

@@ -227,8 +227,7 @@ body {
/* 模态框 */ /* 模态框 */
.modal-header { .modal-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: black;
color: #fff;
border-radius: 10px 10px 0 0; border-radius: 10px 10px 0 0;
} }

View File

@@ -4,8 +4,8 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>客户中心 - 车管家4S店车辆维保管理系统</title> <title>客户中心 - 车管家4S店车辆维保管理系统</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <link href="/lib/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css" rel="stylesheet"> <link href="/lib/bootstrap-icons.css" rel="stylesheet">
<link rel="stylesheet" href="../css/style.css"> <link rel="stylesheet" href="../css/style.css">
</head> </head>
<body> <body>
@@ -231,7 +231,7 @@
</div> </div>
</div> </div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> <script src="/lib/bootstrap.bundle.min.js"></script>
<script src="../js/config.js"></script> <script src="../js/config.js"></script>
<script src="../js/api.js"></script> <script src="../js/api.js"></script>
<script src="../js/app.js"></script> <script src="../js/app.js"></script>

View File

@@ -6,6 +6,112 @@ let allVehiclesData = [];
let allOrdersData = []; let allOrdersData = [];
let allPartsData = []; let allPartsData = [];
// ==================== 函数覆盖 ====================
// 立即覆盖app.js中的显示函数不等待DOMContentLoaded
// 覆盖displayAllUsers
const originalDisplayAllUsers = (typeof displayAllUsers !== 'undefined') ? displayAllUsers : function() {};
displayAllUsers = function(users) {
allUsersData = users || [];
const tbody = document.getElementById('allUsersTableBody');
if (!tbody) {
// 如果不是管理员页面,调用原始函数
return originalDisplayAllUsers(users);
}
if (users.length === 0) {
tbody.innerHTML = '<tr><td colspan="7" class="text-center text-muted py-4">暂无数据</td></tr>';
return;
}
tbody.innerHTML = users.map(u => `
<tr>
<td>${u.userId}</td>
<td>${u.username}</td>
<td>${u.realName}</td>
<td>${u.phone}</td>
<td>${Utils.getRoleText(u.role)}</td>
<td>${u.status === 1 ? '<span class="badge bg-success">启用</span>' : '<span class="badge bg-secondary">禁用</span>'}</td>
<td>
<button class="btn btn-sm btn-info" onclick="viewUser(${u.userId})">查看</button>
<button class="btn btn-sm btn-warning" onclick="editUser(${u.userId})">编辑</button>
<button class="btn btn-sm btn-danger" onclick="deleteUser(${u.userId})">删除</button>
</td>
</tr>
`).join('');
};
// 覆盖displayAllVehicles
const originalDisplayAllVehicles = (typeof displayAllVehicles !== 'undefined') ? displayAllVehicles : function() {};
displayAllVehicles = function(vehicles) {
allVehiclesData = vehicles || [];
const tbody = document.getElementById('allVehiclesTableBody');
if (!tbody) {
// 如果不是管理员页面,调用原始函数
return originalDisplayAllVehicles(vehicles);
}
if (vehicles.length === 0) {
tbody.innerHTML = '<tr><td colspan="6" class="text-center text-muted py-4">暂无数据</td></tr>';
return;
}
tbody.innerHTML = vehicles.map(v => `
<tr>
<td>${v.licensePlate}</td>
<td>${v.brand} ${v.model}</td>
<td>${v.color || '-'}</td>
<td>${v.mileage || 0}</td>
<td>${Utils.getStatusBadge(v.status)}</td>
<td>
<button class="btn btn-sm btn-info" onclick="viewVehicle(${v.vehicleId})">查看</button>
<button class="btn btn-sm btn-warning" onclick="editVehicle(${v.vehicleId})">编辑</button>
<button class="btn btn-sm btn-danger" onclick="deleteVehicle(${v.vehicleId})">删除</button>
</td>
</tr>
`).join('');
};
// 覆盖displayAllOrders
const originalDisplayAllOrders = (typeof displayAllOrders !== 'undefined') ? displayAllOrders : function() {};
displayAllOrders = async function(orders) {
allOrdersData = orders || [];
const tbody = document.getElementById('allOrdersTableBody');
if (!tbody) {
// 如果不是管理员页面,调用原始函数
return await originalDisplayAllOrders(orders);
}
if (orders.length === 0) {
tbody.innerHTML = '<tr><td colspan="8" class="text-center text-muted py-4">暂无数据</td></tr>';
return;
}
// 获取所有车辆信息
const vehiclesRes = await http.get(API.VEHICLES);
const vehicles = vehiclesRes.data || [];
tbody.innerHTML = orders.map(o => {
const vehicle = vehicles.find(v => v.vehicleId === o.vehicleId);
return `
<tr>
<td>${o.orderNo}</td>
<td>${Utils.getServiceTypeText(o.serviceType)}</td>
<td>${vehicle ? vehicle.licensePlate : '-'}</td>
<td>${Utils.formatMoney(o.totalCost)}</td>
<td>${Utils.getStatusBadge(o.status)}</td>
<td>${Utils.getStatusBadge(o.paymentStatus, 'payment')}</td>
<td>${Utils.formatDateTime(o.createTime)}</td>
<td>
<button class="btn btn-sm btn-info" onclick="viewOrder(${o.orderId})">查看</button>
<button class="btn btn-sm btn-warning" onclick="editOrder(${o.orderId})">编辑</button>
<button class="btn btn-sm btn-danger" onclick="deleteOrder(${o.orderId})">删除</button>
</td>
</tr>
`;
}).join('');
};
// ==================== 用户管理 ==================== // ==================== 用户管理 ====================
// 查看用户详情 // 查看用户详情
@@ -434,12 +540,51 @@ function showAddPartModal() {
// 加载所有数据 // 加载所有数据
async function loadAllData() { async function loadAllData() {
await Promise.all([ console.log('开始加载所有数据...');
loadAllUsers(), Utils.loading(true);
loadAllVehicles(), try {
loadAllOrders(), // 并行加载所有数据
loadAllParts() const [usersRes, vehiclesRes, ordersRes, partsRes] = await Promise.all([
http.get(API.USERS),
http.get(API.VEHICLES),
http.get(API.ORDERS),
http.get(API.PARTS)
]); ]);
// 显示用户数据
if (usersRes.code === 200) {
allUsersData = usersRes.data || [];
displayAllUsers(allUsersData);
}
// 显示车辆数据
if (vehiclesRes.code === 200) {
allVehiclesData = vehiclesRes.data || [];
displayAllVehicles(allVehiclesData);
}
// 显示工单数据
if (ordersRes.code === 200) {
allOrdersData = ordersRes.data || [];
await displayAllOrders(allOrdersData);
}
// 显示配件数据
if (partsRes.code === 200) {
allPartsData = partsRes.data || [];
displayAllParts(allPartsData);
}
// 加载预约数据
await loadAppointments();
console.log('所有数据加载完成');
} catch (error) {
console.error('加载数据失败:', error);
Utils.showToast('加载数据失败', 'error');
} finally {
Utils.loading(false);
}
} }
// 加载所有配件 // 加载所有配件
@@ -507,101 +652,7 @@ async function deletePart(id) {
} }
} }
// ==================== 页面初始化 ==================== // ==================== 预约管理 ====================
// 重写displayAllUsers以存储数据
const originalDisplayAllUsers = displayAllUsers;
displayAllUsers = function(users) {
allUsersData = users || [];
const tbody = document.getElementById('allUsersTableBody');
if (!tbody) return;
if (users.length === 0) {
tbody.innerHTML = '<tr><td colspan="7" class="text-center text-muted py-4">暂无数据</td></tr>';
return;
}
tbody.innerHTML = users.map(u => `
<tr>
<td>${u.userId}</td>
<td>${u.username}</td>
<td>${u.realName}</td>
<td>${u.phone}</td>
<td>${Utils.getRoleText(u.role)}</td>
<td>${u.status === 1 ? '<span class="badge bg-success">启用</span>' : '<span class="badge bg-secondary">禁用</span>'}</td>
<td>
<button class="btn btn-sm btn-info" onclick="viewUser(${u.userId})">查看</button>
<button class="btn btn-sm btn-warning" onclick="editUser(${u.userId})">编辑</button>
<button class="btn btn-sm btn-danger" onclick="deleteUser(${u.userId})">删除</button>
</td>
</tr>
`).join('');
};
// 重写displayAllVehicles以存储数据
const originalDisplayAllVehicles = displayAllVehicles;
displayAllVehicles = function(vehicles) {
allVehiclesData = vehicles || [];
const tbody = document.getElementById('allVehiclesTableBody');
if (!tbody) return;
if (vehicles.length === 0) {
tbody.innerHTML = '<tr><td colspan="6" class="text-center text-muted py-4">暂无数据</td></tr>';
return;
}
tbody.innerHTML = vehicles.map(v => `
<tr>
<td>${v.licensePlate}</td>
<td>${v.brand} ${v.model}</td>
<td>${v.color || '-'}</td>
<td>${v.mileage || 0}</td>
<td>${Utils.getStatusBadge(v.status)}</td>
<td>
<button class="btn btn-sm btn-info" onclick="viewVehicle(${v.vehicleId})">查看</button>
<button class="btn btn-sm btn-warning" onclick="editVehicle(${v.vehicleId})">编辑</button>
<button class="btn btn-sm btn-danger" onclick="deleteVehicle(${v.vehicleId})">删除</button>
</td>
</tr>
`).join('');
};
// 重写displayAllOrders以存储数据
const originalDisplayAllOrders = displayAllOrders;
displayAllOrders = async function(orders) {
allOrdersData = orders || [];
const tbody = document.getElementById('allOrdersTableBody');
if (!tbody) return;
if (orders.length === 0) {
tbody.innerHTML = '<tr><td colspan="8" class="text-center text-muted py-4">暂无数据</td></tr>';
return;
}
// 获取所有车辆信息
const vehiclesRes = await http.get(API.VEHICLES);
const vehicles = vehiclesRes.data || [];
tbody.innerHTML = orders.map(o => {
const vehicle = vehicles.find(v => v.vehicleId === o.vehicleId);
return `
<tr>
<td>${o.orderNo}</td>
<td>${Utils.getServiceTypeText(o.serviceType)}</td>
<td>${vehicle ? vehicle.licensePlate : '-'}</td>
<td>${Utils.formatMoney(o.totalCost)}</td>
<td>${Utils.getStatusBadge(o.status)}</td>
<td>${Utils.getStatusBadge(o.paymentStatus, 'payment')}</td>
<td>${Utils.formatDateTime(o.createTime)}</td>
<td>
<button class="btn btn-sm btn-info" onclick="viewOrder(${o.orderId})">查看</button>
<button class="btn btn-sm btn-warning" onclick="editOrder(${o.orderId})">编辑</button>
<button class="btn btn-sm btn-danger" onclick="deleteOrder(${o.orderId})">删除</button>
</td>
</tr>
`;
}).join('');
};
// 加载预约数据 // 加载预约数据
async function loadAppointments() { async function loadAppointments() {
@@ -692,8 +743,11 @@ async function cancelAppointmentAdmin(id) {
// 页面加载完成后初始化 // 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
// 如果是管理员页面,加载所有数据 // 如果是管理员页面,等待一小段时间确保所有脚本加载完成
if (window.location.pathname.includes('admin')) { if (window.location.pathname.includes('admin')) {
console.log('检测到管理员页面,准备加载数据');
setTimeout(() => {
loadAllData(); loadAllData();
}, 100);
} }
}); });

View File

@@ -185,7 +185,7 @@ const Utils = {
if (this.confirm('确定要退出登录吗?')) { if (this.confirm('确定要退出登录吗?')) {
localStorage.removeItem(STORAGE.TOKEN); localStorage.removeItem(STORAGE.TOKEN);
localStorage.removeItem(STORAGE.USER); localStorage.removeItem(STORAGE.USER);
window.location.href = 'login.html'; window.location.href = '/login.html';
} }
}, },
@@ -238,9 +238,9 @@ const Utils = {
// 获取角色文本 // 获取角色文本
getRoleText(role) { getRoleText(role) {
const roles = { const roles = {
admin: '<span class="badge bg-danger">管理员</span>', admin: '管理员',
staff: '<span class="badge bg-success">工作人员</span>', staff: '工作人员',
customer: '<span class="badge bg-info">客户</span>' customer: '客户'
}; };
return roles[role] || role; return roles[role] || role;
}, },

View File

@@ -558,21 +558,31 @@ function showSection(sectionId) {
case 'users': case 'users':
loadAllUsers(); loadAllUsers();
break; break;
case 'parts':
if (typeof loadAllParts === 'function') {
loadAllParts();
}
break;
case 'appointments':
if (typeof loadAppointments === 'function') {
loadAppointments();
}
break;
} }
} }
// 加载所有车辆(管理员页面使用) // 加载所有车辆(管理员页面使用)
async function loadAllVehicles() { async function loadAllVehicles() {
// 如果是管理员页面调用admin.js中的函数
if (typeof loadAllData === 'function') {
return;
}
Utils.loading(true); Utils.loading(true);
try { try {
const response = await http.get(API.VEHICLES); const response = await http.get(API.VEHICLES);
if (response.code === 200) { if (response.code === 200) {
// 如果是管理员页面让admin.js的displayAllVehicles处理
if (typeof displayAllVehicles === 'function' && document.getElementById('allVehiclesTableBody')) {
displayAllVehicles(response.data || []); displayAllVehicles(response.data || []);
} else {
displayAllVehicles(response.data || []);
}
} }
} catch (error) { } catch (error) {
console.error('加载车辆失败:', error); console.error('加载车辆失败:', error);
@@ -584,11 +594,6 @@ async function loadAllVehicles() {
// 显示所有车辆(客户页面使用) // 显示所有车辆(客户页面使用)
function displayAllVehicles(vehicles) { function displayAllVehicles(vehicles) {
// 如果是管理员页面,不执行
if (document.getElementById('allVehiclesTableBody')) {
return;
}
const container = document.getElementById('vehiclesContainer'); const container = document.getElementById('vehiclesContainer');
if (!container) return; if (!container) return;
@@ -624,16 +629,16 @@ function displayAllVehicles(vehicles) {
// 加载所有工单 // 加载所有工单
async function loadAllOrders() { async function loadAllOrders() {
// 如果是管理员页面跳过由admin.js处理
if (document.getElementById('allOrdersTableBody')) {
return;
}
Utils.loading(true); Utils.loading(true);
try { try {
const response = await http.get(API.ORDERS); const response = await http.get(API.ORDERS);
if (response.code === 200) { if (response.code === 200) {
displayAllOrders(response.data || []); // 如果是管理员页面让admin.js的displayAllOrders处理
if (typeof displayAllOrders === 'function' && document.getElementById('allOrdersTableBody')) {
await displayAllOrders(response.data || []);
} else {
await displayAllOrders(response.data || []);
}
} }
} catch (error) { } catch (error) {
console.error('加载工单失败:', error); console.error('加载工单失败:', error);
@@ -645,11 +650,6 @@ async function loadAllOrders() {
// 显示所有工单(客户页面使用) // 显示所有工单(客户页面使用)
async function displayAllOrders(orders) { async function displayAllOrders(orders) {
// 如果是管理员页面,不执行
if (document.getElementById('allOrdersTableBody')) {
return;
}
const tbody = document.getElementById('ordersTableBody'); const tbody = document.getElementById('ordersTableBody');
if (!tbody) return; if (!tbody) return;
@@ -679,9 +679,20 @@ async function displayAllOrders(orders) {
// 加载所有用户 // 加载所有用户
async function loadAllUsers() { async function loadAllUsers() {
// 管理员页面由admin.js处理 Utils.loading(true);
if (document.getElementById('allUsersTableBody')) { try {
return; const response = await http.get(API.USERS);
if (response.code === 200) {
// 如果是管理员页面让admin.js的displayAllUsers处理
if (typeof displayAllUsers === 'function' && document.getElementById('allUsersTableBody')) {
displayAllUsers(response.data || []);
}
}
} catch (error) {
console.error('加载用户失败:', error);
Utils.showToast('加载失败', 'error');
} finally {
Utils.loading(false);
} }
} }

2018
frontend/lib/bootstrap-icons.css vendored Normal file

File diff suppressed because it is too large Load Diff

7
frontend/lib/bootstrap.bundle.min.js vendored Normal file

File diff suppressed because one or more lines are too long

6
frontend/lib/bootstrap.min.css vendored Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

View File

@@ -4,8 +4,8 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>车管家4S店车辆维保管理系统 - 登录</title> <title>车管家4S店车辆维保管理系统 - 登录</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <link href="/lib/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css" rel="stylesheet"> <link href="/lib/bootstrap-icons.css" rel="stylesheet">
<link rel="stylesheet" href="css/style.css"> <link rel="stylesheet" href="css/style.css">
</head> </head>
<body class="bg-light"> <body class="bg-light">
@@ -96,7 +96,7 @@
</div> </div>
</div> </div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> <script src="/lib/bootstrap.bundle.min.js"></script>
<script src="js/config.js"></script> <script src="js/config.js"></script>
<script src="js/api.js"></script> <script src="js/api.js"></script>
<script src="js/app.js"></script> <script src="js/app.js"></script>

View File

@@ -4,8 +4,8 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>工作人员仪表板 - 车管家4S店车辆维保管理系统</title> <title>工作人员仪表板 - 车管家4S店车辆维保管理系统</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <link href="/lib/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css" rel="stylesheet"> <link href="/lib/bootstrap-icons.css" rel="stylesheet">
<link rel="stylesheet" href="../css/style.css"> <link rel="stylesheet" href="../css/style.css">
</head> </head>
<body> <body>
@@ -228,7 +228,7 @@
</div> </div>
</div> </div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> <script src="/lib/bootstrap.bundle.min.js"></script>
<script src="../js/config.js"></script> <script src="../js/config.js"></script>
<script src="../js/api.js"></script> <script src="../js/api.js"></script>
<script> <script>