vue仿甘特图开发工程施工进度表

前言

	本文是根据项目实际开发中一个需求开发的demo,仅用了elementUI,可当作独立组件使用,C V即用。
当然没考虑其他的扩展性和一些数据的校验,主要是提供一个处理思路,有需要的小伙伴可以直接复制;
	本demo的思路是根据开始时间和结束时间动态生成工程时间表,再根据工程的计划开始和结束日期、
实际开始和结束日期再对应单元格生成进度条,最后根据完成进度百分比计算红色进度条。

一、demo成品图

在这里插入图片描述
表格使用的是elementUI,表头是动态的,根据开始日期的年月和结束时间的年月计算获取;
单元格第一行绿色进度条是计划工程进度,第二行绿色是实际功能进度条,红色是实际进度的百分比

二、代码

<template>
  <div class="app-container">
    <el-table :data="tableData" style="width: 100%">
      <el-table-column label="名称" prop="name" width="200"></el-table-column>
      <el-table-column align="center" v-for="(months, year) in dateList" :key="year"  :label="`${year}年`">
        <el-table-column v-for="month in months" align="center" width="100" :key="month" :label="`${month}月`">
          <template slot-scope="scope">
            <div class="process-box" v-if="scope.row.plan_process[year] && scope.row.plan_process[year].includes(month) || scope.row.actual_process[year] && scope.row.actual_process[year].includes(month)">
              <div class="plan-process" v-if="scope.row.plan_process[year] && scope.row.plan_process[year].includes(month)">
                <div class="item" v-if="scope.row.planSameYearMonth" :style="scope.row.planProcessStyle"></div>
                <div v-else>
                  <div class="item start" v-if="scope.row.plan_start.Y == year && scope.row.plan_start.M == month" :style="scope.row.plan_start.itemStyle"></div>
                  <div class="item end" v-if="scope.row.plan_end.Y == year && scope.row.plan_end.M == month" :style="scope.row.plan_end.itemStyle"></div>
                  <div class="item" v-if="!(scope.row.plan_start.Y == year && scope.row.plan_start.M == month || scope.row.plan_end.Y == year && scope.row.plan_end.M == month)"></div>
                </div>
              </div>
              <div class="actual-process" v-if="scope.row.actual_process[year] && scope.row.actual_process[year].includes(month)">
                <div class="item" v-if="scope.row.actualSameYearMonth" :style="scope.row.actualProcessStyle">
                  <div class="percent_item start" v-if="scope.row.percentSameYearMonth" :style="scope.row.percentProcessStyle"></div>
                </div>
                <div class="item-box" v-else>
                  <div class="item start" v-if="scope.row.actual_start.Y == year && scope.row.actual_start.M == month" :style="scope.row.actual_start.itemStyle">
                    <div class="percent_item start" v-if="scope.row.percent_process[year] && scope.row.percent_process[year].includes(month) && scope.row.percent_start.Y == year && scope.row.percent_start.M == month" :style="scope.row.percent_start.itemStyle"></div>
                  </div>
                  <div class="item end" v-if="scope.row.actual_end.Y == year && scope.row.actual_end.M == month" :style="scope.row.actual_end.itemStyle">
                    <div class="percent_item end" v-if="scope.row.percent_process[year] && scope.row.percent_process[year].includes(month) && scope.row.percent_end.Y == year && scope.row.percent_end.M == month" :style="scope.row.percent_end.itemStyle"></div>
                  </div>
                  <div class="item" v-if="!(scope.row.actual_start.Y == year && scope.row.actual_start.M == month || scope.row.actual_end.Y == year && scope.row.actual_end.M == month)">
                    <div class="percent_item" v-if="scope.row.percent_process[year] && scope.row.percent_process[year].includes(month) && scope.row.percent_end.Y == year && scope.row.percent_end.M == month" :style="scope.row.percent_end.itemStyle"></div>
                    <div class="percent_item" v-if="scope.row.percent_process[year] && scope.row.percent_process[year].includes(month) && !(scope.row.percent_end.Y == year && scope.row.percent_end.M == month)"></div>
                  </div>
                </div>
              </div>
            </div>
            
          </template>
        </el-table-column>
      </el-table-column>
    </el-table>
  </div>
