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

avatar
作者
猴君
阅读量:3

前言

	本文是根据项目实际开发中一个需求开发的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> 

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!