el-calendar 自定义样式 带百分比动画效果

本文介绍了如何使用Element UI的el-calendar组件实现自定义样式,通过百分比动态填充颜色,并配合底层div创建柱状图效果,展示了数据可视化在管理平台中的应用。

图片效果, 颜色根据百分比使用动态填充,底层div根据百分比形成柱状图效果

效果图
全部代码

<template>
  <div class="app-container home">
  <div class="app-container">
    <el-row :gutter="20">
      <el-col :sm="24" :lg="12" style="padding-left: 20px">
        <h2>欢迎使用碳中和管理平台</h2>
      </el-col>
    </el-row>
    <el-divider />
    <el-row>
      <el-calendar v-model="valueData" class="calendar_class" id="calendar">
        <!-- 这里使用的是 2.5 slot 语法,对于新项目请使用 2.6 slot 语法-->
        <template
          slot="dateCell"
          slot-scope="{date, data}">
          <!--自定义内容-->
          <div @click="clickDate(data.day)" style="width: 100%;height: 100%;text-align: center;">
              <div v-if="brightDate.indexOf(data.day) != -1" style="height: 100%">
                  <div class="progressbar-wrapper" style="height: 100%">
                    <div class="paddingTopDivNum">
                      <span class="everyDay">{{ data.day.split('-').slice(2).join('-') }}</span>
                    </div>
                      <div>
                        <div class="textDiv" v-html="content(data.day,'num1')"></div>
                      </div>
                      <div :class="data.day" :style="{background:content(data.day,'color')}" style="" class="progressbar">
                      </div>
                </div>
              </div>
              <div v-else class="paddingTopDivNum">
                <div style="padding-top: 3px">
                  <span>{{ data.day.split('-').slice(2).join('-') }}</span>
                </div>
              </div>
            </div>
        </template>
      </el-calendar>
    </el-row>
  </div>
    <el-dialog title="详情信息" :visible.sync="open" append-to-body width="70%" @open="openDialog()" @close='nodeDataOpenCancel'>
      <div style="padding: 10px">
        <el-row>
          <div style="width: 100%;height: 400px" id="main"></div>
        </el-row>
        <el-table
          :data="allData"
          border
        >
          <!-- <el-table-column type="selection" width="55" align="center" /> -->
          <el-table-column label="工序" align="center" prop="process" />
          <el-table-column label="产量(万吨)" align="center" prop="prodTotal">
            <template v-slot="scope">
              {{ (scope.row.prodTotal/10000).toFixed(2) }}
            </template>
          </el-table-column>
          <el-table-column
            label="排放量(万吨)"
            align="center"
            prop="emissionWg"
          >
            <template v-slot="scope">
              {{ (scope.row.emissionWg/10000/1000).toFixed(2) }}
            </template>
          </el-table-column>
          <!-- 排放量/产量 -->
          <el-table-column
            label="排放强度(kgCO2/t)"
            align="center"
            prop="emissionIntensity"
            width="150"
          >
            <template v-slot="scope">
              {{ scope.row.emissionIntensity.toFixed(2) }}
            </template>
          </el-table-column>
        </el-table>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import leftCharts from "./components/homeCharts/headerLeft.vue";
import rightCharts from "./components/homeCharts/headerRight.vue";
import dischareCharts from "./components/homeCharts/dischare.vue";
import emissionCharts from "./components/homeCharts/emissionCharts.vue";
import excessive from "./components/homeCharts/excessive.vue";