</template>
<script>
export default {
  data() {
    return {
      tableData: [
        {
          name: "单位A施工期间",
          plan_start_time: "2023-02-1",
          plan_end_time: "2023-2-28",
          actual_start_time: "2023-2-7",
          actual_end_time: "2023-6-22",
          percent: 85,
        },
        {
          name: "单位B施工期间",
          plan_start_time: "2023-07-12",
          plan_end_time: "2024-01-12",
          actual_start_time: "2023-11-10",
          actual_end_time: "2024-01-10",
          percent: 76,
        }
      ],
      dateList: {},
    }
  },
  mounted(){
    this.initTableData("2023-01-12", "2025-01-30")
  },
  methods: {
    handleDate(date) {
      let monthHasDay = 30;
      let currentDate = new Date(date)
      let day = currentDate.getDate()
      let month = currentDate.getMonth() + 1;
      let year = currentDate.getFullYear();
      if ([1, 3, 5, 7, 8, 10, 12].includes(month)) {
        monthHasDay = 31
      } else {
        if (month === 2) {
          if ((year % 400 === 0) || (year % 4 === 0 && year % 100 !== 0)) {
            monthHasDay = 29;
          } else {
            monthHasDay = 28;
          }
        } else {
          monthHasDay = 30;
        }
      }
      return {d: day, M: month, Y: year, monthHasDay: monthHasDay}
    },
    getDataBetweenDates(startTime, endTime){
      let start = this.handleDate(startTime);
      let end = this.handleDate(endTime);
      let data = {}
      data[start.Y] = [];
      data[end.Y] = [];
      let year = end.Y - start.Y
      if (year === 0) {
        for(let m = start.M; m <= end.M; m++) {
          data[start.Y].push(m)
        }
      } else if (year === 1) {
        for(let m = start.M; m <= 12; m++) {
          data[start.Y].push(m)
        }
        for(let n = 1; n <= end.M; n++) {
          data[end.Y].push(n)
        }
      } else {
        for(let m = start.M; m <= 12; m++) {
          data[start.Y].push(m)
        }
        for(let mid = 1; mid < year; mid++) {
          data[start.Y + mid] = [1,2,3,4,5,6,7,8,9,10,11,12];
        }
        for(let n = 1; n <= end.M; n++) {
          data[end.Y].push(n)
        }
      }
      return data;
    },
    getDaysBetweenDates(startTime, endTime) {
      let d1 = new Date(startTime);
      let d2 = new Date(endTime);
      let timeDiff = Math.abs(d2.getTime() - d1.getTime());
      let days = Math.ceil(timeDiff / (1000 * 3600 * 24));
      return days;
    },
    handleDateStyle(startDate, endDate){
      let start = this.handleDate(startDate)
      let end = this.handleDate(endDate);
      let sameYearMonth = false;
      let processStyle = null;
      if (end.Y === start.Y && end.M === start.M) {
        processStyle = {
          "left": ((start.d - 1) * 100 / start.monthHasDay) + "%",
          "right": ((start.monthHasDay -  end.d) * 100 / start.monthHasDay) + "%",
          "border-radius": '4px'
        }
        if (end.d > start.monthHasDay) processStyle.right = 0
        sameYearMonth = true
      } else {
        start.itemStyle = {
          "left": ((start.d + 1)  * 100 / start.monthHasDay)  + "%",
          "right": 0
        }
        end.itemStyle = {
          "left": 0,
          "right": ((start.monthHasDay -  (end.d + 1))  * 100 / start.monthHasDay)  + "%"
        }
      }
  
      return {
        start: start,
        end: end,
        sameYearMonth: sameYearMonth,
        processStyle: processStyle
      }
    },
    handlePercentDateStyle(actualStartTime, actualEndTime, percent){
      let start = this.handleDate(actualStartTime)
      let end = this.handleDate(actualEndTime);
      let days = this.getDaysBetweenDates(actualStartTime, actualEndTime)
      let percentTime = new Date(actualStartTime).getTime() +  days * percent * 24 * 36000
      let percentProcess = this.getDataBetweenDates(actualStartTime, percentTime)
      let startBorderRadius = '4px 0 0 4px' 
      let endBorderRadius = '0 4px 4px 0'
      let percentDate = this.handleDate(percentTime)
      let sameYearMonth = false;
      let processStyle = null;
      if (end.Y === start.Y) {
        if (end.M === start.M) {
          processStyle = {
            "left": 0,
            "right": ((end.d -  (percentDate.d)) * 100 / end.d) + "%",
            "border-radius": '4px'
          }
          sameYearMonth = true
        } else {
          if(percentDate.M === start.M) {
            start.itemStyle = {
              "left": 0,
              "right": ((start.monthHasDay -  percentDate.d)  * 100 / (start.monthHasDay - start.d))  + "%",
              "border-radius": '4px'
            }
            percentDate.itemStyle = {
              "left": 0,
              "right": ((start.monthHasDay -  percentDate.d)  * 100 / start.monthHasDay)  + "%",
              "border-radius": '4px'
            }
          } else if (percentDate.M > start.M &&  percentDate.M < end.M) {
            start.itemStyle = {
              "left": 0,
              "right": 0,
              "border-radius": startBorderRadius
            }
            percentDate.itemStyle = {
              "left": 0,
              "right": ((percentDate.monthHasDay - percentDate.d)  * 100 / percentDate.monthHasDay)  + "%",
              "border-radius": endBorderRadius
            }
          } else if (percentDate.M === end.M) {
            start.itemStyle = {
              "left": 0,
              "right": 0,
              "border-radius": startBorderRadius
            }
            percentDate.itemStyle = {
              "left": 0,
              "right": ((end.d -  percentDate.d)  * 100 / end.d)  + "%",
              "border-radius": endBorderRadius
            }
          }
        }
      } else {
        
        if (percentDate.M === start.M) {
          start.itemStyle = {
            "left": 0,
            "right": ((start.monthHasDay -  percentDate.d) * 100 / (start.monthHasDay - start.d)) + "%",
            "border-radius": '4px'
          }
        } else if (percentDate.M === end.M && percentDate.Y === end.Y) {
          start.itemStyle = {
            "left": 0,
            "right": 0,
            "border-radius": startBorderRadius
          }
          percentDate.itemStyle = {
            "left": 0,
            "right": ((end.d -  percentDate.d)  * 100 / end.d)  + "%",
            "border-radius": endBorderRadius
          }
        } else {
          start.itemStyle = {
            "left": 0,
            "right": 0,
            "border-radius": startBorderRadius
          }
          percentDate.itemStyle = {
            "left": 0,
            "right": ((percentDate.monthHasDay - percentDate.d)  * 100 / percentDate.monthHasDay)  + "%",
            "border-radius": endBorderRadius
          }
        }
      }
   
      return {
        start: start,
        end: percentDate,
        sameYearMonth: sameYearMonth,
        processStyle: processStyle,
        percentProcess: percentProcess
      }
    },
    initTableData(startTime, endTime){
      this.dateList = this.getDataBetweenDates(startTime, endTime);
      
      this.tableData.map(item => {
        item.plan_process = this.getDataBetweenDates(item.plan_start_time, item.plan_end_time);
        item.actual_process = this.getDataBetweenDates(item.actual_start_time, item.actual_end_time);
        let dateStyle = this.handleDateStyle(item.plan_start_time,item.plan_end_time) ;
        item.planSameYearMonth = dateStyle.sameYearMonth;
        item.planProcessStyle = dateStyle.processStyle ? dateStyle.processStyle : '';
        item.plan_start = dateStyle.start;
        item.plan_end = dateStyle.end;
        let actualDateStyle = this.handleDateStyle(item.actual_start_time,item.actual_end_time);
        item.actualSameYearMonth = actualDateStyle.sameYearMonth;
        item.actualProcessStyle = actualDateStyle.processStyle ? actualDateStyle.processStyle : '';
        item.actual_start = actualDateStyle.start;
        item.actual_end = actualDateStyle.end;
        let percentDateStyle = this.handlePercentDateStyle(item.actual_start_time, item.actual_end_time, item.percent);
        item.percent_start = percentDateStyle.start;
        item.percent_end = percentDateStyle.end;
        item.percentProcessStyle = percentDateStyle.processStyle ? percentDateStyle.processStyle : '';
        item.percentSameYearMonth = percentDateStyle.sameYearMonth;
        item.percent_process = percentDateStyle.percentProcess
        console.log(item)

      })
    },
    
  },
}
</script>
<style lang="scss" scoped>
::v-deep .el-table td.el-table__cell div{
  padding: 0;
}
.process-box{
  width: 100px;
  height: 40px;
  position: relative;
  .plan-process{
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 15px;
  }
  .actual-process{
    position: absolute;
    top: 25px;
    left: 0;
    right: 0;
    height: 15px;
  }
  .percent_item{
    position: absolute;
    height: 15px;
    left: 0;
    right: 0;
    background-color: red;
  }

}
.item {
  position: absolute;
  left: 0;
  right: 0;
  background: greenyellow;
  height: 15px;
  &.start{
    border-radius: 4px 0 0 4px;
  }
  &.end{
    border-radius: 0 4px 4px 0 ;
  }
}

