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>
相关推荐
不想秃头的程序员10 小时前
Vue3 封装 Axios 实战:从基础到生产级,新手也能秒上手
前端·javascript·面试
奔跑的web.11 小时前
UniApp 路由导航守
前端·javascript·uni-app
竟未曾年少轻狂11 小时前
Vue3 生命周期钩子
前端·javascript·vue.js·前端框架·生命周期
TT哇11 小时前
【实习】数字营销系统 银行经理端(interact_bank)前端 Vue 移动端页面的 UI 重构与优化
java·前端·vue.js·ui
不一样的少年_11 小时前
Chrome 插件实战:如何实现“杀不死”的可靠数据上报?
前端·javascript·监控
偶像佳沛11 小时前
JS 对象
前端·javascript
用户9824505141811 小时前
vue3响应式解构注意
vue.js
bjzhang7511 小时前
使用 HTML + JavaScript 实现文件树
javascript·html·文件树
不会敲代码111 小时前
🚀 从DOM操作到Vue3:一个Todo应用的思维革命
vue.js
掘金安东尼11 小时前
⏰前端周刊第 452 期(2026年2月2日-2月8日)
前端·javascript·github