vue 实现类似甘特图大屏效果

news2024/11/20 9:30:04

最近在做大屏展示,其中一个需求是展示生产过程中投料情况,效果类似甘特图。
思路:1.先得到整个过程的开始时间startTime和结束时间endTime。计算出整个过长经历的时长。
2.计算横向坐标的开始时间start和结束时间end,坐标的开始时间为生产开始时间-百分之十的生产时长,即start = startTime - 0.1h;坐标的结束时间为生产结束时间+百分之十的生产时长,即end = endTime + 0.1h.
3.确定横纵坐标值,先计算横计算坐标间隔,我固定了横坐标的打点数,直接用横坐标结束时间-坐标开始时间除以点数+1,即 (end-start) / (number +1)。得到间隔之后就可以计算出横坐标值。纵坐标值直接使用物料名称
4.显示每个料的投放情况显示出来。显示是用的div,每种物料的投料时长就是div的长度。
注意:计算宽度的时候需要依据自己的实际情况进行调整
效果
在这里插入图片描述

代码

<template>
    <div class="Gantt">
      <div class="content" ref="scrollbar">
        <!-- <el-scrollbar> -->
        <div
          class="info"
          style="margin-top: 2px; overflow: scroll; overflow-x: hidden;height: calc(100vh * 220 / 1080);"
        >
          <div id="gui-content" class="gui-content">
            <div
              class="gui-list clear room-gui-list"
              v-for="task in taskList"
              :key="task.materialId"
            >
              <div id="name" class="fasten ellipsis" :title="task.name">
                {{ task.name }}
              </div>
              <div class="gui-tab">
                <li
                  v-for="(o, i)  in config.xAxis"
                  :key="i" 
                  :style="{
                    width: 100 / (number + 1) + '%',
                    cursor: 'pointer',
                  }"
                ></li>
              </div>
              <template v-if="task.materialId">
                <div
                    v-for="(item, index) in task.materialData"
                    :key="index"
                    class="meet-item-one"
                    v-bind:class="[
                    !item.status ? 'meet-color-having' : 'meet-color-finished',
                    ]"
        
                    :style="{
                    left: getLeftTime(item.startTime) + '%',
                    width: getWidth(item) + '%',
                    backgroundColor: item.color,
                    // opacity:0.8
                    }"
                    v-show="getWidth(item) != 0"
                    @click="edit(item)"
                    
                >
                    <el-popover
                        placement="top-start"
                        trigger="hover"
                        :style="{fontSize:'10px',padding:'0px'}"
                         >
                        <p>{{'开始:'+item.startTime}}</p>
                        <p>{{'结束:'+item.endTime}}</p>
                        <div slot="reference" class="meet-item-one-content">
                          <p class="ellipsis" >{{ item.content }}</p>
                        </div>
                        
                    </el-popover>
                </div>
               
              </template>
            </div>
          </div>
        </div>
        <!-- </el-scrollbar> -->
        <div class="time-bar clear">
          <div class="gui-table clear">
            <li
              :style="{
                width: 100 / (number + 1) +'%',
              }"
              v-for="(item, index) in config.xAxis"
              :key="index"
            >
              <div class="gui-cle"></div>
              <div class="gui-lit"></div>
              <div class="gui-title"><span class="">{{item.xAxis}}</span></div>
            </li>
          </div>
        </div>
      </div>
    </div>
  </template>
  
  <script>
  import {Popover,Scrollbar} from 'element-ui'
  export default {
    name: "GanttDemo",
    data() {
      return {
        date: "",
        number:6,
        xInterval:0.1,
        config: {xAxis:[]},
        taskList: [
          {
            materialId: "1",
            name: "物料一",
            startTime: "2022-11-16 08:00:00",
            endTime: "2022-11-16 20:00:00",
            materialData: [
              {
                materialId: "1",
                id: "14444",
                status: 0,
                startTime: '2022-11-16 08:00:00',
                endTime: '2022-11-16 12:00:00',
                color:"#32c5e9",
                content:"800",
              },
              {
                materialId: "1",
                id: "15555",
                status: 0,
                startTime: '2022-11-16 18:30:10',
                endTime: '2022-11-16 20:00:00',
                color:"#32c5e9",
                content:"600",
              },
            ],
          },
          {
            materialId: "2",
            name: "物料二",
            startTime: "2022-11-16 20:00:00",
            endTime: "2022-11-16 23:30:00",
            materialData:[{
                materialId: "2",
                id: "223865",
                status: 0,
                startTime: '2022-11-16 20:00:00',
                endTime: '2022-11-16 23:30:00',
                color:"#eb865e",
                content:"800",
              },
            ]
          },{
            materialId: "3",
            name: "物料三",
            startTime: "2022-11-16 15:00:00",
            endTime: "2022-11-16 16:30:00",
            materialData:[{
                materialId: "3",
                id: "31",
                status: 0,
                startTime: '2022-11-16 15:00:00',
                endTime: '2022-11-16 16:30:00',
                color:"#eb865e",
                content:"500",
              },
            ]
          },{
            materialId: "4",
            name: "物料四",
            startTime: "2022-11-16 12:00:00",
            endTime: "2022-11-16 16:30:00",
            materialData:[{
                materialId: "4",
                id: "41",
                status: 0,
                startTime: '2022-11-16 12:00:00',
                endTime: '2022-11-16 16:30:00',
                color:"#eb865e",
                content:"450",
              },
            ]
          },{
            materialId: "5",
            name: "物料五",
            startTime: "2022-11-16 11:00:00",
            endTime: "2022-11-16 15:30:00",
            materialData:[{
                materialId: "5",
                id: "51",
                status: 0,
                startTime: '2022-11-16 11:00:00',
                endTime: '2022-11-16 15:30:00',
                color:"#eb865e",
                content:"300",
              },
            ]
          },{
            materialId: "6",
            name: "物料六",
            startTime: "2022-11-16 11:00:00",
            endTime: "2022-11-16 12:30:00",
            materialData:[{
                materialId: "6",
                id: "61",
                status: 0,
                startTime: '2022-11-16 11:00:00',
                endTime: '2022-11-16 12:30:00',
                color:"#eb865e",
                content:"200",
              },
            ]
          },{
            materialId: "7",
            name: "物料七",
            startTime: "2022-11-16 09:00:00",
            endTime: "2022-11-16 10:30:00",
            materialData:[{
                materialId: "7",
                id: "71",
                status: 0,
                startTime: '2022-11-16 09:00:00',
                endTime: '2022-11-16 10:30:00',
                color:"#eb865e",
                content:"300",
              },
            ]
          },
        ]
      };
    },
    components:{
      elPopover: Popover,
      elScrollbar:Scrollbar,
    },
    props:{
    },
    watch:{

    },

    mounted(){
      this.getConfig();
    },
    methods: {
     
      getLeftTime(cTime) {
        const dTime = new Date(cTime).getTime();
        const leftTime = new Date(this.config.startTime).getTime();
        const time = (dTime - leftTime) / (1000 * 60 * 60); // 小时数
        const leftPercent = 0.88 * (time * 100) / (this.xInterval * (this.number+1)) ;
        return leftPercent + 12;
      },
      getWidth(item) {
        const _left1 = this.getLeftTime(item.startTime);
        const _left2 = this.getLeftTime(item.endTime);
        return _left2 - _left1;
      },
      edit(item) {
        console.log(item);
      },
      getConfig(){
        
        if(this.taskList.length>0){
          let startTime = this.taskList[0].startTime;
          let endTime = this.taskList[0].endTime;
          console.log(endTime)
          for(let index in this.taskList){
              let task = this.taskList[index];
              let start1 = startTime?new Date(startTime):new Date();
              let start2 = new Date(task.startTime);
              if(start1 > start2 && null != task.startTime){
                  startTime = task.startTime;
              }
              let end1 = new Date(endTime);
              let end2 = new Date(task.endTime?task.endTime:start2);
              if(end1 < end2){
                  endTime = task.endTime;
              }
          }
          let hour =((new Date(endTime)).getTime() - (new Date(startTime)).getTime());

          this.config.start = startTime;
          this.config.end = endTime;
          this.config.startTime = this.getDateTime(new Date((new Date(startTime)).getTime()-0.1*hour));
          this.config.endTime = this.getDateTime(new Date((new Date(endTime)).getTime()+0.1*hour));
          hour = ((new Date(this.config.endTime)).getTime() - (new Date(this.config.startTime)).getTime());
          this.config.hour = hour;
          if(hour){
            this.xInterval = (hour / (this.number+1)) / (1000*60*60);
          }
          this.config.xAxis = []
          let hh = (new Date(this.config.startTime)).getHours() < 10 ? '0' + (new Date(this.config.startTime)).getHours() : (new Date(this.config.startTime)).getHours();
          let mm = (new Date(this.config.startTime)).getMinutes() < 10 ? '0' + (new Date(this.config.startTime)).getMinutes() : (new Date(this.config.startTime)).getMinutes();
          let xOne = hh +":" +mm;
          this.config.xAxis.push({xAxis:xOne});
          for(let i  = 0;i < this.number;i++){
            console.log();
              let node = (new Date(this.config.startTime)).getTime()+(this.xInterval * 60 *60 * 1000 * ( i + 1 ));
              let nodeHh = (new Date(node)).getHours() < 10 ? '0' + (new Date(node)).getHours() : (new Date(node)).getHours();
              let nodeMm = (new Date(node)).getMinutes() < 10 ? '0' + (new Date(node)).getMinutes() : (new Date(node)).getMinutes();
              let nodeX = nodeHh + ":" + nodeMm;
              this.config.xAxis.push({xAxis:nodeX});
          }
        }
      },
      getDateTime(time){
        let year = time.getFullYear();  //获取年 2021
        let month = time.getMonth() + 1;  // 获取月  5
        let day = time.getDate();    // 获取天  11
  
        let h = time.getHours() < 10 ? '0' + time.getHours() : time.getHours();   // 获取小时  18
        let m = time.getMinutes() < 10 ? '0' + time.getMinutes() : time.getMinutes();  // 获取分钟  42
        let s = time.getSeconds() < 10 ? '0' + time.getSeconds() : time.getSeconds();    // 获取秒  51
        let dataTime = year + '-' + month + '-' + day + ' ' + h + ':' + m + ':' + s;
        return dataTime;
      },
      
    }
   
  };
  </script>
  
  <style lang="scss" scoped >
  .Gantt {
    padding: calc(100vw * 20 / 1920 );;
    border-radius: 3px;
    /* border: 1px solid red; */
    height: 100%;
    box-sizing: border-box;
    display: flex;
    flex-direction: column-reverse;
    position: relative;
  }
  .content {
    padding-top: calc(100vw * 20 / 1920 );

  }
  
  .content /deep/ .el-scrollbar{
    height: calc(100vh * 220 / 1080);
    .el-scrollbar__wrap {
      overflow-x: hidden;
    }
  }
  .content /deep/ .el-scrollbar__view {
    height: 100%;
    // display: flex;
    // flex-direction: column-reverse;
  }
  .Gantt .gui-table,
  .gui-tab {
    font-size: calc(100vw * 12 / 1920 );
    color: #333;
    margin: 0;
    width: 88%;
    float: right;
    white-space: nowrap;
    height: calc(100vh * 48 / 1080 );
  }
  .Gantt .gui-table li {
    position: relative;
    border-top: solid 1px #1ba5fa;
    z-index: 666;
    word-wrap: break-word;
  }
  .Gantt .gui-table li {
    cursor: default;
  }
  
  .Gantt .gui-table li{
    float: left;
    text-align: left;
    width: 8.9%;
    height: calc(100vh * 48 / 1080 );
    line-height: calc(100vh * 48 / 1080 );
    /* cursor: pointer; */
    white-space: pre-wrap;
  }
  .Gantt .gui-table .gui-title{
    line-height: calc(100vh * 24 / 1080 );
    position: relative;
    width: 100%;
  }
  .Gantt .gui-table .gui-title span{
    line-height: calc(100vh * 24 / 1080 );
    color: rgba(255,255,255,.7);
    position: absolute;
    left: -50%;
    text-align: center;
    width: 100%;
  }
  .gui-tab li {
    float: left;
    text-align: left;
    width: 8.9%;
    height: calc(100vh * 28 / 1080 );
    line-height: calc(100vh * 28 / 1080 );
    /* cursor: pointer; */
    white-space: pre-wrap;

  }
  .Gantt .gui-cle {
    position: absolute;
    left: -5px;
    top: -5px;
    width: 6px;
    height: 6px;
    background: #fff;
    border-radius: 50%;
    border: solid 2px #1ba5fa;
    z-index: 666;
  }
  .Gantt .gui-lit {
    position: absolute;
    left: 0;
    top: -3px;
    width: 3px;
    height: 3px;
    background: #fff;
    border-radius: 50%;
    border: solid 1px #1ba5fa;
    margin-left: 50%;
    z-index: 666;
  }
  .clear {
    *zoom: 1;
  }
  .clear:after {
    content: ".";
    display: block;
    clear: both;
    visibility: hidden;
    line-height: 0;
    height: 0;
    font-size: 0;
  }
  .Gantt .fasten {
    width: 12%;
    float: left;
    height: calc(100vh * 28 / 1080 );
    text-align: center;
    line-height: calc(100vh * 28 / 1080 );
    font-size: calc(100vw * 12 / 1920 );
    color: rgba(255, 255, 255, .7);
    border-right: solid 1px #1ba5fa;
    /* word-break: break-word;
    white-space: pre-line; */
  }
  .Gantt .gui-table{
    font-size: calc(100vw * 12 / 1920 );
    color: #333;
    margin: 0;
    width: 88%;
    float: right;
    white-space: nowrap;
    height: calc(100vh * 48 / 1080 );
  }
  .gui-tab {
    font-size: calc(100vw * 12 / 1920 );
    color: #333;
    margin: 0;
    width: 88%;
    float: right;
    white-space: nowrap;
    height: calc(100vh * 28 / 1080 );
  }
  /* .Gantt .gui-list:first-child {
    background: #fff;
  } */
  .Gantt .gui-list {
    position: relative;
    display: flex;
  }
  

  .Gantt .meet-color-finished {
    background: #4dc394;
  }
  
  .Gantt .meet-color-having {
    background: #eb865e;
  }
  .Gantt .meet-item-one {
    color: #000;
    text-align: center;
    position: absolute;
    height: calc(100vh * 26 / 1080 );
    left: 12%;
    top: 1px;
    color: #fafafa;
    font: 14px/60px microsoft yahei;
    /* padding: 0 5px; */
    box-sizing: border-box;
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
    overflow: hidden;
    cursor: pointer;
    width: 20%;
    line-height: calc(100vh * 26 / 1080 );
  }
  
  li {
    list-style: none;
  }
  .Gantt .meet-item-one-content{
    height: 100%;
  }
  .ellipsis {
    overflow: hidden;
    margin-top: 0;
    white-space: nowrap;
    text-overflow: ellipsis;
    line-height: calc(100vh * 28 / 1080 );
  }
  .info,.gui-content{
    display: flex;
    flex-direction: column-reverse;
  }

  .info::-webkit-scrollbar {
  width : 5px;  
  height: 1px;
  }
  .info::-webkit-scrollbar-thumb {
    box-shadow: 0px 1px 3px rgba(144,147,153,.3) inset; /*滚动条的内阴影*/
    border-radius: 10px; /*滚动条的圆角*/
    background-color: rgba(144,147,153,.3); /*滚动条的背景颜色*/
  }
  .info::-webkit-scrollbar-track {
    box-shadow: 0px 1px 3px #071e4a inset; /*滚动条的背景区域的内阴影*/
    border-radius: 10px; /*滚动条的背景区域的圆角*/
    background-color: #071e4a; /*滚动条的背景颜色*/
  }
  /* .gui-yAxis{
    position: absolute;
    height: 100%;
    border: solid 1px #1ba5fa;
  } */
  </style>
  
  

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

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

