Ai生成时间排期进度

展示

代码

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>
相关推荐
Aliex_git2 小时前
Vue 错误处理机制源码理解
前端·javascript·vue.js
ejjdhdjdjdjdjjsl2 小时前
Winform初步认识
开发语言·javascript·ecmascript
2501_942818913 小时前
AI 多模态全栈项目实战:Vue3 + Node 打造 TTS+ASR 全家桶!
vue.js·人工智能·node.js
Komorebi゛3 小时前
【Vue3+Element Plus】el-dialog弹窗点击遮罩层无法关闭弹窗问题记录
前端·vue.js·elementui
掘金安东尼4 小时前
Vercel:我们为 React2Shell 发起了一项价值 100 万美元的黑客挑战
前端·javascript·github
掘金安东尼4 小时前
浏览器处理Base64数据的速度有多快?
前端·javascript·github
掘金安东尼4 小时前
为不同场景设计多样化的页面过渡动画
前端·javascript·github
多仔ヾ4 小时前
Vue.js 前端开发实战之 02-Vue 开发基础(1)
vue.js
持续升级打怪中4 小时前
深入解析深浅拷贝:原理、实现与最佳实践
开发语言·前端·javascript