当前位置: 首页 > news >正文

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.Yif (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 = 0sameYearMonth = 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 * 36000let 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.percentProcessconsole.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>

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • openeuler 终端中文显示乱码、linux vim中文乱码
  • Billu_b0x靶机
  • Hadoop中的YARN组件
  • 计算机网络——网络层(IP地址与MAC地址、地址解析协议ARP、IP数据报格式以及转发分组、ICMP、IPV6)
  • 鸿蒙语言基础类库:【@system.brightness (屏幕亮度)】
  • 【Python】Python-docx使用实例 科技档案封面批量生成
  • CollectionUtils的使用
  • Python实现发票信息识别
  • 编译打包自己的云手机(redroid)镜像
  • Puppeteer 是什么以及如何在网络抓取中使用它 | 2024 完整指南
  • 掌握Laravel的策略与授权门面:构建安全的Web应用
  • React Native: 构建原生级移动应用的跨平台框架
  • matine组件库踩坑日记 --- react
  • Django ORM中的Q对象
  • 1.3Zygote
  • 分享的文章《人生如棋》
  • 分享一款快速APP功能测试工具
  • 收藏网友的 源程序下载网
  • [笔记] php常见简单功能及函数
  • 【跃迁之路】【735天】程序员高效学习方法论探索系列(实验阶段492-2019.2.25)...
  • Angular 响应式表单 基础例子
  • C++回声服务器_9-epoll边缘触发模式版本服务器
  • golang中接口赋值与方法集
  • HTML-表单
  • JAVA_NIO系列——Channel和Buffer详解
  • Material Design
  • Python进阶细节
  • react-core-image-upload 一款轻量级图片上传裁剪插件
  • Redis字符串类型内部编码剖析
  • Vue2 SSR 的优化之旅
  • vue-router 实现分析
  • Vue源码解析(二)Vue的双向绑定讲解及实现
  • 关于使用markdown的方法(引自CSDN教程)
  • 什么是Javascript函数节流?
  • 通过获取异步加载JS文件进度实现一个canvas环形loading图
  • 我的zsh配置, 2019最新方案
  • 移动端唤起键盘时取消position:fixed定位
  • 主流的CSS水平和垂直居中技术大全
  • ionic入门之数据绑定显示-1
  • # windows 运行框输入mrt提示错误:Windows 找不到文件‘mrt‘。请确定文件名是否正确后,再试一次
  • $refs 、$nextTic、动态组件、name的使用
  • (06)Hive——正则表达式
  • (8)Linux使用C语言读取proc/stat等cpu使用数据
  • (c语言+数据结构链表)项目:贪吃蛇
  • (react踩过的坑)Antd Select(设置了labelInValue)在FormItem中initialValue的问题
  • (Redis使用系列) SpirngBoot中关于Redis的值的各种方式的存储与取出 三
  • (超详细)2-YOLOV5改进-添加SimAM注意力机制
  • (附源码)springboot 基于HTML5的个人网页的网站设计与实现 毕业设计 031623
  • (六)vue-router+UI组件库
  • (三十)Flask之wtforms库【剖析源码上篇】
  • (四)【Jmeter】 JMeter的界面布局与组件概述
  • (转)JAVA中的堆栈
  • .\OBJ\test1.axf: Error: L6230W: Ignoring --entry command. Cannot find argumen 'Reset_Handler'
  • .L0CK3D来袭:如何保护您的数据免受致命攻击
  • .NET Core 成都线下面基会拉开序幕