Author: Yang Lu School: Liaoning Institute of Science and Technology Major: Computer Science and Technology Class: BZ246 Tech Stack: - Backend: Spring Boot 2.7.18 + JPA + MySQL - Frontend: HTML5 + CSS3 + JavaScript Features: - User Management (Admin/Staff/Customer roles) - Vehicle Archive Management - Service Order Management - Parts Inventory Management - Online Appointment Service - Data Statistics and Analysis Generated with Claude Code Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
469 lines
16 KiB
JavaScript
469 lines
16 KiB
JavaScript
// 管理员仪表板JavaScript
|
|
|
|
// 检查登录状态和权限
|
|
if (!utils.checkAuth() || !utils.hasRole('admin')) {
|
|
window.location.href = '../login.html';
|
|
}
|
|
|
|
// 页面加载时初始化
|
|
window.addEventListener('DOMContentLoaded', () => {
|
|
initializeDashboard();
|
|
loadOverviewData();
|
|
});
|
|
|
|
// 初始化仪表板
|
|
function initializeDashboard() {
|
|
const user = utils.getCurrentUser();
|
|
if (user) {
|
|
document.getElementById('userName').textContent = user.realName;
|
|
document.getElementById('userAvatar').textContent = user.realName.charAt(0);
|
|
}
|
|
}
|
|
|
|
// 切换显示区域
|
|
function showSection(sectionName) {
|
|
// 隐藏所有区域
|
|
const sections = document.querySelectorAll('.section');
|
|
sections.forEach(section => section.style.display = 'none');
|
|
|
|
// 移除所有菜单项的活动状态
|
|
const menuItems = document.querySelectorAll('.menu-item');
|
|
menuItems.forEach(item => item.classList.remove('active'));
|
|
|
|
// 显示选中的区域
|
|
document.getElementById(`${sectionName}-section`).style.display = 'block';
|
|
|
|
// 设置对应菜单项为活动状态
|
|
event.currentTarget.classList.add('active');
|
|
|
|
// 加载对应数据
|
|
switch(sectionName) {
|
|
case 'overview':
|
|
loadOverviewData();
|
|
break;
|
|
case 'users':
|
|
loadUsers();
|
|
break;
|
|
case 'vehicles':
|
|
loadVehicles();
|
|
break;
|
|
case 'orders':
|
|
loadOrders();
|
|
break;
|
|
case 'parts':
|
|
loadParts();
|
|
break;
|
|
case 'appointments':
|
|
loadAppointments();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// 加载概览数据
|
|
async function loadOverviewData() {
|
|
try {
|
|
// 加载统计数据
|
|
const [usersRes, vehiclesRes, ordersRes, partsRes] = await Promise.all([
|
|
api.get(API_ENDPOINTS.USERS),
|
|
api.get(API_ENDPOINTS.VEHICLES),
|
|
api.get(API_ENDPOINTS.ORDERS),
|
|
api.get(API_ENDPOINTS.PARTS_LOW_STOCK)
|
|
]);
|
|
|
|
document.getElementById('totalUsers').textContent = usersRes.data?.length || 0;
|
|
document.getElementById('totalVehicles').textContent = vehiclesRes.data?.length || 0;
|
|
document.getElementById('totalOrders').textContent = ordersRes.data?.length || 0;
|
|
document.getElementById('lowStockParts').textContent = partsRes.data?.length || 0;
|
|
|
|
// 加载最近工单
|
|
if (ordersRes.data && ordersRes.data.length > 0) {
|
|
const recentOrders = ordersRes.data.slice(0, 5);
|
|
displayRecentOrders(recentOrders);
|
|
}
|
|
} catch (error) {
|
|
console.error('加载概览数据失败:', error);
|
|
}
|
|
}
|
|
|
|
// 显示最近工单
|
|
async function displayRecentOrders(orders) {
|
|
const tbody = document.getElementById('recentOrdersBody');
|
|
if (orders.length === 0) {
|
|
tbody.innerHTML = '<tr><td colspan="5" class="empty-state">暂无数据</td></tr>';
|
|
return;
|
|
}
|
|
|
|
// 获取所有车辆信息
|
|
const vehiclesRes = await api.get(API_ENDPOINTS.VEHICLES);
|
|
const vehicles = vehiclesRes.data || [];
|
|
|
|
tbody.innerHTML = orders.map(order => {
|
|
const vehicle = vehicles.find(v => v.vehicleId === order.vehicleId);
|
|
return `
|
|
<tr>
|
|
<td>${order.orderNo}</td>
|
|
<td>${utils.getServiceTypeText(order.serviceType)}</td>
|
|
<td>${vehicle ? vehicle.licensePlate : '-'}</td>
|
|
<td>${utils.getStatusBadge(order.status)}</td>
|
|
<td>${utils.formatDateTime(order.createTime)}</td>
|
|
</tr>
|
|
`;
|
|
}).join('');
|
|
}
|
|
|
|
// 加载用户列表
|
|
async function loadUsers() {
|
|
try {
|
|
const response = await api.get(API_ENDPOINTS.USERS);
|
|
if (response.code === 200 && response.data) {
|
|
displayUsers(response.data);
|
|
}
|
|
} catch (error) {
|
|
console.error('加载用户列表失败:', error);
|
|
utils.showError('加载用户列表失败');
|
|
}
|
|
}
|
|
|
|
// 显示用户列表
|
|
function displayUsers(users) {
|
|
const tbody = document.getElementById('usersTableBody');
|
|
if (users.length === 0) {
|
|
tbody.innerHTML = '<tr><td colspan="7" class="empty-state">暂无数据</td></tr>';
|
|
return;
|
|
}
|
|
|
|
tbody.innerHTML = users.map(user => `
|
|
<tr>
|
|
<td>${user.userId}</td>
|
|
<td>${user.username}</td>
|
|
<td>${user.realName}</td>
|
|
<td>${user.phone}</td>
|
|
<td>${utils.getRoleText(user.role)}</td>
|
|
<td>${user.status === 1 ? '<span class="badge badge-success">启用</span>' : '<span class="badge badge-secondary">禁用</span>'}</td>
|
|
<td class="table-actions">
|
|
<button class="btn btn-info" onclick="viewUser(${user.userId})">查看</button>
|
|
<button class="btn btn-warning" onclick="editUser(${user.userId})">编辑</button>
|
|
<button class="btn btn-danger" onclick="deleteUser(${user.userId})">删除</button>
|
|
</td>
|
|
</tr>
|
|
`).join('');
|
|
}
|
|
|
|
// 加载车辆列表
|
|
async function loadVehicles() {
|
|
try {
|
|
const response = await api.get(API_ENDPOINTS.VEHICLES);
|
|
if (response.code === 200 && response.data) {
|
|
displayVehicles(response.data);
|
|
}
|
|
} catch (error) {
|
|
console.error('加载车辆列表失败:', error);
|
|
utils.showError('加载车辆列表失败');
|
|
}
|
|
}
|
|
|
|
// 显示车辆列表
|
|
function displayVehicles(vehicles) {
|
|
const tbody = document.getElementById('vehiclesTableBody');
|
|
if (vehicles.length === 0) {
|
|
tbody.innerHTML = '<tr><td colspan="6" class="empty-state">暂无数据</td></tr>';
|
|
return;
|
|
}
|
|
|
|
tbody.innerHTML = vehicles.map(vehicle => `
|
|
<tr>
|
|
<td>${vehicle.licensePlate}</td>
|
|
<td>${vehicle.brand} ${vehicle.model}</td>
|
|
<td>${vehicle.color || '-'}</td>
|
|
<td>${vehicle.mileage || 0} 公里</td>
|
|
<td>${utils.getStatusBadge(vehicle.status)}</td>
|
|
<td class="table-actions">
|
|
<button class="btn btn-info" onclick="viewVehicle(${vehicle.vehicleId})">查看</button>
|
|
<button class="btn btn-warning" onclick="editVehicle(${vehicle.vehicleId})">编辑</button>
|
|
<button class="btn btn-danger" onclick="deleteVehicle(${vehicle.vehicleId})">删除</button>
|
|
</td>
|
|
</tr>
|
|
`).join('');
|
|
}
|
|
|
|
// 加载工单列表
|
|
async function loadOrders(status = '') {
|
|
try {
|
|
const url = status ? API_ENDPOINTS.ORDERS_BY_STATUS(status) : API_ENDPOINTS.ORDERS;
|
|
const response = await api.get(url);
|
|
if (response.code === 200 && response.data) {
|
|
displayOrders(response.data);
|
|
}
|
|
} catch (error) {
|
|
console.error('加载工单列表失败:', error);
|
|
utils.showError('加载工单列表失败');
|
|
}
|
|
}
|
|
|
|
// 显示工单列表
|
|
async function displayOrders(orders) {
|
|
const tbody = document.getElementById('ordersTableBody');
|
|
if (orders.length === 0) {
|
|
tbody.innerHTML = '<tr><td colspan="7" class="empty-state">暂无数据</td></tr>';
|
|
return;
|
|
}
|
|
|
|
const vehiclesRes = await api.get(API_ENDPOINTS.VEHICLES);
|
|
const vehicles = vehiclesRes.data || [];
|
|
|
|
tbody.innerHTML = orders.map(order => {
|
|
const vehicle = vehicles.find(v => v.vehicleId === order.vehicleId);
|
|
return `
|
|
<tr>
|
|
<td>${order.orderNo}</td>
|
|
<td>${utils.getServiceTypeText(order.serviceType)}</td>
|
|
<td>${vehicle ? vehicle.licensePlate : '-'}</td>
|
|
<td>¥${order.totalCost || 0}</td>
|
|
<td>${utils.getStatusBadge(order.status)}</td>
|
|
<td>${utils.formatDateTime(order.createTime)}</td>
|
|
<td class="table-actions">
|
|
<button class="btn btn-info" onclick="viewOrder(${order.orderId})">查看</button>
|
|
<button class="btn btn-warning" onclick="editOrder(${order.orderId})">编辑</button>
|
|
<button class="btn btn-danger" onclick="deleteOrder(${order.orderId})">删除</button>
|
|
</td>
|
|
</tr>
|
|
`;
|
|
}).join('');
|
|
}
|
|
|
|
// 加载配件列表
|
|
async function loadParts() {
|
|
try {
|
|
const response = await api.get(API_ENDPOINTS.PARTS);
|
|
if (response.code === 200 && response.data) {
|
|
displayParts(response.data);
|
|
}
|
|
} catch (error) {
|
|
console.error('加载配件列表失败:', error);
|
|
utils.showError('加载配件列表失败');
|
|
}
|
|
}
|
|
|
|
// 显示配件列表
|
|
function displayParts(parts) {
|
|
const tbody = document.getElementById('partsTableBody');
|
|
if (parts.length === 0) {
|
|
tbody.innerHTML = '<tr><td colspan="7" class="empty-state">暂无数据</td></tr>';
|
|
return;
|
|
}
|
|
|
|
tbody.innerHTML = parts.map(part => {
|
|
const isLowStock = part.stockQuantity <= part.minStock;
|
|
return `
|
|
<tr ${isLowStock ? 'style="background-color: #fff1f0;"' : ''}>
|
|
<td>${part.partNo}</td>
|
|
<td>${part.partName}</td>
|
|
<td>${part.category || '-'}</td>
|
|
<td>${part.stockQuantity} ${part.unit}${isLowStock ? ' <span class="badge badge-danger">预警</span>' : ''}</td>
|
|
<td>¥${part.unitPrice}</td>
|
|
<td>${part.status === 1 ? '<span class="badge badge-success">正常</span>' : '<span class="badge badge-secondary">停用</span>'}</td>
|
|
<td class="table-actions">
|
|
<button class="btn btn-info" onclick="viewPart(${part.partId})">查看</button>
|
|
<button class="btn btn-warning" onclick="editPart(${part.partId})">编辑</button>
|
|
<button class="btn btn-danger" onclick="deletePart(${part.partId})">删除</button>
|
|
</td>
|
|
</tr>
|
|
`;
|
|
}).join('');
|
|
}
|
|
|
|
// 加载预约列表
|
|
async function loadAppointments(status = '') {
|
|
try {
|
|
const url = status ? API_ENDPOINTS.APPOINTMENTS_BY_STATUS(status) : API_ENDPOINTS.APPOINTMENTS;
|
|
const response = await api.get(url);
|
|
if (response.code === 200 && response.data) {
|
|
displayAppointments(response.data);
|
|
}
|
|
} catch (error) {
|
|
console.error('加载预约列表失败:', error);
|
|
utils.showError('加载预约列表失败');
|
|
}
|
|
}
|
|
|
|
// 显示预约列表
|
|
async function displayAppointments(appointments) {
|
|
const tbody = document.getElementById('appointmentsTableBody');
|
|
if (appointments.length === 0) {
|
|
tbody.innerHTML = '<tr><td colspan="7" class="empty-state">暂无数据</td></tr>';
|
|
return;
|
|
}
|
|
|
|
const vehiclesRes = await api.get(API_ENDPOINTS.VEHICLES);
|
|
const vehicles = vehiclesRes.data || [];
|
|
|
|
tbody.innerHTML = appointments.map(appointment => {
|
|
const vehicle = vehicles.find(v => v.vehicleId === appointment.vehicleId);
|
|
return `
|
|
<tr>
|
|
<td>${appointment.appointmentId}</td>
|
|
<td>${utils.getServiceTypeText(appointment.serviceType)}</td>
|
|
<td>${vehicle ? vehicle.licensePlate : '-'}</td>
|
|
<td>${utils.formatDateTime(appointment.appointmentTime)}</td>
|
|
<td>${appointment.contactPhone}</td>
|
|
<td>${utils.getStatusBadge(appointment.status)}</td>
|
|
<td class="table-actions">
|
|
<button class="btn btn-success" onclick="confirmAppointment(${appointment.appointmentId})">确认</button>
|
|
<button class="btn btn-danger" onclick="cancelAppointment(${appointment.appointmentId})">取消</button>
|
|
</td>
|
|
</tr>
|
|
`;
|
|
}).join('');
|
|
}
|
|
|
|
// 过滤工单
|
|
function filterOrders() {
|
|
const status = document.getElementById('orderStatusFilter').value;
|
|
loadOrders(status);
|
|
}
|
|
|
|
// 过滤预约
|
|
function filterAppointments() {
|
|
const status = document.getElementById('appointmentStatusFilter').value;
|
|
loadAppointments(status);
|
|
}
|
|
|
|
// 搜索用户
|
|
function searchUsers() {
|
|
const keyword = document.getElementById('searchUser').value.toLowerCase();
|
|
// 实现搜索逻辑
|
|
}
|
|
|
|
// 搜索车辆
|
|
function searchVehicles() {
|
|
const keyword = document.getElementById('searchVehicle').value.toLowerCase();
|
|
// 实现搜索逻辑
|
|
}
|
|
|
|
// 搜索配件
|
|
function searchParts() {
|
|
const keyword = document.getElementById('searchPart').value.toLowerCase();
|
|
// 实现搜索逻辑
|
|
}
|
|
|
|
// 显示低库存配件
|
|
async function showLowStockParts() {
|
|
try {
|
|
const response = await api.get(API_ENDPOINTS.PARTS_LOW_STOCK);
|
|
if (response.code === 200 && response.data) {
|
|
displayParts(response.data);
|
|
utils.showSuccess(`找到 ${response.data.length} 个库存预警配件`);
|
|
}
|
|
} catch (error) {
|
|
console.error('加载库存预警失败:', error);
|
|
utils.showError('加载库存预警失败');
|
|
}
|
|
}
|
|
|
|
// 占位函数 - 实际项目中需要实现完整功能
|
|
function showAddUserModal() { alert('添加用户功能'); }
|
|
function viewUser(id) { alert('查看用户: ' + id); }
|
|
function editUser(id) { alert('编辑用户: ' + id); }
|
|
async function deleteUser(id) {
|
|
if (utils.confirm('确定要删除此用户吗?')) {
|
|
try {
|
|
const response = await api.delete(API_ENDPOINTS.USER_BY_ID(id));
|
|
if (response.code === 200) {
|
|
utils.showSuccess('删除成功');
|
|
loadUsers();
|
|
} else {
|
|
utils.showError(response.message);
|
|
}
|
|
} catch (error) {
|
|
utils.showError('删除失败');
|
|
}
|
|
}
|
|
}
|
|
|
|
function showAddVehicleModal() { alert('添加车辆功能'); }
|
|
function viewVehicle(id) { alert('查看车辆: ' + id); }
|
|
function editVehicle(id) { alert('编辑车辆: ' + id); }
|
|
async function deleteVehicle(id) {
|
|
if (utils.confirm('确定要删除此车辆吗?')) {
|
|
try {
|
|
const response = await api.delete(API_ENDPOINTS.VEHICLE_BY_ID(id));
|
|
if (response.code === 200) {
|
|
utils.showSuccess('删除成功');
|
|
loadVehicles();
|
|
} else {
|
|
utils.showError(response.message);
|
|
}
|
|
} catch (error) {
|
|
utils.showError('删除失败');
|
|
}
|
|
}
|
|
}
|
|
|
|
function showAddOrderModal() { alert('创建工单功能'); }
|
|
function viewOrder(id) { alert('查看工单: ' + id); }
|
|
function editOrder(id) { alert('编辑工单: ' + id); }
|
|
async function deleteOrder(id) {
|
|
if (utils.confirm('确定要删除此工单吗?')) {
|
|
try {
|
|
const response = await api.delete(API_ENDPOINTS.ORDER_BY_ID(id));
|
|
if (response.code === 200) {
|
|
utils.showSuccess('删除成功');
|
|
loadOrders();
|
|
} else {
|
|
utils.showError(response.message);
|
|
}
|
|
} catch (error) {
|
|
utils.showError('删除失败');
|
|
}
|
|
}
|
|
}
|
|
|
|
function showAddPartModal() { alert('添加配件功能'); }
|
|
function viewPart(id) { alert('查看配件: ' + id); }
|
|
function editPart(id) { alert('编辑配件: ' + id); }
|
|
async function deletePart(id) {
|
|
if (utils.confirm('确定要删除此配件吗?')) {
|
|
try {
|
|
const response = await api.delete(API_ENDPOINTS.PART_BY_ID(id));
|
|
if (response.code === 200) {
|
|
utils.showSuccess('删除成功');
|
|
loadParts();
|
|
} else {
|
|
utils.showError(response.message);
|
|
}
|
|
} catch (error) {
|
|
utils.showError('删除失败');
|
|
}
|
|
}
|
|
}
|
|
|
|
async function confirmAppointment(id) {
|
|
try {
|
|
const response = await api.put(API_ENDPOINTS.APPOINTMENT_BY_ID(id), { status: 'confirmed' });
|
|
if (response.code === 200) {
|
|
utils.showSuccess('预约已确认');
|
|
loadAppointments();
|
|
} else {
|
|
utils.showError(response.message);
|
|
}
|
|
} catch (error) {
|
|
utils.showError('操作失败');
|
|
}
|
|
}
|
|
|
|
async function cancelAppointment(id) {
|
|
if (utils.confirm('确定要取消此预约吗?')) {
|
|
try {
|
|
const response = await api.put(API_ENDPOINTS.CANCEL_APPOINTMENT(id));
|
|
if (response.code === 200) {
|
|
utils.showSuccess('预约已取消');
|
|
loadAppointments();
|
|
} else {
|
|
utils.showError(response.message);
|
|
}
|
|
} catch (error) {
|
|
utils.showError('操作失败');
|
|
}
|
|
}
|
|
}
|