import * as echarts from 'echarts';
// excessive
export default {
  name: "Index",
  components: {
    leftCharts,
    rightCharts,
    dischareCharts,
    emissionCharts,
    excessive
  },
  data() {
    return {
      //刷新标识
      refresh : false,
      //选中日期
      selectDay:undefined,
      //控制弹出框开关
      open : false,
      valueData : new Date(),
      calendarData: [
        {
          'tribunalName': '第一审判法庭',
          'startDate': '2022-04-01',
          'judgeId': '00109',
          'num1' : '10%',
          'num2' : '33.1%',
          'num3' : '32.1%',
          'limitingPercentage':'50%'
        },
        {
          'tribunalName': '第一审判法庭',
          'startDate': '2022-04-02',
          'judgeId': '00109',
          'num1' : '20.1%',
          'num2' : '33.1%',
          'num3' : '32.1%',
          'limitingPercentage':'50%'
        },
        {
          'tribunalName': '第一审判法庭',
          'startDate': '2022-04-03',
          'judgeId': '00109',
          'num1' : '30.1%',
          'num2' : '33.1%',
          'num3' : '32.1%',
          'limitingPercentage':'50%'
        },
        {
          'tribunalName': '第一审判法庭',
          'startDate': '2022-04-04',
          'judgeId': '00109',
          'num1' : '40.1%',
          'num2' : '33.1%',
          'num3' : '32.1%',
          'limitingPercentage':'50%'
        },
        {
          'tribunalName': '第一审判法庭',
          'startDate': '2022-04-05',
          'judgeId': '00109',
          'num1' : '50.1%',
          'num2' : '33.1%',
          'num3' : '32.1%',
          'limitingPercentage':'50%'
        },
        {
          'tribunalName': '第一审判法庭',
          'startDate': '2022-04-06',
          'judgeId': '00109',
          'num1' : '60.1%',
          'num2' : '33.1%',
          'num3' : '32.1%',
          'limitingPercentage':'50%'
        },
        {
          'tribunalName': '第一审判法庭',
          'startDate': '2022-04-07',
          'judgeId': '00109',
          'num1' : '70.1%',
          'num2' : '33.1%',
          'num3' : '32.1%',
          'limitingPercentage':'50%'
        },
        {
          'tribunalName': '第一审判法庭',
          'startDate': '2022-04-08',
          'judgeId': '00109',
          'num1' : '80.1%',
          'num2' : '33.1%',
          'num3' : '32.1%',
          'limitingPercentage':'50%'
        },
        {
          'tribunalName': '第一审判法庭',
          'startDate': '2022-04-09',
          'judgeId': '00109',
          'num1' : '90.1%',
          'num2' : '33.1%',
          'num3' : '32.1%',
          'limitingPercentage':'50%'
        },
        {
          'tribunalName': '第一审判法庭',
          'startDate': '2022-04-10',
          'judgeId': '00109',
          'num1' : '100%',
          'num2' : '33.1%',
          'num3' : '32.1%',
          'limitingPercentage':'50%'
        },
        {
          'tribunalName': '第二审判法庭',
          'startDate': '2022-04-23',
          'judgeId': '00109',
          'num1' : '35.1%',
          'num2' : '33.1%',
          'num3' : '32.1%',
          'limitingPercentage':'50%'
        }
      ],
      allData:[
        {
          process:'石灰',
          prodTotal:120,
          emissionWg:556,
          emissionIntensity: 115.5
        },
        {
          process:'烧结',
          prodTotal:200,
          emissionWg:556,
          emissionIntensity: 115.5
        },
        {
          process:'球团',
          prodTotal:150,
          emissionWg:556,
          emissionIntensity: 115.5
        },
        {
          process:'炼铁',
          prodTotal:80,
          emissionWg:556,
          emissionIntensity: 115.5
        },
        {
          process:'炼钢',
          prodTotal:70,
          emissionWg:556,
          emissionIntensity: 115.5
        },
        {
          process:'电炉',
          prodTotal:110,
          emissionWg:556,
          emissionIntensity: 115.5
        },
        {
          process:'轧钢',
          prodTotal:130,
          emissionWg:556,
          emissionIntensity: 115.5
        },
      ],
      value: new Date()
    }
  },
  created(){
  	//按钮点击事件
    this.$nextTick(() => {
      //修改“今天”为“当月”
      let span1 = document.querySelector(".el-calendar__button-group .el-button-group>button:nth-child(2)");
      span1.innerText = '当月';
      // 点击上个月
      let prevBtn = document.querySelector('.el-calendar__button-group .el-button-group>button:nth-child(1)');
      prevBtn.addEventListener('click', () => {
        console.info(this.valueData)
        console.log(this.dateFormat('YYYY-mm-dd', this.valueData));;
      })
      // 点击今天
      let currBtn = document.querySelector('.el-calendar__button-group .el-button-group>button:nth-child(2)');
      currBtn.addEventListener('click', () => {
        console.info(this.valueData)
        console.log(this.dateFormat('YYYY-mm-dd', this.valueData));
      })
      // 点击下个月
      let nextBtn = document.querySelector('.el-calendar__button-group .el-button-group>button:nth-child(3)');
      nextBtn.addEventListener('click', () => {
        console.info(this.valueData)
        console.log(this.dateFormat('YYYY-mm-dd', this.valueData));
      })
    })
  },
  computed: {
    // 时间高亮的数组
    brightDate () {
      let ary = []
      for (let i in this.calendarData) {
        ary.push(this.calendarData[i].startDate)
      }
      return ary
    }
  },
  activated() {
    this.dynamicFillingHeight();
  },
  mounted(){
    this.dynamicFillingHeight();
  },
  methods: {
    //打开弹窗初始化图表
    openDialog(){
      this.$nextTick(() => {
        //  执行echarts方法
        this.getEchart()
      })
    },
    getEchart(){
      var chartDom = document.getElementById('main');
      var myChart = echarts.init(chartDom);
      var option;

      option = {
        title: {
          text: this.selectDay,
        },
        xAxis: {
          type: 'category',
          data: ['石灰', '烧结', '球团', '炼铁', '炼钢', '电炉', '轧钢']
        },
        yAxis: {
          type: 'value'
        },
        series: [
          {
            data: [
              120,
              {
                value: 200,
                // itemStyle: {
                //   color: '#a90000'
                // }
              },
              150,
              80,
              70,
              110,
              130
            ],
            type: 'bar',
            itemStyle: {
              normal: {
                label: {
                  show: true,		//开启显示
                  position: 'top',	//在上方显示
                  textStyle: {	    //数值样式
                    color: 'black',
                    fontSize: 16
                  }
                }
              }
            }
          }
        ]
      };

      option && myChart.setOption(option);

      // option && myChart.setOption(option);
    },
    //按钮取消事件
    nodeDataOpenCancel(){

    },
    clickDate(day){
      this.open = true;
      this.selectDay = day;
      console.log(day);
    },
    /**
     * @param {Object} fmt 需要的时间格式 例如:'YYYY-mm-dd'
     * @param {Object} date  格林尼治时间
     */
    dateFormat(fmt, date) {
      let ret;
      const opt = {
        "Y+": date.getFullYear().toString(), // 年
        "m+": (date.getMonth() + 1).toString(), // 月
        "d+": date.getDate().toString(), // 日
        "H+": date.getHours().toString(), // 时
        "M+": date.getMinutes().toString(), // 分
        "S+": date.getSeconds().toString() // 秒
      };
      for (let k in opt) {
        ret = new RegExp("(" + k + ")").exec(fmt);
        if (ret) {
          fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
        };
      };
      return fmt;
    },
    // 动态获取对象信息
    content (date,type) {
      let content = ''
      for (let i in this.calendarData) {
        if (date === this.calendarData[i].startDate) {
          switch (type) {
            case 'color' :
              let num = this.calendarData[i].num1
              num = num.substring(0, num.length - 1);
              num = parseInt(num)/100
              if (num === 1){
                return "rgba(255,14,18,"+num+')'
              }else {
                return "rgba(50, 205, 50,"+num+')'
              }
            default :
              content = this.calendarData[i][type]
          }
        }
      }
      return content
    },
    dynamicFillingHeight(){

      //为了每次进入首页都重置动画
      for (let i in this.calendarData) {
        let thisData = this.calendarData[i]
        let dateClass = document.getElementsByClassName(thisData.startDate);
        dateClass[0].style.height = 0;
      }
      setTimeout(()=>{
        for (let i in this.calendarData) {
          let thisData = this.calendarData[i]
          let dateClass = document.getElementsByClassName(thisData.startDate);
          dateClass[0].style.height = thisData.num1;
        }
      },500)

    }
  }
}
</script>

