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.rhkb.cn/news/378371.html

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

相关文章

元服务体验-服务发现

服务发现&#xff0c;无论线上或线下的方式都可以发现元服务。 线上&#xff1a;基于用户意图。从精准意图的搜索、用户事件触发的推荐到主动探索等场景。用户可以在设备的负一屏、全局搜索、应用市场、桌面等场景发现元服务。 线下&#xff1a;用户在 HarmonyOS Connect标签…

C++ | Leetcode C++题解之第238题除自身以外数组的乘积

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<int> productExceptSelf(vector<int>& nums) {int length nums.size();// L 和 R 分别表示左右两侧的乘积列表vector<int> L(length, 0), R(length, 0);vector<int> answer(l…

Modbus转Ethernet/IP网关模块与汇川PLC通讯案例

Modbus转Ethernet/IP网关模块&#xff08;XD-MDEP100&#xff09;是一种用于将Modbus协议转换为Ethernet/IP协议的设备。它可以将Modbus RTU和Modbus TCP两种不同格式的Modbus数据包转换为Ethernet/IP协议的数据包&#xff0c;实现不同厂家的设备之间的数据交换和共享。在汇川P…

解决elementUI列表的疑难杂症,排序显示错乱的问题

大家好&#xff0c;在使用elementUI表格时&#xff0c;有时会出现一些意料之外的问题&#xff0c;比如数据排序正常但表格显示、排序错乱等。在网上搜索后一般有2种解决方法&#xff1a;1.给表格每一项的el-table-column添加唯一的id用于区分。2.给表格每一项的el-table-column…

案例 | 人大金仓助力山西政务服务核心业务系统实现全栈国产化升级改造

近日&#xff0c;人大金仓支撑山西涉企政策服务平台、政务服务热线联动平台、政务网、办件中心等近30个政务核心系统完成全栈国产化升级改造&#xff0c;推进全省通办、跨省通办、综合业务受理、智能审批、一件事一次办等业务的数字化办结进程&#xff0c;为我国数字政务服务提…

mybatis语法进阶1

日志的使用 我们在使用MyBatis的时候, 其实MyBatis框架会打印一些必要的日志信息, 在开发阶段这些日志信息对我们分析问题,理解代码的执行是特别有帮助的; 包括项目上线之后,我们也可以收集项目的错误日志到文件里面去; 所以我们采用专门的日志系统来处理. 步骤 导入坐标拷贝…

如何在SpringCloud中使用Kafka Streams实现实时数据处理

使用Kafka Streams在Spring Cloud中实现实时数据处理可以帮助我们构建可扩展、高性能的实时数据处理应用。Kafka Streams是一个基于Kafka的流处理库&#xff0c;它可以用来处理流式数据&#xff0c;进行流式计算和转换操作。 下面将介绍如何在Spring Cloud中使用Kafka Streams实…

pytorch说明

深度学习中的重要概念&#xff1a; 激活函数&#xff1a; 激活函数的必要性&#xff1a;激活函数不是绝对必须的&#xff0c;但在深度学习中&#xff0c;它们几乎总是被使用。激活函数可以引入非线性&#xff0c;这使得神经网络能够学习更复杂的模式。 激活函数的位置&#x…

记录些MySQL题集(9)

MySQL之死锁问题分析、事务隔离与锁机制的底层原理剖析 一、MySQL中的死锁现象 所谓的并发事务&#xff0c;本质上就是MySQL内部多条工作线程并行执行的情况&#xff0c;也正由于MySQL是多线程应用&#xff0c;所以需要具备完善的锁机制来避免线程不安全问题的问题产生&#…

嵌入式智能手表项目实现分享

简介 这是一个基于STM32F411CUE6和FreeRTOS和LVGL的低成本的超多功能的STM32智能手表~ 推荐 如果觉得这个手表的硬件难做,又想学习相关的东西,可以试下这个新出的开发板,功能和例程demo更多!FriPi炸鸡派STM32F411开发板: 【STM32开发板】 FryPi炸鸡派 - 嘉立创EDA开源硬件平…

STM32入门开发操作记录(二)——LED与蜂鸣器

目录 一、工程模板二、点亮主板1. 配置寄存器2. 调用库函数 三、LED1. 闪烁2. 流水灯 四、蜂鸣器 一、工程模板 参照第一篇&#xff0c;新建工程目录ProjectMould&#xff0c;将先前打包好的Start&#xff0c;Library和User文件^C^V过来&#xff0c;并在Keil5内完成器件支持包的…

【ARM】CCI集成指导整理

目录 1.CCI集成流程 2.CCI功能集成指导 2.1CCI结构框图解释 Request concentrator Transaction tracker Read-data Network Write-data Network B-response Network 2.2 接口注意项 记录一下CCI500的ACE slave interface不支持的功能&#xff1a; 对于ACE-Lite slav…

手机和电脑通过TCP传输(一)

一.工具 手机端&#xff1a;网络调试精灵 电脑端&#xff1a;野火网络调试助手 在开始通信之前&#xff0c;千万要查看一下电脑的防火墙是否关闭&#xff0c;否则可能会无法通信 在开始通信之前&#xff0c;千万要查看一下电脑的防火墙是否关闭&#xff0c;否则可能会无法通信…

vue3+TS从0到1手撸后台管理系统

1.路由配置 1.1路由组件的雏形 src\views\home\index.vue&#xff08;以home组件为例&#xff09; 1.2路由配置 1.2.1路由index文件 src\router\index.ts //通过vue-router插件实现模板路由配置 import { createRouter, createWebHashHistory } from vue-router import …

【学习笔记】无人机系统(UAS)的连接、识别和跟踪(一)-3GPP TS 23.256 技术规范概述

3GPP TS 23.256 技术规范&#xff0c;主要定义了3GPP系统对无人机&#xff08;UAV&#xff09;的连接性、身份识别、跟踪及A2X&#xff08;Aircraft-to-Everything&#xff09;服务的支持。 3GPP TS 23.256 技术规范&#xff1a; 以下是文档的核心内容总结&#xff1a; UAV系…

类和对象的简述(c++篇)

开局之前&#xff0c;先来个小插曲&#xff0c;放松一下&#xff1a; 让我们的熊二来消灭所有bug 各位&#xff0c;在这祝我们&#xff1a; 放松过后&#xff0c;开始步入正轨吧。爱学习的铁子们&#xff1a; 目录&#xff1a; 一类的定义&#xff1a; 1.简述&#xff1a; 2…

【Springboot】新增profile环境配置应用启动失败

RT 最近接手了一个新的项目&#xff0c;为了不污染别人的环境&#xff0c;我新增了一个自己的环境配置。结果&#xff0c;在启动的时候总是失败&#xff0c;就算是反复mvn clean install也是无效。 问题现象 卡住无法进行下一步 解决思路 由于之前都是能启动的&#xff0c…

Spring Boot项目的404是如何发生的

问题 在日常开发中&#xff0c;假如我们访问一个Sping容器中并不存在的路径&#xff0c;通常会返回404的报错&#xff0c;具体原因是什么呢&#xff1f; 结论 错误的访问会调用两次DispatcherServlet&#xff1a;第一次调用无法找到对应路径时&#xff0c;会给Response设置一个…

SpringBoot使用开发环境的application.properties

在Spring Boot项目中&#xff0c;application.properties 或 application.yml 文件是用于配置应用程序外部属性的重要文件。这些文件允许定制你的应用&#xff0c;而无需更改代码。根据不同的运行环境&#xff0c;可以通过创建以application-{profile}.properties格式命名的文件…

MMFewshot框架少样本目标检测配置学习(二)

教程 0&#xff1a;MMFEWSHOT 检测概述 在 MMFewShot 中&#xff0c;有三个用于获取数据的重要组件&#xff1a; Datasets&#xff1a;ann_cfg从少数镜头设置中加载注释并过滤图像和注释。 Dataset Wrappers&#xff1a;确定采样逻辑&#xff0c;例如根据查询图像采样支持图像…