这是一个为您设计的单页 HTML 应用,专门用于矿车生产运营数据的统计与可视化。
### 设计思路
1. **布局与比例**:界面采用自适应容器设计,但在大屏幕上会尽量保持宽屏视觉效果(16:9 的核心图表区域)。整体采用现代化的深色/科技蓝风格,符合工业监控系统的审美。
2. **核心功能**:
* **顶部控制栏**:选择时间维度(年/月/天)、具体日期区间,以及关键指标筛选。
* **关键指标卡片**:直接展示您要求的 8 个核心统计数据(运行、作业、循环、怠速、装载、卸载、空车、重车)。
* **图表可视化**:使用 HTML5 Canvas 原生绘制折线图和柱状图,展示数据随时间(按天或按月)的分布趋势,不依赖第三方库。
* **详细数据列表**:底部提供表格,支持滚动查看具体的周期性数据。
3. **交互体验**:
* 点击“生成报表”会模拟数据加载并刷新界面。
* 切换“年/月/日”视图时,图表的 X 轴和粒度会自动调整。
* 包含数据导出和打印功能的模拟按钮。
* 无原生 `alert`,使用自定义的 Toast 消息提示。
### 完整代码
您可以直接保存以下代码为 `.html` 文件并在浏览器中打开。
```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>矿车生产运营数据统计平台</title>
<style>
:root {
--bg-dark: #0f172a;
--bg-panel: #1e293b;
--text-primary: #f8fafc;
--text-secondary: #94a3b8;
--accent-blue: #3b82f6;
--accent-cyan: #06b6d4;
--accent-green: #10b981;
--accent-orange: #f59e0b;
--border-color: #334155;
--card-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif;
}
body {
background-color: var(--bg-dark);
color: var(--text-primary);
min-height: 100vh;
display: flex;
flex-direction: column;
overflow-x: hidden;
}
/* 16:9 容器模拟 (在大屏上限制最大宽度以保持比例感) */
.container {
width: 100%;
max-width: 1600px;
margin: 0 auto;
padding: 20px;
display: flex;
flex-direction: column;
gap: 20px;
flex: 1;
}
/* 顶部导航与控制栏 */
header {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 20px;
border-bottom: 1px solid var(--border-color);
}
h1 {
font-size: 24px;
font-weight: 600;
display: flex;
align-items: center;
gap: 10px;
}
h1::before {
content: '';
display: block;
width: 6px;
height: 24px;
background: var(--accent-cyan);
border-radius: 2px;
}
.controls {
display: flex;
gap: 12px;
align-items: center;
flex-wrap: wrap;
}
/* 表单元素样式 */
select, input[type="date"], input[type="text"] {
background-color: var(--bg-panel);
border: 1px solid var(--border-color);
color: var(--text-primary);
padding: 8px 12px;
border-radius: 6px;
font-size: 14px;
outline: none;
transition: border-color 0.2s;
}
select:focus, input:focus {
border-color: var(--accent-blue);
}
button.btn-primary {
background: linear-gradient(135deg, var(--accent-blue), var(--accent-cyan));
border: none;
color: white;
padding: 8px 20px;
border-radius: 6px;
cursor: pointer;
font-weight: 600;
transition: opacity 0.2s, transform 0.1s;
}
button.btn-primary:hover {
opacity: 0.9;
}
button.btn-primary:active {
transform: scale(0.98);
}
button.btn-icon {
background: transparent;
border: 1px solid var(--border-color);
color: var(--text-secondary);
width: 36px;
height: 36px;
border-radius: 6px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s;
}
button.btn-icon:hover {
color: var(--text-primary);
border-color: var(--text-secondary);
background-color: rgba(255,255,255,0.05);
}
/* 统计卡片区域 */
.metrics-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
}
.metric-card {
background-color: var(--bg-panel);
padding: 20px;
border-radius: 12px;
box-shadow: var(--card-shadow);
border: 1px solid rgba(255,255,255,0.05);
position: relative;
overflow: hidden;
}
.metric-card::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 4px;
height: 100%;
background-color: var(--accent-blue);
}
.metric-card:nth-child(2)::after { background-color: var(--accent-cyan); }
.metric-card:nth-child(3)::after { background-color: var(--accent-green); }
.metric-card:nth-child(4)::after { background-color: var(--accent-orange); }
.metric-title {
font-size: 13px;
color: var(--text-secondary);
margin-bottom: 8px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.metric-value {
font-size: 28px;
font-weight: 700;
color: var(--text-primary);
display: flex;
align-items: baseline;
gap: 4px;
}
.metric-unit {
font-size: 14px;
color: var(--text-secondary);
font-weight: 400;
}
/* 图表区域 */
.charts-container {
display: grid;
grid-template-columns: 2fr 1fr; /* 2:1 比例 */
gap: 20px;
height: 400px;
}
.chart-panel {
background-color: var(--bg-panel);
border-radius: 12px;
padding: 20px;
box-shadow: var(--card-shadow);
display: flex;
flex-direction: column;
}
.panel-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
}
.panel-title {
font-size: 16px;
font-weight: 600;
}
.chart-wrapper {
flex: 1;
position: relative;
width: 100%;
height: 100%;
}
canvas {
width: 100%;
height: 100%;
}
/* 详细数据表格 */
.data-table-section {
background-color: var(--bg-panel);
border-radius: 12px;
padding: 20px;
box-shadow: var(--card-shadow);
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
}
.table-container {
overflow-y: auto;
flex: 1;
margin-top: 10px;
}
table {
width: 100%;
border-collapse: collapse;
font-size: 14px;
}
thead th {
text-align: left;
padding: 12px;
background-color: rgba(255,255,255,0.05);
color: var(--text-secondary);
position: sticky;
top: 0;
z-index: 10;
}
tbody td {
padding: 12px;
border-bottom: 1px solid var(--border-color);
color: var(--text-primary);
}
tbody tr:hover {
background-color: rgba(255,255,255,0.02);
}
/* 状态标签 */
.status-tag {
display: inline-block;
padding: 2px 8px;
border-radius: 4px;
font-size: 12px;
background-color: rgba(16, 185, 129, 0.2);
color: var(--accent-green);
}
/* Toast 提示 */
#toast-container {
position: fixed;
top: 20px;
right: 20px;
z-index: 1000;
}
.toast {
background-color: var(--bg-panel);
border-left: 4px solid var(--accent-blue);
color: var(--text-primary);
padding: 15px 20px;
border-radius: 4px;
margin-bottom: 10px;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.5);
opacity: 0;
transform: translateX(20px);
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 10px;
}
.toast.show {
opacity: 1;
transform: translateX(0);
}
/* 响应式适配 */
@media (max-width: 1024px) {
.metrics-grid {
grid-template-columns: repeat(2, 1fr);
}
.charts-container {
grid-template-columns: 1fr;
height: auto;
}
.chart-panel {
height: 350px;
}
}
@media (max-width: 768px) {
.metrics-grid {
grid-template-columns: 1fr;
}
header {
flex-direction: column;
align-items: flex-start;
gap: 15px;
}
.controls {
width: 100%;
}
.controls select, .controls input {
flex: 1;
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>矿车生产运营数据统计</h1>
<div class="controls">
<select id="timeRangeType" onchange="handleTimeTypeChange()">
<option value="day">按日统计</option>
<option value="month">按月统计</option>
<option value="year">按年统计</option>
</select>
<input type="date" id="startDate">
<span style="color: var(--text-secondary)">至</span>
<input type="date" id="endDate">
<button class="btn-primary" onclick="updateDashboard()">生成报表</button>
<button class="btn-icon" onclick="exportData()" title="导出数据">
<svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path></svg>
</button>
<button class="btn-icon" onclick="printReport()" title="打印">
<svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 17h2a2 2 0 002-2v-4a2 2 0 00-2-2H5a2 2 0 00-2 2v4a2 2 0 002 2h2m2 4h6a2 2 0 002-2v-4a2 2 0 00-2-2H9a2 2 0 00-2 2v4a2 2 0 002 2zm8-12V5a2 2 0 00-2-2H9a2 2 0 00-2 2v4h10z"></path></svg>
</button>
</div>
</header>
<!-- 关键指标卡片 -->
<section class="metrics-grid">
<div class="metric-card">
<div class="metric-title">运行时长</div>
<div class="metric-value"><span id="val-totalTime">0</span> <span class="metric-unit">小时</span></div>
</div>
<div class="metric-card">
<div class="metric-title">作业循环次数</div>
<div class="metric-value"><span id="val-cycles">0</span> <span class="metric-unit">次</span></div>
</div>
<div class="metric-card">
<div class="metric-title">作业时长</div>
<div class="metric-value"><span id="val-workTime">0</span> <span class="metric-unit">小时</span></div