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

vue页面,绘制项目的计划进度和实际进度;展示不同阶段示意图

如下如图,公司有很多项目,想看每个工程项目计划情况和实际情况,他们之间的进展对比,效果如下:
在这里插入图片描述在这里插入图片描述在这里插入图片描述
代码如下:
页面

<template>
  <div class="image-schedule-dialog">
    <div class="content-box">
      <div class="colse-btn" @click="cliclBtn">x</div>
      <div class="image-schedule">
      <div class="date-progress">
      <div class="label" style="align-self: flex-end">进度</div>
      <div v-if="dateAndMonth.length==0"></div>
      <div v-else class="date" v-for="(yitem, yindex) in dateAndMonth" :key="yindex">
        <div class="year">
          <div class="year-item" :style="yearItem(yitem)">{{ yitem.year }}年</div>
        </div>
        <div class="month">
          <div class="month-item" :style="{width: widthNum+'px'}"
            v-for="(mitem, mindex) in yitem.months"
            :key="mindex">
            {{ mitem }}月份
          </div>
        </div>
      </div>
      </div>
      <div class="plan-progress">
      <div class="label">计划进度</div>
      <div v-if="plannedProgress.length==0"></div>
      <div
        v-else
        class="bookmark"
        v-for="(item, index) in plannedProgress"
        :key="item.code"
        :style="bookmarkStyleP(item)">
        <span class="bookmark-text" :style="bookmarkTextP(item)">{{ item.plan_schedule }}</span>
      </div>
      </div>
      <div class="actual-progress">
      <div class="label">实际进度</div>
      <div v-if="actualProgress.length==0"></div>
      <div
        v-else
        class="bookmark"
        :style="bookmarkStyleA()">
        <span class="bookmark-text" style="color: #fff">{{actualProgress[aLength-1].plan_schedule}}</span>
      </div>
      </div>
      </div>
    </div>
  </div>
</template>

逻辑数据处理

