Files
wangziqi 35098f3028 add
2026-01-08 13:23:09 +08:00

794 lines
26 KiB
JavaScript
Raw Permalink 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.

// 应用程序初始化
document.addEventListener('DOMContentLoaded', function() {
// 检查是否已登录
const token = localStorage.getItem(STORAGE.TOKEN);
const user = Utils.getCurrentUser();
// 如果在登录页面
if (window.location.pathname.endsWith('login.html')) {
if (token && user) {
Utils.redirectToDashboard(user.role);
return;
}
initLoginPage();
return;
}
// 如果在仪表板页面
if (token && user) {
initDashboard(user);
} else {
window.location.href = 'login.html';
}
});
// 初始化登录页面
function initLoginPage() {
const loginForm = document.getElementById('loginForm');
const loginBtn = document.getElementById('loginBtn');
if (loginForm) {
loginForm.addEventListener('submit', async function(e) {
e.preventDefault();
const username = document.getElementById('username').value.trim();
const password = document.getElementById('password').value.trim();
const role = document.getElementById('role').value;
// 验证输入
if (!username) {
Utils.showToast('请输入用户名', 'warning');
return;
}
if (!password) {
Utils.showToast('请输入密码', 'warning');
return;
}
// 禁用按钮并显示loading
loginBtn.disabled = true;
loginBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span>登录中...';
Utils.loading(true);
try {
const response = await http.post(API.LOGIN, {
username: username,
password: password
});
if (response.code === 200) {
const { token, userInfo } = response.data;
// 验证角色
if (userInfo.role !== role) {
Utils.showToast('登录角色不匹配,请选择正确的角色', 'error');
loginBtn.disabled = false;
loginBtn.innerHTML = '<i class="bi bi-box-arrow-in-right"></i> 登录';
Utils.loading(false);
return;
}
// 保存登录信息
localStorage.setItem(STORAGE.TOKEN, token);
localStorage.setItem(STORAGE.USER, JSON.stringify(userInfo));
Utils.showToast('登录成功!', 'success');
// 延迟跳转
setTimeout(() => {
Utils.redirectToDashboard(userInfo.role);
}, 500);
} else {
Utils.showToast(response.message || '登录失败', 'error');
loginBtn.disabled = false;
loginBtn.innerHTML = '<i class="bi bi-box-arrow-in-right"></i> 登录';
Utils.loading(false);
}
} catch (error) {
console.error('登录错误:', error);
Utils.showToast('登录失败,请检查网络连接', 'error');
loginBtn.disabled = false;
loginBtn.innerHTML = '<i class="bi bi-box-arrow-in-right"></i> 登录';
Utils.loading(false);
}
});
}
// 回车键登录
const passwordInput = document.getElementById('password');
if (passwordInput) {
passwordInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
loginForm.dispatchEvent(new Event('submit'));
}
});
}
}
// 初始化仪表板
function initDashboard(user) {
// 显示用户信息
const userNameEl = document.getElementById('userName');
const userRoleEl = document.getElementById('userRole');
const userAvatarEl = document.getElementById('userAvatar');
if (userNameEl) userNameEl.textContent = user.realName;
if (userRoleEl) userRoleEl.textContent = Utils.getRoleText(user.role);
if (userAvatarEl && !userAvatarEl.textContent) {
userAvatarEl.textContent = user.realName.charAt(0).toUpperCase();
}
// 根据角色加载不同内容
switch(user.role) {
case 'admin':
initAdminDashboard();
break;
case 'staff':
initStaffDashboard();
break;
case 'customer':
initCustomerDashboard();
break;
}
}
// 初始化管理员仪表板
function initAdminDashboard() {
console.log('初始化管理员仪表板');
// 加载所有数据
if (typeof loadAllData === 'function') {
loadAllData();
} else {
// 单独加载各个模块
loadAdminStats();
loadRecentOrders();
loadAppointments();
}
}
// 加载最近工单
async function loadRecentOrders() {
try {
const response = await http.get(API.ORDERS);
if (response.code === 200 && response.data) {
const orders = response.data.slice(0, 5); // 只取前5条
displayRecentOrders(orders);
}
} 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('');
}
// 加载管理员统计数据
async function loadAdminStats() {
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);
}
if (partsRes.code === 200) {
updateStat('lowStockParts', partsRes.data?.length || 0);
}
} catch (error) {
console.error('加载统计数据失败:', error);
}
}
// 更新统计数字
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);
}
}
// 初始化工作人员仪表板
function initStaffDashboard() {
console.log('初始化工作人员仪表板');
loadStaffStats();
}
// 加载工作人员统计数据
async function loadStaffStats() {
const user = Utils.getCurrentUser();
if (!user) return;
try {
const response = await http.get(API.ORDERS);
if (response.code === 200 && response.data) {
const myOrders = response.data.filter(o => o.staffId === user.userId);
const inProgress = myOrders.filter(o => o.status === 'in_progress');
const completed = myOrders.filter(o => o.status === 'completed');
updateStat('myOrdersCount', myOrders.length);
updateStat('inProgressCount', inProgress.length);
updateStat('completedCount', completed.length);
}
} catch (error) {
console.error('加载统计数据失败:', error);
}
}
// 初始化客户仪表板
function initCustomerDashboard() {
console.log('初始化客户仪表板');
loadCustomerData();
}
// 加载客户数据
async function loadCustomerData() {
const user = Utils.getCurrentUser();
if (!user) return;
try {
// 获取用户信息、客户信息、车辆信息
const [usersRes, customersRes] = await Promise.all([
http.get(API.USERS),
http.get(API.CUSTOMERS)
]);
if (usersRes.code === 200 && customersRes.code === 200) {
// 找到当前用户对应的客户记录
const currentCustomer = customersRes.data.find(c => c.userId === user.userId);
if (currentCustomer) {
// 加载车辆、工单、预约数据使用customer_id而不是user_id
loadCustomerVehicles(currentCustomer.customerId);
loadCustomerOrders(currentCustomer.customerId);
loadCustomerAppointments(currentCustomer.customerId);
}
}
} catch (error) {
console.error('加载客户数据失败:', error);
}
}
// 加载客户车辆
async function loadCustomerVehicles(customerId) {
try {
// 使用专门的API端点获取客户的车辆而不是获取所有车辆再过滤
const response = await http.get(API.VEHICLE_CUSTOMER(customerId));
if (response.code === 200 && response.data) {
displayVehicles(response.data);
populateVehicleSelect(response.data);
}
} catch (error) {
console.error('加载车辆失败:', error);
}
}
// 显示车辆列表
function displayVehicles(vehicles) {
const container = document.getElementById('vehiclesContainer');
if (!container) return;
if (vehicles.length === 0) {
container.innerHTML = `
<div class="empty-state">
<i class="bi bi-car-front"></i>
<p>暂无车辆信息</p>
</div>
`;
return;
}
container.innerHTML = vehicles.map(v => `
<div class="col-md-6 col-lg-4 mb-4">
<div class="vehicle-card">
<div class="vehicle-plate">${v.licensePlate}</div>
<h6 class="mb-2">${v.brand} ${v.model}</h6>
<p class="text-muted small mb-1">
<i class="bi bi-palette"></i> 颜色: ${v.color || '-'}
</p>
<p class="text-muted small mb-1">
<i class="bi bi-speedometer2"></i> 里程: ${v.mileage || 0} 公里
</p>
<p class="text-muted small mb-2">
<i class="bi bi-calendar-check"></i> 上次保养: ${Utils.formatDate(v.lastMaintenanceDate)}
</p>
${Utils.getStatusBadge(v.status)}
</div>
</div>
`).join('');
}
// 填充车辆选择框
function populateVehicleSelect(vehicles) {
const select = document.getElementById('vehicleSelect');
if (!select) return;
select.innerHTML = '<option value="">请选择车辆</option>' +
vehicles.map(v => `<option value="${v.vehicleId}">${v.licensePlate} - ${v.brand} ${v.model}</option>`).join('');
}
// 加载客户工单
async function loadCustomerOrders(customerId) {
try {
const [ordersRes, vehiclesRes] = await Promise.all([
http.get(API.ORDER_CUSTOMER(customerId)),
http.get(API.VEHICLES)
]);
if (ordersRes.code === 200 && ordersRes.data) {
const vehicles = vehiclesRes.data || [];
displayOrders(ordersRes.data, vehicles);
}
} catch (error) {
console.error('加载工单失败:', error);
}
}
// 显示工单列表
function displayOrders(orders, vehicles) {
const tbody = document.getElementById('ordersTableBody');
if (!tbody) return;
if (orders.length === 0) {
tbody.innerHTML = '<tr><td colspan="6" class="text-center text-muted py-4">暂无维保记录</td></tr>';
return;
}
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('');
}
// 加载客户预约
async function loadCustomerAppointments(customerId) {
try {
const [appointmentsRes, vehiclesRes] = await Promise.all([
http.get(API.APPOINTMENT_CUSTOMER(customerId)),
http.get(API.VEHICLES)
]);
if (appointmentsRes.code === 200 && appointmentsRes.data) {
const vehicles = vehiclesRes.data || [];
displayAppointments(appointmentsRes.data, vehicles);
}
} catch (error) {
console.error('加载预约失败:', error);
}
}
// 显示预约列表
function displayAppointments(appointments, vehicles) {
const tbody = document.getElementById('appointmentsTableBody');
if (!tbody) return;
if (appointments.length === 0) {
tbody.innerHTML = '<tr><td colspan="5" 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>${Utils.getServiceTypeText(a.serviceType)}</td>
<td>${vehicle ? vehicle.licensePlate : '-'}</td>
<td>${Utils.formatDateTime(a.appointmentTime)}</td>
<td>${Utils.getStatusBadge(a.status, 'appointment')}</td>
<td>
${a.status === 'pending' ? `<button class="btn btn-sm btn-danger" onclick="cancelAppointment(${a.appointmentId})">取消</button>` : '-'}
</td>
</tr>
`;
}).join('');
}
// 取消预约
async function cancelAppointment(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');
// 重新加载预约列表 - 需要获取customer_id
const user = Utils.getCurrentUser();
if (user) {
const customersRes = await http.get(API.CUSTOMERS);
if (customersRes.code === 200) {
const currentCustomer = customersRes.data.find(c => c.userId === user.userId);
if (currentCustomer) {
loadCustomerAppointments(currentCustomer.customerId);
}
}
}
} else {
Utils.showToast(response.message || '取消失败', 'error');
}
} catch (error) {
console.error('取消预约失败:', error);
Utils.showToast('操作失败,请重试', 'error');
} finally {
Utils.loading(false);
}
}
// 提交预约
async function submitAppointment() {
const user = Utils.getCurrentUser();
if (!user) return;
const vehicleId = document.getElementById('vehicleSelect').value;
const serviceType = document.getElementById('serviceType').value;
const appointmentTime = document.getElementById('appointmentTime').value;
const contactPhone = document.getElementById('contactPhone').value;
const description = document.getElementById('description').value;
// 验证
if (!vehicleId) {
Utils.showToast('请选择车辆', 'warning');
return;
}
if (!appointmentTime) {
Utils.showToast('请选择预约时间', 'warning');
return;
}
if (!contactPhone) {
Utils.showToast('请输入联系电话', 'warning');
return;
}
Utils.loading(true);
try {
// 获取customer_id
const customersRes = await http.get(API.CUSTOMERS);
if (customersRes.code !== 200) {
Utils.showToast('获取客户信息失败', 'error');
Utils.loading(false);
return;
}
const currentCustomer = customersRes.data.find(c => c.userId === user.userId);
if (!currentCustomer) {
Utils.showToast('未找到客户信息', 'error');
Utils.loading(false);
return;
}
const response = await http.post(API.APPOINTMENTS, {
customerId: currentCustomer.customerId,
vehicleId: parseInt(vehicleId),
serviceType: serviceType,
appointmentTime: appointmentTime,
contactPhone: contactPhone,
description: description
});
if (response.code === 200) {
Utils.showToast('预约成功!', 'success');
// 重置表单
document.getElementById('appointmentForm').reset();
// 重新加载预约列表
loadCustomerAppointments(currentCustomer.customerId);
} else {
Utils.showToast(response.message || '预约失败', 'error');
}
} catch (error) {
console.error('预约失败:', error);
Utils.showToast('预约失败,请重试', 'error');
} finally {
Utils.loading(false);
}
}
// 显示Toast全局函数
function showToast(message, type = 'info') {
Utils.showToast(message, type);
}
// 显示Section
function showSection(sectionId) {
// 隐藏所有section
document.querySelectorAll('.content-section').forEach(section => {
section.style.display = 'none';
});
// 显示选中的section
const targetSection = document.getElementById(sectionId + '-section');
if (targetSection) {
targetSection.style.display = 'block';
}
// 更新菜单激活状态
document.querySelectorAll('.menu-item').forEach(item => {
item.classList.remove('active');
});
event.currentTarget.classList.add('active');
// 加载对应数据
switch(sectionId) {
case 'overview':
if (Utils.hasRole('admin')) {
loadAdminStats();
} else if (Utils.hasRole('staff')) {
loadStaffStats();
}
break;
case 'vehicles':
loadAllVehicles();
break;
case 'orders':
loadAllOrders();
break;
case 'users':
loadAllUsers();
break;
case 'parts':
if (typeof loadAllParts === 'function') {
loadAllParts();
}
break;
case 'appointments':
if (typeof loadAppointments === 'function') {
loadAppointments();
}
break;
}
}
// 加载所有车辆(管理员页面使用)
async function loadAllVehicles() {
Utils.loading(true);
try {
const response = await http.get(API.VEHICLES);
if (response.code === 200) {
// 如果是管理员页面让admin.js的displayAllVehicles处理
if (typeof displayAllVehicles === 'function' && document.getElementById('allVehiclesTableBody')) {
displayAllVehicles(response.data || []);
} else {
displayAllVehicles(response.data || []);
}
}
} catch (error) {
console.error('加载车辆失败:', error);
Utils.showToast('加载失败', 'error');
} finally {
Utils.loading(false);
}
}
// 显示所有车辆(客户页面使用)
function displayAllVehicles(vehicles) {
const container = document.getElementById('vehiclesContainer');
if (!container) return;
if (vehicles.length === 0) {
container.innerHTML = `
<div class="col-12 text-center text-muted py-5">
<i class="bi bi-car-front fs-1 d-block mb-3"></i>
<p>暂无车辆信息</p>
</div>
`;
return;
}
container.innerHTML = vehicles.map(v => `
<div class="col-md-6 col-lg-4 mb-4">
<div class="vehicle-card">
<div class="vehicle-plate">${v.licensePlate}</div>
<h6 class="mb-2">${v.brand} ${v.model}</h6>
<p class="text-muted small mb-1">
<i class="bi bi-palette"></i> 颜色: ${v.color || '-'}
</p>
<p class="text-muted small mb-1">
<i class="bi bi-speedometer2"></i> 里程: ${v.mileage || 0} 公里
</p>
<p class="text-muted small mb-2">
<i class="bi bi-calendar-check"></i> 上次保养: ${Utils.formatDate(v.lastMaintenanceDate)}
</p>
${Utils.getStatusBadge(v.status)}
</div>
</div>
`).join('');
}
// 加载所有工单
async function loadAllOrders() {
Utils.loading(true);
try {
const response = await http.get(API.ORDERS);
if (response.code === 200) {
// 如果是管理员页面让admin.js的displayAllOrders处理
if (typeof displayAllOrders === 'function' && document.getElementById('allOrdersTableBody')) {
await displayAllOrders(response.data || []);
} else {
await displayAllOrders(response.data || []);
}
}
} catch (error) {
console.error('加载工单失败:', error);
Utils.showToast('加载失败', 'error');
} finally {
Utils.loading(false);
}
}
// 显示所有工单(客户页面使用)
async function displayAllOrders(orders) {
const tbody = document.getElementById('ordersTableBody');
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('');
}
// 加载所有用户
async function loadAllUsers() {
Utils.loading(true);
try {
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);
}
}
// 显示所有用户(占位)
function displayAllUsers(users) {
// 管理员页面由admin.js处理
}
// CRUD操作函数
async function deleteVehicle(id) {
if (!Utils.confirm('确定要删除此车辆吗?')) return;
Utils.loading(true);
try {
const response = await http.delete(API.VEHICLE(id));
if (response.code === 200) {
Utils.showToast('删除成功', 'success');
loadAllVehicles();
} else {
Utils.showToast(response.message || '删除失败', 'error');
}
} catch (error) {
Utils.showToast('删除失败', 'error');
} finally {
Utils.loading(false);
}
}
async function deleteOrder(id) {
if (!Utils.confirm('确定要删除此工单吗?')) return;
Utils.loading(true);
try {
const response = await http.delete(API.ORDER(id));
if (response.code === 200) {
Utils.showToast('删除成功', 'success');
loadAllOrders();
} else {
Utils.showToast(response.message || '删除失败', 'error');
}
} catch (error) {
Utils.showToast('删除失败', 'error');
} finally {
Utils.loading(false);
}
}
async function deleteUser(id) {
if (!Utils.confirm('确定要删除此用户吗?')) return;
Utils.loading(true);
try {
const response = await http.delete(API.USER(id));
if (response.code === 200) {
Utils.showToast('删除成功', 'success');
loadAllUsers();
} else {
Utils.showToast(response.message || '删除失败', 'error');
}
} catch (error) {
Utils.showToast('删除失败', 'error');
} finally {
Utils.loading(false);
}
}
// 占位函数
function viewVehicle(id) { Utils.showToast('查看车辆功能', 'info'); }
function editVehicle(id) { Utils.showToast('编辑车辆功能', 'info'); }
function viewOrder(id) { Utils.showToast('查看工单功能', 'info'); }
function editOrder(id) { Utils.showToast('编辑工单功能', 'info'); }
function viewUser(id) { Utils.showToast('查看用户功能', 'info'); }
function editUser(id) { Utils.showToast('编辑用户功能', 'info'); }