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:
wangziqi
2026-01-07 14:28:50 +08:00
commit cfae122685
45 changed files with 5447 additions and 0 deletions

View File

@@ -0,0 +1,361 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>客户中心 - 车管家4S店车辆维保管理系统</title>
<link rel="stylesheet" href="../css/common.css">
<link rel="stylesheet" href="../css/dashboard.css">
</head>
<body>
<div class="dashboard-container">
<div class="sidebar">
<div class="sidebar-header">
<h2>车管家系统</h2>
<p>客户中心</p>
</div>
<div class="sidebar-menu">
<div class="menu-item active" onclick="showSection('myvehicles')">
<span class="menu-icon">🚗</span>
<span>我的车辆</span>
</div>
<div class="menu-item" onclick="showSection('myorders')">
<span class="menu-icon">📋</span>
<span>维保记录</span>
</div>
<div class="menu-item" onclick="showSection('appointments')">
<span class="menu-icon">📅</span>
<span>我的预约</span>
</div>
<div class="menu-item" onclick="showSection('newappointment')">
<span class="menu-icon"></span>
<span>在线预约</span>
</div>
</div>
</div>
<div class="main-content">
<div class="top-nav">
<div class="top-nav-left">
<h1>客户中心</h1>
</div>
<div class="top-nav-right">
<div class="user-info">
<div class="user-avatar" id="userAvatar">C</div>
<span class="user-name" id="userName">客户</span>
</div>
<button class="btn-logout" onclick="utils.logout()">退出登录</button>
</div>
</div>
<div id="myvehicles-section" class="section">
<div class="content-card">
<div class="content-header">
<h2>我的车辆</h2>
</div>
<div class="content-body">
<div id="vehiclesGrid" style="display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:20px;">
<p class="empty-state">加载中...</p>
</div>
</div>
</div>
</div>
<div id="myorders-section" class="section" style="display: none;">
<div class="content-card">
<div class="content-header">
<h2>维保记录</h2>
</div>
<div class="content-body">
<table class="table">
<thead>
<tr>
<th>工单编号</th>
<th>服务类型</th>
<th>车牌号</th>
<th>费用</th>
<th>状态</th>
<th>创建时间</th>
</tr>
</thead>
<tbody id="ordersBody">
<tr><td colspan="6" class="empty-state">加载中...</td></tr>
</tbody>
</table>
</div>
</div>
</div>
<div id="appointments-section" class="section" style="display: none;">
<div class="content-card">
<div class="content-header">
<h2>我的预约</h2>
</div>
<div class="content-body">
<table class="table">
<thead>
<tr>
<th>服务类型</th>
<th>车牌号</th>
<th>预约时间</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody id="appointmentsBody">
<tr><td colspan="5" class="empty-state">加载中...</td></tr>
</tbody>
</table>
</div>
</div>
</div>
<div id="newappointment-section" class="section" style="display: none;">
<div class="content-card">
<div class="content-header">
<h2>在线预约服务</h2>
</div>
<div class="content-body">
<form id="appointmentForm" style="max-width:600px;">
<div class="form-group">
<label>选择车辆</label>
<select id="vehicleSelect" required>
<option value="">请选择车辆</option>
</select>
</div>
<div class="form-group">
<label>服务类型</label>
<select id="serviceType" required>
<option value="maintenance">保养维护</option>
<option value="repair">维修服务</option>
<option value="beauty">美容服务</option>
<option value="insurance">保险代理</option>
</select>
</div>
<div class="form-group">
<label>预约时间</label>
<input type="datetime-local" id="appointmentTime" required>
</div>
<div class="form-group">
<label>联系电话</label>
<input type="tel" id="contactPhone" required>
</div>
<div class="form-group">
<label>预约说明</label>
<textarea id="description" placeholder="请描述您的需求"></textarea>
</div>
<button type="submit" class="btn btn-primary">提交预约</button>
</form>
</div>
</div>
</div>
</div>
</div>
<script src="../js/config.js"></script>
<script src="../js/api.js"></script>
<script>
if (!utils.checkAuth() || !utils.hasRole('customer')) {
window.location.href = '../login.html';
}
let currentCustomerId = null;
window.addEventListener('DOMContentLoaded', async () => {
const user = utils.getCurrentUser();
if (user) {
document.getElementById('userName').textContent = user.realName;
document.getElementById('userAvatar').textContent = user.realName.charAt(0);
document.getElementById('contactPhone').value = user.phone;
await loadCustomerData(user.userId);
}
});
async function loadCustomerData(userId) {
try {
const usersRes = await api.get(API_ENDPOINTS.USERS);
const customers = usersRes.data?.filter(u => u.role === 'customer') || [];
const currentUser = customers.find(c => c.userId === userId);
if (currentUser) {
currentCustomerId = currentUser.userId;
loadVehicles();
loadOrders();
loadAppointments();
loadVehicleOptions();
}
} catch (error) {
console.error('加载数据失败:', error);
}
}
async function loadVehicles() {
try {
const response = await api.get(API_ENDPOINTS.VEHICLES);
if (response.code === 200 && response.data) {
const myVehicles = response.data.filter(v => v.customerId === currentCustomerId);
displayVehicles(myVehicles);
}
} catch (error) {
console.error('加载车辆失败:', error);
}
}
function displayVehicles(vehicles) {
const grid = document.getElementById('vehiclesGrid');
if (vehicles.length === 0) {
grid.innerHTML = '<p class="empty-state">暂无车辆</p>';
return;
}
grid.innerHTML = vehicles.map(v => `
<div class="card">
<h3 style="color:#1890ff;">${v.licensePlate}</h3>
<p><strong>品牌:</strong> ${v.brand} ${v.model}</p>
<p><strong>颜色:</strong> ${v.color || '-'}</p>
<p><strong>里程:</strong> ${v.mileage || 0} 公里</p>
<p><strong>上次保养:</strong> ${utils.formatDate(v.lastMaintenanceDate)}</p>
<p><strong>下次保养:</strong> ${utils.formatDate(v.nextMaintenanceDate)}</p>
<p><strong>状态:</strong> ${utils.getStatusBadge(v.status)}</p>
</div>
`).join('');
}
async function loadOrders() {
try {
const [ordersRes, vehiclesRes] = await Promise.all([
api.get(API_ENDPOINTS.ORDERS),
api.get(API_ENDPOINTS.VEHICLES)
]);
if (ordersRes.code === 200 && ordersRes.data) {
const myOrders = ordersRes.data.filter(o => o.customerId === currentCustomerId);
const vehicles = vehiclesRes.data || [];
const tbody = document.getElementById('ordersBody');
if (myOrders.length === 0) {
tbody.innerHTML = '<tr><td colspan="6" class="empty-state">暂无维保记录</td></tr>';
return;
}
tbody.innerHTML = myOrders.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>¥${o.totalCost || 0}</td>
<td>${utils.getStatusBadge(o.status)}</td>
<td>${utils.formatDateTime(o.createTime)}</td>
</tr>
`;
}).join('');
}
} catch (error) {
console.error('加载工单失败:', error);
}
}
async function loadAppointments() {
try {
const [appointmentsRes, vehiclesRes] = await Promise.all([
api.get(API_ENDPOINTS.APPOINTMENTS),
api.get(API_ENDPOINTS.VEHICLES)
]);
if (appointmentsRes.code === 200 && appointmentsRes.data) {
const myAppointments = appointmentsRes.data.filter(a => a.customerId === currentCustomerId);
const vehicles = vehiclesRes.data || [];
const tbody = document.getElementById('appointmentsBody');
if (myAppointments.length === 0) {
tbody.innerHTML = '<tr><td colspan="5" class="empty-state">暂无预约记录</td></tr>';
return;
}
tbody.innerHTML = myAppointments.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)}</td>
<td>
${a.status === 'pending' ? `<button class="btn btn-danger" onclick="cancelAppointment(${a.appointmentId})">取消</button>` : '-'}
</td>
</tr>
`;
}).join('');
}
} catch (error) {
console.error('加载预约失败:', error);
}
}
async function loadVehicleOptions() {
try {
const response = await api.get(API_ENDPOINTS.VEHICLES);
if (response.code === 200 && response.data) {
const myVehicles = response.data.filter(v => v.customerId === currentCustomerId);
const select = document.getElementById('vehicleSelect');
select.innerHTML = '<option value="">请选择车辆</option>' +
myVehicles.map(v => `<option value="${v.vehicleId}">${v.licensePlate} - ${v.brand} ${v.model}</option>`).join('');
}
} catch (error) {
console.error('加载车辆选项失败:', error);
}
}
document.getElementById('appointmentForm').addEventListener('submit', async (e) => {
e.preventDefault();
const data = {
customerId: currentCustomerId,
vehicleId: parseInt(document.getElementById('vehicleSelect').value),
serviceType: document.getElementById('serviceType').value,
appointmentTime: document.getElementById('appointmentTime').value,
contactPhone: document.getElementById('contactPhone').value,
description: document.getElementById('description').value
};
try {
const response = await api.post(API_ENDPOINTS.APPOINTMENTS, data);
if (response.code === 200) {
utils.showSuccess('预约成功!');
document.getElementById('appointmentForm').reset();
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('操作失败');
}
}
}
function showSection(name) {
document.querySelectorAll('.section').forEach(s => s.style.display = 'none');
document.querySelectorAll('.menu-item').forEach(m => m.classList.remove('active'));
event.currentTarget.classList.add('active');
document.getElementById(name + '-section').style.display = 'block';
}
</script>
</body>
</html>