<script>
export default {
  props: ['scheduleData'],
  data() {
    return {
      widthNum: 70,
      schedule: {
        // actualProgress: [
        //   {
        //     code: "3",
        //     min_plan: 202402,
        //     max_plan: 202403,
        //     plan_schedule: "招标采购",
        //   },
        //   {
        //     code: "4",
        //     min_plan: 202404,
        //     max_plan: 202407,
        //     plan_schedule: "签订合同",
        //   },
        //   {
        //     code: "5",
        //     min_plan: 202408,
        //     max_plan: 202408,
        //     plan_schedule: "到货",
        //   },
        // ],
        // plannedProgress: [
        //   {
        //     code: "1",
        //     min_plan: 202310,
        //     max_plan: 202402,
        //     plan_schedule: "前期",
        //   },
        //   {
        //     code: "2",
        //     min_plan: 202403,
        //     max_plan: 202403,
        //     plan_schedule: "招标",
        //   },
        //   {
        //     code: "3",
        //     min_plan: 202404,
        //     max_plan: 202408,
        //     plan_schedule: "合同",
        //   },
        //   {
        //     code: "4",
        //     min_plan: 202409,
        //     max_plan: 202409,
        //     plan_schedule: "到货",
        //   },
        //   {
        //     code: "5",
        //     min_plan: 202410,
        //     max_plan: 202410,
        //     plan_schedule: "施工",
        //   },
        //   {
        //     code: "6",
        //     min_plan: 202411,
        //     max_plan: 202411,
        //     plan_schedule: "投运",
        //   },
        //   {
        //     code: "8",
        //     min_plan: 202412,
        //     max_plan: 202412,
        //     plan_schedule: "关闭",
        //   },
        // ],
      },
      plannedProgress: [],
      actualProgress: [],
      colorObj1: {
        1: { bgColor: "#CAF6D8", textColor: "#24A74B" },
        2: { bgColor: "#C8FAF0", textColor: "#10CFA5" },
        3: { bgColor: "#D1E5FF", textColor: "#006FFF" },
        4: { bgColor: "#FDDACD", textColor: "#E82222" },
        5: { bgColor: "#E8CAFD", textColor: "#8034B5" },
        6: { bgColor: "#CACAFD", textColor: "#3A35C9" },
        7: { bgColor: "#FAE9C5", textColor: "#E79900" },
        8: { bgColor: "#D5E1ED", textColor: "#4E6581" },
      },
      colorObj2: {
        1: { bgColor: "linear-gradient( 270deg, #5BE284 0%, #2FC25B 99%)"},
        2: { bgColor: "linear-gradient( 270deg, #EEA073 0%, #E8864D 100%)"},
        3: { bgColor: "linear-gradient( 270deg, #64E6CA 0%, #31CCBC 100%)"},
        4: { bgColor: "linear-gradient( 270deg, #48BBFC 0%, #398FFF 100%)"},
        5: { bgColor: "linear-gradient( 270deg, #FF7272 0%, #FF0808 100%)"},
        6: { bgColor: "linear-gradient( 270deg, #B988DC 0%, #8939C1 100%)"},
        7: { bgColor: "linear-gradient( 270deg, #AAA7F8 0%, #554FF3 100%)"},
        8: { bgColor: "linear-gradient( 270deg, #FAC458 0%, #E99B00 100%)"},
        9: { bgColor: "linear-gradient( 270deg, #8EB1DD 0%, #60799B 100%)"},
      },
      actualBar: "", //实际进度用了多少月
      pLength:0,
      aLength:0,
      dateAndMonth: [],
      advance: 0,//实际第一阶段比计划第一阶段提前
      lagging:0,//实际最后阶段比计划最后阶段滞后
    };
  },
  created() {
  },
  mounted() {
  },
  methods: {
    handleData() {
      this.plannedProgress = [];
      this.actualProgress = [];
      if (JSON.stringify(this.scheduleData) == '{}') {
        return
      } else {
        this.schedule = this.scheduleData;
      }
      this.getWidthBar(this.schedule.actualProgress, 0);
      this.getWidthBar(this.schedule.plannedProgress, 1);
      this.getAdvanceMargin()
      this.getActualBar();
      this.getDateAndMonth();
    },
    getWidthBar(progress, flag) {
      if (!progress) {
        return;
      }
      if (progress.length == 0) {
        return;
      }
      let result = progress; let length = progress.length;
      let minDate, maxDate, minYear, maxYear, minMonth, maxMonth;
      result.forEach((item, index) => {
        //当前阶段 数据
        minDate = item.min_plan;
        maxDate = item.max_plan;
        minYear = Math.floor(item.min_plan / 100);
        maxYear = Math.floor(item.max_plan / 100);
        minMonth = Math.floor(item.min_plan % 100);
        maxMonth = Math.floor(item.max_plan % 100);
        if (minYear == maxYear) {
          item.widthBar = maxMonth - minMonth + 1;
        } else {
          item.widthBar =
            12 - minMonth + maxMonth + 1 + (maxYear - minYear - 1) * 12;
        }
        if (index == 0) {
          
        }
        else {
          //上个阶段
          let fmaxDate = result[index - 1].max_plan;
          let fmaxYear = Math.floor(result[index - 1].max_plan / 100); //上一个阶段年
          let fmaxMonth = Math.floor(result[index - 1].max_plan % 100);//上个阶段月
          //判断是否同年
          if (minYear == fmaxYear) {//同年
            if ((minMonth-fmaxMonth) == 1) {//月份连续
              item.marginLeftBar = 0
            } else {//月份不连续
              item.marginLeftBar=(minMonth - fmaxMonth - 1)
            }
          } else {//隔年 例如 202311 202401 隔了 12月,一个月
            item.marginLeftBar=(minMonth + 12 - fmaxMonth - 1)
          }
        }
      });
      console.log(result, "result");
      if (flag == 0) {
        this.actualProgress = result||[];
      }
      if (flag == 1) {
        this.plannedProgress = result||[];
      }
    },
    getAdvanceMargin() {
      if (this.plannedProgress.length != 0 && this.actualProgress.length != 0) {
        let pminDate, pminYear, pminMonth, aminDate, aminYear, aminMonth;
        let marginLeftBar = 0
        pminDate = this.plannedProgress[0].min_plan;
        pminYear = Math.floor(this.plannedProgress[0].min_plan / 100);
        pminMonth = Math.floor(this.plannedProgress[0].min_plan % 100);
        aminDate = this.actualProgress[0].min_plan;
        aminYear = Math.floor(this.actualProgress[0].min_plan / 100);
        aminMonth = Math.floor(this.actualProgress[0].min_plan % 100);
        //比计划提前 p 202403   a 202401          p 202401  a 202312
        if (aminDate < pminDate) {
          if (pminYear == aminYear) {
            marginLeftBar = pminMonth - aminMonth
          } else {
            marginLeftBar = aminMonth + 12 - pminMonth
          }
          this.plannedProgress[0]['marginLeftBar'] =marginLeftBar
        }
      }
    },
    getActualBar() {
      if(this.actualProgress.length==0){return}
      let minDate, maxDate, minYear, maxYear, minMonth, maxMonth;
      this.aLength = this.actualProgress.length;
      if (this.plannedProgress.length == 0) {
        minDate = this.actualProgress[0].min_plan;
      } else {
        minDate =this.actualProgress[0].min_plan>this.plannedProgress[0].min_plan?this.plannedProgress[0].min_plan:this.actualProgress[0].min_plan
      }
      maxDate = this.actualProgress[this.aLength - 1].max_plan;
      minYear = Math.floor(minDate / 100);
      maxYear = Math.floor(maxDate / 100);
      minMonth = Math.floor(minDate % 100);
      maxMonth = Math.floor(maxDate % 100);
      this.actualBar =
        12 - minMonth + maxMonth + 1 + (maxYear - minYear - 1) * 12;
      console.log(this.actualBar, "this.actualBar");
      },
    getDateAndMonth() {
      if (this.plannedProgress.length == 0 && this.actualProgress.length == 0) {
        return
      }
      let pLength,aLength, minDate, maxDate, minYear, maxYear, minMonth, maxMonth;
      //有计划进度
      if (this.plannedProgress.length != 0) {
        pLength = this.plannedProgress.length;
        minDate = this.plannedProgress[0].min_plan;
        maxDate = this.plannedProgress[pLength - 1].max_plan;
        //有实际进度,则对比最小时间,最大时间
        if (this.actualProgress.length != 0) {
          aLength=this.actualProgress.length;
          let aminDate = this.actualProgress[0].min_plan;
          let amaxDate = this.actualProgress[aLength - 1].max_plan;
          minDate = minDate < aminDate ? minDate : aminDate;
          maxDate = maxDate < amaxDate ? amaxDate : maxDate;
        }
      }
      //无计划进度,用实际进度
      else {
        aLength = this.actualProgress.length;
        minDate = this.actualProgress[0].min_plan;
        maxDate = this.actualProgress[aLength - 1].max_plan;
      }
      minYear = Math.floor(minDate / 100);
      maxYear = Math.floor(maxDate / 100);
      minMonth = Math.floor(minDate % 100);
      maxMonth = Math.floor(maxDate % 100);
      //年、月
      this.dateAndMonth = [];
      let temp = minYear;
      while (temp <= maxYear) {
        let minarr = [];
        //一年之内
        if (minYear==maxYear) {
          for (let i = minMonth; i <= maxMonth; i++) {
            minarr.push(i);
          }
          this.dateAndMonth.push({
            year: temp,
            months: minarr,
          });
        }
        //两年
        else if (maxYear - minYear == 1) {
          //项目总阶段两年之内;计算项目在哪年,有哪些月
          if (temp == minYear&&temp!=maxYear) {
            for (let i = minMonth; i <= 12; i++) {
              minarr.push(i);
            }
            this.dateAndMonth.push({
              year: temp,
              months: minarr,
            });
          }
          else if (temp == maxYear && temp != minYear) {
            for (let i = 1; i <= maxMonth; i++) {
              minarr.push(i);
            }
            this.dateAndMonth.push({
              year: temp,
              months: minarr,
            });
          }
        }
        //大于两年
        else if (maxYear - minYear > 1) {
          if (minYear != temp && maxYear != temp) {
            this.dateAndMonth.push({
              year: temp,
              months: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
            });
          }
        }
        temp++;
      }
      console.log(this.dateAndMonth, "this.dateAndMonth");
    },
    yearItem(yitem) {
      let obj = { width: yitem.months.length * this.widthNum + 'px' }
      return obj
      },
      bookmarkStyleP(item, val) {
          if (!item) {
              return
          }
          let obj = {};
            obj = {
                  'width': item.widthBar * this.widthNum + 'px',
              'background': this.colorObj1[item.code].bgColor,
                  'margin-left':item.marginLeftBar * this.widthNum + 'px',
              }
          return obj;
      },
      bookmarkTextP(item) {
          if (!item) { return }
          let obj = {};
          obj = {
              'color':this.colorObj1[item.code].textColor
          }
          return obj
      },
     bookmarkStyleA() {
         let obj={};
        let aLength = this.actualProgress.length
        let aitem=this.actualProgress[aLength-1]
        obj = {
            'width': this.actualBar * this.widthNum + 'px',
            'background':this.colorObj2[aitem.code].bgColor,
         }
        return obj
    },
    cliclBtn(){
      this.$emit('close')
    }
  },
  watch: {
    scheduleData: {
      handler(n, o) {
        this.handleData()
      },
      immediate: true,
    }
  }
};
</script>