相关文章

五分钟了解GRE是什么,四信GRE相关应用推荐

随着互联网新技术的发展以及智能化水平的提高&#xff0c;各企业对实时数据传输的需求也在不断提升&#xff0c;企业愈发重视数据中心的建设&#xff0c;各类虚拟网络技术相继被引入。今天&#xff0c;我们重点了解下云端“借道”鼻祖&#xff0c;善于“包装”的GRE&#xff0c…

新品上市|四信LTE Cat.1无线数传终端 推进中低速蜂窝典型应用

当前&#xff0c;物联网作为新型信息基础设施&#xff0c;已成为推动制造业、零售业、金融业、服务业等行业数字转型、智能升级、融合创新的重要支撑。《“十四五”信息通信行业发展规划》提出&#xff0c;要推进移动物联网全面发展&#xff0c;推动存量2G/3G物联网业务向NB-Io…

SSM医院病历

开发工具(eclipse/idea/vscode等)&#xff1a; 数据库(sqlite/mysql/sqlserver等)&#xff1a; 功能模块(请用文字描述&#xff0c;至少200字)&#xff1a;

CentOS7安装git

CentOS7安装git前言一、git介绍二、使用yum安装git1.安装git2.查看git版本3.移除git三、源码包安装git1.安装依赖2.下载源码包3.解压4.git安装5.查看git版本总结前言 CentOS7安装git&#xff0c;刚开始使用yum安装git&#xff0c;发现安装的版本默认是1.8.3.1&#xff0c;如果…

