Files
assist/src/web/static/js/pages/vehicle.js
zhaojie 2026007045 refactor: 移除冗余文件并优化代码结构
- 删除多个不再使用的脚本和配置文件,包括 `auto_push.bat`, `check_and_fix_users.py`, `init.sql` 等。
- 新增 `git_push.bat` 和 `git_push.sh` 脚本以简化 Git 推送流程。
- 更新 `README.md` 以反映最新的功能和结构变化。
- 优化前端代码,添加新的页面和组件,提升用户体验。

此提交旨在清理项目结构并增强代码可维护性。
2025-12-08 00:53:23 +08:00

403 lines
16 KiB
JavaScript
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.
/**
* 车辆数据页面组件
*/
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');
}
};