<style scoped lang="scss">
.home {
  blockquote {
    padding: 10px 20px;
    margin: 0 0 20px;
    font-size: 17.5px;
    border-left: 5px solid #eee;
  }
  hr {
    margin-top: 20px;
    margin-bottom: 20px;
    border: 0;
    border-top: 1px solid #eee;
  }
  .col-item {
    margin-bottom: 20px;
  }

  ul {
    padding: 0;
    margin: 0;
  }

  font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 13px;
  color: #676a6c;
  overflow-x: hidden;
  ul {
    list-style-type: none;
  }

  h4 {
    margin-top: 0px;
  }

  h2 {
    margin-top: 10px;
    font-size: 26px;
    font-weight: 100;
  }

  p {
    margin-top: 10px;
    b {
      font-weight: 700;
    }
  }

  .update-log {
    ol {
      display: block;
      list-style-type: decimal;
      margin-block-start: 1em;
      margin-block-end: 1em;
      margin-inline-start: 0;
      margin-inline-end: 0;
      padding-inline-start: 40px;
    }
  }
}
.everyDay {
  display: inline-block;
  padding-top: 7px;
  width:  40px;
  height: 40px;
  background-color: #409eff;
  color: #fff;
  border-radius: 50%;
}
</style>

<style scoped>
  /*calendar_class 是el-calendar所在父标签的css 去除灰色表格的点击事件*/
  .calendar_class >>>.el-calendar-table:not(.is-range)
    td.next{
      pointer-events: none;
    }
  .calendar_class >>>.el-calendar-table:not(.is-range)
    td.prev{
      pointer-events: none;
    }
    /*去除表格外padding*/ 
  .calendar_class >>>.el-calendar-table .el-calendar-day{
    padding: 0px;
  }
  .paddingTopDiv{
    padding-top: 1px;
    text-align: right;
  }
  .paddingTopDivNum{
    font-size: 25px;
    padding-top: 8px;
  }
  .textDiv{
    color: black;
    padding-left: 8px;
    font-size: 20px;
    font-weight: bold;
    padding-top: 10px;
    text-align: center;
  }
  /*浮动外框*/
  .progressbar-wrapper {
    position: relative;
    height: 100%;
    z-index: 1;
  }
  /*浮动内框*/
  .progressbar {
    position: absolute;
    bottom: 0;
    left: 0;
    z-index: -1;
    width: 100%;
    height: 0;
    -webkit-transition:height 2s; /*动画效果*/
  }
  .beyond{
    background-color: #ef9a9a;
  }
  .below{
    background-color: #00e676;
  }
