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>

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

高职院校人工智能人才培养成果导向系统构建、实施要点与评量方法

一、引言 近年来&#xff0c;人工智能技术在全球范围内迅速发展&#xff0c;对各行各业产生了深远的影响。高职院校作为培养高技能人才的重要基地&#xff0c;肩负着培养人工智能领域专业人才的重任。为了适应社会对人工智能人才的需求&#xff0c;高职院校需要构建一套科学、…

【node-RED 4.0.2】连接 Oracle 数据库踩坑解决,使用模组:node-red-contrib-agur-connector

关于 Oracle Oracle 就好像一张吸满水的面巾纸&#xff0c;你稍一用力它就烂了。 PS&#xff1a;我更新了更好的模组的教程&#xff0c;这篇已经是旧款的教程&#xff0c;但是它仍旧包含了必要的配置环境变量等操作。 最新的模组教程&#xff1a;node-red-contrib-agur-connec…

AI时代:探索个人潜能的新视角

文章目录 Al时代的个人发展1 AI的高速发展意味着什么1.1 生产力大幅提升1.2 生产关系的改变1.3 产品范式1.4 产业革命1.5 Al的局限性1.5.1局限一:大模型的幻觉1.5.2 局限二&#xff1a;Token 2 个体如何应对这种改变?2.1 职场人2.2 K12家长2.3 大学生2.4 创业者 3 人工智能发展…

解决vue3中el-input在form表单按下回车刷新页面

问题&#xff1a;在input框中点击回车之后不是调用我写的回车事件&#xff0c;而是刷新页面 原因&#xff1a; 如果表单中只有一个input 框则按下回车会直接关闭表单 所以导致刷新页面 解决方法 &#xff1a; 再写一个input 表单 &#xff0c;并设置style"display:none&…

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

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

解决虚拟机与主机ping不通,解决主机没有vmware网络

由于注册表文件缺失导致&#xff0c;使用这个工具 下载cclean 白嫖就行 https://www.ccleaner.com/ 是 点击修复就可以了

防火墙双机热备带宽管理综合实验

一、实验拓扑 二、实验要求 12&#xff0c;对现有网络进行改造升级&#xff0c;将当个防火墙组网改成双机热备的组网形式&#xff0c;做负载分担模式&#xff0c;游客区和DMZ区走FW3&#xff0c;生产区和办公区的流量走FW1 13&#xff0c;办公区上网用户限制流量不超过100M&am…

技术速递|Let’s Learn .NET Aspire – 开始您的云原生之旅!

作者&#xff1a;James Montemagno 排版&#xff1a;Alan Wang Let’s Learn .NET 是我们全球性的直播学习活动。在过去 3 年里&#xff0c;来自世界各地的开发人员与团队成员一起学习最新的 .NET 技术&#xff0c;并参加现场研讨会学习如何使用它&#xff01;最重要的是&#…

Java IO中的 InputStreamReader 和 OutputStreamWriter

Java IO 的流&#xff0c;有三个分类的维度&#xff1a; 输入流 or 输出流节点流 or 处理流字节流 or 字符流 在Java IO库中&#xff0c;InputStreamReader和OutputStreamWriter是两个非常重要的类&#xff0c;它们作为字符流和字节流之间的桥梁。 这两个类使得开发者可以方…

整数或小数点后补0操作

效果展示&#xff1a; 整数情况&#xff1a; 小数情况&#xff1a; 小编这里是以微信小程序举例&#xff0c;代码通用可兼容vue等。 1.在utils文件下创建工具util.js文本 util.js页面&#xff1a; // 格式…

淘宝扭蛋机小程序:旋转惊喜,开启购物新篇章!

在追求创新与惊喜的购物时代&#xff0c;淘宝再次引领潮流&#xff0c;精心打造——淘宝扭蛋机小程序&#xff0c;为您的购物之旅增添一抹不同寻常的色彩。这不仅仅是一个购物工具&#xff0c;更是一个充满趣味、互动与惊喜的宝藏盒子&#xff0c;等待您来探索与发现。 【旋转…

