| | |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="GPS点数" align="center" prop="gpsPointCount" width="90" /> |
| | | <el-table-column label="任务数" align="center" prop="taskCount" width="80" /> |
| | | <el-table-column label="分段数" align="center" prop="segmentCount" width="80" /> |
| | | |
| | | <el-table-column label="统计时间" align="center" prop="createTime" width="160"> |
| | | <template slot-scope="scope"> |
| | | <span>{{ parseTime(scope.row.createTime) }}</span> |
| | |
| | | <!-- 手动统计对话框 --> |
| | | <el-dialog title="手动里程统计" :visible.sync="calculateOpen" width="500px" append-to-body> |
| | | <el-form ref="calculateForm" :model="calculateForm" :rules="calculateRules" label-width="100px"> |
| | | <el-form-item label="车辆ID" prop="vehicleId"> |
| | | <el-input v-model="calculateForm.vehicleId" placeholder="请输入车辆ID" type="number" /> |
| | | <el-form-item label="车牌号" prop="vehicleId"> |
| | | <el-select |
| | | v-model="calculateForm.vehicleId" |
| | | placeholder="请输入车牌号搜索" |
| | | filterable |
| | | remote |
| | | :remote-method="searchVehicles" |
| | | :loading="vehicleSearchLoading" |
| | | clearable |
| | | style="width: 100%" |
| | | @change="handleVehicleChange" |
| | | > |
| | | <el-option |
| | | v-for="vehicle in vehicleOptions" |
| | | :key="vehicle.vehicleId" |
| | | :label="vehicle.vehicleNo" |
| | | :value="vehicle.vehicleId" |
| | | > |
| | | <span style="float: left">{{ vehicle.vehicleNo }}</span> |
| | | <span style="float: right; color: #8492a6; font-size: 13px" v-if="vehicle.deptName"> |
| | | {{ vehicle.deptName }} |
| | | </span> |
| | | </el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="统计日期" prop="statDate"> |
| | | <el-date-picker |
| | |
| | | </el-dialog> |
| | | |
| | | <!-- 详情对话框 --> |
| | | <el-dialog title="里程统计详情" :visible.sync="detailOpen" width="600px" append-to-body> |
| | | <el-dialog title="里程统计详情" :visible.sync="detailOpen" width="900px" append-to-body> |
| | | <el-descriptions :column="2" border> |
| | | <el-descriptions-item label="车牌号">{{ detailData.vehicleNo }}</el-descriptions-item> |
| | | <el-descriptions-item label="归属分公司">{{ detailData.deptName || '-' }}</el-descriptions-item> |
| | |
| | | {{ formatRatio(detailData.taskRatio) }} |
| | | </el-tag> |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="GPS点数">{{ detailData.gpsPointCount }}</el-descriptions-item> |
| | | <el-descriptions-item label="任务数">{{ detailData.taskCount }}</el-descriptions-item> |
| | | <el-descriptions-item label="分段数">{{ detailData.segmentCount }}</el-descriptions-item> |
| | | <el-descriptions-item label="数据来源"> |
| | | <el-tag :type="detailData.dataSource === 'segment' ? 'success' : 'info'" size="small"> |
| | | {{ detailData.dataSource === 'segment' ? '从分段汇总' : '直接计算' }} |
| | | </el-tag> |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="统计时间" :span="2"> |
| | | {{ parseTime(detailData.createTime) }} |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | | |
| | | <!-- 分段明细表格 --> |
| | | <div v-if="segmentList.length > 0" style="margin-top: 20px;"> |
| | | <el-divider content-position="left"> |
| | | <i class="el-icon-tickets"></i> 里程分段明细 |
| | | </el-divider> |
| | | |
| | | <el-table |
| | | :data="segmentList" |
| | | size="small" |
| | | :max-height="400" |
| | | stripe |
| | | border |
| | | v-loading="segmentLoading" |
| | | > |
| | | <el-table-column type="index" label="序号" width="50" align="center" /> |
| | | <el-table-column label="开始时间" prop="segmentStartTime" width="160" align="center"> |
| | | <template slot-scope="scope"> |
| | | {{ parseTime(scope.row.segmentStartTime, '{y}-{m}-{d} {h}:{i}:{s}') }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="结束时间" prop="segmentEndTime" width="160" align="center"> |
| | | <template slot-scope="scope"> |
| | | {{ parseTime(scope.row.segmentEndTime, '{y}-{m}-{d} {h}:{i}:{s}') }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="里程(km)" prop="segmentDistance" width="100" align="center"> |
| | | <template slot-scope="scope"> |
| | | <span class="mileage-value">{{ (scope.row.segmentDistance || 0).toFixed(2) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | |
| | | <el-table-column label="关联任务" prop="taskCode" align="center" min-width="120"> |
| | | <template slot-scope="scope"> |
| | | <el-tag v-if="scope.row.taskCode" size="small" type="success">{{ scope.row.taskCode }}</el-tag> |
| | | <span v-else style="color: #909399;">无任务</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="计算方式" prop="calculateMethod" align="center" width="100"> |
| | | <template slot-scope="scope"> |
| | | <el-tag size="small" :type="scope.row.calculateMethod === 'haversine' ? 'primary' : 'info'"> |
| | | {{ scope.row.calculateMethod === 'haversine' ? '球面距离' : '直线距离' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | |
| | | <div slot="footer" class="dialog-footer"> |
| | | <el-button @click="detailOpen = false">关 闭</el-button> |
| | | </div> |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import { listMileageStats, getMileageStats, delMileageStats, calculateMileageStats, batchCalculateMileageStats } from "@/api/system/mileageStats"; |
| | | import { listMileageStats, getMileageStats, delMileageStats, calculateMileageStats, batchCalculateMileageStats, getSegmentsByDateRange } from "@/api/system/mileageStats"; |
| | | import { listDept } from "@/api/system/dept"; |
| | | import { listVehicle } from "@/api/system/vehicle"; |
| | | |
| | | export default { |
| | | name: "MileageStats", |
| | |
| | | detailOpen: false, |
| | | // 详情数据 |
| | | detailData: {}, |
| | | // 分段明细列表 |
| | | segmentList: [], |
| | | // 分段明细加载状态 |
| | | segmentLoading: false, |
| | | // 手动统计加载状态 |
| | | calculateLoading: false, |
| | | // 批量统计加载状态 |
| | | batchCalculateLoading: false, |
| | | // 车辆搜索加载状态 |
| | | vehicleSearchLoading: false, |
| | | // 车辆选项列表 |
| | | vehicleOptions: [], |
| | | // 查询参数 |
| | | queryParams: { |
| | | pageNum: 1, |
| | |
| | | // 手动统计表单校验 |
| | | calculateRules: { |
| | | vehicleId: [ |
| | | { required: true, message: "车辆ID不能为空", trigger: "blur" } |
| | | { required: true, message: "请选择车辆", trigger: "change" } |
| | | ], |
| | | statDate: [ |
| | | { required: true, message: "统计日期不能为空", trigger: "change" } |
| | |
| | | /** 手动统计按钮操作 */ |
| | | handleCalculate() { |
| | | this.reset(); |
| | | this.vehicleOptions = []; |
| | | this.calculateOpen = true; |
| | | // 打开对话框时加载一些车辆数据 |
| | | this.searchVehicles(''); |
| | | }, |
| | | /** 搜索车辆 */ |
| | | searchVehicles(query) { |
| | | if (query !== '') { |
| | | this.vehicleSearchLoading = true; |
| | | listVehicle({ |
| | | vehicleNo: query, |
| | | pageNum: 1, |
| | | pageSize: 50 |
| | | }).then(response => { |
| | | this.vehicleOptions = response.rows || []; |
| | | this.vehicleSearchLoading = false; |
| | | }).catch(() => { |
| | | this.vehicleSearchLoading = false; |
| | | }); |
| | | } else { |
| | | // 如果查询为空,加载前50条车辆数据 |
| | | this.vehicleSearchLoading = true; |
| | | listVehicle({ |
| | | pageNum: 1, |
| | | pageSize: 50 |
| | | }).then(response => { |
| | | this.vehicleOptions = response.rows || []; |
| | | this.vehicleSearchLoading = false; |
| | | }).catch(() => { |
| | | this.vehicleSearchLoading = false; |
| | | }); |
| | | } |
| | | }, |
| | | /** 车辆选择变化 */ |
| | | handleVehicleChange(value) { |
| | | // 可以在这里添加额外的处理逻辑 |
| | | console.log('选择的车辆ID:', value); |
| | | }, |
| | | /** 批量统计按钮操作 */ |
| | | handleBatchCalculate() { |
| | |
| | | /** 查看详情按钮操作 */ |
| | | handleView(row) { |
| | | const statsId = row.statsId; |
| | | |
| | | // 重置分段明细 |
| | | this.segmentList = []; |
| | | |
| | | // 加载统计详情 |
| | | getMileageStats(statsId).then(response => { |
| | | this.detailData = response.data; |
| | | this.detailOpen = true; |
| | | |
| | | // 如果有车辆ID和统计日期,加载分段明细 |
| | | if (this.detailData.vehicleId && this.detailData.statDate) { |
| | | this.loadSegmentDetails(this.detailData.vehicleId, this.detailData.statDate); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | /** 加载分段明细 */ |
| | | loadSegmentDetails(vehicleId, statDate) { |
| | | this.segmentLoading = true; |
| | | |
| | | // 格式化日期:统计日期的开始和结束时间 |
| | | const startDate = this.parseTime(statDate, '{y}-{m}-{d}'); |
| | | const endDate = this.parseTime(statDate, '{y}-{m}-{d}'); |
| | | |
| | | // 查询该日期的分段里程明细 |
| | | getSegmentsByDateRange(vehicleId, startDate, endDate).then(response => { |
| | | if (response.code === 200 && response.data) { |
| | | this.segmentList = response.data; |
| | | console.log('分段明细数据:', this.segmentList); |
| | | } else { |
| | | this.segmentList = []; |
| | | } |
| | | }).catch(error => { |
| | | console.error('加载分段明细失败', error); |
| | | this.segmentList = []; |
| | | this.$modal.msgWarning('加载分段明细失败,但不影响统计数据查看'); |
| | | }).finally(() => { |
| | | this.segmentLoading = false; |
| | | }); |
| | | }, |
| | | /** 删除按钮操作 */ |