yaml 资源配置清单使用详解——k8s声明式资源管理

目录 一、kubectl 操作 yaml 文件 1.应用yaml文件指定的资源 2.删除yaml文件指定的资源 3.查看资源的yaml格式信息 4.查看yaml文件字段说明 5.修改yaml文件指定的资源 &#xff08;1&#xff09;离线修改 &#xff08;2&#xff09;在线修改 二、编辑yaml配置清单生成…

Java开发如何通过IoT边缘ModuleSDK进行进程应用的开发?

摘要&#xff1a;为解决用户自定义处理设备数据以及自定义协议设备快速接入IOT平台的诉求&#xff0c;华为IoT边缘提供ModuleSDK&#xff0c;用户可通过集成SDK让设备以及设备数据快速上云。本文分享自华为云社区《【华为云IoTEdge开发实战】Java开发如何通过IoT边缘ModuleSDK进…

字符串函数剖析(2)

最慢的步伐不是跬步&#xff0c;而是徘徊&#xff1b;最快的脚步不是冲刺&#xff0c;而是坚持。——《人民日报》 字符串函数的重点&#xff1a; 文章不长&#xff0c;是为了让你一点点消化所有内容&#xff1a; 1.strncpy函数的脾气 1.1模拟实现strncpy函数 2.strncmp函数…