通过Dockerfile构建镜像

案例一&#xff1a; 使用Dockerfile构建tomcat镜像 cd /opt mkdir tomcat cd tomcat/ 上传tomcat所需的依赖包 使用tar xf 解压三个压缩包vim Dockerfile FROM centos:7 LABEL function"tomcat image" author"tc" createtime"2024-07-16"ADD j…

【 香橙派 AIpro评测】烧系统运行部署LLMS大模型跑开源yolov5物体检测并体验Jupyter Lab AI 应用样例(新手入门)

文章目录 一、引言⭐1.1下载镜像烧系统⭐1.2开发板初始化系统配置远程登陆&#x1f496; 远程ssh&#x1f496;查看ubuntu桌面&#x1f496; 远程向日葵 二、部署LLMS大模型&yolov5物体检测⭐2.1 快速启动LLMS大模型&#x1f496;拉取代码&#x1f496;下载mode数据&#x…

第九课:服务器发布(静态nat配置)

一个要用到静态NAT的场景&#xff0c;当内网有一台服务器server1&#xff0c;假如一个用户在外网&#xff0c;从外网访问内网怎么访问呢&#xff0c;无法访问&#xff0c;这是因为外网没办法直接访问内网&#xff0c;这时候需要给服务器做一个静态NAT。 静态NAT指的是给服务器…

gltf模型加载 与3d背景贴图

Poly Haveny 用于3d模型跟贴图下载资源 Sketchfab 里面有免费的模型 模型放到public里面 const loader new GLTFLoader()// 加载GLTF模型loader.load(/scene.gltf,(gltf) > {// 将加载的模型添加到场景中scene.add(gltf.scene)// 现在你可以开始渲染循环了let angle …

深度学习落地实战:基于UNet实现血管瘤超声图像分割

前言 大家好&#xff0c;我是机长 本专栏将持续收集整理市场上深度学习的相关项目&#xff0c;旨在为准备从事深度学习工作或相关科研活动的伙伴&#xff0c;储备、提升更多的实际开发经验&#xff0c;每个项目实例都可作为实际开发项目写入简历&#xff0c;且都附带完整的代…

类和对象(补充)

1.static成员 1>静态成员变量在类外进行初始化 2>静态成员变量为所有类对象所共享&#xff0c;不属于任何具体对象&#xff0c;存放在静态区中 3>静态成员函数没有this指针&#xff0c;可访问其他静态成员&#xff0c;但不可访问非静态的 4>非静态成员函数可以…

jmeter做接口压力测试_jmeter接口性能测试

jmeter是apache公司基于java开发的一款开源压力测试工具&#xff0c;体积小&#xff0c;功能全&#xff0c;使用方便&#xff0c;是一个比较轻量级的测试工具&#xff0c;使用起来非常简单。因为jmeter是java开发的&#xff0c;所以运行的时候必须先要安装jdk才可以。jmeter是免…

SQL Server 使用 OPTION (RECOMPILE) 和查询存储的查询

设置 我们正在使用 WideWorldImporters 数据库&#xff0c;您可以从 Github 下载【sql-server-samples/samples/databases/wide-world-importers at master microsoft/sql-server-samples GitHub】。我正在运行SQL Server 2017 的最新 CU【https://sqlserverbuilds.b…

[Vulnhub] digitalworld.local-JOY snmp+ProFTPD权限提升

信息收集 IP AddressOpening Ports192.168.101.150TCP:21,22,25,80,110,139,143,445,465,587,993,995 $ nmap -p- 192.168.101.150 --21,22,25,min-rate 1000 -sC -sV PORT STATE SERVICE VERSION 21/tcp open ftp ProFTPD | ftp-anon: Anonymous FTP logi…