Files
assist/src/web/static/js/pages/vehicle.js

403 lines
16 KiB
JavaScript
Raw Normal View History

/**
* 车辆数据页面组件
*/
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');
}
};