马化腾说视频号是全公司希望

我是卢松松&#xff0c;点点上面的头像&#xff0c;欢迎关注我哦&#xff01; 这应该是&#xff0c;腾讯这家公司创办以来&#xff0c;马化腾最焦虑也最外露的一次讲话了&#xff0c;对于腾讯内部的大会&#xff0c;马化腾先生作了重要发言&#xff0c;因其在内部员工大会的讲…

边界网关协议BGP(计算机网络-网络层)

目录 因特网分层路由 分层路由和自治系统 边界网关协议 BGP BGP 的设计目标 BGP 发言人 路径向量算法 BGP 协议的要点 因特网分层路由 规模问题 路由选择算法将很难收敛 交换的路由信息会占用大量的带宽 管理问题 许多单位不愿意外界了解自己单位网络的具体细节 希望采用…

新能源汽车补贴即将取消,汽车金融的促进作用逐渐显现

中国新能源汽车产业发展强劲。自2015年起&#xff0c;新能源汽车销量连续7年位居世界第一。特别是2021年以来&#xff0c;在政策支持、技术驱动、消费者接受度提升等多重因素共同影响下&#xff0c;中国新能源汽车市场实现了超越式的发展。2022年1-10月&#xff0c;新能源汽车批…

这份京东T8级程序员整理的新版Spring Cloud手抄本,把微服务讲透了

