Files
car-maintenance-system/frontend/customer/dashboard.html
wangziqi cfae122685 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>
2026-01-07 14:28:50 +08:00

362 lines
16 KiB
HTML
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.

<!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>