样式书写

<style lang="less" scoped>

  .image-schedule-dialog{
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.4);
  z-index: 998;
  }
  .content-box{
  background: #fff;
  display: inline-block;
  margin: 0 auto;
  position: relative;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 999;
  }
  .image-schedule {
  min-width: 300px;
  max-width: 1500px;
  overflow-x: auto;
  }
  .colse-btn{
  color: #bbcbde;
  cursor: pointer;
  text-align: right;
  font-weight: 600;
  padding-right: 10px;
  height: 20px;
  line-height: 20px;
  }
  .date-progress,
  .plan-progress,
  .actual-progress {
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  .label {
    width: 80px;
    text-align: center;
    flex-shrink: 0; //不允许弹性布局挤压子元素宽度
  }
  .bookmark {
    width: 60px;
    height: 30px;
    background: red;
    flex-shrink: 0; //不允许弹性布局挤压子元素宽度
    clip-path: polygon(
      calc(100% - 0.5rem) 0%,
      100% 50%,
      calc(100% - 0.5rem) 100%,
      0% 100%,
      0.5rem 50%,
      0% 0%
    );
  }
  .bookmark-text {
    font-size: 12px;
    font-weight: 700;
    float: right;
    padding-right: 12px;
    line-height: 30px;
  }
  }
  .date-progress {
  margin-bottom: 5px;
  .date {
    text-align: center;
    .year,.month {
      display: flex;
    }
    .year-item {
        height: 20px;
      border-left: 1px solid #ccc;
      box-sizing: border-box;
    }
  }
    .date:nth-child(2){
        .year-item{
            border: none;
        }
    }
  .month-item {
    height: 20px;
    border-left: 1px solid #ccc;
    box-sizing: border-box;
  }
  }
  .plan-progress {
  margin: 0 5px;
  }
  .actual-progress {
  margin: 0 5px;
  }