近几年&#xff0c;微服务可谓是红的发紫&#xff0c;仿佛一时间所有系统无不以拆分为荣&#xff0c;以构建烟囱型应用为耻。最近&#xff0c;一位朋友刚好赶上公司基础服务的微服务化项目&#xff0c;加上之前又主动学习了不少微服务的内容&#xff0c;便主动请缨参与到项目里…

前端实现网站悼念【灰色效果】几行代码轻松解决

博主介绍 &#x1f4e2;点击下列内容可跳转对应的界面&#xff0c;查看更多精彩内容&#xff01; &#x1f34e;主页&#xff1a;水香木鱼 &#x1f34d;专栏&#xff1a;CSS3 文章目录 简介&#xff1a;这是一篇有关【前端实现网站悼念【灰色效果】几行代码轻松搞定】的文章&…

遗传编程(Genetic Programming, GP)

1. 绪言 1.1 遗传编程概述 \quad\quad自计算机出现以来&#xff0c;计算机科学的一个重要目标是让计算机自动进行程序设计&#xff0c;即只要明确地告诉计算机要解决的问题&#xff0c;而不需要告诉它如何去做&#xff0c;遗传规划便是在该领域内的一种尝试。它采用遗传算法的…

IDEA反编译Jar包

一.安装Java Bytecode Decomplier插件 (1) File–>Settings–>Plugins &#xff0c;搜索 Java Bytecode Decomplier 插件 (2) 查看安装插件的路径 File->Import Setting 注意&#xff1a;如果你的插件里面搜不到 Java Bytecode Decomplier&#xff0c;但是能搜到…