</style>
<template> <div class="container"> <TablePane ref="tablePane" :buttons="this.operations" :search-fields="searchFields" :query-params.sync="this.queryParams" :get-list="getListFun" :table-data="tableData" v-if="showGantt" > </TablePane> <div v-if="!showGantt"> <div class="search-wrapper"> <el-form class="search-from" :inline="true" label-width="70px" @submit.prevent="initGantt"> <el-form-item label="名称"> <el-input v-model="queryParams.name" placeholder="请输入名称" clearable/> </el-form-item> <el-form-item label="责任人"> <el-input v-model="queryParams.respPerson" placeholder="请输入责任人" clearable/> </el-form-item> <el-form-item> <el-button type="primary" @click="initGantt"> <i class="el-icon-search"></i> 搜索 </el-button> <el-button @click="resetQuery"> <i class="el-icon-refresh"></i> 重置 </el-button> <el-button type="primary" style="margin-left: 10px;" @click="retractGantt" > {{ '收起甘特图' }} </el-button> </el-form-item> </el-form> </div> <div ref="gantt" class="gantt-container"></div> </div> <!-- 添加或修改治理计划对话框 --> <Dialog title="查看治理计划" :visible.sync="open" width="850px" height="600px" append-to-body> <el-form ref="form" :model="form" label-width="100px" disabled> <el-row> <el-col :span="12"> <el-form-item label="编号" prop="code"> <el-input v-model="form.code" placeholder="请输入编号"/> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="名称" prop="text"> <el-input v-model="form.text" placeholder="请输入名称"/> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="12"> <el-form-item label="上级计划" prop="parent"> <treeselect v-model="form.parent" :options="planOptions" :normalizer="normalizer" placeholder="选择上级计划" disabled /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="完成度(%)" prop="progress"> <el-input-number v-model="form.progress" placeholder="请输入完成百分比"/> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="12"> <el-form-item label="责任人" prop="respPerson"> <span slot="label"> <span class="content-font">责任人</span> </span> <!-- 用户向导 --> <p style="margin-top:0px; float: left;font-size: 12px;"> {{ form.respPerson }} <el-button size="mini" type="primary" icon="el-icon-user" class="btn-wizard-trigger" style="margin-left: 10px" >选择用户 </el-button> </p> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="责任部门" prop="respDept"> <el-input v-model="form.respDept" placeholder="请输入责任部门"/> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="12"> <el-form-item label="计划开始日期" prop="planStartDate"> <el-date-picker clearable v-model="form.planStartDate" type="date" value-format="yyyy-MM-dd" placeholder="请选择计划开始日期"> </el-date-picker> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="实际开始日期" prop="realStartDate"> <el-date-picker clearable v-model="form.realStartDate" type="date" value-format="yyyy-MM-dd" placeholder="请选择实际开始日期"> </el-date-picker> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="12"> <el-form-item label="计划结束时间" prop="planEndDate"> <el-date-picker clearable v-model="form.planEndDate" type="date" value-format="yyyy-MM-dd" placeholder="请选择计划结束时间"> </el-date-picker> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="实际结束日期" prop="realEndDate"> <el-date-picker clearable v-model="form.realEndDate" type="date" value-format="yyyy-MM-dd" placeholder="请选择实际结束日期"> </el-date-picker> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="12"> <el-form-item label="计划工期(天)" prop="planDuration"> <el-input v-model="form.planDuration" placeholder="请选择计划日期"/> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="实际工期(天)" prop="realDuration"> <el-input v-model="form.realDuration" placeholder="请选择实际日期"/> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="24"> <el-form-item label="备注" prop="remarks"> <el-input v-model="form.remarks" type="textarea" placeholder="请输入备注"/> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="24"> <el-form-item label="反馈内容" prop="feedback"> <el-input v-model="form.feedback" type="textarea" placeholder="请输入内容"/> </el-form-item> </el-col> </el-row> </el-form> <div slot="buttons" class="dialog-footer"> <el-button @click="open = false">关 闭</el-button> </div> </Dialog> </div> </template> <script> import TablePane from '@/components/TablePane' import Dialog from '@/components/Dialog' import Treeselect from '@riophae/vue-treeselect' import '@riophae/vue-treeselect/dist/vue-treeselect.css' import {gantt} from "dhtmlx-gantt"; import "dhtmlx-gantt/codebase/dhtmlxgantt.css"; import {listPlan} from "@/api/dw/plan/planview"; export default { components: {TablePane, Dialog, Treeselect}, name: "gantt", data() { return { getListFun: listPlan, searchFields: [ {'field': 'name', 'label': '名称', 'type': 'input'}, {'field': 'respPerson', 'label': '责任人', 'type': 'input'}, ], operations: [ { 'label': '展开甘特图', 'click': this.expandGantt, 'hasPermi': ['dw:planview:list'] }], tableData: { 'idField': 'uid', //加载数据后进行转换用于特殊处理 'loadDataHook': this.loadDataHook, 'attrs': { 'row-key': 'uid', '@row-click': this.rowClick, 'tree-props': { children: 'children', hasChildren: 'hasChildren' }, 'default-expand-all': true }, 'column': [ {'label': '编号', 'prop': 'code', 'attrs': { 'sortable': false,'align': 'left' } }, {'label': '状态', 'prop': 'status1', 'attrs': { 'sortable': false } ,'width': 80,'columnHook': this.light}, {'label': '名称', 'prop': 'name', 'attrs': { 'sortable': false } }, {'label': '完成百分比', 'prop': 'schedule', 'attrs': { 'sortable': false } }, {'label': '责任人', 'prop': 'respPerson', 'attrs': { 'sortable': false } }, {'label': '责任部门', 'prop': 'respDept' , 'attrs': { 'sortable': false }}, {'label': '计划开始日期', 'prop': 'planStartDate' ,'type':"dateTime" , 'format': (date) => { return this.parseTime(date, '{y}-{m}-{d}')}}, {'label': '计划结束时间', 'prop': 'planEndDate' ,'type':"dateTime" , 'format': (date) => { return this.parseTime(date, '{y}-{m}-{d}')}}, {'label': '实际开始日期', 'prop': 'realStartDate' ,'type':"dateTime" , 'format': (date) => { return this.parseTime(date, '{y}-{m}-{d}')}}, {'label': '实际结束日期', 'prop': 'realEndDate' ,'type':"dateTime" , 'format': (date) => { return this.parseTime(date, '{y}-{m}-{d}')}}, {'label': '计划工期', 'prop': 'planDuration' }, {'label': '实际工期', 'prop': 'realDuration' }, {'label': '备注', 'prop': 'remarks' }, { 'width': 100, 'label': '操作', 'type': 'button', 'attrs': { 'sortable': false, 'fixed': 'right' }, 'buttons': [ { 'icon': 'el-icon-view', 'label': '查看', 'hasPermi': ['dw:planview:query'], 'click': this.handleView }, ] } ] }, /***************************************************甘特图 start****************************************************************/ tasks: { data: [], }, queryParams: { name: null, respPerson: null }, showGantt: true, // 状态控制甘特图显示 planOptions: [], open: false, // 控制详情弹窗显示 form: {} // 当前查看的任务 /***************************************************甘特图 end****************************************************************/ }; }, // 把携的参数放到queryParams查询参数里 created() { // console.log(this.$route.params.id); }, methods: { /** 查询治理计划列表 */ getList() { this.$refs.tablePane.loadData() }, loadDataHook(response) { response.data = this.handleTree(response.data, 'uid','parentUid') return response }, light(column, row){ const currentDate = this.getCurrentDate(); if( row.realStartDate != null){//有实际开始时间 // 状态灯:绿色:已完成; // 红色:计划开始时间小于当前日期并且没有实际开始日期; // 黄色:有实际开始日期,但是没有实际结束日期,并且计划结束日期小宇当前日期。 // 其他状态都没有颜色(数据体系里面的计划状态灯昨天没写,也按这个规则) var res = this.compareDate(new Date(row.planEndDate),new Date(currentDate)) if( row.realEndDate == null){ if(res== -1){ column.class='circle-light-yellow' } }else{ column.class='circle-light-green' } }else{//没用实际开始时间 红色:没有实际开始,但是当前日期大于计划开始日期; if(row.planStartDate != null){//有计划开始时间 var res = this.compareDate(new Date(row.planStartDate),new Date(currentDate)) if(res == -1){ column.class='circle-light-red' } } } }, getCurrentDate(){ const dateObj = new Date(); const year = dateObj.getFullYear(); // 获取当前年份 const month = ("0" + (dateObj.getMonth() + 1)).slice(-2); // 获取当前月份,其中需要将月份加1,因为月份是从0开始计数的 const day = ("0" + dateObj.getDate()).slice(-2); // 获取当前日期 const formattedDate = `${year}-${month}-${day}`; // 格式化日期 return formattedDate; // 输出当前时间的年月日 }, compareDate(date1,date2){//date1 > date2 返回1;date1 < date2 返回-1 相等返回0 if (date1.getTime() > date2.getTime()) { return 1; } else if (date1.getTime() < date2.getTime()) { return -1; } else { return 0; } }, // 上级节点 getTreeselect() { listPlan().then(response => { const data = {uid: 0, name: '顶级节点', children: []}; data.children = this.handleTree(response.data, 'uid', 'parentUid') this.planOptions.push(data) }) }, normalizer(node) { if (node.children && !node.children.length) { delete node.children } return { id: node.uid, label: node.name, children: node.children } }, rowClick(row, column, event) { // 行点击事件 }, /***************************************************甘特图 start****************************************************************/ // 查看任务详情 handleView(taskId) { // 根据任务ID查找任务详情 const task = this.tasks.data.find(item => item.id == taskId); if (task) { this.getTreeselect(); this.form = task; this.open = true; } }, expandGantt() { this.showGantt = false this.$nextTick(() => { this.initGantt(); // 确保DOM更新后再初始化甘特图 }); }, retractGantt() { this.showGantt = true; this.destroyGantt(); // 添加销毁甘特图方法 }, //开始时间-结束时间参数 DateDifference: function (strDateStart, strDateEnd) { var begintime_ms = Date.parse(new Date(strDateStart.replace(/-/g, "/"))); //begintime 为开始时间 var endtime_ms = Date.parse(new Date(strDateEnd.replace(/-/g, "/"))); // endtime 为结束时间 var date3 = endtime_ms - begintime_ms; //时间差的毫秒数 var days = Math.floor(date3 / (24 * 3600 * 1000)); return days; }, // 重置查询 resetQuery() { this.queryParams = { name: null, respPerson: null }; this.initGantt(); }, initGantt: function () { this.destroyGantt(); // 先销毁旧实例 // 确保容器存在 if (!this.$refs.gantt) return; // 设置容器尺寸 this.$refs.gantt.style.height = `${window.innerHeight - 150}px`; // 在初始化前配置所有设置 //自适应甘特图的尺寸大小, 使得在不出现滚动条的情况下, 显示全部任务 gantt.config.autosize = true; //只读模式 gantt.config.readonly = true; //是否显示左侧树表格 gantt.config.show_grid = true; //时间轴配置 gantt.config.show_task_cells = true; //当task的长度改变时,自动调整图表坐标轴区间用于适配task的长度 gantt.config.fit_tasks = true; gantt.config.min_column_width = 50; gantt.config.auto_types = true; gantt.config.xml_date = "%Y-%m-%d"; gantt.config.scale_unit = "month"; gantt.config.step = 1; gantt.config.date_scale = "%Y年%M"; gantt.config.start_on_monday = true; gantt.config.scale_height = 160; gantt.config.autoscroll = true; gantt.config.calendar_property = "start_date"; gantt.config.calendar_property = "end_date"; gantt.config.readonly = true; //时间刻度配置 var weekScaleTemplate = function (date) { var dateToStr = gantt.date.date_to_str("%m %d"); var endDate = gantt.date.add( gantt.date.add(date, 1, "week"), -1, "day" ); var weekNum = gantt.date.date_to_str("第 %W 周"); return weekNum(date); }; gantt.config.subscales = [ { unit: "week", step: 1, template: weekScaleTemplate, }, { unit: "day", step: 1, format: "%d", }, ]; //表格列设置 gantt.config.columns = [ { name: "code", label: "编号", tree: true, width: "160", onrender: function (task, node) { node.setAttribute( "class", "gantt_cell gantt_last_cell gantt_cell_tree " + task.status ); }, }, { name: "status", label: "状态", align: "center", width: "80", template: function (task) { // 自定义状态列显示为状态灯 return `<div class="status-light" style="background-color: ${task.color}"></div>`; } }, {name: "text", label: "名称", align: "center", width: "180", hide: true}, {name: "progress", label: "完成度(%)", align: "center", width: "90", hide: true}, {name: "respPerson", label: "责任人", align: "center", width: "120", hide: true}, {name: "respDept", label: "责任部门", align: "center", width: "140", hide: true}, {name: "planStartDate", label: "计划开始日期", align: "center", width: "130", hide: true}, {name: "planEndDate", label: "计划结束时间", align: "center", width: "130", hide: true}, {name: "realStartDate", label: "实际开始日期", align: "center", width: "130", hide: true}, {name: "realEndDate", label: "实际结束日期", align: "center", width: "130", hide: true}, {name: "planDuration", label: "计划工期", align: "center", width: "90", hide: true}, {name: "realDuration", label: "实际工期", align: "center", width: "90", hide: true}, {name: "remarks", label: "备注", align: "center", width: "220", hide: true}, ]; // 设置布局 - 修复表格铺满问题 gantt.config.layout = { css: "gantt_container", cols: [ { width: 400, // 固定左侧表格宽度 min_width: 300, rows: [ { view: "grid", scrollX: "gridScroll", scrollable: true, scrollY: "scrollVer", }, { view: "scrollbar", id: "gridScroll", group: "horizontal", }, ], }, { resizer: true, width: 1, }, { rows: [ { view: "timeline", scrollX: "scrollHor", scrollY: "scrollVer", }, { view: "scrollbar", id: "scrollHor", group: "horizontal", }, ] } ], }; // 初始化 gantt.init(this.$refs.gantt); gantt.plugins({ tooltip: true, }); //设置鼠标放置显示事件 gantt.attachEvent("onGanttReady", function() { var tooltips = gantt.ext.tooltips; gantt.templates.tooltip_text = function(start, end, task) { return "编号:" + task.code + "<br/>" + "名称:" + task.text + "<br/>" + "计划开始:" + gantt.templates.tooltip_date_format(start) + "<br/>" + "工期:" + task.duration }; }); //设置任务条进度内容 gantt.templates.progress_text = function (start, end, task) { return ( "<div style='text-align:left;color:#fff;padding-left:20px'>" + task.progress + "% </div>" ); }; //任务条显示内容 gantt.templates.task_text = function (start, end, task) { return ( "<div style='text-align:center;color:#fff'>" + task.text + "(" + task.duration + "天)" + "</div>" ); }; //任务条上的文字大小 以及取消border自样式 gantt.templates.task_class = function (start, end, item) { return item.$level == 0 ? "firstLevelTask" : "secondLevelTask"; }; gantt.i18n.setLocale("cn"); listPlan(this.queryParams).then((res) => { this.tasks.data = res.data.map((item) => { let statusColor; //存在status字段 说明非一级菜单,判断阶段的具体类型 设置不同颜色 if (item.status == '1') { //冒烟 statusColor = "#84bd54" } else if (item.status == '2') { //单元 statusColor = "#fcca02" } else if (item.status == '3') { //回归 statusColor = "#dc1626" } else { statusColor = "#999999" } return { id: item.uid, parent: item.parent, text: item.name, start_date: item.planStartDate, duration: item.planDuration, open: true, //默认打开, toolTipsTxt: item.name, progress: item.schedule, status: item.status, code: item.code, respPerson: item.respPerson, respDept: item.respDept, planStartDate: item.planStartDate, planEndDate: item.planEndDate, realStartDate: item.realStartDate, realEndDate: item.realEndDate, planDuration: item.planDuration, realDuration: item.realDuration, remarks: item.remarks, feedback: item.feedback, color: statusColor, } }); // 数据解析 gantt.parse(this.tasks); }); // 添加双击行事件监听器 gantt.attachEvent("onTaskDblClick", function(id, e) { // 调用查看详情方法 window.vueInstance.handleView(id); return true; }); }, destroyGantt() { // 使用正确的API检查和销毁甘特图实例 if (this.$refs.gantt && this.$refs.gantt.children.length > 0) { // 使用正确的销毁方法 if (gantt.destructor) { gantt.destructor(); } } // 清空容器 if (this.$refs.gantt) { this.$refs.gantt.innerHTML = ""; } }, }, mounted() { window.vueInstance = this; if (!this.showGantt) { this.$nextTick(this.initGantt); } else { this.getList(); } }, }; </script> <style lang="scss" scoped> .firstLevelTask { border: none; .gantt_task_content { font-size: 13px; } } .secondLevelTask { border: none; } .thirdLevelTask { border: 2px solid #da645d; color: #da645d; background: #da645d; } .milestone-default { border: none; background: rgba(0, 0, 0, 0.45); } .milestone-unfinished { border: none; background: #5692f0; } .milestone-finished { border: none; background: #84bd54; } .milestone-canceled { border: none; background: #da645d; } html, body { margin: 0; padding: 0; height: 100%; overflow: hidden; } .container { height: 100%; width: 100%; position: relative; padding: 10px; .gantt_grid_head_cell { padding-left: 20px; text-align: left !important; font-size: 14px; color: #333; } .left-container { height: 100%; } .green, .yellow, .pink, .popular { .gantt_tree_icon.gantt_file { background: none; position: relative; &::before { content: ""; width: 10px; height: 10px; border-radius: 50%; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); } } } .green { .gantt_tree_icon.gantt_file { &::before { background: #84bd54; } } } .yellow { .gantt_tree_icon.gantt_file { &::before { background: #fcca02; } } } .pink { .gantt_tree_icon.gantt_file { &::before { background: #da645d; } } } .popular { .gantt_tree_icon.gantt_file { &::before { background: #d1a6ff; } } } } .left-container { height: 100%; } .gantt_task_content { text-align: left; padding-left: 10px; } .gantt-container { height: calc(100vh - 150px) !important; width: 100%; } // 状态灯样式 ::v-deep .gantt_grid_data .gantt_cell div.status-light { width: 12px; height: 12px; border-radius: 50%; display: inline-block; margin: 0 auto; } // 表格表头居中样式 ::v-deep .gantt_grid_head_cell { text-align: center !important; } .search-wrapper { text-align: left; padding: 10px 0; } .search-from { .el-form-item--mini.el-form-item, .el-form-item--small.el-form-item { margin-bottom: 3px; } } </style> <style lang="less"> .circle-light-yellow > span::before { content: ''; display: inline-block; width: 16px; height: 16px; background-color: #e6a23c; border-radius: 50%; margin-right: 10px; } .circle-light-green > span::before { content: ""; display: inline-block; width: 16px; height: 16px; background-color: #67c23a; border-radius: 50%; margin-right: 10px; } .circle-light-red > span::before { content: ""; display: inline-block; width: 16px; height: 16px; background-color: #f56c6c; border-radius: 50%; margin-right: 10px; } </style> Error in nextTick: "TypeError: Cannot read properties of undefined (reading 'tasksStore')" 第二次展开是报错
最新发布
08-08
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值