Initial commit: Car Maintenance Management System
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>
This commit is contained in:
468
frontend/js/admin-dashboard.js
Normal file
468
frontend/js/admin-dashboard.js
Normal file
@@ -0,0 +1,468 @@
|
||||
// 管理员仪表板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('操作失败');
|
||||
}
|
||||
}
|
||||
}
|
||||
194
frontend/js/api.js
Normal file
194
frontend/js/api.js
Normal file
@@ -0,0 +1,194 @@
|
||||
// API请求工具类
|
||||
class API {
|
||||
constructor() {
|
||||
this.baseURL = API_CONFIG.BASE_URL;
|
||||
this.timeout = API_CONFIG.TIMEOUT;
|
||||
}
|
||||
|
||||
// 获取请求头
|
||||
getHeaders() {
|
||||
const headers = {
|
||||
'Content-Type': 'application/json'
|
||||
};
|
||||
|
||||
const token = localStorage.getItem(STORAGE_KEYS.TOKEN);
|
||||
if (token) {
|
||||
headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
// 通用请求方法
|
||||
async request(url, options = {}) {
|
||||
const config = {
|
||||
method: options.method || 'GET',
|
||||
headers: this.getHeaders(),
|
||||
...options
|
||||
};
|
||||
|
||||
if (options.body && typeof options.body === 'object') {
|
||||
config.body = JSON.stringify(options.body);
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(this.baseURL + url, config);
|
||||
const data = await response.json();
|
||||
|
||||
if (data.code === 401) {
|
||||
this.handleUnauthorized();
|
||||
throw new Error('未授权,请重新登录');
|
||||
}
|
||||
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error('API请求错误:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// GET请求
|
||||
async get(url) {
|
||||
return this.request(url, { method: 'GET' });
|
||||
}
|
||||
|
||||
// POST请求
|
||||
async post(url, body) {
|
||||
return this.request(url, { method: 'POST', body });
|
||||
}
|
||||
|
||||
// PUT请求
|
||||
async put(url, body) {
|
||||
return this.request(url, { method: 'PUT', body });
|
||||
}
|
||||
|
||||
// DELETE请求
|
||||
async delete(url) {
|
||||
return this.request(url, { method: 'DELETE' });
|
||||
}
|
||||
|
||||
// 处理未授权情况
|
||||
handleUnauthorized() {
|
||||
localStorage.removeItem(STORAGE_KEYS.TOKEN);
|
||||
localStorage.removeItem(STORAGE_KEYS.USER_INFO);
|
||||
window.location.href = 'login.html';
|
||||
}
|
||||
}
|
||||
|
||||
// 创建API实例
|
||||
const api = new API();
|
||||
|
||||
// 工具函数
|
||||
const utils = {
|
||||
// 显示提示消息
|
||||
showMessage(message, type = 'info') {
|
||||
alert(message);
|
||||
},
|
||||
|
||||
// 显示成功消息
|
||||
showSuccess(message) {
|
||||
this.showMessage(message, 'success');
|
||||
},
|
||||
|
||||
// 显示错误消息
|
||||
showError(message) {
|
||||
this.showMessage(message, 'error');
|
||||
},
|
||||
|
||||
// 确认对话框
|
||||
confirm(message) {
|
||||
return window.confirm(message);
|
||||
},
|
||||
|
||||
// 格式化日期
|
||||
formatDate(dateString) {
|
||||
if (!dateString) return '-';
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleDateString('zh-CN');
|
||||
},
|
||||
|
||||
// 格式化日期时间
|
||||
formatDateTime(dateString) {
|
||||
if (!dateString) return '-';
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleString('zh-CN');
|
||||
},
|
||||
|
||||
// 获取当前用户信息
|
||||
getCurrentUser() {
|
||||
const userStr = localStorage.getItem(STORAGE_KEYS.USER_INFO);
|
||||
return userStr ? JSON.parse(userStr) : null;
|
||||
},
|
||||
|
||||
// 检查用户角色
|
||||
hasRole(role) {
|
||||
const user = this.getCurrentUser();
|
||||
return user && user.role === role;
|
||||
},
|
||||
|
||||
// 退出登录
|
||||
logout() {
|
||||
if (this.confirm('确定要退出登录吗?')) {
|
||||
localStorage.removeItem(STORAGE_KEYS.TOKEN);
|
||||
localStorage.removeItem(STORAGE_KEYS.USER_INFO);
|
||||
window.location.href = 'login.html';
|
||||
}
|
||||
},
|
||||
|
||||
// 检查登录状态
|
||||
checkAuth() {
|
||||
const token = localStorage.getItem(STORAGE_KEYS.TOKEN);
|
||||
if (!token) {
|
||||
window.location.href = 'login.html';
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
// 获取状态标签HTML
|
||||
getStatusBadge(status, type) {
|
||||
const badges = {
|
||||
// 工单状态
|
||||
pending: '<span class="badge badge-info">待处理</span>',
|
||||
appointed: '<span class="badge badge-info">已预约</span>',
|
||||
in_progress: '<span class="badge badge-warning">进行中</span>',
|
||||
completed: '<span class="badge badge-success">已完成</span>',
|
||||
cancelled: '<span class="badge badge-secondary">已取消</span>',
|
||||
|
||||
// 支付状态
|
||||
unpaid: '<span class="badge badge-danger">未支付</span>',
|
||||
paid: '<span class="badge badge-success">已支付</span>',
|
||||
refunded: '<span class="badge badge-secondary">已退款</span>',
|
||||
|
||||
// 预约状态
|
||||
confirmed: '<span class="badge badge-success">已确认</span>',
|
||||
|
||||
// 车辆状态
|
||||
normal: '<span class="badge badge-success">正常</span>',
|
||||
in_service: '<span class="badge badge-warning">维修中</span>'
|
||||
};
|
||||
|
||||
return badges[status] || `<span class="badge badge-secondary">${status}</span>`;
|
||||
},
|
||||
|
||||
// 获取服务类型文本
|
||||
getServiceTypeText(type) {
|
||||
const types = {
|
||||
maintenance: '保养维护',
|
||||
repair: '维修服务',
|
||||
beauty: '美容服务',
|
||||
insurance: '保险代理'
|
||||
};
|
||||
return types[type] || type;
|
||||
},
|
||||
|
||||
// 获取用户角色文本
|
||||
getRoleText(role) {
|
||||
const roles = {
|
||||
admin: '管理员',
|
||||
staff: '工作人员',
|
||||
customer: '客户'
|
||||
};
|
||||
return roles[role] || role;
|
||||
}
|
||||
};
|
||||
52
frontend/js/config.js
Normal file
52
frontend/js/config.js
Normal file
@@ -0,0 +1,52 @@
|
||||
// API配置
|
||||
const API_CONFIG = {
|
||||
BASE_URL: 'http://localhost:8080/api',
|
||||
TIMEOUT: 30000
|
||||
};
|
||||
|
||||
// API端点
|
||||
const API_ENDPOINTS = {
|
||||
// 认证相关
|
||||
LOGIN: '/auth/login',
|
||||
LOGOUT: '/auth/logout',
|
||||
REGISTER: '/auth/register',
|
||||
|
||||
// 用户管理
|
||||
USERS: '/users',
|
||||
USER_BY_ID: (id) => `/users/${id}`,
|
||||
USERS_BY_ROLE: (role) => `/users/role/${role}`,
|
||||
CHANGE_PASSWORD: (id) => `/users/${id}/password`,
|
||||
|
||||
// 车辆管理
|
||||
VEHICLES: '/vehicles',
|
||||
VEHICLE_BY_ID: (id) => `/vehicles/${id}`,
|
||||
VEHICLES_BY_CUSTOMER: (customerId) => `/vehicles/customer/${customerId}`,
|
||||
VEHICLE_BY_PLATE: (plate) => `/vehicles/plate/${plate}`,
|
||||
|
||||
// 工单管理
|
||||
ORDERS: '/orders',
|
||||
ORDER_BY_ID: (id) => `/orders/${id}`,
|
||||
ORDERS_BY_CUSTOMER: (customerId) => `/orders/customer/${customerId}`,
|
||||
ORDERS_BY_VEHICLE: (vehicleId) => `/orders/vehicle/${vehicleId}`,
|
||||
ORDERS_BY_STATUS: (status) => `/orders/status/${status}`,
|
||||
|
||||
// 配件管理
|
||||
PARTS: '/parts',
|
||||
PART_BY_ID: (id) => `/parts/${id}`,
|
||||
PARTS_BY_CATEGORY: (category) => `/parts/category/${category}`,
|
||||
PARTS_LOW_STOCK: '/parts/low-stock',
|
||||
|
||||
// 预约管理
|
||||
APPOINTMENTS: '/appointments',
|
||||
APPOINTMENT_BY_ID: (id) => `/appointments/${id}`,
|
||||
APPOINTMENTS_BY_CUSTOMER: (customerId) => `/appointments/customer/${customerId}`,
|
||||
APPOINTMENTS_BY_STATUS: (status) => `/appointments/status/${status}`,
|
||||
CANCEL_APPOINTMENT: (id) => `/appointments/${id}/cancel`
|
||||
};
|
||||
|
||||
// 本地存储键名
|
||||
const STORAGE_KEYS = {
|
||||
TOKEN: 'car_maintenance_token',
|
||||
USER_INFO: 'car_maintenance_user',
|
||||
REMEMBER_ME: 'car_maintenance_remember'
|
||||
};
|
||||
102
frontend/js/login.js
Normal file
102
frontend/js/login.js
Normal file
@@ -0,0 +1,102 @@
|
||||
// 登录页面JavaScript
|
||||
|
||||
// 页面加载时检查是否已登录
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
const token = localStorage.getItem(STORAGE_KEYS.TOKEN);
|
||||
if (token) {
|
||||
const user = utils.getCurrentUser();
|
||||
if (user) {
|
||||
redirectToDashboard(user.role);
|
||||
}
|
||||
}
|
||||
|
||||
// 回车键登录
|
||||
document.getElementById('password').addEventListener('keypress', (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
handleLogin();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 处理登录
|
||||
async function handleLogin() {
|
||||
const username = document.getElementById('username').value.trim();
|
||||
const password = document.getElementById('password').value.trim();
|
||||
const role = document.getElementById('role').value;
|
||||
|
||||
// 验证输入
|
||||
if (!username) {
|
||||
utils.showError('请输入用户名');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!password) {
|
||||
utils.showError('请输入密码');
|
||||
return;
|
||||
}
|
||||
|
||||
// 禁用登录按钮
|
||||
const loginBtn = document.querySelector('.btn-login');
|
||||
const originalText = loginBtn.textContent;
|
||||
loginBtn.disabled = true;
|
||||
loginBtn.textContent = '登录中...';
|
||||
|
||||
try {
|
||||
// 调用登录API
|
||||
const response = await api.post(API_ENDPOINTS.LOGIN, {
|
||||
username: username,
|
||||
password: password
|
||||
});
|
||||
|
||||
if (response.code === 200) {
|
||||
const { token, userInfo } = response.data;
|
||||
|
||||
// 验证角色
|
||||
if (userInfo.role !== role) {
|
||||
utils.showError('登录角色不匹配,请选择正确的角色');
|
||||
loginBtn.disabled = false;
|
||||
loginBtn.textContent = originalText;
|
||||
return;
|
||||
}
|
||||
|
||||
// 保存登录信息
|
||||
localStorage.setItem(STORAGE_KEYS.TOKEN, token);
|
||||
localStorage.setItem(STORAGE_KEYS.USER_INFO, JSON.stringify(userInfo));
|
||||
|
||||
utils.showSuccess('登录成功!');
|
||||
|
||||
// 延迟跳转以显示成功消息
|
||||
setTimeout(() => {
|
||||
redirectToDashboard(userInfo.role);
|
||||
}, 500);
|
||||
|
||||
} else {
|
||||
utils.showError(response.message || '登录失败');
|
||||
loginBtn.disabled = false;
|
||||
loginBtn.textContent = originalText;
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('登录错误:', error);
|
||||
utils.showError('登录失败,请检查网络连接');
|
||||
loginBtn.disabled = false;
|
||||
loginBtn.textContent = originalText;
|
||||
}
|
||||
}
|
||||
|
||||
// 根据角色跳转到对应的仪表板
|
||||
function redirectToDashboard(role) {
|
||||
switch (role) {
|
||||
case 'admin':
|
||||
window.location.href = 'admin/dashboard.html';
|
||||
break;
|
||||
case 'staff':
|
||||
window.location.href = 'staff/dashboard.html';
|
||||
break;
|
||||
case 'customer':
|
||||
window.location.href = 'customer/dashboard.html';
|
||||
break;
|
||||
default:
|
||||
utils.showError('未知的用户角色');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user