spring之Bean的生命周期

文章目录一、Bean的生命周期之五步1、准备User类2、spring配置文件3、测试类4、运行结果二、Bean的生命周期之七步1、实现BeanPostProcessor类2、配置文件3、运行结果&#xff1a;三、Bean的生命周期之十步1、点位12、点位23、点位3四、Bean的作用域一、Bean的生命周期之五步 …

Coinbase或在不久使用Zebec发放工资,并对Web3支付赛道发展寄予厚望

流支付协议Zebec Protocol目前已经完成了生态向BNB Chian上的迁移&#xff0c;目前得到了以PancakeSwap为代表的头部生态的支持。在12月20日Zebec生态在PancakeSwap官方的支持下&#xff0c;经过社区投票&#xff0c;ZBC通证上线了糖浆池&#xff0c;并有望继续上线Binance。而…

ELK集群部署---Kibana的部署

1. 环境规划&#xff1a; 主机名IP地址角色node1192.168.56.111 ElasticSearch(master) Zookeeper Kafka node2192.168.56.112 ElasticSearch(slave) Kibana Zookeeper Kafka node3192.168.56.113 ElasticSearch(slave) Zookeeper Kafka node4192.168.56.114 Logstash Filebe…

优雅数据同步--canal实现mysql同步demo

当需要两张表数据同步的时候&#xff0c;我们会想到几种方案&#xff1f; 最简单的一种方式就是触发器的方式。例如A同步到B,可以通过下面的sql来添加触发器 create trigger tri_trade_update after UPDATE on A for each row begin update B set company_id new.compan…

数据结构和算法学习——稀疏数组

目录 一、数据结构和算法的关系 二、数据结构的分类 (一)线性结构 (二)非线性结构 三、稀疏数组(sparsearray) (一)稀疏数组的基本介绍 (二)稀疏数组的处理方法 一、数据结构和算法的关系 数据data结构(structure)是一门研究组织数据方式的学科&#xff0c;有了编程语言…

Grafana 查询数据和转换数据

Grafana 系列文章&#xff0c;版本&#xff1a;OOS v9.3.1 Grafana 的介绍和安装Grafana监控大屏配置参数介绍&#xff08;一&#xff09;Grafana监控大屏配置参数介绍&#xff08;二&#xff09;Grafana监控大屏可视化图表Grafana 查询数据和转换数据 介绍 Grafana能够支持各…