Files
car-maintenance-system/frontend/js/admin.js
wangziqi 35098f3028 add
2026-01-08 13:23:09 +08:00

905 lines
33 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 管理员仪表板专用JavaScript
// 全局数据存储
let allUsersData = [];
let allVehiclesData = [];
let allOrdersData = [];
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('');
};
// ==================== 用户管理 ====================
// 查看用户详情
async function viewUser(id) {
Utils.loading(true);
try {
const response = await http.get(API.USER(id));
if (response.code === 200 && response.data) {
const user = response.data;
// 填充表单(只读模式)
document.getElementById('userId').value = user.userId;
document.getElementById('userUsername').value = user.username;
document.getElementById('userRealName').value = user.realName;
document.getElementById('userPhone').value = user.phone;
document.getElementById('userEmail').value = user.email || '';
document.getElementById('userRole').value = user.role;
document.getElementById('userStatus').value = user.status;
// 禁用表单控件
document.getElementById('userForm').querySelectorAll('input, select').forEach(el => {
el.disabled = true;
});
document.getElementById('userModalTitle').textContent = '查看用户详情';
const modal = new bootstrap.Modal(document.getElementById('userModal'));
modal.show();
// 启用表单控件(在关闭时)
document.getElementById('userModal').addEventListener('hidden.bs.modal', function() {
document.getElementById('userForm').querySelectorAll('input, select').forEach(el => {
el.disabled = false;
});
}, { once: true });
}
} catch (error) {
Utils.showToast('加载用户信息失败', 'error');
} finally {
Utils.loading(false);
}
}
// 编辑用户
async function editUser(id) {
const user = allUsersData.find(u => u.userId === id);
if (!user) {
Utils.showToast('用户不存在', 'error');
return;
}
// 填充表单
document.getElementById('userId').value = user.userId;
document.getElementById('userUsername').value = user.username;
document.getElementById('userRealName').value = user.realName;
document.getElementById('userPhone').value = user.phone;
document.getElementById('userEmail').value = user.email || '';
document.getElementById('userRole').value = user.role;
document.getElementById('userStatus').value = user.status;
document.getElementById('userModalTitle').textContent = '编辑用户';
const modal = new bootstrap.Modal(document.getElementById('userModal'));
modal.show();
}
// 保存用户
async function saveUser() {
const userId = document.getElementById('userId').value;
const userData = {
username: document.getElementById('userUsername').value,
realName: document.getElementById('userRealName').value,
phone: document.getElementById('userPhone').value,
email: document.getElementById('userEmail').value,
role: document.getElementById('userRole').value,
status: parseInt(document.getElementById('userStatus').value)
};
Utils.loading(true);
try {
let response;
if (userId) {
// 更新
response = await http.put(API.USER(userId), userData);
} else {
// 新增
userData.password = '123456'; // 默认密码
response = await http.post(API.USERS, userData);
}
if (response.code === 200) {
Utils.showToast(userId ? '更新成功' : '创建成功', 'success');
const modal = bootstrap.Modal.getInstance(document.getElementById('userModal'));
modal.hide();
loadAllUsers();
} else {
Utils.showToast(response.message || '保存失败', 'error');
}
} catch (error) {
console.error('保存用户失败:', error);
Utils.showToast('保存失败', 'error');
} finally {
Utils.loading(false);
}
}
// 添加用户
function showAddUserModal() {
// 清空表单
document.getElementById('userForm').reset();
document.getElementById('userId').value = '';
document.getElementById('userStatus').value = '1';
document.getElementById('userModalTitle').textContent = '添加用户';
const modal = new bootstrap.Modal(document.getElementById('userModal'));
modal.show();
}
// ==================== 车辆管理 ====================
// 查看车辆详情
async function viewVehicle(id) {
Utils.loading(true);
try {
const response = await http.get(API.VEHICLE(id));
if (response.code === 200 && response.data) {
const vehicle = response.data;
document.getElementById('vehicleId').value = vehicle.vehicleId;
document.getElementById('vehicleLicensePlate').value = vehicle.licensePlate;
document.getElementById('vehicleBrand').value = vehicle.brand;
document.getElementById('vehicleModel').value = vehicle.model;
document.getElementById('vehicleColor').value = vehicle.color || '';
document.getElementById('vehicleMileage').value = vehicle.mileage || 0;
document.getElementById('vehicleStatus').value = vehicle.status;
// 禁用表单
document.getElementById('vehicleForm').querySelectorAll('input, select').forEach(el => {
el.disabled = true;
});
document.getElementById('vehicleModalTitle').textContent = '查看车辆详情';
const modal = new bootstrap.Modal(document.getElementById('vehicleModal'));
modal.show();
document.getElementById('vehicleModal').addEventListener('hidden.bs.modal', function() {
document.getElementById('vehicleForm').querySelectorAll('input, select').forEach(el => {
el.disabled = false;
});
}, { once: true });
}
} catch (error) {
Utils.showToast('加载车辆信息失败', 'error');
} finally {
Utils.loading(false);
}
}
// 编辑车辆
async function editVehicle(id) {
const vehicle = allVehiclesData.find(v => v.vehicleId === id);
if (!vehicle) {
Utils.showToast('车辆不存在', 'error');
return;
}
document.getElementById('vehicleId').value = vehicle.vehicleId;
document.getElementById('vehicleLicensePlate').value = vehicle.licensePlate;
document.getElementById('vehicleBrand').value = vehicle.brand;
document.getElementById('vehicleModel').value = vehicle.model;
document.getElementById('vehicleColor').value = vehicle.color || '';
document.getElementById('vehicleMileage').value = vehicle.mileage || 0;
document.getElementById('vehicleStatus').value = vehicle.status;
document.getElementById('vehicleModalTitle').textContent = '编辑车辆';
const modal = new bootstrap.Modal(document.getElementById('vehicleModal'));
modal.show();
}
// 保存车辆
async function saveVehicle() {
const vehicleId = document.getElementById('vehicleId').value;
const vehicleData = {
licensePlate: document.getElementById('vehicleLicensePlate').value,
brand: document.getElementById('vehicleBrand').value,
model: document.getElementById('vehicleModel').value,
color: document.getElementById('vehicleColor').value,
mileage: parseFloat(document.getElementById('vehicleMileage').value) || 0,
status: document.getElementById('vehicleStatus').value
};
// 获取客户ID这里简化处理实际应该让用户选择
if (!vehicleId) {
vehicleData.customerId = 1; // 默认使用第一个客户
}
Utils.loading(true);
try {
let response;
if (vehicleId) {
response = await http.put(API.VEHICLE(vehicleId), vehicleData);
} else {
response = await http.post(API.VEHICLES, vehicleData);
}
if (response.code === 200) {
Utils.showToast(vehicleId ? '更新成功' : '添加成功', 'success');
const modal = bootstrap.Modal.getInstance(document.getElementById('vehicleModal'));
modal.hide();
loadAllVehicles();
} else {
Utils.showToast(response.message || '保存失败', 'error');
}
} catch (error) {
console.error('保存车辆失败:', error);
Utils.showToast('保存失败', 'error');
} finally {
Utils.loading(false);
}
}
// 添加车辆
function showAddVehicleModal() {
document.getElementById('vehicleForm').reset();
document.getElementById('vehicleId').value = '';
document.getElementById('vehicleMileage').value = 0;
document.getElementById('vehicleModalTitle').textContent = '添加车辆';
const modal = new bootstrap.Modal(document.getElementById('vehicleModal'));
modal.show();
}
// ==================== 工单管理 ====================
// 查看工单详情
async function viewOrder(id) {
Utils.loading(true);
try {
const response = await http.get(API.ORDER(id));
if (response.code === 200 && response.data) {
const order = response.data;
document.getElementById('orderId').value = order.orderId;
document.getElementById('orderServiceType').value = order.serviceType;
document.getElementById('orderFaultDescription').value = order.faultDescription || '';
document.getElementById('orderDiagnosisResult').value = order.diagnosisResult || '';
document.getElementById('orderPartsCost').value = order.partsCost || 0;
document.getElementById('orderLaborCost').value = order.laborCost || 0;
document.getElementById('orderTotalCost').value = order.totalCost || 0;
document.getElementById('orderStatus').value = order.status;
// 禁用表单
document.getElementById('orderForm').querySelectorAll('input, select, textarea').forEach(el => {
el.disabled = true;
});
document.getElementById('orderModalTitle').textContent = '查看工单详情';
const modal = new bootstrap.Modal(document.getElementById('orderModal'));
modal.show();
document.getElementById('orderModal').addEventListener('hidden.bs.modal', function() {
document.getElementById('orderForm').querySelectorAll('input, select, textarea').forEach(el => {
el.disabled = false;
});
}, { once: true });
}
} catch (error) {
Utils.showToast('加载工单信息失败', 'error');
} finally {
Utils.loading(false);
}
}
// 编辑工单
async function editOrder(id) {
const order = allOrdersData.find(o => o.orderId === id);
if (!order) {
Utils.showToast('工单不存在', 'error');
return;
}
document.getElementById('orderId').value = order.orderId;
document.getElementById('orderServiceType').value = order.serviceType;
document.getElementById('orderFaultDescription').value = order.faultDescription || '';
document.getElementById('orderDiagnosisResult').value = order.diagnosisResult || '';
document.getElementById('orderPartsCost').value = order.partsCost || 0;
document.getElementById('orderLaborCost').value = order.laborCost || 0;
document.getElementById('orderTotalCost').value = order.totalCost || 0;
document.getElementById('orderStatus').value = order.status;
document.getElementById('orderModalTitle').textContent = '编辑工单';
const modal = new bootstrap.Modal(document.getElementById('orderModal'));
modal.show();
// 监听费用变化自动计算总额
setupOrderCostCalculation();
}
// 设置工单费用自动计算
function setupOrderCostCalculation() {
const partsCost = document.getElementById('orderPartsCost');
const laborCost = document.getElementById('orderLaborCost');
const totalCost = document.getElementById('orderTotalCost');
function updateTotal() {
const parts = parseFloat(partsCost.value) || 0;
const labor = parseFloat(laborCost.value) || 0;
totalCost.value = (parts + labor).toFixed(2);
}
partsCost.addEventListener('input', updateTotal);
laborCost.addEventListener('input', updateTotal);
}
// 保存工单
async function saveOrder() {
const orderId = document.getElementById('orderId').value;
const orderData = {
serviceType: document.getElementById('orderServiceType').value,
faultDescription: document.getElementById('orderFaultDescription').value,
diagnosisResult: document.getElementById('orderDiagnosisResult').value,
partsCost: parseFloat(document.getElementById('orderPartsCost').value) || 0,
laborCost: parseFloat(document.getElementById('orderLaborCost').value) || 0,
totalCost: parseFloat(document.getElementById('orderTotalCost').value) || 0,
status: document.getElementById('orderStatus').value
};
Utils.loading(true);
try {
// 更新工单
const response = await http.put(API.ORDER(orderId), orderData);
if (response.code === 200) {
Utils.showToast('更新成功', 'success');
const modal = bootstrap.Modal.getInstance(document.getElementById('orderModal'));
modal.hide();
loadAllOrders();
} else {
Utils.showToast(response.message || '保存失败', 'error');
}
} catch (error) {
console.error('保存工单失败:', error);
Utils.showToast('保存失败', 'error');
} finally {
Utils.loading(false);
}
}
// 添加工单
function showAddOrderModal() {
document.getElementById('orderForm').reset();
document.getElementById('orderId').value = '';
document.getElementById('orderPartsCost').value = 0;
document.getElementById('orderLaborCost').value = 0;
document.getElementById('orderTotalCost').value = 0;
document.getElementById('orderModalTitle').textContent = '创建工单';
const modal = new bootstrap.Modal(document.getElementById('orderModal'));
modal.show();
setupOrderCostCalculation();
}
// 过滤工单
function filterOrders(status) {
if (!status) {
displayAllOrders(allOrdersData);
} else {
const filtered = allOrdersData.filter(o => o.status === status);
displayAllOrders(filtered);
}
}
// ==================== 配件管理 ====================
// 查看配件详情
async function viewPart(id) {
const part = allPartsData.find(p => p.partId === id);
if (!part) {
Utils.showToast('配件不存在', 'error');
return;
}
// 填充表单
document.getElementById('partId').value = part.partId;
document.getElementById('partPartNo').value = part.partNo;
document.getElementById('partPartName').value = part.partName;
document.getElementById('partCategory').value = part.category || '';
document.getElementById('partBrand').value = part.brand || '';
document.getElementById('partModel').value = part.model || '';
document.getElementById('partUnit').value = part.unit || '个';
document.getElementById('partUnitPrice').value = part.unitPrice;
document.getElementById('partStockQuantity').value = part.stockQuantity;
document.getElementById('partMinStock').value = part.minStock;
document.getElementById('partSupplier').value = part.supplier || '';
document.getElementById('partWarehouseLocation').value = part.warehouseLocation || '';
document.getElementById('partRemark').value = part.remark || '';
// 禁用表单(只读模式)
document.getElementById('partForm').querySelectorAll('input, select, textarea').forEach(el => {
el.disabled = true;
});
document.getElementById('partModalTitle').textContent = '查看配件详情';
const modal = new bootstrap.Modal(document.getElementById('partModal'));
modal.show();
// 启用表单控件(在关闭时)
document.getElementById('partModal').addEventListener('hidden.bs.modal', function() {
document.getElementById('partForm').querySelectorAll('input, select, textarea').forEach(el => {
el.disabled = false;
});
}, { once: true });
}
// 编辑配件
async function editPart(id) {
const part = allPartsData.find(p => p.partId === id);
if (!part) {
Utils.showToast('配件不存在', 'error');
return;
}
// 填充表单
document.getElementById('partId').value = part.partId;
document.getElementById('partPartNo').value = part.partNo;
document.getElementById('partPartName').value = part.partName;
document.getElementById('partCategory').value = part.category || '';
document.getElementById('partBrand').value = part.brand || '';
document.getElementById('partModel').value = part.model || '';
document.getElementById('partUnit').value = part.unit || '个';
document.getElementById('partUnitPrice').value = part.unitPrice;
document.getElementById('partStockQuantity').value = part.stockQuantity;
document.getElementById('partMinStock').value = part.minStock;
document.getElementById('partSupplier').value = part.supplier || '';
document.getElementById('partWarehouseLocation').value = part.warehouseLocation || '';
document.getElementById('partRemark').value = part.remark || '';
document.getElementById('partModalTitle').textContent = '编辑配件';
const modal = new bootstrap.Modal(document.getElementById('partModal'));
modal.show();
}
// 保存配件
async function savePart() {
const partId = document.getElementById('partId').value;
const partData = {
partNo: document.getElementById('partPartNo').value,
partName: document.getElementById('partPartName').value,
category: document.getElementById('partCategory').value,
brand: document.getElementById('partBrand').value,
model: document.getElementById('partModel').value,
unit: document.getElementById('partUnit').value,
unitPrice: parseFloat(document.getElementById('partUnitPrice').value),
stockQuantity: parseInt(document.getElementById('partStockQuantity').value),
minStock: parseInt(document.getElementById('partMinStock').value),
supplier: document.getElementById('partSupplier').value,
warehouseLocation: document.getElementById('partWarehouseLocation').value,
remark: document.getElementById('partRemark').value
};
Utils.loading(true);
try {
let response;
if (partId) {
// 更新
response = await http.put(API.PART(partId), partData);
} else {
// 新增
response = await http.post(API.PARTS, partData);
}
if (response.code === 200) {
Utils.showToast(partId ? '更新成功' : '添加成功', 'success');
const modal = bootstrap.Modal.getInstance(document.getElementById('partModal'));
modal.hide();
loadAllParts();
} else {
Utils.showToast(response.message || '保存失败', 'error');
}
} catch (error) {
console.error('保存配件失败:', error);
Utils.showToast('保存失败', 'error');
} finally {
Utils.loading(false);
}
}
// 添加配件
function showAddPartModal() {
// 清空表单
document.getElementById('partForm').reset();
document.getElementById('partId').value = '';
document.getElementById('partUnit').value = '个';
document.getElementById('partModalTitle').textContent = '添加配件';
const modal = new bootstrap.Modal(document.getElementById('partModal'));
modal.show();
}
// ==================== 数据加载函数 ====================
// 加载所有数据
async function loadAllData() {
console.log('开始加载所有数据...');
Utils.loading(true);
try {
// 并行加载所有数据
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();
// 加载管理员首页统计数据和最近工单
await loadAdminStatsData();
console.log('所有数据加载完成');
} catch (error) {
console.error('加载数据失败:', error);
Utils.showToast('加载数据失败', 'error');
} finally {
Utils.loading(false);
}
}
// 加载管理员首页数据(统计和最近工单)
async function loadAdminStatsData() {
try {
// 加载统计数据
const [usersRes, vehiclesRes, ordersRes, partsRes] = await Promise.all([
http.get(API.USERS),
http.get(API.VEHICLES),
http.get(API.ORDERS),
http.get(API.PARTS_LOW_STOCK)
]);
if (usersRes.code === 200) {
updateStat('totalUsers', usersRes.data?.length || 0);
}
if (vehiclesRes.code === 200) {
updateStat('totalVehicles', vehiclesRes.data?.length || 0);
}
if (ordersRes.code === 200) {
updateStat('totalOrders', ordersRes.data?.length || 0);
// 显示最近工单前5条
const recentOrders = ordersRes.data.slice(0, 5);
await displayRecentOrders(recentOrders);
}
if (partsRes.code === 200) {
updateStat('lowStockParts', partsRes.data?.length || 0);
}
} catch (error) {
console.error('加载统计数据失败:', error);
}
}
// 显示最近工单
async function displayRecentOrders(orders) {
const tbody = document.getElementById('recentOrdersTableBody');
if (!tbody) return;
if (orders.length === 0) {
tbody.innerHTML = '<tr><td colspan="6" 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.formatDateTime(o.createTime)}</td>
</tr>
`;
}).join('');
}
// 更新统计数字
function updateStat(id, value) {
const el = document.getElementById(id);
if (el) {
el.textContent = value;
// 添加动画效果
el.style.transition = 'all 0.3s';
el.style.transform = 'scale(1.2)';
setTimeout(() => {
el.style.transform = 'scale(1)';
}, 300);
}
}
// 加载所有配件
async function loadAllParts() {
Utils.loading(true);
try {
const response = await http.get(API.PARTS);
if (response.code === 200) {
allPartsData = response.data || [];
displayAllParts(allPartsData);
}
} catch (error) {
console.error('加载配件失败:', error);
} finally {
Utils.loading(false);
}
}
// 显示所有配件
function displayAllParts(parts) {
const tbody = document.getElementById('partsTableBody');
if (!tbody) return;
if (parts.length === 0) {
tbody.innerHTML = '<tr><td colspan="6" class="text-center text-muted py-4">暂无数据</td></tr>';
return;
}
tbody.innerHTML = parts.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>
<td>
<button class="btn btn-sm btn-info" onclick="viewPart(${p.partId})">查看</button>
<button class="btn btn-sm btn-warning" onclick="editPart(${p.partId})">编辑</button>
<button class="btn btn-sm btn-danger" onclick="deletePart(${p.partId})">删除</button>
</td>
</tr>
`).join('');
}
// 删除配件
async function deletePart(id) {
if (!Utils.confirm('确定要删除此配件吗?')) return;
Utils.loading(true);
try {
const response = await http.delete(API.PART(id));
if (response.code === 200) {
Utils.showToast('删除成功', 'success');
loadAllParts();
} else {
Utils.showToast(response.message || '删除失败', 'error');
}
} catch (error) {
Utils.showToast('删除失败', 'error');
} finally {
Utils.loading(false);
}
}
// ==================== 预约管理 ====================
// 加载预约数据
async function loadAppointments() {
Utils.loading(true);
try {
const [appointmentsRes, vehiclesRes] = await Promise.all([
http.get(API.APPOINTMENTS),
http.get(API.VEHICLES)
]);
if (appointmentsRes.code === 200) {
const vehicles = vehiclesRes.data || [];
displayAppointments(appointmentsRes.data || [], vehicles);
}
} catch (error) {
console.error('加载预约失败:', error);
} finally {
Utils.loading(false);
}
}
// 显示预约列表
function displayAppointments(appointments, vehicles) {
const tbody = document.getElementById('appointmentsTableBody');
if (!tbody) return;
if (appointments.length === 0) {
tbody.innerHTML = '<tr><td colspan="7" class="text-center text-muted py-4">暂无数据</td></tr>';
return;
}
tbody.innerHTML = appointments.map(a => {
const vehicle = vehicles.find(v => v.vehicleId === a.vehicleId);
return `
<tr>
<td>${a.appointmentId}</td>
<td>${Utils.getServiceTypeText(a.serviceType)}</td>
<td>${vehicle ? vehicle.licensePlate : '-'}</td>
<td>${Utils.formatDateTime(a.appointmentTime)}</td>
<td>${a.contactPhone}</td>
<td>${Utils.getStatusBadge(a.status, 'appointment')}</td>
<td>
<button class="btn btn-sm btn-success" onclick="confirmAppointment(${a.appointmentId})">确认</button>
<button class="btn btn-sm btn-danger" onclick="cancelAppointmentAdmin(${a.appointmentId})">取消</button>
</td>
</tr>
`;
}).join('');
}
// 管理员确认预约
async function confirmAppointment(id) {
Utils.loading(true);
try {
const response = await http.put(API.APPOINTMENT(id), { status: 'confirmed' });
if (response.code === 200) {
Utils.showToast('预约已确认', 'success');
loadAppointments();
} else {
Utils.showToast(response.message || '操作失败', 'error');
}
} catch (error) {
Utils.showToast('操作失败', 'error');
} finally {
Utils.loading(false);
}
}
// 管理员取消预约
async function cancelAppointmentAdmin(id) {
if (!Utils.confirm('确定要取消此预约吗?')) return;
Utils.loading(true);
try {
const response = await http.put(API.APPOINTMENT_CANCEL(id), {});
if (response.code === 200) {
Utils.showToast('预约已取消', 'success');
loadAppointments();
} else {
Utils.showToast(response.message || '操作失败', 'error');
}
} catch (error) {
Utils.showToast('操作失败', 'error');
} finally {
Utils.loading(false);
}
}
// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', function() {
// 如果是管理员页面,等待一小段时间确保所有脚本加载完成
if (window.location.pathname.includes('admin')) {
console.log('检测到管理员页面,准备加载数据');
setTimeout(() => {
loadAllData();
}, 100);
}
});