You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2037 lines
79 KiB
HTML
2037 lines
79 KiB
HTML
1 week ago
|
<!DOCTYPE html>
|
||
|
<html lang="zh-CN">
|
||
|
|
||
|
<head>
|
||
|
<meta charset="UTF-8">
|
||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
|
<title>垃圾转运管理系统</title>
|
||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||
|
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700&display=swap" rel="stylesheet">
|
||
|
<script src="chart.js"></script>
|
||
|
<style>
|
||
|
/* ==== 全局样式 ==== */
|
||
|
* {
|
||
|
margin: 0;
|
||
|
padding: 0;
|
||
|
box-sizing: border-box;
|
||
|
}
|
||
|
|
||
|
body {
|
||
|
margin: 0;
|
||
|
padding: 0;
|
||
|
font-family: 'Noto Sans SC', 'Arial', sans-serif;
|
||
|
background-color: #f5f9ff;
|
||
|
color: #333;
|
||
|
min-height: 100vh;
|
||
|
padding: 20px;
|
||
|
}
|
||
|
|
||
|
/* ==== 主容器 ==== */
|
||
|
.main-container {
|
||
|
display: flex;
|
||
|
/* min-height: 100vh; */
|
||
|
height: calc(100vh - 40px);
|
||
|
gap: 20px;
|
||
|
}
|
||
|
|
||
|
/* ==== 内容区域 ==== */
|
||
|
.content-area {
|
||
|
flex: 1;
|
||
|
background: #ffffff;
|
||
|
border-radius: 12px;
|
||
|
box-shadow: 0 4px 20px rgba(0, 75, 150, 0.1);
|
||
|
padding: 20px;
|
||
|
display: flex;
|
||
|
flex-direction: column;
|
||
|
overflow: hidden;
|
||
|
}
|
||
|
|
||
|
/* ==== 头部区域 ==== */
|
||
|
.header {
|
||
|
display: flex;
|
||
|
justify-content: space-between;
|
||
|
align-items: center;
|
||
|
margin-bottom: 20px;
|
||
|
padding-bottom: 15px;
|
||
|
border-bottom: 1px solid #e1e9f5;
|
||
|
}
|
||
|
|
||
|
.header-title {
|
||
|
color: #1a4b8c;
|
||
|
font-size: 24px;
|
||
|
font-weight: 600;
|
||
|
display: flex;
|
||
|
align-items: center;
|
||
|
gap: 10px;
|
||
|
}
|
||
|
|
||
|
.header-actions {
|
||
|
display: flex;
|
||
|
gap: 10px;
|
||
|
}
|
||
|
|
||
|
.action-btn {
|
||
|
background: linear-gradient(135deg, #2a7de1, #1a4b8c);
|
||
|
color: #fff;
|
||
|
border: none;
|
||
|
padding: 8px 16px;
|
||
|
border-radius: 6px;
|
||
|
cursor: pointer;
|
||
|
transition: all 0.3s ease;
|
||
|
font-size: 14px;
|
||
|
box-shadow: 0 2px 8px rgba(42, 125, 225, 0.2);
|
||
|
display: flex;
|
||
|
align-items: center;
|
||
|
gap: 8px;
|
||
|
}
|
||
|
|
||
|
.action-btn:hover {
|
||
|
background: linear-gradient(135deg, #1a4b8c, #2a7de1);
|
||
|
transform: translateY(-2px);
|
||
|
box-shadow: 0 4px 12px rgba(42, 125, 225, 0.3);
|
||
|
}
|
||
|
|
||
|
/* ==== 标签页 ==== */
|
||
|
.nav-tabs {
|
||
|
display: flex;
|
||
|
background: #e1e9f5;
|
||
|
border-radius: 10px;
|
||
|
padding: 5px;
|
||
|
margin-bottom: 20px;
|
||
|
}
|
||
|
|
||
|
.nav-tab {
|
||
|
flex: 1;
|
||
|
padding: 12px 20px;
|
||
|
background: transparent;
|
||
|
color: #4a6fa5;
|
||
|
border: none;
|
||
|
border-radius: 8px;
|
||
|
cursor: pointer;
|
||
|
transition: all 0.3s ease;
|
||
|
font-size: 14px;
|
||
|
font-weight: 500;
|
||
|
}
|
||
|
|
||
|
.nav-tab.active {
|
||
|
background: #ffffff;
|
||
|
color: #1a4b8c;
|
||
|
font-weight: 600;
|
||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||
|
}
|
||
|
|
||
|
.tab-content {
|
||
|
display: none;
|
||
|
flex: 1;
|
||
|
overflow-y: auto;
|
||
|
padding-right: 5px;
|
||
|
|
||
|
/* 滚动条整体样式 */
|
||
|
scrollbar-width: thin;
|
||
|
/* Firefox */
|
||
|
scrollbar-color: #d1e0f5 #ffffff;
|
||
|
/* Firefox */
|
||
|
}
|
||
|
|
||
|
/* Chrome/Edge/Safari 滚动条样式 */
|
||
|
.tab-content::-webkit-scrollbar {
|
||
|
width: 8px;
|
||
|
/* 垂直滚动条宽度 */
|
||
|
height: 8px;
|
||
|
/* 水平滚动条高度 */
|
||
|
}
|
||
|
|
||
|
.tab-content::-webkit-scrollbar-track {
|
||
|
background: #ffffff;
|
||
|
/* 轨道颜色与背景一致 */
|
||
|
border-radius: 4px;
|
||
|
}
|
||
|
|
||
|
.tab-content::-webkit-scrollbar-thumb {
|
||
|
background-color: #d1e0f5;
|
||
|
/* 浅蓝色滑块 */
|
||
|
border-radius: 4px;
|
||
|
border: 2px solid #ffffff;
|
||
|
/* 创建边距效果 */
|
||
|
}
|
||
|
|
||
|
.tab-content::-webkit-scrollbar-thumb:hover {
|
||
|
background-color: #a8c4eb;
|
||
|
/* 悬停时稍深的蓝色 */
|
||
|
}
|
||
|
|
||
|
.tab-content.active {
|
||
|
display: block;
|
||
|
animation: fadeIn 0.5s ease;
|
||
|
}
|
||
|
|
||
|
@keyframes fadeIn {
|
||
|
from {
|
||
|
opacity: 0;
|
||
|
transform: translateY(10px);
|
||
|
}
|
||
|
|
||
|
to {
|
||
|
opacity: 1;
|
||
|
transform: translateY(0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* ==== 卡片样式 ==== */
|
||
|
.card {
|
||
|
background: #ffffff;
|
||
|
border-radius: 12px;
|
||
|
padding: 20px;
|
||
|
margin-bottom: 20px;
|
||
|
border: 1px solid #e1e9f5;
|
||
|
box-shadow: 0 2px 10px rgba(0, 75, 150, 0.05);
|
||
|
}
|
||
|
|
||
|
.card-title {
|
||
|
color: #1a4b8c;
|
||
|
font-size: 18px;
|
||
|
font-weight: 600;
|
||
|
margin-bottom: 15px;
|
||
|
display: flex;
|
||
|
align-items: center;
|
||
|
gap: 10px;
|
||
|
}
|
||
|
|
||
|
.card-title i {
|
||
|
color: #2a7de1;
|
||
|
}
|
||
|
|
||
|
/* ==== 统计卡片 ==== */
|
||
|
.stats-grid {
|
||
|
display: grid;
|
||
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||
|
gap: 15px;
|
||
|
margin-bottom: 20px;
|
||
|
}
|
||
|
|
||
|
.stat-card {
|
||
|
background: #f5f9ff;
|
||
|
border-radius: 8px;
|
||
|
padding: 20px;
|
||
|
text-align: center;
|
||
|
border: 1px solid #e1e9f5;
|
||
|
transition: all 0.3s ease;
|
||
|
}
|
||
|
|
||
|
.stat-card:hover {
|
||
|
transform: translateY(-5px);
|
||
|
box-shadow: 0 8px 20px rgba(0, 75, 150, 0.1);
|
||
|
}
|
||
|
|
||
|
.stat-value {
|
||
|
color: #2a7de1;
|
||
|
font-size: 28px;
|
||
|
font-weight: 700;
|
||
|
display: block;
|
||
|
margin-bottom: 5px;
|
||
|
}
|
||
|
|
||
|
.stat-label {
|
||
|
color: #4a6fa5;
|
||
|
font-size: 14px;
|
||
|
}
|
||
|
|
||
|
/* ==== 表格样式 ==== */
|
||
|
.data-table {
|
||
|
width: 100%;
|
||
|
background: #ffffff;
|
||
|
border-radius: 10px;
|
||
|
overflow: hidden;
|
||
|
border-collapse: separate;
|
||
|
border-spacing: 0;
|
||
|
box-shadow: 0 2px 10px rgba(0, 75, 150, 0.05);
|
||
|
}
|
||
|
|
||
|
.data-table th,
|
||
|
.data-table td {
|
||
|
padding: 12px 15px;
|
||
|
text-align: left;
|
||
|
border-bottom: 1px solid #e1e9f5;
|
||
|
}
|
||
|
|
||
|
.data-table th {
|
||
|
background: #f5f9ff;
|
||
|
color: #1a4b8c;
|
||
|
font-weight: 600;
|
||
|
font-size: 14px;
|
||
|
}
|
||
|
|
||
|
.data-table td {
|
||
|
color: #4a6fa5;
|
||
|
font-size: 13px;
|
||
|
}
|
||
|
|
||
|
.data-table tr:last-child td {
|
||
|
border-bottom: none;
|
||
|
}
|
||
|
|
||
|
.data-table tr:hover {
|
||
|
background: #f5f9ff;
|
||
|
}
|
||
|
|
||
|
/* ==== 状态标签 ==== */
|
||
|
.status-badge {
|
||
|
padding: 4px 8px;
|
||
|
border-radius: 12px;
|
||
|
font-size: 12px;
|
||
|
font-weight: 500;
|
||
|
text-align: center;
|
||
|
display: inline-block;
|
||
|
min-width: 60px;
|
||
|
}
|
||
|
|
||
|
.status-active {
|
||
|
background: rgba(40, 167, 69, 0.1);
|
||
|
color: #28a745;
|
||
|
border: 1px solid rgba(40, 167, 69, 0.3);
|
||
|
}
|
||
|
|
||
|
.status-inactive {
|
||
|
background: rgba(220, 53, 69, 0.1);
|
||
|
color: #dc3545;
|
||
|
border: 1px solid rgba(220, 53, 69, 0.3);
|
||
|
}
|
||
|
|
||
|
.status-pending {
|
||
|
background: rgba(255, 193, 7, 0.1);
|
||
|
color: #ffc107;
|
||
|
border: 1px solid rgba(255, 193, 7, 0.3);
|
||
|
}
|
||
|
|
||
|
/* ==== 表单样式 ==== */
|
||
|
.form-grid {
|
||
|
display: grid;
|
||
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||
|
gap: 15px;
|
||
|
margin-bottom: 20px;
|
||
|
}
|
||
|
|
||
|
.filter-group {
|
||
|
display: flex;
|
||
|
flex-direction: column;
|
||
|
}
|
||
|
|
||
|
.filter-label {
|
||
|
color: #4a6fa5;
|
||
|
font-size: 14px;
|
||
|
margin-bottom: 5px;
|
||
|
font-weight: 500;
|
||
|
}
|
||
|
|
||
|
.filter-select,
|
||
|
.search-input {
|
||
|
background: #f5f9ff;
|
||
|
border: 1px solid #d1e0f5;
|
||
|
border-radius: 6px;
|
||
|
padding: 10px;
|
||
|
color: #1a4b8c;
|
||
|
font-size: 14px;
|
||
|
transition: all 0.3s ease;
|
||
|
}
|
||
|
|
||
|
.filter-select:focus,
|
||
|
.search-input:focus {
|
||
|
border-color: #2a7de1;
|
||
|
box-shadow: 0 0 0 3px rgba(42, 125, 225, 0.2);
|
||
|
outline: none;
|
||
|
}
|
||
|
|
||
|
/* ==== 图表容器 ==== */
|
||
|
.chart-container {
|
||
|
background: #ffffff;
|
||
|
border-radius: 8px;
|
||
|
padding: 20px;
|
||
|
margin-bottom: 20px;
|
||
|
border: 1px solid #e1e9f5;
|
||
|
box-shadow: 0 2px 8px rgba(0, 75, 150, 0.05);
|
||
|
}
|
||
|
|
||
|
.chart-title {
|
||
|
color: #1a4b8c;
|
||
|
font-size: 16px;
|
||
|
font-weight: 600;
|
||
|
margin-bottom: 15px;
|
||
|
text-align: center;
|
||
|
border-bottom: 1px solid #e1e9f5;
|
||
|
padding-bottom: 10px;
|
||
|
}
|
||
|
|
||
|
.chart-canvas {
|
||
|
height: 250px;
|
||
|
}
|
||
|
|
||
|
.large-chart {
|
||
|
grid-column: 1 / -1;
|
||
|
}
|
||
|
|
||
|
.large-chart .chart-canvas {
|
||
|
height: 300px;
|
||
|
}
|
||
|
|
||
|
#attendanceChart,
|
||
|
#transferChart {
|
||
|
width: 100%;
|
||
|
height: 300px;
|
||
|
}
|
||
|
|
||
|
/* ==== 按钮样式 ==== */
|
||
|
.btn {
|
||
|
background: #f5f9ff;
|
||
|
color: #2a7de1;
|
||
|
border: 1px solid #d1e0f5;
|
||
|
padding: 8px 16px;
|
||
|
border-radius: 6px;
|
||
|
cursor: pointer;
|
||
|
transition: all 0.3s ease;
|
||
|
font-size: 12px;
|
||
|
margin-right: 5px;
|
||
|
display: inline-flex;
|
||
|
align-items: center;
|
||
|
gap: 5px;
|
||
|
}
|
||
|
|
||
|
.btn:hover {
|
||
|
background: #e1e9f5;
|
||
|
}
|
||
|
|
||
|
.btn-primary {
|
||
|
background: rgba(42, 125, 225, 0.1);
|
||
|
color: #2a7de1;
|
||
|
border-color: rgba(42, 125, 225, 0.3);
|
||
|
}
|
||
|
|
||
|
.btn-primary:hover {
|
||
|
background: rgba(42, 125, 225, 0.2);
|
||
|
}
|
||
|
|
||
|
.btn-success {
|
||
|
background: rgba(40, 167, 69, 0.1);
|
||
|
color: #28a745;
|
||
|
border-color: rgba(40, 167, 69, 0.3);
|
||
|
}
|
||
|
|
||
|
.btn-success:hover {
|
||
|
background: rgba(40, 167, 69, 0.2);
|
||
|
}
|
||
|
|
||
|
.btn-warning {
|
||
|
background: rgba(255, 193, 7, 0.1);
|
||
|
color: #ffc107;
|
||
|
border-color: rgba(255, 193, 7, 0.3);
|
||
|
}
|
||
|
|
||
|
.btn-warning:hover {
|
||
|
background: rgba(255, 193, 7, 0.2);
|
||
|
}
|
||
|
|
||
|
.btn-danger {
|
||
|
background: rgba(220, 53, 69, 0.1);
|
||
|
color: #dc3545;
|
||
|
border-color: rgba(220, 53, 69, 0.3);
|
||
|
}
|
||
|
|
||
|
.btn-danger:hover {
|
||
|
background: rgba(220, 53, 69, 0.2);
|
||
|
}
|
||
|
|
||
|
/* ==== 模态框 ==== */
|
||
|
.modal {
|
||
|
display: none;
|
||
|
position: fixed;
|
||
|
top: 0;
|
||
|
left: 0;
|
||
|
width: 100%;
|
||
|
height: 100%;
|
||
|
background: rgba(0, 0, 0, 0.5);
|
||
|
z-index: 1000;
|
||
|
backdrop-filter: blur(5px);
|
||
|
}
|
||
|
|
||
|
.modal-content {
|
||
|
background: #ffffff;
|
||
|
margin: 5% auto;
|
||
|
padding: 30px;
|
||
|
border-radius: 15px;
|
||
|
width: 80%;
|
||
|
max-width: 800px;
|
||
|
max-height: 80vh;
|
||
|
overflow-y: auto;
|
||
|
box-shadow: 0 10px 30px rgba(0, 75, 150, 0.2);
|
||
|
}
|
||
|
|
||
|
.modal-header {
|
||
|
display: flex;
|
||
|
justify-content: space-between;
|
||
|
align-items: center;
|
||
|
margin-bottom: 20px;
|
||
|
padding-bottom: 10px;
|
||
|
border-bottom: 1px solid #e1e9f5;
|
||
|
}
|
||
|
|
||
|
.modal-title {
|
||
|
color: #1a4b8c;
|
||
|
font-size: 20px;
|
||
|
font-weight: 600;
|
||
|
}
|
||
|
|
||
|
.close {
|
||
|
color: #4a6fa5;
|
||
|
font-size: 28px;
|
||
|
font-weight: bold;
|
||
|
cursor: pointer;
|
||
|
transition: all 0.3s ease;
|
||
|
}
|
||
|
|
||
|
.close:hover {
|
||
|
color: #2a7de1;
|
||
|
}
|
||
|
|
||
|
.modal-body {
|
||
|
margin-bottom: 20px;
|
||
|
}
|
||
|
|
||
|
.modal-footer {
|
||
|
display: flex;
|
||
|
justify-content: flex-end;
|
||
|
gap: 10px;
|
||
|
padding-top: 20px;
|
||
|
border-top: 1px solid #e1e9f5;
|
||
|
}
|
||
|
|
||
|
/* ==== 表单组 ==== */
|
||
|
.form-group {
|
||
|
margin-bottom: 15px;
|
||
|
}
|
||
|
|
||
|
.form-group label {
|
||
|
display: block;
|
||
|
margin-bottom: 5px;
|
||
|
color: #4a6fa5;
|
||
|
font-size: 14px;
|
||
|
font-weight: 500;
|
||
|
}
|
||
|
|
||
|
.form-group input,
|
||
|
.form-group select,
|
||
|
.form-group textarea {
|
||
|
width: 100%;
|
||
|
padding: 10px;
|
||
|
background: #f5f9ff;
|
||
|
border: 1px solid #d1e0f5;
|
||
|
border-radius: 6px;
|
||
|
font-size: 14px;
|
||
|
color: #1a4b8c;
|
||
|
transition: all 0.3s ease;
|
||
|
}
|
||
|
|
||
|
.form-group input:focus,
|
||
|
.form-group select:focus,
|
||
|
.form-group textarea:focus {
|
||
|
border-color: #2a7de1;
|
||
|
box-shadow: 0 0 0 3px rgba(42, 125, 225, 0.2);
|
||
|
outline: none;
|
||
|
}
|
||
|
|
||
|
/* ==== 通知 ==== */
|
||
|
.notification {
|
||
|
position: fixed;
|
||
|
top: 20px;
|
||
|
right: 20px;
|
||
|
padding: 15px 20px;
|
||
|
border-radius: 8px;
|
||
|
color: white;
|
||
|
font-weight: 500;
|
||
|
z-index: 1001;
|
||
|
animation: slideIn 0.3s ease;
|
||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||
|
}
|
||
|
|
||
|
.notification.success {
|
||
|
background: rgba(40, 167, 69, 0.9);
|
||
|
}
|
||
|
|
||
|
.notification.error {
|
||
|
background: rgba(220, 53, 69, 0.9);
|
||
|
}
|
||
|
|
||
|
.notification.warning {
|
||
|
background: rgba(255, 193, 7, 0.9);
|
||
|
}
|
||
|
|
||
|
@keyframes slideIn {
|
||
|
from {
|
||
|
transform: translateX(100%);
|
||
|
opacity: 0;
|
||
|
}
|
||
|
|
||
|
to {
|
||
|
transform: translateX(0);
|
||
|
opacity: 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* ==== 详情模态框 ==== */
|
||
|
.detail-item {
|
||
|
margin-bottom: 15px;
|
||
|
padding-bottom: 15px;
|
||
|
border-bottom: 1px solid #e1e9f5;
|
||
|
}
|
||
|
|
||
|
.detail-label {
|
||
|
color: #4a6fa5;
|
||
|
font-size: 14px;
|
||
|
font-weight: 500;
|
||
|
margin-bottom: 5px;
|
||
|
}
|
||
|
|
||
|
.detail-value {
|
||
|
color: #1a4b8c;
|
||
|
font-size: 16px;
|
||
|
}
|
||
|
|
||
|
/* ==== 响应式设计 ==== */
|
||
|
@media (max-width: 768px) {
|
||
|
.main-container {
|
||
|
flex-direction: column;
|
||
|
}
|
||
|
|
||
|
.nav-tabs {
|
||
|
flex-wrap: wrap;
|
||
|
}
|
||
|
|
||
|
.nav-tab {
|
||
|
flex: none;
|
||
|
padding: 8px 12px;
|
||
|
font-size: 12px;
|
||
|
}
|
||
|
|
||
|
.stats-grid {
|
||
|
grid-template-columns: 1fr 1fr;
|
||
|
}
|
||
|
|
||
|
.form-grid {
|
||
|
grid-template-columns: 1fr;
|
||
|
}
|
||
|
|
||
|
.data-table {
|
||
|
font-size: 12px;
|
||
|
}
|
||
|
|
||
|
.data-table th,
|
||
|
.data-table td {
|
||
|
padding: 8px;
|
||
|
}
|
||
|
}
|
||
|
</style>
|
||
|
</head>
|
||
|
|
||
|
<body>
|
||
|
<div class="main-container">
|
||
|
<div class="content-area">
|
||
|
<div class="header">
|
||
|
<h1 class="header-title">
|
||
|
<i class="fas fa-truck"></i>
|
||
|
垃圾转运管理系统
|
||
|
</h1>
|
||
|
<div class="header-actions">
|
||
|
<button class="action-btn" onclick="location.href='index.html'">
|
||
|
<i class="fas fa-home-alt" style="color: orange;"></i> 回到首页
|
||
|
</button>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<div class="nav-tabs">
|
||
|
<button class="nav-tab active" onclick="switchTab('overview')">概览统计</button>
|
||
|
<button class="nav-tab" onclick="switchTab('standards')">考核标准</button>
|
||
|
<button class="nav-tab" onclick="switchTab('records')">转运记录</button>
|
||
|
<button class="nav-tab" onclick="switchTab('attendance')">出勤统计</button>
|
||
|
<button class="nav-tab" onclick="switchTab('stations')">中转站管理</button>
|
||
|
</div>
|
||
|
|
||
|
<!-- 概览统计 -->
|
||
|
<div id="overview" class="tab-content active">
|
||
|
<div class="card">
|
||
|
<div class="card-title">
|
||
|
<i class="fas fa-chart-pie"></i>
|
||
|
转运概览
|
||
|
</div>
|
||
|
<div class="header-actions" style="margin-bottom: 20px;">
|
||
|
<button class="action-btn" onclick="generateReport()">
|
||
|
<i class="fas fa-chart-bar"></i> 生成报告
|
||
|
</button>
|
||
|
<button class="action-btn" onclick="exportData()">
|
||
|
<i class="fas fa-download"></i> 导出数据
|
||
|
</button>
|
||
|
</div>
|
||
|
<div class="stats-grid">
|
||
|
<div class="stat-card">
|
||
|
<span class="stat-value" id="totalVehicles">24</span>
|
||
|
<div class="stat-label">总车辆数</div>
|
||
|
</div>
|
||
|
<div class="stat-card">
|
||
|
<span class="stat-value" id="activeVehicles">22</span>
|
||
|
<div class="stat-label">在线车辆</div>
|
||
|
</div>
|
||
|
<div class="stat-card">
|
||
|
<span class="stat-value" id="monthlyTransfers">1,256</span>
|
||
|
<div class="stat-label">本月转运次数</div>
|
||
|
</div>
|
||
|
<div class="stat-card">
|
||
|
<span class="stat-value" id="attendanceRate">92%</span>
|
||
|
<div class="stat-label">出勤率</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<div class="chart-container">
|
||
|
<div class="chart-title">月度出勤率趋势</div>
|
||
|
<div class="chart-canvas">
|
||
|
<canvas id="attendanceChart"></canvas>
|
||
|
</div>
|
||
|
|
||
|
</div>
|
||
|
|
||
|
<div class="chart-container">
|
||
|
<div class="chart-title">垃圾转运量统计</div>
|
||
|
<div class="chart-canvas">
|
||
|
<canvas id="transferChart"></canvas>
|
||
|
</div>
|
||
|
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<!-- 考核标准 -->
|
||
|
<div id="standards" class="tab-content">
|
||
|
<div class="card">
|
||
|
<div class="card-title">
|
||
|
<i class="fas fa-clipboard-check"></i>
|
||
|
河道考核标准设置
|
||
|
</div>
|
||
|
<div class="header-actions" style="margin-bottom: 20px;">
|
||
|
<button class="action-btn" onclick="addStandard()">
|
||
|
<i class="fas fa-plus"></i> 新增标准
|
||
|
</button>
|
||
|
<button class="action-btn" onclick="importStandards()">
|
||
|
<i class="fas fa-upload"></i> 导入标准
|
||
|
</button>
|
||
|
</div>
|
||
|
<table class="data-table">
|
||
|
<thead>
|
||
|
<tr>
|
||
|
<th>考核项目</th>
|
||
|
<th>标准分值</th>
|
||
|
<th>扣分标准</th>
|
||
|
<th>权重</th>
|
||
|
<th>状态</th>
|
||
|
<th>操作</th>
|
||
|
</tr>
|
||
|
</thead>
|
||
|
<tbody id="standardsTable">
|
||
|
<tr>
|
||
|
<td>河道清洁度</td>
|
||
|
<td>100分</td>
|
||
|
<td>发现垃圾每处扣5分</td>
|
||
|
<td>30%</td>
|
||
|
<td><span class="status-badge status-active">启用</span></td>
|
||
|
<td>
|
||
|
<button class="btn btn-primary" onclick="editStandard('std1')">
|
||
|
<i class="fas fa-edit"></i> 编辑
|
||
|
</button>
|
||
|
<button class="btn btn-danger" onclick="deleteStandard('std1')">
|
||
|
<i class="fas fa-trash"></i> 删除
|
||
|
</button>
|
||
|
</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td>转运及时性</td>
|
||
|
<td>100分</td>
|
||
|
<td>超时每小时扣10分</td>
|
||
|
<td>25%</td>
|
||
|
<td><span class="status-badge status-active">启用</span></td>
|
||
|
<td>
|
||
|
<button class="btn btn-primary" onclick="editStandard('std2')">
|
||
|
<i class="fas fa-edit"></i> 编辑
|
||
|
</button>
|
||
|
<button class="btn btn-danger" onclick="deleteStandard('std2')">
|
||
|
<i class="fas fa-trash"></i> 删除
|
||
|
</button>
|
||
|
</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td>设备维护</td>
|
||
|
<td>100分</td>
|
||
|
<td>故障每次扣15分</td>
|
||
|
<td>20%</td>
|
||
|
<td><span class="status-badge status-active">启用</span></td>
|
||
|
<td>
|
||
|
<button class="btn btn-primary" onclick="editStandard('std3')">
|
||
|
<i class="fas fa-edit"></i> 编辑
|
||
|
</button>
|
||
|
<button class="btn btn-danger" onclick="deleteStandard('std3')">
|
||
|
<i class="fas fa-trash"></i> 删除
|
||
|
</button>
|
||
|
</td>
|
||
|
</tr>
|
||
|
</tbody>
|
||
|
</table>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<!-- 转运记录 -->
|
||
|
<div id="records" class="tab-content">
|
||
|
<div class="card">
|
||
|
<div class="card-title">
|
||
|
<i class="fas fa-list-alt"></i>
|
||
|
垃圾转运记录
|
||
|
</div>
|
||
|
<div class="header-actions" style="margin-bottom: 20px;">
|
||
|
<button class="action-btn" onclick="addRecord()">
|
||
|
<i class="fas fa-plus"></i> 新增记录
|
||
|
</button>
|
||
|
<button class="action-btn" onclick="exportRecords()">
|
||
|
<i class="fas fa-download"></i> 导出记录
|
||
|
</button>
|
||
|
</div>
|
||
|
<div class="form-grid">
|
||
|
<div class="filter-group">
|
||
|
<label class="filter-label">日期范围</label>
|
||
|
<input type="date" class="search-input" id="startDate">
|
||
|
</div>
|
||
|
<div class="filter-group">
|
||
|
<label class="filter-label">至</label>
|
||
|
<input type="date" class="search-input" id="endDate">
|
||
|
</div>
|
||
|
<div class="filter-group">
|
||
|
<label class="filter-label">车辆</label>
|
||
|
<select class="filter-select" id="vehicleFilter">
|
||
|
<option value="">全部车辆</option>
|
||
|
<option value="truck1">转运车001</option>
|
||
|
<option value="truck2">转运车002</option>
|
||
|
<option value="truck3">转运车003</option>
|
||
|
</select>
|
||
|
</div>
|
||
|
<div class="filter-group">
|
||
|
<label class="filter-label">状态</label>
|
||
|
<select class="filter-select" id="statusFilter">
|
||
|
<option value="">全部状态</option>
|
||
|
<option value="completed">已完成</option>
|
||
|
<option value="pending">进行中</option>
|
||
|
<option value="cancelled">已取消</option>
|
||
|
</select>
|
||
|
</div>
|
||
|
<!-- <button class="action-btn" onclick="filterRecords()">
|
||
|
<i class="fas fa-filter"></i> 筛选
|
||
|
</button> -->
|
||
|
</div>
|
||
|
<table class="data-table">
|
||
|
<thead>
|
||
|
<tr>
|
||
|
<th>记录ID</th>
|
||
|
<th>车辆编号</th>
|
||
|
<th>司机</th>
|
||
|
<th>起点</th>
|
||
|
<th>终点</th>
|
||
|
<th>垃圾量(吨)</th>
|
||
|
<th>开始时间</th>
|
||
|
<th>完成时间</th>
|
||
|
<th>状态</th>
|
||
|
<th>操作</th>
|
||
|
</tr>
|
||
|
</thead>
|
||
|
<tbody id="recordsTable">
|
||
|
<tr>
|
||
|
<td>TR20241201001</td>
|
||
|
<td>转运车001</td>
|
||
|
<td>张师傅</td>
|
||
|
<td>A区收集点</td>
|
||
|
<td>中转站1</td>
|
||
|
<td>2.5</td>
|
||
|
<td>2024-12-01 08:30</td>
|
||
|
<td>2024-12-01 09:15</td>
|
||
|
<td><span class="status-badge status-active">已完成</span></td>
|
||
|
<td>
|
||
|
<button class="btn btn-primary" onclick="viewRecord('TR20241201001')">
|
||
|
<i class="fas fa-eye"></i> 详情
|
||
|
</button>
|
||
|
<button class="btn btn-warning" onclick="editRecord('TR20241201001')">
|
||
|
<i class="fas fa-edit"></i> 编辑
|
||
|
</button>
|
||
|
</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td>TR20241201002</td>
|
||
|
<td>转运车002</td>
|
||
|
<td>李师傅</td>
|
||
|
<td>B区收集点</td>
|
||
|
<td>中转站2</td>
|
||
|
<td>3.2</td>
|
||
|
<td>2024-12-01 09:00</td>
|
||
|
<td>2024-12-01 10:30</td>
|
||
|
<td><span class="status-badge status-active">已完成</span></td>
|
||
|
<td>
|
||
|
<button class="btn btn-primary" onclick="viewRecord('TR20241201002')">
|
||
|
<i class="fas fa-eye"></i> 详情
|
||
|
</button>
|
||
|
<button class="btn btn-warning" onclick="editRecord('TR20241201002')">
|
||
|
<i class="fas fa-edit"></i> 编辑
|
||
|
</button>
|
||
|
</td>
|
||
|
</tr>
|
||
|
</tbody>
|
||
|
</table>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<!-- 出勤统计 -->
|
||
|
<div id="attendance" class="tab-content">
|
||
|
<div class="card">
|
||
|
<div class="card-title">
|
||
|
<i class="fas fa-user-clock"></i>
|
||
|
车辆出勤统计
|
||
|
</div>
|
||
|
<div class="header-actions" style="margin-bottom: 20px;">
|
||
|
<button class="action-btn" onclick="generateAttendanceReport()">
|
||
|
<i class="fas fa-chart-line"></i> 生成报告
|
||
|
</button>
|
||
|
<button class="action-btn" onclick="exportAttendance()">
|
||
|
<i class="fas fa-download"></i> 导出统计
|
||
|
</button>
|
||
|
<button class="action-btn" onclick="updateAttendanceStats()">
|
||
|
<i class="fas fa-sync-alt"></i> 更新统计
|
||
|
</button>
|
||
|
</div>
|
||
|
<div class="form-grid">
|
||
|
<div class="filter-group">
|
||
|
<label class="filter-label">统计月份</label>
|
||
|
<input type="month" class="search-input" id="attendanceMonth" value="2024-12">
|
||
|
</div>
|
||
|
<div class="filter-group">
|
||
|
<label class="filter-label">车辆类型</label>
|
||
|
<select class="filter-select" id="vehicleTypeFilter">
|
||
|
<option value="">全部类型</option>
|
||
|
<option value="truck">转运车</option>
|
||
|
<option value="boat">清洁船</option>
|
||
|
<option value="special">特种车辆</option>
|
||
|
</select>
|
||
|
</div>
|
||
|
</div>
|
||
|
<table class="data-table">
|
||
|
<thead>
|
||
|
<tr>
|
||
|
<th>车辆编号</th>
|
||
|
<th>车辆类型</th>
|
||
|
<th>司机</th>
|
||
|
<th>应出勤天数</th>
|
||
|
<th>实际出勤天数</th>
|
||
|
<th>出勤率</th>
|
||
|
<th>完成任务数</th>
|
||
|
<th>完成率</th>
|
||
|
<th>评分</th>
|
||
|
<th>操作</th>
|
||
|
</tr>
|
||
|
</thead>
|
||
|
<tbody id="attendanceTable">
|
||
|
<tr>
|
||
|
<td>转运车001</td>
|
||
|
<td>转运车</td>
|
||
|
<td>张师傅</td>
|
||
|
<td>30</td>
|
||
|
<td>28</td>
|
||
|
<td>93.3%</td>
|
||
|
<td>156</td>
|
||
|
<td>95.1%</td>
|
||
|
<td>92分</td>
|
||
|
<td>
|
||
|
<button class="btn btn-primary" onclick="viewAttendanceDetail('truck001')">
|
||
|
<i class="fas fa-eye"></i> 详情
|
||
|
</button>
|
||
|
</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td>转运车002</td>
|
||
|
<td>转运车</td>
|
||
|
<td>李师傅</td>
|
||
|
<td>30</td>
|
||
|
<td>30</td>
|
||
|
<td>100%</td>
|
||
|
<td>168</td>
|
||
|
<td>98.2%</td>
|
||
|
<td>96分</td>
|
||
|
<td>
|
||
|
<button class="btn btn-primary" onclick="viewAttendanceDetail('truck002')">
|
||
|
<i class="fas fa-eye"></i> 详情
|
||
|
</button>
|
||
|
</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td>清洁船001</td>
|
||
|
<td>清洁船</td>
|
||
|
<td>王师傅</td>
|
||
|
<td>25</td>
|
||
|
<td>23</td>
|
||
|
<td>92%</td>
|
||
|
<td>89</td>
|
||
|
<td>91.8%</td>
|
||
|
<td>89分</td>
|
||
|
<td>
|
||
|
<button class="btn btn-primary" onclick="viewAttendanceDetail('boat001')">
|
||
|
<i class="fas fa-eye"></i> 详情
|
||
|
</button>
|
||
|
</td>
|
||
|
</tr>
|
||
|
</tbody>
|
||
|
</table>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<!-- 中转站管理 -->
|
||
|
<div id="stations" class="tab-content">
|
||
|
<div class="card">
|
||
|
<div class="card-title">
|
||
|
<i class="fas fa-warehouse"></i>
|
||
|
中转站管理
|
||
|
</div>
|
||
|
<div class="header-actions" style="margin-bottom: 20px;">
|
||
|
<button class="action-btn" onclick="addStation()">
|
||
|
<i class="fas fa-plus"></i> 新增中转站
|
||
|
</button>
|
||
|
<button class="action-btn" onclick="stationMaintenance()">
|
||
|
<i class="fas fa-tools"></i> 维护管理
|
||
|
</button>
|
||
|
</div>
|
||
|
<table class="data-table">
|
||
|
<thead>
|
||
|
<tr>
|
||
|
<th>中转站ID</th>
|
||
|
<th>名称</th>
|
||
|
<th>地址</th>
|
||
|
<th>容量(吨)</th>
|
||
|
<th>当前存量(吨)</th>
|
||
|
<th>使用率</th>
|
||
|
<th>负责人</th>
|
||
|
<th>状态</th>
|
||
|
<th>操作</th>
|
||
|
</tr>
|
||
|
</thead>
|
||
|
<tbody id="stationsTable">
|
||
|
<tr>
|
||
|
<td>ST001</td>
|
||
|
<td>中转站1</td>
|
||
|
<td>河东区环保路123号</td>
|
||
|
<td>50</td>
|
||
|
<td>32</td>
|
||
|
<td>64%</td>
|
||
|
<td>陈主任</td>
|
||
|
<td><span class="status-badge status-active">正常</span></td>
|
||
|
<td>
|
||
|
<button class="btn btn-primary" onclick="viewStation('ST001')">
|
||
|
<i class="fas fa-eye"></i> 详情
|
||
|
</button>
|
||
|
<button class="btn btn-warning" onclick="editStation('ST001')">
|
||
|
<i class="fas fa-edit"></i> 编辑
|
||
|
</button>
|
||
|
<button class="btn btn-danger" onclick="deleteStation('ST001')">
|
||
|
<i class="fas fa-trash"></i> 删除
|
||
|
</button>
|
||
|
</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td>ST002</td>
|
||
|
<td>中转站2</td>
|
||
|
<td>河西区清洁大道456号</td>
|
||
|
<td>80</td>
|
||
|
<td>45</td>
|
||
|
<td>56%</td>
|
||
|
<td>刘主任</td>
|
||
|
<td><span class="status-badge status-active">正常</span></td>
|
||
|
<td>
|
||
|
<button class="btn btn-primary" onclick="viewStation('ST002')">
|
||
|
<i class="fas fa-eye"></i> 详情
|
||
|
</button>
|
||
|
<button class="btn btn-warning" onclick="editStation('ST002')">
|
||
|
<i class="fas fa-edit"></i> 编辑
|
||
|
</button>
|
||
|
<button class="btn btn-danger" onclick="deleteStation('ST002')">
|
||
|
<i class="fas fa-trash"></i> 删除
|
||
|
</button>
|
||
|
</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td>ST003</td>
|
||
|
<td>中转站3</td>
|
||
|
<td>南区工业园区789号</td>
|
||
|
<td>60</td>
|
||
|
<td>58</td>
|
||
|
<td>97%</td>
|
||
|
<td>赵主任</td>
|
||
|
<td><span class="status-badge status-pending">维护中</span></td>
|
||
|
<td>
|
||
|
<button class="btn btn-primary" onclick="viewStation('ST003')">
|
||
|
<i class="fas fa-eye"></i> 详情
|
||
|
</button>
|
||
|
<button class="btn btn-warning" onclick="editStation('ST003')">
|
||
|
<i class="fas fa-edit"></i> 编辑
|
||
|
</button>
|
||
|
<button class="btn btn-danger" onclick="deleteStation('ST003')">
|
||
|
<i class="fas fa-trash"></i> 删除
|
||
|
</button>
|
||
|
</td>
|
||
|
</tr>
|
||
|
</tbody>
|
||
|
</table>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<!-- 考核标准模态框 -->
|
||
|
<div id="standardModal" class="modal">
|
||
|
<div class="modal-content">
|
||
|
<div class="modal-header">
|
||
|
<h3 class="modal-title" id="standardModalTitle">新增考核标准</h3>
|
||
|
<span class="close" onclick="closeModal('standardModal')">×</span>
|
||
|
</div>
|
||
|
<div class="modal-body">
|
||
|
<form id="standardForm">
|
||
|
<div class="form-group">
|
||
|
<label>考核项目</label>
|
||
|
<input type="text" name="name" required>
|
||
|
</div>
|
||
|
<div class="form-group">
|
||
|
<label>标准分值</label>
|
||
|
<input type="number" name="score" required>
|
||
|
</div>
|
||
|
<div class="form-group">
|
||
|
<label>扣分标准</label>
|
||
|
<textarea name="deduction" rows="3" required></textarea>
|
||
|
</div>
|
||
|
<div class="form-group">
|
||
|
<label>权重(%)</label>
|
||
|
<input type="number" name="weight" min="1" max="100" required>
|
||
|
</div>
|
||
|
<div class="form-group">
|
||
|
<label>状态</label>
|
||
|
<select name="status" required>
|
||
|
<option value="active">启用</option>
|
||
|
<option value="inactive">禁用</option>
|
||
|
</select>
|
||
|
</div>
|
||
|
</form>
|
||
|
</div>
|
||
|
<div class="modal-footer">
|
||
|
<button class="btn" onclick="closeModal('standardModal')">取消</button>
|
||
|
<button class="btn btn-primary" onclick="saveStandard()">保存</button>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<!-- 转运记录模态框 -->
|
||
|
<div id="recordModal" class="modal">
|
||
|
<div class="modal-content">
|
||
|
<div class="modal-header">
|
||
|
<h3 class="modal-title" id="recordModalTitle">新增转运记录</h3>
|
||
|
<span class="close" onclick="closeModal('recordModal')">×</span>
|
||
|
</div>
|
||
|
<div class="modal-body">
|
||
|
<form id="recordForm">
|
||
|
<div class="form-grid">
|
||
|
<div class="form-group">
|
||
|
<label>车辆编号</label>
|
||
|
<select name="vehicle" required>
|
||
|
<option value="">请选择车辆</option>
|
||
|
<option value="转运车001">转运车001</option>
|
||
|
<option value="转运车002">转运车002</option>
|
||
|
<option value="转运车003">转运车003</option>
|
||
|
</select>
|
||
|
</div>
|
||
|
<div class="form-group">
|
||
|
<label>司机</label>
|
||
|
<input type="text" name="driver" required>
|
||
|
</div>
|
||
|
<div class="form-group">
|
||
|
<label>起点</label>
|
||
|
<input type="text" name="start" required>
|
||
|
</div>
|
||
|
<div class="form-group">
|
||
|
<label>终点</label>
|
||
|
<input type="text" name="end" required>
|
||
|
</div>
|
||
|
<div class="form-group">
|
||
|
<label>垃圾量(吨)</label>
|
||
|
<input type="number" step="0.1" name="amount" required>
|
||
|
</div>
|
||
|
<div class="form-group">
|
||
|
<label>开始时间</label>
|
||
|
<input type="datetime-local" name="startTime" required>
|
||
|
</div>
|
||
|
<div class="form-group">
|
||
|
<label>完成时间</label>
|
||
|
<input type="datetime-local" name="endTime">
|
||
|
</div>
|
||
|
<div class="form-group">
|
||
|
<label>状态</label>
|
||
|
<select name="status" required>
|
||
|
<option value="pending">进行中</option>
|
||
|
<option value="completed">已完成</option>
|
||
|
<option value="cancelled">已取消</option>
|
||
|
</select>
|
||
|
</div>
|
||
|
</div>
|
||
|
</form>
|
||
|
</div>
|
||
|
<div class="modal-footer">
|
||
|
<button class="btn" onclick="closeModal('recordModal')">取消</button>
|
||
|
<button class="btn btn-primary" onclick="saveRecord()">保存</button>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<!-- 转运记录详情模态框 -->
|
||
|
<div id="recordDetailModal" class="modal">
|
||
|
<div class="modal-content">
|
||
|
<div class="modal-header">
|
||
|
<h3 class="modal-title">转运记录详情</h3>
|
||
|
<span class="close" onclick="closeModal('recordDetailModal')">×</span>
|
||
|
</div>
|
||
|
<div class="modal-body" id="recordDetailContent">
|
||
|
<!-- 内容将通过JS动态加载 -->
|
||
|
</div>
|
||
|
<div class="modal-footer">
|
||
|
<button class="btn btn-primary" onclick="closeModal('recordDetailModal')">关闭</button>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<!-- 中转站模态框 -->
|
||
|
<div id="stationModal" class="modal">
|
||
|
<div class="modal-content">
|
||
|
<div class="modal-header">
|
||
|
<h3 class="modal-title" id="stationModalTitle">新增中转站</h3>
|
||
|
<span class="close" onclick="closeModal('stationModal')">×</span>
|
||
|
</div>
|
||
|
<div class="modal-body">
|
||
|
<form id="stationForm">
|
||
|
<div class="form-grid">
|
||
|
<div class="form-group">
|
||
|
<label>中转站ID</label>
|
||
|
<input type="text" name="id" required>
|
||
|
</div>
|
||
|
<div class="form-group">
|
||
|
<label>名称</label>
|
||
|
<input type="text" name="name" required>
|
||
|
</div>
|
||
|
<div class="form-group">
|
||
|
<label>地址</label>
|
||
|
<input type="text" name="address" required>
|
||
|
</div>
|
||
|
<div class="form-group">
|
||
|
<label>容量(吨)</label>
|
||
|
<input type="number" name="capacity" required>
|
||
|
</div>
|
||
|
<div class="form-group">
|
||
|
<label>当前存量(吨)</label>
|
||
|
<input type="number" name="current" required>
|
||
|
</div>
|
||
|
<div class="form-group">
|
||
|
<label>负责人</label>
|
||
|
<input type="text" name="manager" required>
|
||
|
</div>
|
||
|
<div class="form-group">
|
||
|
<label>状态</label>
|
||
|
<select name="status" required>
|
||
|
<option value="active">正常</option>
|
||
|
<option value="maintenance">维护中</option>
|
||
|
<option value="inactive">停用</option>
|
||
|
</select>
|
||
|
</div>
|
||
|
</div>
|
||
|
</form>
|
||
|
</div>
|
||
|
<div class="modal-footer">
|
||
|
<button class="btn" onclick="closeModal('stationModal')">取消</button>
|
||
|
<button class="btn btn-primary" onclick="saveStation()">保存</button>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<!-- 中转站详情模态框 -->
|
||
|
<div id="stationDetailModal" class="modal">
|
||
|
<div class="modal-content">
|
||
|
<div class="modal-header">
|
||
|
<h3 class="modal-title">中转站详情</h3>
|
||
|
<span class="close" onclick="closeModal('stationDetailModal')">×</span>
|
||
|
</div>
|
||
|
<div class="modal-body" id="stationDetailContent">
|
||
|
<!-- 内容将通过JS动态加载 -->
|
||
|
</div>
|
||
|
<div class="modal-footer">
|
||
|
<button class="btn btn-primary" onclick="closeModal('stationDetailModal')">关闭</button>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<!-- 在原有模态框之后添加出勤详情模态框 -->
|
||
|
<div id="attendanceDetailModal" class="modal">
|
||
|
<div class="modal-content">
|
||
|
<div class="modal-header">
|
||
|
<h3 class="modal-title">出勤统计详情</h3>
|
||
|
<span class="close" onclick="closeModal('attendanceDetailModal')">×</span>
|
||
|
</div>
|
||
|
<div class="modal-body" id="attendanceDetailContent">
|
||
|
<!-- 内容将通过JS动态加载 -->
|
||
|
</div>
|
||
|
<div class="modal-footer">
|
||
|
<button class="btn btn-primary" onclick="closeModal('attendanceDetailModal')">关闭</button>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<script src="chart.js"></script>
|
||
|
<script>
|
||
|
// 模拟数据
|
||
|
let standardsData = [
|
||
|
{ id: 'std1', name: '河道清洁度', score: 100, deduction: '发现垃圾每处扣5分', weight: 30, status: 'active' },
|
||
|
{ id: 'std2', name: '转运及时性', score: 100, deduction: '超时每小时扣10分', weight: 25, status: 'active' },
|
||
|
{ id: 'std3', name: '设备维护', score: 100, deduction: '故障每次扣15分', weight: 20, status: 'active' }
|
||
|
];
|
||
|
|
||
|
let recordsData = [
|
||
|
{ id: 'TR20241201001', vehicle: '转运车001', driver: '张师傅', start: 'A区收集点', end: '中转站1', amount: 2.5, startTime: '2024-12-01 08:30', endTime: '2024-12-01 09:15', status: 'completed' },
|
||
|
{ id: 'TR20241201002', vehicle: '转运车002', driver: '李师傅', start: 'B区收集点', end: '中转站2', amount: 3.2, startTime: '2024-12-01 09:00', endTime: '2024-12-01 10:30', status: 'completed' }
|
||
|
];
|
||
|
|
||
|
let attendanceData = [
|
||
|
{ id: 'truck001', vehicle: '转运车001', type: 'truck', driver: '张师傅', shouldWork: 30, actualWork: 28, attendanceRate: 93.3, tasks: 156, completionRate: 95.1, score: 92 },
|
||
|
{ id: 'truck002', vehicle: '转运车002', type: 'truck', driver: '李师傅', shouldWork: 30, actualWork: 30, attendanceRate: 100, tasks: 168, completionRate: 98.2, score: 96 },
|
||
|
{ id: 'boat001', vehicle: '清洁船001', type: 'boat', driver: '王师傅', shouldWork: 25, actualWork: 23, attendanceRate: 92, tasks: 89, completionRate: 91.8, score: 89 }
|
||
|
];
|
||
|
|
||
|
let stationsData = [
|
||
|
{ id: 'ST001', name: '中转站1', address: '河东区环保路123号', capacity: 50, current: 32, manager: '陈主任', status: 'active' },
|
||
|
{ id: 'ST002', name: '中转站2', address: '河西区清洁大道456号', capacity: 80, current: 45, manager: '刘主任', status: 'active' },
|
||
|
{ id: 'ST003', name: '中转站3', address: '南区工业园区789号', capacity: 60, current: 58, manager: '赵主任', status: 'maintenance' }
|
||
|
];
|
||
|
|
||
|
// 当前编辑的ID
|
||
|
let currentEditId = null;
|
||
|
|
||
|
// 全局变量存储图表实例
|
||
|
let attendanceChartInstance = null;
|
||
|
let transferChartInstance = null;
|
||
|
|
||
|
// 切换标签页
|
||
|
function switchTab(tabName) {
|
||
|
// 隐藏所有标签页内容
|
||
|
document.querySelectorAll('.tab-content').forEach(tab => {
|
||
|
tab.classList.remove('active');
|
||
|
});
|
||
|
|
||
|
// 移除所有标签按钮的激活状态
|
||
|
document.querySelectorAll('.nav-tab').forEach(tab => {
|
||
|
tab.classList.remove('active');
|
||
|
});
|
||
|
|
||
|
// 显示选中的标签页内容
|
||
|
document.getElementById(tabName).classList.add('active');
|
||
|
|
||
|
// 激活选中的标签按钮
|
||
|
event.target.classList.add('active');
|
||
|
|
||
|
// 如果是概览标签,绘制图表
|
||
|
if (tabName === 'overview') {
|
||
|
// 销毁旧图表实例
|
||
|
if (attendanceChartInstance) {
|
||
|
attendanceChartInstance.destroy();
|
||
|
}
|
||
|
if (transferChartInstance) {
|
||
|
transferChartInstance.destroy();
|
||
|
}
|
||
|
|
||
|
// 创建新图表
|
||
|
drawAttendanceChart();
|
||
|
drawTransferChart();
|
||
|
}
|
||
|
}
|
||
|
// 考核标准管理
|
||
|
function addStandard() {
|
||
|
currentEditId = null;
|
||
|
document.getElementById('standardModalTitle').textContent = '新增考核标准';
|
||
|
document.getElementById('standardForm').reset();
|
||
|
openModal('standardModal');
|
||
|
}
|
||
|
|
||
|
function editStandard(id) {
|
||
|
const standard = standardsData.find(s => s.id === id);
|
||
|
if (standard) {
|
||
|
currentEditId = id;
|
||
|
document.getElementById('standardModalTitle').textContent = '编辑考核标准';
|
||
|
const form = document.getElementById('standardForm');
|
||
|
form.name.value = standard.name;
|
||
|
form.score.value = standard.score;
|
||
|
form.deduction.value = standard.deduction;
|
||
|
form.weight.value = standard.weight;
|
||
|
form.status.value = standard.status;
|
||
|
openModal('standardModal');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function deleteStandard(id) {
|
||
|
if (confirm('确定要删除这个考核标准吗?')) {
|
||
|
const index = standardsData.findIndex(s => s.id === id);
|
||
|
if (index !== -1) {
|
||
|
standardsData.splice(index, 1);
|
||
|
showNotification('考核标准删除成功', 'success');
|
||
|
updateStandardsTable();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function saveStandard() {
|
||
|
const form = document.getElementById('standardForm');
|
||
|
const standard = {
|
||
|
id: currentEditId || 'std' + Date.now(),
|
||
|
name: form.name.value,
|
||
|
score: parseInt(form.score.value),
|
||
|
deduction: form.deduction.value,
|
||
|
weight: parseInt(form.weight.value),
|
||
|
status: form.status.value
|
||
|
};
|
||
|
|
||
|
if (currentEditId) {
|
||
|
const index = standardsData.findIndex(s => s.id === currentEditId);
|
||
|
if (index !== -1) {
|
||
|
standardsData[index] = standard;
|
||
|
showNotification('考核标准更新成功', 'success');
|
||
|
}
|
||
|
} else {
|
||
|
standardsData.push(standard);
|
||
|
showNotification('考核标准添加成功', 'success');
|
||
|
}
|
||
|
|
||
|
closeModal('standardModal');
|
||
|
updateStandardsTable();
|
||
|
}
|
||
|
|
||
|
function updateStandardsTable() {
|
||
|
const tbody = document.getElementById('standardsTable');
|
||
|
tbody.innerHTML = standardsData.map(s => `
|
||
|
<tr>
|
||
|
<td>${s.name}</td>
|
||
|
<td>${s.score}分</td>
|
||
|
<td>${s.deduction}</td>
|
||
|
<td>${s.weight}%</td>
|
||
|
<td><span class="status-badge status-${s.status}">${s.status === 'active' ? '启用' : '禁用'}</span></td>
|
||
|
<td>
|
||
|
<button class="btn btn-primary" onclick="editStandard('${s.id}')">
|
||
|
<i class="fas fa-edit"></i> 编辑
|
||
|
</button>
|
||
|
<button class="btn btn-danger" onclick="deleteStandard('${s.id}')">
|
||
|
<i class="fas fa-trash"></i> 删除
|
||
|
</button>
|
||
|
</td>
|
||
|
</tr>
|
||
|
`).join('');
|
||
|
}
|
||
|
|
||
|
// 转运记录管理
|
||
|
function addRecord() {
|
||
|
currentEditId = null;
|
||
|
document.getElementById('recordModalTitle').textContent = '新增转运记录';
|
||
|
document.getElementById('recordForm').reset();
|
||
|
openModal('recordModal');
|
||
|
}
|
||
|
|
||
|
function viewRecord(id) {
|
||
|
const record = recordsData.find(r => r.id === id);
|
||
|
if (record) {
|
||
|
const content = document.getElementById('recordDetailContent');
|
||
|
content.innerHTML = `
|
||
|
<div class="detail-item">
|
||
|
<div class="detail-label">记录ID</div>
|
||
|
<div class="detail-value">${record.id}</div>
|
||
|
</div>
|
||
|
<div class="detail-item">
|
||
|
<div class="detail-label">车辆编号</div>
|
||
|
<div class="detail-value">${record.vehicle}</div>
|
||
|
</div>
|
||
|
<div class="detail-item">
|
||
|
<div class="detail-label">司机</div>
|
||
|
<div class="detail-value">${record.driver}</div>
|
||
|
</div>
|
||
|
<div class="detail-item">
|
||
|
<div class="detail-label">起点</div>
|
||
|
<div class="detail-value">${record.start}</div>
|
||
|
</div>
|
||
|
<div class="detail-item">
|
||
|
<div class="detail-label">终点</div>
|
||
|
<div class="detail-value">${record.end}</div>
|
||
|
</div>
|
||
|
<div class="detail-item">
|
||
|
<div class="detail-label">垃圾量</div>
|
||
|
<div class="detail-value">${record.amount} 吨</div>
|
||
|
</div>
|
||
|
<div class="detail-item">
|
||
|
<div class="detail-label">开始时间</div>
|
||
|
<div class="detail-value">${record.startTime}</div>
|
||
|
</div>
|
||
|
<div class="detail-item">
|
||
|
<div class="detail-label">完成时间</div>
|
||
|
<div class="detail-value">${record.endTime || '-'}</div>
|
||
|
</div>
|
||
|
<div class="detail-item">
|
||
|
<div class="detail-label">状态</div>
|
||
|
<div class="detail-value"><span class="status-badge status-${record.status === 'completed' ? 'active' : record.status === 'pending' ? 'pending' : 'inactive'}">${getStatusText(record.status)}</span></div>
|
||
|
</div>
|
||
|
`;
|
||
|
openModal('recordDetailModal');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function editRecord(id) {
|
||
|
const record = recordsData.find(r => r.id === id);
|
||
|
if (record) {
|
||
|
currentEditId = id;
|
||
|
document.getElementById('recordModalTitle').textContent = '编辑转运记录';
|
||
|
const form = document.getElementById('recordForm');
|
||
|
form.vehicle.value = record.vehicle;
|
||
|
form.driver.value = record.driver;
|
||
|
form.start.value = record.start;
|
||
|
form.end.value = record.end;
|
||
|
form.amount.value = record.amount;
|
||
|
form.startTime.value = record.startTime.replace(' ', 'T');
|
||
|
form.endTime.value = record.endTime ? record.endTime.replace(' ', 'T') : '';
|
||
|
form.status.value = record.status;
|
||
|
openModal('recordModal');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function saveRecord() {
|
||
|
const form = document.getElementById('recordForm');
|
||
|
const record = {
|
||
|
id: currentEditId || 'TR' + new Date().toISOString().slice(0, 10).replace(/-/g, '') + String(Date.now()).slice(-3),
|
||
|
vehicle: form.vehicle.value,
|
||
|
driver: form.driver.value,
|
||
|
start: form.start.value,
|
||
|
end: form.end.value,
|
||
|
amount: parseFloat(form.amount.value),
|
||
|
startTime: form.startTime.value.replace('T', ' '),
|
||
|
endTime: form.endTime.value ? form.endTime.value.replace('T', ' ') : '',
|
||
|
status: form.status.value
|
||
|
};
|
||
|
|
||
|
if (currentEditId) {
|
||
|
const index = recordsData.findIndex(r => r.id === currentEditId);
|
||
|
if (index !== -1) {
|
||
|
recordsData[index] = record;
|
||
|
showNotification('转运记录更新成功', 'success');
|
||
|
}
|
||
|
} else {
|
||
|
recordsData.push(record);
|
||
|
showNotification('转运记录添加成功', 'success');
|
||
|
}
|
||
|
|
||
|
closeModal('recordModal');
|
||
|
updateRecordsTable();
|
||
|
}
|
||
|
|
||
|
function updateRecordsTable() {
|
||
|
const tbody = document.getElementById('recordsTable');
|
||
|
tbody.innerHTML = recordsData.map(r => `
|
||
|
<tr>
|
||
|
<td>${r.id}</td>
|
||
|
<td>${r.vehicle}</td>
|
||
|
<td>${r.driver}</td>
|
||
|
<td>${r.start}</td>
|
||
|
<td>${r.end}</td>
|
||
|
<td>${r.amount}</td>
|
||
|
<td>${r.startTime}</td>
|
||
|
<td>${r.endTime || '-'}</td>
|
||
|
<td><span class="status-badge status-${r.status === 'completed' ? 'active' : r.status === 'pending' ? 'pending' : 'inactive'}">${getStatusText(r.status)}</span></td>
|
||
|
<td>
|
||
|
<button class="btn btn-primary" onclick="viewRecord('${r.id}')">
|
||
|
<i class="fas fa-eye"></i> 详情
|
||
|
</button>
|
||
|
<button class="btn btn-warning" onclick="editRecord('${r.id}')">
|
||
|
<i class="fas fa-edit"></i> 编辑
|
||
|
</button>
|
||
|
</td>
|
||
|
</tr>
|
||
|
`).join('');
|
||
|
}
|
||
|
|
||
|
function getStatusText(status) {
|
||
|
const statusMap = {
|
||
|
'completed': '已完成',
|
||
|
'pending': '进行中',
|
||
|
'cancelled': '已取消'
|
||
|
};
|
||
|
return statusMap[status] || status;
|
||
|
}
|
||
|
|
||
|
// 中转站管理
|
||
|
function addStation() {
|
||
|
currentEditId = null;
|
||
|
document.getElementById('stationModalTitle').textContent = '新增中转站';
|
||
|
document.getElementById('stationForm').reset();
|
||
|
openModal('stationModal');
|
||
|
}
|
||
|
|
||
|
function viewStation(id) {
|
||
|
const station = stationsData.find(s => s.id === id);
|
||
|
if (station) {
|
||
|
const content = document.getElementById('stationDetailContent');
|
||
|
content.innerHTML = `
|
||
|
<div class="detail-item">
|
||
|
<div class="detail-label">中转站ID</div>
|
||
|
<div class="detail-value">${station.id}</div>
|
||
|
</div>
|
||
|
<div class="detail-item">
|
||
|
<div class="detail-label">名称</div>
|
||
|
<div class="detail-value">${station.name}</div>
|
||
|
</div>
|
||
|
<div class="detail-item">
|
||
|
<div class="detail-label">地址</div>
|
||
|
<div class="detail-value">${station.address}</div>
|
||
|
</div>
|
||
|
<div class="detail-item">
|
||
|
<div class="detail-label">容量</div>
|
||
|
<div class="detail-value">${station.capacity} 吨</div>
|
||
|
</div>
|
||
|
<div class="detail-item">
|
||
|
<div class="detail-label">当前存量</div>
|
||
|
<div class="detail-value">${station.current} 吨</div>
|
||
|
</div>
|
||
|
<div class="detail-item">
|
||
|
<div class="detail-label">使用率</div>
|
||
|
<div class="detail-value">${Math.round((station.current / station.capacity) * 100)}%</div>
|
||
|
</div>
|
||
|
<div class="detail-item">
|
||
|
<div class="detail-label">负责人</div>
|
||
|
<div class="detail-value">${station.manager}</div>
|
||
|
</div>
|
||
|
<div class="detail-item">
|
||
|
<div class="detail-label">状态</div>
|
||
|
<div class="detail-value"><span class="status-badge status-${station.status}">${getStationStatusText(station.status)}</span></div>
|
||
|
</div>
|
||
|
`;
|
||
|
openModal('stationDetailModal');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function editStation(id) {
|
||
|
const station = stationsData.find(s => s.id === id);
|
||
|
if (station) {
|
||
|
currentEditId = id;
|
||
|
document.getElementById('stationModalTitle').textContent = '编辑中转站';
|
||
|
const form = document.getElementById('stationForm');
|
||
|
form.id.value = station.id;
|
||
|
form.name.value = station.name;
|
||
|
form.address.value = station.address;
|
||
|
form.capacity.value = station.capacity;
|
||
|
form.current.value = station.current;
|
||
|
form.manager.value = station.manager;
|
||
|
form.status.value = station.status;
|
||
|
openModal('stationModal');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function deleteStation(id) {
|
||
|
if (confirm('确定要删除这个中转站吗?')) {
|
||
|
const index = stationsData.findIndex(s => s.id === id);
|
||
|
if (index !== -1) {
|
||
|
stationsData.splice(index, 1);
|
||
|
showNotification('中转站删除成功', 'success');
|
||
|
updateStationsTable();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function saveStation() {
|
||
|
const form = document.getElementById('stationForm');
|
||
|
const station = {
|
||
|
id: form.id.value,
|
||
|
name: form.name.value,
|
||
|
address: form.address.value,
|
||
|
capacity: parseInt(form.capacity.value),
|
||
|
current: parseInt(form.current.value),
|
||
|
manager: form.manager.value,
|
||
|
status: form.status.value
|
||
|
};
|
||
|
|
||
|
if (currentEditId) {
|
||
|
const index = stationsData.findIndex(s => s.id === currentEditId);
|
||
|
if (index !== -1) {
|
||
|
stationsData[index] = station;
|
||
|
showNotification('中转站信息更新成功', 'success');
|
||
|
}
|
||
|
} else {
|
||
|
if (stationsData.find(s => s.id === station.id)) {
|
||
|
showNotification('中转站ID已存在', 'error');
|
||
|
return;
|
||
|
}
|
||
|
stationsData.push(station);
|
||
|
showNotification('中转站添加成功', 'success');
|
||
|
}
|
||
|
|
||
|
closeModal('stationModal');
|
||
|
updateStationsTable();
|
||
|
}
|
||
|
|
||
|
function updateStationsTable() {
|
||
|
const tbody = document.getElementById('stationsTable');
|
||
|
tbody.innerHTML = stationsData.map(s => `
|
||
|
<tr>
|
||
|
<td>${s.id}</td>
|
||
|
<td>${s.name}</td>
|
||
|
<td>${s.address}</td>
|
||
|
<td>${s.capacity}</td>
|
||
|
<td>${s.current}</td>
|
||
|
<td>${Math.round((s.current / s.capacity) * 100)}%</td>
|
||
|
<td>${s.manager}</td>
|
||
|
<td><span class="status-badge status-${s.status}">${getStationStatusText(s.status)}</span></td>
|
||
|
<td>
|
||
|
<button class="btn btn-primary" onclick="viewStation('${s.id}')">
|
||
|
<i class="fas fa-eye"></i> 详情
|
||
|
</button>
|
||
|
<button class="btn btn-warning" onclick="editStation('${s.id}')">
|
||
|
<i class="fas fa-edit"></i> 编辑
|
||
|
</button>
|
||
|
<button class="btn btn-danger" onclick="deleteStation('${s.id}')">
|
||
|
<i class="fas fa-trash"></i> 删除
|
||
|
</button>
|
||
|
</td>
|
||
|
</tr>
|
||
|
`).join('');
|
||
|
}
|
||
|
|
||
|
function getStationStatusText(status) {
|
||
|
const statusMap = {
|
||
|
'active': '正常',
|
||
|
'maintenance': '维护中',
|
||
|
'inactive': '停用'
|
||
|
};
|
||
|
return statusMap[status] || status;
|
||
|
}
|
||
|
|
||
|
// 通用功能
|
||
|
function openModal(id) {
|
||
|
document.getElementById(id).style.display = 'block';
|
||
|
}
|
||
|
|
||
|
function closeModal(id) {
|
||
|
document.getElementById(id).style.display = 'none';
|
||
|
currentEditId = null;
|
||
|
}
|
||
|
|
||
|
function showNotification(message, type = 'success') {
|
||
|
const notification = document.createElement('div');
|
||
|
notification.className = `notification ${type}`;
|
||
|
notification.textContent = message;
|
||
|
document.body.appendChild(notification);
|
||
|
|
||
|
setTimeout(() => {
|
||
|
notification.remove();
|
||
|
}, 3000);
|
||
|
}
|
||
|
|
||
|
// 其他功能
|
||
|
function generateReport() {
|
||
|
showNotification('正在生成业务报表...', 'success');
|
||
|
}
|
||
|
|
||
|
function exportData() {
|
||
|
showNotification('正在导出数据...', 'success');
|
||
|
}
|
||
|
|
||
|
function importStandards() {
|
||
|
showNotification('正在导入考核标准...', 'success');
|
||
|
}
|
||
|
|
||
|
function exportRecords() {
|
||
|
showNotification('正在导出转运记录...', 'success');
|
||
|
}
|
||
|
|
||
|
function filterRecords() {
|
||
|
showNotification('正在筛选记录...', 'success');
|
||
|
}
|
||
|
|
||
|
function generateAttendanceReport() {
|
||
|
showNotification('正在生成出勤报告...', 'success');
|
||
|
}
|
||
|
|
||
|
function exportAttendance() {
|
||
|
showNotification('正在导出出勤统计...', 'success');
|
||
|
}
|
||
|
|
||
|
function updateAttendanceStats() {
|
||
|
showNotification('正在更新出勤统计...', 'success');
|
||
|
}
|
||
|
|
||
|
// 修改viewAttendanceDetail函数
|
||
|
function viewAttendanceDetail(id) {
|
||
|
const attendance = attendanceData.find(a => a.id === id);
|
||
|
if (attendance) {
|
||
|
const content = document.getElementById('attendanceDetailContent');
|
||
|
content.innerHTML = `
|
||
|
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px; margin-bottom: 20px;">
|
||
|
<div class="detail-item">
|
||
|
<div class="detail-label">车辆编号</div>
|
||
|
<div class="detail-value">${attendance.vehicle}</div>
|
||
|
</div>
|
||
|
<div class="detail-item">
|
||
|
<div class="detail-label">车辆类型</div>
|
||
|
<div class="detail-value">${getVehicleTypeText(attendance.type)}</div>
|
||
|
</div>
|
||
|
<div class="detail-item">
|
||
|
<div class="detail-label">司机</div>
|
||
|
<div class="detail-value">${attendance.driver}</div>
|
||
|
</div>
|
||
|
<div class="detail-item">
|
||
|
<div class="detail-label">应出勤天数</div>
|
||
|
<div class="detail-value">${attendance.shouldWork}天</div>
|
||
|
</div>
|
||
|
<div class="detail-item">
|
||
|
<div class="detail-label">实际出勤天数</div>
|
||
|
<div class="detail-value">${attendance.actualWork}天</div>
|
||
|
</div>
|
||
|
<div class="detail-item">
|
||
|
<div class="detail-label">出勤率</div>
|
||
|
<div class="detail-value">${attendance.attendanceRate}%</div>
|
||
|
</div>
|
||
|
<div class="detail-item">
|
||
|
<div class="detail-label">完成任务数</div>
|
||
|
<div class="detail-value">${attendance.tasks}次</div>
|
||
|
</div>
|
||
|
<div class="detail-item">
|
||
|
<div class="detail-label">任务完成率</div>
|
||
|
<div class="detail-value">${attendance.completionRate}%</div>
|
||
|
</div>
|
||
|
<div class="detail-item">
|
||
|
<div class="detail-label">综合评分</div>
|
||
|
<div class="detail-value">${attendance.score}分</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
<div class="chart-container" style="margin-top: 20px;">
|
||
|
<div class="chart-title">月度出勤趋势</div>
|
||
|
<div class="chart-canvas">
|
||
|
<canvas id="detailAttendanceChart"></canvas>
|
||
|
</div>
|
||
|
</div>
|
||
|
`;
|
||
|
openModal('attendanceDetailModal');
|
||
|
|
||
|
// 绘制详情中的图表
|
||
|
drawDetailAttendanceChart(attendance);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function getVehicleTypeText(type) {
|
||
|
const typeMap = {
|
||
|
'truck': '转运车',
|
||
|
'boat': '清洁船',
|
||
|
'special': '特种车辆'
|
||
|
};
|
||
|
return typeMap[type] || type;
|
||
|
}
|
||
|
|
||
|
function drawDetailAttendanceChart(attendance) {
|
||
|
const ctx = document.getElementById('detailAttendanceChart').getContext('2d');
|
||
|
const days = Array.from({length: 30}, (_, i) => `${i+1}日`);
|
||
|
|
||
|
// 模拟每日出勤小时数(0-8小时)
|
||
|
const attendanceHours = Array.from({length: 30}, () => {
|
||
|
return Math.floor(Math.random() * 9) * (Math.random() < (attendance.actualWork / attendance.shouldWork) ? 1 : 0);
|
||
|
});
|
||
|
|
||
|
new Chart(ctx, {
|
||
|
type: 'bar',
|
||
|
data: {
|
||
|
labels: days,
|
||
|
datasets: [{
|
||
|
label: '出勤小时数',
|
||
|
data: attendanceHours,
|
||
|
backgroundColor: '#2a7de1',
|
||
|
borderColor: '#1a4b8c',
|
||
|
borderWidth: 1
|
||
|
}]
|
||
|
},
|
||
|
options: {
|
||
|
responsive: true,
|
||
|
maintainAspectRatio: false,
|
||
|
plugins: {
|
||
|
legend: {
|
||
|
labels: {
|
||
|
color: '#1a4b8c',
|
||
|
font: {
|
||
|
weight: 'bold'
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
tooltip: {
|
||
|
callbacks: {
|
||
|
label: function(context) {
|
||
|
return `${context.parsed.y} 小时`;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
scales: {
|
||
|
x: {
|
||
|
ticks: {
|
||
|
color: '#4a6fa5',
|
||
|
maxRotation: 45,
|
||
|
minRotation: 45
|
||
|
},
|
||
|
grid: {
|
||
|
color: 'rgba(209, 224, 245, 0.5)',
|
||
|
display: false
|
||
|
}
|
||
|
},
|
||
|
y: {
|
||
|
ticks: {
|
||
|
color: '#4a6fa5',
|
||
|
stepSize: 2,
|
||
|
callback: function(value) {
|
||
|
return value + 'h';
|
||
|
}
|
||
|
},
|
||
|
grid: {
|
||
|
color: 'rgba(209, 224, 245, 0.5)'
|
||
|
},
|
||
|
min: 0,
|
||
|
max: 8
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
function stationMaintenance() {
|
||
|
showNotification('正在进入维护管理...', 'success');
|
||
|
}
|
||
|
|
||
|
// 初始化 - 确保在页面完全加载后执行
|
||
|
window.onload = function () {
|
||
|
// 默认加载概览标签
|
||
|
document.querySelector('.nav-tab[onclick*="overview"]').classList.add('active');
|
||
|
document.getElementById('overview').classList.add('active');
|
||
|
|
||
|
// 初始化图表
|
||
|
drawAttendanceChart();
|
||
|
drawTransferChart();
|
||
|
|
||
|
// 点击模态框外部关闭
|
||
|
window.onclick = function (event) {
|
||
|
const modals = document.querySelectorAll('.modal');
|
||
|
modals.forEach(modal => {
|
||
|
if (event.target === modal) {
|
||
|
modal.style.display = 'none';
|
||
|
currentEditId = null;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// 绘制出勤率趋势图
|
||
|
function drawAttendanceChart() {
|
||
|
const ctx = document.getElementById('attendanceChart').getContext('2d');
|
||
|
const months = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'];
|
||
|
const attendanceRates = Array.from({ length: 12 }, () => Math.floor(85 + Math.random() * 16));
|
||
|
|
||
|
new Chart(ctx, {
|
||
|
type: 'line',
|
||
|
data: {
|
||
|
labels: months,
|
||
|
datasets: [{
|
||
|
label: '出勤率(%)',
|
||
|
data: attendanceRates,
|
||
|
borderColor: '#28a745',
|
||
|
backgroundColor: 'rgba(40, 167, 69, 0.1)',
|
||
|
tension: 0.4,
|
||
|
borderWidth: 2,
|
||
|
fill: true
|
||
|
}]
|
||
|
},
|
||
|
options: {
|
||
|
responsive: true,
|
||
|
maintainAspectRatio: false,
|
||
|
plugins: {
|
||
|
legend: {
|
||
|
labels: {
|
||
|
color: '#1a4b8c',
|
||
|
font: {
|
||
|
weight: 'bold'
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
scales: {
|
||
|
x: {
|
||
|
ticks: { color: '#4a6fa5' },
|
||
|
grid: { color: 'rgba(209, 224, 245, 0.5)' }
|
||
|
},
|
||
|
y: {
|
||
|
ticks: { color: '#4a6fa5' },
|
||
|
grid: { color: 'rgba(209, 224, 245, 0.5)' },
|
||
|
min: 80,
|
||
|
max: 100
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// 绘制转运量统计图
|
||
|
function drawTransferChart() {
|
||
|
const ctx = document.getElementById('transferChart').getContext('2d');
|
||
|
const months = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'];
|
||
|
const transferAmounts = Array.from({ length: 12 }, () => Math.floor(1000 + Math.random() * 501));
|
||
|
|
||
|
new Chart(ctx, {
|
||
|
type: 'bar',
|
||
|
data: {
|
||
|
labels: months,
|
||
|
datasets: [{
|
||
|
label: '转运量(吨)',
|
||
|
data: transferAmounts,
|
||
|
backgroundColor: 'rgba(42, 125, 225, 0.6)',
|
||
|
borderColor: '#2a7de1',
|
||
|
borderWidth: 1
|
||
|
}]
|
||
|
},
|
||
|
options: {
|
||
|
responsive: true,
|
||
|
maintainAspectRatio: false,
|
||
|
plugins: {
|
||
|
legend: {
|
||
|
labels: {
|
||
|
color: '#1a4b8c',
|
||
|
font: {
|
||
|
weight: 'bold'
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
scales: {
|
||
|
x: {
|
||
|
ticks: { color: '#4a6fa5' },
|
||
|
grid: { color: 'rgba(209, 224, 245, 0.5)' }
|
||
|
},
|
||
|
y: {
|
||
|
ticks: { color: '#4a6fa5' },
|
||
|
grid: { color: 'rgba(209, 224, 245, 0.5)' },
|
||
|
min: 900,
|
||
|
max: 1600
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
</script>
|
||
|
</body>
|
||
|
|
||
|
</html>
|