- 删除多个不再使用的脚本和配置文件,包括 `auto_push.bat`, `check_and_fix_users.py`, `init.sql` 等。 - 新增 `git_push.bat` 和 `git_push.sh` 脚本以简化 Git 推送流程。 - 更新 `README.md` 以反映最新的功能和结构变化。 - 优化前端代码,添加新的页面和组件,提升用户体验。 此提交旨在清理项目结构并增强代码可维护性。
403 lines
16 KiB
JavaScript
403 lines
16 KiB
JavaScript
/**
|
||
* 车辆数据页面组件
|
||
*/
|
||
|
||
export default class Vehicle {
|
||
constructor(container, route) {
|
||
this.container = container;
|
||
this.route = route;
|
||
this.init();
|
||
}
|
||
|
||
async init() {
|
||
try {
|
||
this.render();
|
||
this.bindEvents();
|
||
this.loadVehicleData();
|
||
} catch (error) {
|
||
console.error('Vehicle init error:', error);
|
||
this.showError(error);
|
||
}
|
||
}
|
||
|
||
render() {
|
||
this.container.innerHTML = `
|
||
<div class="page-header">
|
||
<div>
|
||
<h1 class="page-title">车辆数据管理</h1>
|
||
<p class="page-subtitle">查看和管理车辆实时数据</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 查询条件 -->
|
||
<div class="card mb-4">
|
||
<div class="card-header">
|
||
<h5 class="card-title mb-0">
|
||
<i class="fas fa-search me-2"></i>数据查询
|
||
</h5>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="row g-3">
|
||
<div class="col-md-3">
|
||
<label for="vehicle_id" class="form-label">车辆ID</label>
|
||
<input type="text" class="form-control" id="vehicle_id"
|
||
placeholder="输入车辆ID">
|
||
</div>
|
||
<div class="col-md-3">
|
||
<label for="vehicle_vin" class="form-label">车架号(VIN)</label>
|
||
<input type="text" class="form-control" id="vehicle_vin"
|
||
placeholder="输入车架号">
|
||
</div>
|
||
<div class="col-md-3">
|
||
<label for="data_type" class="form-label">数据类型</label>
|
||
<select class="form-select" id="data_type">
|
||
<option value="">全部类型</option>
|
||
<option value="location">位置信息</option>
|
||
<option value="status">状态信息</option>
|
||
<option value="fault">故障信息</option>
|
||
<option value="performance">性能数据</option>
|
||
</select>
|
||
</div>
|
||
<div class="col-md-3">
|
||
<label for="limit" class="form-label">显示数量</label>
|
||
<select class="form-select" id="limit">
|
||
<option value="10">10条</option>
|
||
<option value="50">50条</option>
|
||
<option value="100">100条</option>
|
||
<option value="500">500条</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="row mt-3">
|
||
<div class="col-12">
|
||
<button class="btn btn-primary me-2" id="search-btn">
|
||
<i class="fas fa-search me-2"></i>查询
|
||
</button>
|
||
<button class="btn btn-success me-2" id="init-sample-btn">
|
||
<i class="fas fa-plus me-2"></i>初始化示例数据
|
||
</button>
|
||
<button class="btn btn-info" id="add-data-btn">
|
||
<i class="fas fa-plus-circle me-2"></i>添加数据
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 数据表格 -->
|
||
<div class="card">
|
||
<div class="card-header d-flex justify-content-between align-items-center">
|
||
<h5 class="card-title mb-0">
|
||
<i class="fas fa-table me-2"></i>车辆数据列表
|
||
</h5>
|
||
<div id="data-count" class="text-muted small">共 0 条数据</div>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="table-responsive">
|
||
<table class="table table-striped table-hover" id="vehicle-data-table">
|
||
<thead>
|
||
<tr>
|
||
<th>ID</th>
|
||
<th>车辆ID</th>
|
||
<th>车架号</th>
|
||
<th>数据类型</th>
|
||
<th>数据内容</th>
|
||
<th>时间戳</th>
|
||
<th>操作</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="vehicle-data-body">
|
||
<tr>
|
||
<td colspan="7" class="text-center text-muted">
|
||
<i class="fas fa-spinner fa-spin me-2"></i>加载中...
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 添加数据模态框 -->
|
||
<div class="modal fade" id="addDataModal" tabindex="-1">
|
||
<div class="modal-dialog modal-lg">
|
||
<div class="modal-content">
|
||
<div class="modal-header">
|
||
<h5 class="modal-title">添加车辆数据</h5>
|
||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<form id="add-data-form">
|
||
<div class="row g-3">
|
||
<div class="col-md-6">
|
||
<label for="add_vehicle_id" class="form-label">车辆ID *</label>
|
||
<input type="text" class="form-control" id="add_vehicle_id"
|
||
name="vehicle_id" required>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<label for="add_vehicle_vin" class="form-label">车架号(VIN)</label>
|
||
<input type="text" class="form-control" id="add_vehicle_vin"
|
||
name="vehicle_vin">
|
||
</div>
|
||
<div class="col-md-6">
|
||
<label for="add_data_type" class="form-label">数据类型 *</label>
|
||
<select class="form-select" id="add_data_type" name="data_type" required>
|
||
<option value="location">位置信息</option>
|
||
<option value="status">状态信息</option>
|
||
<option value="fault">故障信息</option>
|
||
<option value="performance">性能数据</option>
|
||
</select>
|
||
</div>
|
||
<div class="col-md-12">
|
||
<label for="add_data_value" class="form-label">数据内容 (JSON格式) *</label>
|
||
<textarea class="form-control" id="add_data_value" name="data_value"
|
||
rows="6" placeholder='例如:{"latitude": 39.9042, "longitude": 116.4074}'
|
||
required></textarea>
|
||
<div class="form-text">请输入有效的JSON格式数据</div>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
|
||
<button type="button" class="btn btn-primary" id="save-data-btn">保存</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
bindEvents() {
|
||
// 查询按钮
|
||
document.getElementById('search-btn').addEventListener('click', () => {
|
||
this.loadVehicleData();
|
||
});
|
||
|
||
// 初始化示例数据
|
||
document.getElementById('init-sample-btn').addEventListener('click', () => {
|
||
this.initSampleData();
|
||
});
|
||
|
||
// 添加数据按钮
|
||
document.getElementById('add-data-btn').addEventListener('click', () => {
|
||
this.showAddDataModal();
|
||
});
|
||
|
||
// 保存数据
|
||
document.getElementById('save-data-btn').addEventListener('click', () => {
|
||
this.saveVehicleData();
|
||
});
|
||
|
||
// 输入框回车查询
|
||
['vehicle_id', 'vehicle_vin'].forEach(id => {
|
||
document.getElementById(id).addEventListener('keypress', (e) => {
|
||
if (e.key === 'Enter') {
|
||
this.loadVehicleData();
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
async loadVehicleData() {
|
||
const vehicleId = document.getElementById('vehicle_id').value.trim();
|
||
const vehicleVin = document.getElementById('vehicle_vin').value.trim();
|
||
const dataType = document.getElementById('data_type').value;
|
||
const limit = document.getElementById('limit').value;
|
||
|
||
const params = new URLSearchParams();
|
||
if (vehicleId) params.append('vehicle_id', vehicleId);
|
||
if (vehicleVin) params.append('vehicle_vin', vehicleVin);
|
||
if (dataType) params.append('data_type', dataType);
|
||
if (limit) params.append('limit', limit);
|
||
|
||
try {
|
||
const response = await fetch(`/api/vehicle/data?${params}`);
|
||
const data = await response.json();
|
||
|
||
if (Array.isArray(data)) {
|
||
this.renderVehicleData(data);
|
||
document.getElementById('data-count').textContent = `共 ${data.length} 条数据`;
|
||
} else {
|
||
this.showErrorInTable('数据格式错误');
|
||
}
|
||
} catch (error) {
|
||
console.error('加载车辆数据失败:', error);
|
||
this.showErrorInTable('加载数据失败');
|
||
}
|
||
}
|
||
|
||
renderVehicleData(data) {
|
||
const tbody = document.getElementById('vehicle-data-body');
|
||
|
||
if (data.length === 0) {
|
||
tbody.innerHTML = `
|
||
<tr>
|
||
<td colspan="7" class="text-center text-muted">
|
||
<i class="fas fa-inbox me-2"></i>暂无数据
|
||
</td>
|
||
</tr>
|
||
`;
|
||
return;
|
||
}
|
||
|
||
tbody.innerHTML = data.map(item => {
|
||
const timestamp = new Date(item.timestamp).toLocaleString();
|
||
let dataValue = item.data_value;
|
||
|
||
try {
|
||
const parsed = JSON.parse(dataValue);
|
||
dataValue = JSON.stringify(parsed, null, 2);
|
||
} catch (e) {
|
||
// 如果不是JSON格式,保持原样
|
||
}
|
||
|
||
return `
|
||
<tr>
|
||
<td>${item.id}</td>
|
||
<td>${item.vehicle_id}</td>
|
||
<td>${item.vehicle_vin || '-'}</td>
|
||
<td><span class="badge bg-primary">${item.data_type}</span></td>
|
||
<td>
|
||
<pre class="small mb-0" style="max-height: 100px; overflow: hidden;">${dataValue}</pre>
|
||
</td>
|
||
<td>${timestamp}</td>
|
||
<td>
|
||
<button class="btn btn-sm btn-outline-info me-1" onclick="showDataDetails(${item.id})">
|
||
<i class="fas fa-eye"></i>
|
||
</button>
|
||
</td>
|
||
</tr>
|
||
`;
|
||
}).join('');
|
||
}
|
||
|
||
showErrorInTable(message) {
|
||
const tbody = document.getElementById('vehicle-data-body');
|
||
tbody.innerHTML = `
|
||
<tr>
|
||
<td colspan="7" class="text-center text-danger">
|
||
<i class="fas fa-exclamation-triangle me-2"></i>${message}
|
||
</td>
|
||
</tr>
|
||
`;
|
||
}
|
||
|
||
async initSampleData() {
|
||
if (!confirm('确定要初始化示例车辆数据吗?这将会添加一些测试数据。')) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const response = await fetch('/api/vehicle/init-sample-data', { method: 'POST' });
|
||
const data = await response.json();
|
||
|
||
if (data.success) {
|
||
if (window.showToast) {
|
||
window.showToast('示例数据初始化成功', 'success');
|
||
}
|
||
this.loadVehicleData();
|
||
} else {
|
||
if (window.showToast) {
|
||
window.showToast(data.message || '初始化失败', 'error');
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('初始化示例数据失败:', error);
|
||
if (window.showToast) {
|
||
window.showToast('网络错误', 'error');
|
||
}
|
||
}
|
||
}
|
||
|
||
showAddDataModal() {
|
||
const modal = new bootstrap.Modal(document.getElementById('addDataModal'));
|
||
modal.show();
|
||
}
|
||
|
||
async saveVehicleData() {
|
||
const form = document.getElementById('add-data-form');
|
||
const formData = new FormData(form);
|
||
|
||
const data = {
|
||
vehicle_id: formData.get('vehicle_id'),
|
||
vehicle_vin: formData.get('vehicle_vin') || null,
|
||
data_type: formData.get('data_type'),
|
||
data_value: formData.get('data_value')
|
||
};
|
||
|
||
// 验证JSON格式
|
||
try {
|
||
JSON.parse(data.data_value);
|
||
} catch (e) {
|
||
if (window.showToast) {
|
||
window.showToast('数据内容必须是有效的JSON格式', 'error');
|
||
}
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const response = await fetch('/api/vehicle/data', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(data)
|
||
});
|
||
|
||
const result = await response.json();
|
||
|
||
if (result.success) {
|
||
if (window.showToast) {
|
||
window.showToast('数据添加成功', 'success');
|
||
}
|
||
|
||
// 关闭模态框
|
||
const modal = bootstrap.Modal.getInstance(document.getElementById('addDataModal'));
|
||
modal.hide();
|
||
|
||
// 清空表单
|
||
form.reset();
|
||
|
||
// 重新加载数据
|
||
this.loadVehicleData();
|
||
} else {
|
||
if (window.showToast) {
|
||
window.showToast(result.message || '添加失败', 'error');
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('保存数据失败:', error);
|
||
if (window.showToast) {
|
||
window.showToast('网络错误', 'error');
|
||
}
|
||
}
|
||
}
|
||
|
||
showError(error) {
|
||
this.container.innerHTML = `
|
||
<div class="row justify-content-center">
|
||
<div class="col-md-6">
|
||
<div class="card">
|
||
<div class="card-body text-center">
|
||
<i class="fas fa-exclamation-triangle fa-3x text-danger mb-3"></i>
|
||
<h4>页面加载失败</h4>
|
||
<p class="text-muted">${error.message || '未知错误'}</p>
|
||
<button class="btn btn-primary" onclick="location.reload()">
|
||
<i class="fas fa-redo me-2"></i>重新加载
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`;
|
||
}
|
||
}
|
||
|
||
// 全局函数,用于查看数据详情
|
||
window.showDataDetails = function(id) {
|
||
// 这里可以实现查看详细数据的功能
|
||
console.log('查看数据详情:', id);
|
||
if (window.showToast) {
|
||
window.showToast('详情查看功能开发中', 'info');
|
||
}
|
||
};
|