</style>


http://www.kler.cn/a/522583.html

相关文章:

  • 设计模式-建造者模式、原型模式
  • mysql DDL可重入讨论
  • 哈工大:LLM高质量嵌入模型KaLM-Embedding
  • 三角形的最大周长(LeetCode 976)
  • CTF-web: Python YAML反序列化利用
  • [免费]基于Python的Django博客系统【论文+源码+SQL脚本】
  • 07JavaWeb——Mysql02
  • 02-硬件入门学习/嵌入式教程-Type-C使用教程
  • 【读书笔记】万字浅析游戏场景中常见的渲染性能优化手段
  • 学到一些小知识关于Maven 与 logback 与 jpa 日志
  • 探索Baklib企业内容管理系统CMS优化企业文档管理的最佳实践
  • 【华为OD-E卷 - 基站维修工程师 100分(python、java、c++、js、c)】
  • Swoole的MySQL连接池实现
  • ResNeSt: Split-Attention Networks 参考论文
  • 用layui表单,前端页面的样式正常显示,但是表格内无数据显示(数据库连接和获取数据无问题)——已经解决
  • 动手学图神经网络(6):利用图神经网络进行点云分类
  • 期权帮|做空股指期货是否会对股指产生影响?
  • 深入学习Java的线程的生命周期
  • 【快速上手】阿里云百炼大模型
  • 领域知识图谱的应用案例---下
  • vxe-table和element表尾合计行
  • “com.docker.vmnetd”将对你的电脑造成伤害。 如何解决 |Mac
  • 基于Flask的豆瓣电影可视化系统的设计与实现
  • IDEA 中 Maven 依赖变灰并带斜线的解决方法及原理分析
  • 数据结构——实验七·排序
  • 【LeetCode: 704. 二分查找 + 二分】