展示

代码
javascript
<template>
<el-table :data="tableData" style="width: 100%; table-layout: fixed" border>
<!-- 车牌号列 -->
<el-table-column prop="carNo" label="车牌号" width="120" align="center" fixed />
<!-- 动态日期列 -->
<el-table-column
v-for="date in allDates"
:key="date"
:label="date"
width="150"
align="center"
>
<template #default="{ row }">
<div class="time-bar-container">
<div
v-for="(block, idx) in getTimeBlocks(row.dayTimeRanges[date])"
:key="idx"
class="time-block"
:style="{
left: block.left + '%',
width: block.width + '%'
}"
:title="block.tooltip"
></div>
</div>
</template>
</el-table-column>
</el-table>
</template>
<script setup>
import { ref, computed } from 'vue';
// ====== 工具函数 ======
function formatDateToLocalYMD(date) {
const y = date.getFullYear();
const m = String(date.getMonth() + 1).padStart(2, '0');
const d = String(date.getDate()).padStart(2, '0');
return `${y}-${m}-${d}`;
}
function formatTimeHHMMSS(date) {
const h = String(date.getHours()).padStart(2, '0');
const m = String(date.getMinutes()).padStart(2, '0');
const s = String(date.getSeconds()).padStart(2, '0');
return `${h}:${m}:${s}`;
}
// 按天拆分跨天时间段
function groupByDay(timeRanges) {
const result = {};
timeRanges.forEach(range => {
let currentStart = new Date(range.startTime);
const finalEnd = new Date(range.endTime);
while (currentStart < finalEnd) {
const currentDateStr = formatDateToLocalYMD(currentStart);
const year = currentStart.getFullYear();
const month = currentStart.getMonth();
const day = currentStart.getDate();
const nextDayStart = new Date(year, month, day + 1);
const segmentEnd = nextDayStart < finalEnd ? nextDayStart : finalEnd;
let displayEnd = segmentEnd;
if (segmentEnd.getTime() === nextDayStart.getTime()) {
displayEnd = new Date(segmentEnd.getTime() - 1);
}
const timeStr = `${formatTimeHHMMSS(currentStart)}-${formatTimeHHMMSS(displayEnd)}`;
if (!result[currentDateStr]) result[currentDateStr] = [];
result[currentDateStr].push(timeStr);
currentStart = segmentEnd;
}
});
return result; // 返回 { '2025-12-24': ['08:00:00-09:00:00', ...], ... }
}
// 将时间字符串(如 "08:00:00-09:00:00")解析为秒数区间
function parseRangeStr(rangeStr) {
const [startStr, endStr] = rangeStr.split('-');
const toSeconds = (t) => {
const [h, m, s] = t.split(':').map(Number);
return h * 3600 + m * 60 + s;
};
let startSec = toSeconds(startStr);
let endSec = toSeconds(endStr);
// 处理 23:59:59 → 视为 24:00:00(86400 秒)
if (endSec === 23 * 3600 + 59 * 60 + 59) {
endSec = 24 * 3600;
}
return { startSec, endSec };
}
// 计算时间段在 0~100% 中的位置
function getTimeBlocks(rangeStrs) {
if (!rangeStrs || !Array.isArray(rangeStrs)) return [];
const totalSec = 24 * 3600; // 86400
return rangeStrs.map(str => {
const { startSec, endSec } = parseRangeStr(str);
const left = (startSec / totalSec) * 100;
const width = ((endSec - startSec) / totalSec) * 100;
const formatSec = (sec) => {
if (sec >= 86400) return '24:00';
const h = Math.floor(sec / 3600);
const m = Math.floor((sec % 3600) / 60);
const s = sec % 60;
return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
};
const tooltip = `${formatSec(startSec)} - ${formatSec(endSec)}`;
return { left, width, tooltip };
});
}
// ====== 原始数据 ======
const rawData = [
{
carNo: "沪A12345",
infoList: [
{ startTime: "2025-12-24 08:00:00", endTime: "2025-12-24 09:00:00" },
{ startTime: "2025-12-24 10:00:00", endTime: "2025-12-24 11:00:00" },
{ startTime: "2025-12-24 12:00:00", endTime: "2025-12-25 08:00:00" },
{ startTime: "2025-12-26 08:00:00", endTime: "2026-01-09 08:00:00" }
]
},
{
carNo: "京B67890",
infoList: [
{ startTime: "2025-12-25 09:00:00", endTime: "2025-12-25 17:00:00" }
]
}
];
// ====== 处理表格数据 ======
const processedCars = rawData.map(car => {
const dayTimeRanges = groupByDay(car.infoList); // { '2025-12-24': [...], ... }
return {
carNo: car.carNo,
dayTimeRanges // 直接存 map,方便后续按日期取
};
});
// 提取所有唯一日期(排序)
const allDatesSet = new Set();
processedCars.forEach(car => {
Object.keys(car.dayTimeRanges).forEach(date => allDatesSet.add(date));
});
const allDates = Array.from(allDatesSet).sort();
// 表格数据
const tableData = ref(processedCars);
</script>
<style scoped>
.time-bar-container {
position: relative;
width: 100%;
height: 24px;
overflow: hidden;
}
.time-block {
position: absolute;
top: 0;
height: 100%;
background-color: #409eff;
}
:deep(.cell){
padding: 0;
}
</style>