</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/801823.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

厂家置换电费如何达到最大化收益

新能源行业知识体系-------主目录-----持续更新https://blog.csdn.net/grd_java/article/details/140004020 文章目录 一、电能电费二、同时刻不同厂家置换&#xff0c;不会影响最终电能电费结果三、风险防范补偿和回收机制四、我们的数据如何考虑补偿和回收五、如何利用补偿和…

K8S私有云裸金属服务器负载均衡器OpenELB——筑梦之路

OpenELB介绍 OpenELB 是一个专为裸机 Kubernetes 集群设计的开源负载均衡器实现。 在云服务环境中的 Kubernetes 集群里&#xff0c;通常可以用云服务提供商提供的负载均衡服务来暴露 Service&#xff0c;但是在本地没办法这样操作。而 OpenELB 可以让用户在裸金属服务器、边缘…

二叉树问题,两种解决方法(1遍历 2直接定义名字功能递归

1第一种方法就是另写一个traverse方法&#xff0c;2第二种方法就是把函数名当成已经实现的功能&#xff0c;直接写 1、翻转二叉树 class Solution {public TreeNode invertTree(TreeNode root) {if(rootnull) return null;TreeNode leftinvertTree(root.left);TreeNode righti…

Facebook:数字时代的社交瑰宝

在当今数字化飞速发展的时代&#xff0c;社交媒体已经成为人们日常生活中不可或缺的一部分&#xff0c;而Facebook作为其中的领军者&#xff0c;不仅连接了全球数十亿的用户&#xff0c;更深刻地改变了人们的社交方式和生活方式。本文将探讨Facebook如何成为数字时代的社交瑰宝…

【排序算法】1.冒泡排序-C语言实现

冒泡排序&#xff08;Bubble Sort&#xff09;是最简单和最通用的排序方法&#xff0c;其基本思想是&#xff1a;在待排序的一组数中&#xff0c;将相邻的两个数进行比较&#xff0c;若前面的数比后面的数大就交换两数&#xff0c;否则不交换&#xff1b;如此下去&#xff0c;直…

SimMIM:一个类BERT的计算机视觉的预训练框架

1、前言 呃…好久没有写博客了&#xff0c;主要是最近时间比较少。今天来做一期视频博客的内容。本文主要讲SimMIM&#xff0c;它是一个将计算机视觉&#xff08;图像&#xff09;进行自监督训练的框架。 原论文&#xff1a;SimMIM&#xff1a;用于掩码图像建模的简单框架 (a…

支持大量边缘盒子集中管理调度的智慧物流开源了。

智慧物流视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒&#xff0c;省去繁琐重复的适配流程&#xff0c;实现芯片、算法、应用的全流程组合&#xff0c;从而大大减少企业级应用约95%的开发成本。用户只需在界面上…

在golang中Sprintf和Printf 的区别

最近一直在学习golang这个编程语言&#xff0c;我们这里做一个笔记就是 Sprintf和Printf 的区别 fmt.Sprintf 根据格式化参数生成格式化的字符串并返回该字符串。 fmt.Printf 根据格式化参数生成格式化的字符串并写入标准输出。由上面就可以知道&#xff0c;fmt.Sprintf返回的…

NodeJS技巧:在循环中管理异步函数的执行次数

背景介绍 在现代Web开发中&#xff0c;NodeJS因其高效的异步处理能力而备受青睐。尤其在数据抓取、网络爬虫等应用场景中&#xff0c;NodeJS的非阻塞I/O特性使其成为不二之选。然而&#xff0c;在实际编程过程中&#xff0c;我们经常会遇到一个棘手的问题——如何在循环中控制…

初识Docker及管理Docker

Docker部署 初识DockerDocker是什么Docker的核心概念镜像容器仓库 容器优点容器在内核中支持2种重要技术&#xff1a;Docker容器与虚拟机的区别 安装Docker源码安装yum安装检查Docker Docker 镜像操作配置镜像加速器&#xff08;阿里系&#xff09;搜索镜像获取镜像查看镜像信息…

python实现九九乘法表

1.self i 1 while i<9:j 1while j< i:print("j * i ",end)print(j * i ,end)print(" ",end)j 1i 1print() 实现结果&#xff1a; 2.改进 i 1 while i<9:j 1while j< i:# print("j * i ",end)# print(j * i ,end)# print(&…

CSA笔记1-基础知识和目录管理命令

[litonglocalhost ~]$ 是终端提示符&#xff0c;类似于Windows下的cmd的命令行 litong 当前系统登录的用户名 分隔符 localhost 当前机器名称&#xff0c;本地主机 ~ 当前用户的家目录 $ 表示当前用户为普通用户若为#则表示当前用户为超级管理员 su root 切换root权限…

详解曼达拉升级:如何用网络拓扑结构扩容BSV区块链

​​发表时间&#xff1a;2024年5月24日 BSV曼达拉升级是对BSV基础设施的战略性重塑&#xff0c;意在显著增强其性能&#xff0c;运行效率和可扩容。该概念于2018年提出&#xff0c;其战略落地将使BSV区块链顺利过渡&#xff0c;从现有的基于单一集成功能组件的网络拓扑结构&am…

java面向对象进阶篇--static

一、前言 java进阶篇已经开始了&#xff0c;先从面向对象开始&#xff0c;由于时间原因今天就只更新了static部分&#xff0c;内容上特别详细&#xff0c;一些特别的注意事项也在反复的提醒大家。 温馨提示一下&#xff0c;往后的java篇会越来越难&#xff0c;希望大家能够坚…

Logistic回归(Logistic Regression)

机器学习的分类问题&#xff0c;使用logistics回归&#xff08;虽然叫回归&#xff0c;但是是做分类任务的&#xff09; 一&#xff1a;简介 MINIST Dataset 一个手写数字的数据集 其中有10分类&#xff0c;0&#xff0c;1&#xff0c;2&#xff0c;....&#xff0c;9 未来y…

002uboot Makefile分析

1.分析配置过程 我们把补丁文件打到uboot源码中&#xff0c;&#xff08;补丁文件时根据自己的板子所修改的代码&#xff09;&#xff0c;然后看一下Makefile。 make 100ask24x0_config #这个指令用来配置uboot打入补丁文件后 Makefile中会自动的生成这样的代码&#xff0c;我…

mybatis动态传入参数 pgsql 日期 Interval ,day,minute

mybatis动态传入参数 pgsql 日期 Interval 在navicat中&#xff0c;标准写法 SELECT * FROM test WHERE time > (NOW() - INTERVAL 5 day)在mybatis中&#xff0c;错误写法 SELECT * FROM test WHERE time > (NOW() - INTERVAL#{numbers,jdbcTypeINTEGER} day)报错内…

王道计算机考研数据结构思维导图笔记(持续更新)

第1章 绪论 1.1 数据结构的基本概念 1.1.1 基本概念和术语 1.1.1 数据结构三要素 1.2 算法和算法评价 1.2.1算法的基本概念 1.2.2 算法效率的度量 第2章 线性表 2.1 线性表的定义和基本操作 2.1.1 线性表的定义 2.1.2 线性表的基本操作 2.2.1 顺序表上的定义 2.2.2 顺序…

UE4-光照渲染、自动曝光、雾

目录 一.光源种类 二.灯光的移动性 三.自动曝光 四.指数级高度雾 五.实现光束 一.光源种类 1.定向光源 用来模拟现实中的太阳光。 2.点光源 比如现实中的灯泡 3.聚光源 4.矩形光源 是这几个光源中性能开销最大的&#xff0c;一般不用到游戏场景中&#xff0c;因为游…

项目方案:视频图像结构化分析技术在车辆和人体检测中的应用方案(视频公共安全领域的解决方案)

目录 一、视频结构化分析技术介绍 1、概述 2、定义 3、核心环节 4、应用领域 二、视频中车辆和人的结构化 1、需求 2、信息内容 3、功能说明 &#xff08;1&#xff09;信息智能识别功能 &#xff08;2&#xff09;智能检索功能 &#xff08;3&#xff09;数据统计…