echarts5.4.0 を使用して vue2.X でプロジェクト進捗ガント チャートを実装する

echarts5.4.0 を使用して vue2.X でプロジェクト進捗ガント チャートを実装する

レンダリング:はい
ここに画像の説明を挿入します
左侧すべてです。コンテンツは次のとおりです。名称上面时间日志内容

  1. コンポーネント:gantt.vue
<template>
    <div id="main" style="width: 100%; height: 100%"></div>
  </template>
  <script>
  import * as echarts from "echarts";
  export default {
    
    
    name: "Gantt",
    props: {
    
    
      baseDate: {
    
    
        type: String,
        default: "",
      },
      ganttData: {
    
    
        type: Array,
        default: () => [],
      },
      roomData: {
    
    
        type: Array,
        default: () => [],
      },
    },
    data() {
    
    
      return {
    
    
          minHours: '08:00',
          maxHours: '24:00',
         // colors: ['#5c2223','#346c9c', '#525288', '#87723e', '#d1c2d3','#f07c82', '#835e1d', '#d99156', '#954416', '#ee8055', '#126e82', '#61649f', '#a7a8bd']
      };
    },
    created() {
    
    },
    mounted() {
    
    
     this.myEcharts();
    },
    watch: {
    
    
      ganttData(newVal) {
    
    
        this.myEcharts();
      },
    },
    methods: {
    
    
      getTimes() {
    
    
        let baseDate = `${
      
      this.baseDate}`;
        // 获取日志的最早和最晚时间,这样防止两边出现空白,比如00:00-09:00;
        this.$http.post(`/sys/task/times`, {
    
    taskDate: baseDate}).then(({
     
      data: res }) => {
    
    
          if (res.code !== 0) {
    
    
              return this.$message.error(res.msg)
          }
          this.minHours = res.data.minTime
          this.maxHours = res.data.maxTime
        }).catch(() => {
    
    })
      },
      myEcharts() {
    
    
        this.getTimes();
        // 基于准备好的dom,初始化echarts实例
        const container = document.getElementById("main");
        this.$echarts.init(container).dispose();
        var myChart = this.$echarts.init(container);
        // 用于随机颜色
        var colors= ['#8dddfa','#f98e72', '#f7b84f', '#a872f9', '#d6a9d1','#a7e56d', '#ff73c7', '#d6a9d1', '#b1e7fb', '#d3b3af', '#2859b1', '#1f6cb0']
        //let min = `${this.$moment().format("YYYY-MM-DD")} 00:00:00`;
        //let max1 = `${this.$moment().add(1, "day").format("YYYY-MM-DD")} 00:00:00`;
        // 指定图表的配置项和数据
        var option = {
    
    
          color: "#0A8BFF",
          backgroundColor: "#fff",
          title: {
    
    },
          tooltip: {
    
    
            // enterable: true,
            trigger: "item",
            show: true,
            // axisPointer: { // 坐标轴指示器,坐标轴触发有效
            //   type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
            // },
            // alwaysShowContent: true,
            hideDelay: 100,
            backgroundColor: "rgba(255,255,255,1)", // 背景颜色(此时为默认色)
            borderRadius: 5, // 边框圆角
            confine: true,
            textStyle: {
    
    
              color: "#000"
            },
            // 悬浮的时候展示对应的数据
            formatter: function (params) {
    
    
              for(var i = 0; i < params.data.value.length; i++) {
    
    
                var content = (
                  params.data.value[i].content +
                  // "<br/>" +
                  // (params.data.value[i].status === "1" ? '<span style="color:#4dc394;">已完成</span>' : '<span style="color:#e5835b;">进行中</span>') +
                  "<br/>" +
                  params.data.value[i].stime +
                  " - " +
                  params.data.value[i].etime
                );
                // 作用:鼠标悬浮在内容,出现弹窗显示内容详情,这里限制了宽,以防止宽度过长
                 var tooltipHtml = '<div style="width:fit-content; max-width: 500px; white-space: wrap;">'+content+'</div>';
                 return tooltipHtml;
                //return content;
              }
            },
          },
          legend: {
    
    
            // left: '90px',
            top: "1%",
            itemWidth: 16,
            itemHeight: 16,
            show: true,
            // selectedMode: false, // 图例设为不可点击
            textStyle: {
    
    
              color: "rgba(0, 0, 0, 0.45)",
              fontSize: 14,
            },
          },
          grid: {
    
    
            // 绘图网格
            left: "2%",
            right: "3%",
            top: "10%",
            bottom: "10%",
            containLabel: true,
          },
          xAxis: {
    
    
            type: "time",
            position: "top",
          //  interval: 3600 * 1000, // 以一个小时递增
          // 以一小时的时间递增
            minInterval: 3600 * 1000 ,
            maxInterval: 3600 * 1000 ,
            min: `${
      
      this.baseDate} ` + this.minHours,
            max: `${
      
      this.baseDate} ` + this.maxHours,
            //max:`${this.baseDate} 24:00`,
            //max: `${this.baseDate} 19:00`, // 设置最大时间为18点
            //min:`${this.baseDate} 00:00`, //将data里最小时间的整点时间设为min,否则min会以data里面的min为开始进行整点递增
            //min: `${this.baseDate} 08:00`, // 将data里最小时间的整点时间设为min,否则min会以data里面的min为开始进行整点递增
            axisLabel: {
    
    
              // 设置最后一个数据显示
              showMaxLabel: true,
              formatter: function (value, index) {
    
    
                var data = new Date(value);
                var hours = data.getHours();
                var minutes = data.getMinutes();
                if ((index !== 0 && hours === 0) || index === 25){
    
    
                  return "23:59"
                } else {
    
    
                  //return hours + ":00";
                  if (minutes === 0) {
    
    
                    return hours + ":00";
                  } else {
    
    
                    return hours + ":" + minutes;
                  }
                }
              },
              textStyle: {
    
    
                color: "rgba(0,0,0,0.65)", // 更改坐标轴文字颜色
                fontSize: 14, // 更改坐标轴文字大小
              },
            },
            axisLine: {
    
    
              lineStyle: {
    
    
                color: "#e5e5e5",
              },
              onZero: false,
            },
            splitLine: {
    
    
              show: true,
              lineStyle: {
    
    
                type: "dashed",
              },
            },
          },
          // dataZoom: [
          //   // 给x轴设置滚动条
          //   {
    
    
          //     type: 'slider',
          //     show: true,
          //     yAxisIndex: [0, 1],
          //     left: '96%',
          //     start: 1,
          //     end: 100,
          //     fiterMode: 'filter'
          //   },
          //   {
    
    
          //     type: 'inside',
          //     fiterMode: 'filter',
          //     yAxisIndex: [0, 1],
          //     start: 1,
          //     end: 100
  
          //   }
          // ],
          yAxis: {
    
    
            inverse: true, // 是否反转
            type: "category",
            axisTick:{
    
    
              show: true //不显示坐标轴刻度线
            },
            splitLine: {
    
         //网格线
              "show": true
            },
            axisLine: {
    
    
              show: true,
              lineStyle: {
    
    
                color: "#e5e5e5",
              },
            },
            data: this.roomData,
            axisLabel: {
    
    
              textStyle: {
    
    
                color: "rgba(0, 0, 0, 0.65)", // 刻度颜色
                fontSize: 14, // 刻度大小
              },
            },
          },
          series: [
            {
    
    
              type: "custom",
              clickable: false,
              renderItem: function (params, api) {
    
    
               // 开发者自定义的图形元素渲染逻辑,是通过书写 renderItem 函数实现的
                var categoryIndex = api.value(0).index; // 这里使用 api.value(0) 取出当前 dataItem 中第一个维度的数值。
                var start = api.coord([api.value(0).startTime, categoryIndex]); // 这里使用 api.coord(...) 将数值在当前坐标系中转换成为屏幕上的点的像素值。
                var end = api.coord([api.value(0).endTime, categoryIndex]);
                var height = 26;
                return {
    
    
                  type: "rect", // 表示这个图形元素是矩形。还可以是 'rect', 'circle', 'sector', 'polygon' 等等。
                  shape: echarts.graphic.clipRectByRect(
                    {
    
    
                      // 矩形的位置和大小。
                      x: start[0],
                      y: start[1] - height / 2,
                      width: end[0] - start[0],
                      height: 27,
                    },
                    {
    
    
                      // 当前坐标系的包围盒。
                      x: params.coordSys.x,
                      y: params.coordSys.y,
                      width: params.coordSys.width,
                      height: params.coordSys.height,
                    }
                  ),
                  style: api.style(),
                };
              },
              label: {
    
    
                normal: {
    
    
                  show: true,
                  position: "insideBottom",
                  formatter: function (params) {
    
    
                    //return params.value[0].content;
                    let value =  params.value[0].content;
                    if (!value) return "";
                    if (value.length > 6) {
    
    
                      return value.slice(0, 6) + "...";
                    }
                    return value;
                  },
                  textStyle: {
    
    
                    align: "center",
                    fontSize: 14,
                    fontWeight: "400",
                    lineHeight: "20",
                  },
                },
              },
              encode: {
    
    
                x: 1, // data 中『维度1』对应到 X 轴
                y: 0, // 把"维度0"映射到 Y 轴。
              },
  
              itemStyle: {
    
    
                normal: {
    
    
                  color: function (params) {
    
    
                    const randomIndex = Math.floor(Math.random() * colors.length);
                    return colors[randomIndex];
                  },
                },
              },
              // dataZoom: [
              //   {
    
    
              //     show: true,
              //     realtime: true,
              //     start: 0,
              //     end: 50
              //   }
              // ],
              data: this.ganttData,
            },
          ],
        };
        // 使用刚指定的配置项和数据显示图表。
        myChart.setOption(option);
        window.onresize = function () {
    
    
          myChart.resize();
        };
        // myChart.getZr().on("mousemove", (param) => {
    
    
        //   var pointInPixel = [param.offsetX, param.offsetY];
        //   if (myChart.containPixel("grid", pointInPixel)) {
    
    
        //     // 若鼠标滑过区域位置在当前图表范围内 鼠标设置为小手
        //     // myChart.getZr().setBackgroundColor('red')
        //     myChart.getZr().setCursorStyle("pointer");
        //   } else {
    
    
        //     myChart.getZr().setCursorStyle("default");
        //   }
        // });
        // 任意位置点击事件----注册双击
        // myChart.getZr().on("click", (params) => {
    
    
        //   if (!params.target) {
    
    
        //     // 点击在了空白处,做些什么。
        //     const point = [params.offsetX, params.offsetY];
        //     if (myChart.containPixel("grid", point)) {
    
    
        //       // 获取被点击的点在y轴上的索引
        //       const idxArr = myChart.convertFromPixel({ seriesIndex: 0 }, point);
        //       const xValue = new Date(+idxArr[0]).getHours();
        //       const yValue = idxArr[1];
        //       const sendData = [xValue, yValue];
        //       this.$emit("getInfoCallback", sendData);
        //     }
        //   }
        // });
        // // 图例点击事件-返回数据给父组件---单击事件
        // myChart.on("click", (params) => {
    
    
        //   this.$emit("getInfoCallback", params.data.value);
        // });
      },
      
    },
    computed: {
    
    },
  };
  </script>
  
  <style scoped lang="less">
  </style>
  1. js文件
import Gantt from './src/gantt'

Gantt.install = function (Vue) {
    
    
  Vue.component(Gantt.name, Gantt)
}
export default Gantt
  1. main.js のコンポーネント参照コンポーネント
    ここに画像の説明を挿入します
    ここに画像の説明を挿入します
  2. ログページ
<template>
  <div class="appointment">
    <div class="a-gantt">
      <el-row style="padding: 12px 10px; background-color: #fff">
        <el-col :span="12" align="left" style="font-weight: 700">
          日志
        </el-col>
        <el-col :span="12" align="right">
          <el-date-picker
            v-model="baseDate"
            type="date"
            @change="handleSelect"
            placeholder="选择日期"
            value-format="yyyy-MM-dd"
          >
          </el-date-picker>
        </el-col>
      </el-row>
    </div>
    <div class="f-gantt">
      <Gantt
        :baseDate="baseDate"
        ref="gantt"
        :ganttData="ganttData"
        @getInfoCallback="getGanttInfo"
        :roomData="roomData"
      ></Gantt>
    </div>
    <!-- 新增编辑框 -->
    <!-- <el-dialog :title="formTitle" :visible.sync="dialogVisible" width="30%">
      <el-form :model="form" :label-width="formLabelWidth">
        <el-form-item label="会议室">
          <el-input
            disabled
            v-model="usernameData[form.index]"
            autocomplete="off"
          ></el-input>
        </el-form-item>
        <el-form-item label="内容">
          <el-input v-model="form.content" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="时间" :label-width="formLabelWidth">
          <el-date-picker
            v-model="form.startTime"
            type="datetime"
            placeholder="选择日期"
            value-format="yyyy-MM-dd HH:mm"
          >
          </el-date-picker>
          -
          <el-date-picker
            v-model="form.endTime"
            type="datetime"
            placeholder="选择日期"
            value-format="yyyy-MM-dd HH:mm"
          >
          </el-date-picker>
        </el-form-item>
        <el-form-item label="状态" :label-width="formLabelWidth">
          <el-select v-model="form.status" style="width: 100%">
            <el-option label="进行中" value="0"></el-option>
            <el-option label="已完成" value="1"></el-option>
          </el-select>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="saveData">确 定</el-button>
      </span>
    </el-dialog> -->
  </div>
</template>

<script>


export default {
    
     
  data() {
    
    
    return {
    
    
      baseDate: `${
      
      new Date().getFullYear()}-${
      
      
        new Date().getMonth() + 1
      }-${
      
      new Date().getDate()}`,
      roomData: [],
      ganttData: [],
      dialogVisible: false,
      formLabelWidth: "120px",
      formTitle: "",
      form: {
    
    
        id: "",
        index: "",
        content: "",
        endTime: "",
        status: "",
        startTime: "",
      },
    };
  },
  created() {
    
    
    this.getDataList()

    // this.ganttData = [
    //   {
    
    
    //     value: [
    //       {
    
    
    //         index: 1,
    //         roomName: "会议室二",
    //         RoomId: "123",
    //         id: "333",
    //         startTime: '2023-09-05 08:28', //`${this.baseDate} 8:28`,
    //         endTime: '2023-09-05 09:28', // `${this.baseDate} 9:28`,
    //         status: "1",
    //         content: "睡觉",
    //       }
    //     ],
    //   },
    //   {
    
    
    //     value: [
    //     {
    
    
    //         index: 1,
    //         roomName: "会议室二",
    //         RoomId: "123",
    //         id: "333",
    //         startTime: '2023-09-05 12:28', //`${this.baseDate} 8:28`,
    //         endTime: '2023-09-05 15:28', // `${this.baseDate} 9:28`,
    //         status: "1",
    //         content: "工作",
    //       },
    //     ]
    //   },
    //   {
    
    
    //     value: [
    //       {
    
    
    //         index: 0,
    //         roomName: "会议室一",
    //         RoomId: "2234",
    //         id: "444",
    //         startTime: `2023-09-05 10:28`,
    //         endTime: `2023-09-05 12:28`,
    //         status: "0",
    //         content: "吃饭",
    //       },
    //     ],
    //   },
    //   {
    
    
    //     value: [
    //     {
    
    
    //         index: 0,
    //         roomName: "会议室一",
    //         RoomId: "123",
    //         id: "333",
    //         startTime: '2023-09-05 13:28', //`${this.baseDate} 8:28`,
    //         endTime: '2023-09-05 15:28', // `${this.baseDate} 9:28`,
    //         status: "1",
    //         content: "工作111",
    //       },
    //     ]
    //   }
    // ];
    //this.roomData = ['会议室一', '会议室二', '会议室三', '会议室四'];
  },
  mounted() {
    
    
    this.getDataList();
  },
  methods: {
    
    
    handleSelect() {
    
    
      this.getDataList()
      this.$refs.gantt.myEcharts();
    },
    getDataList() {
    
    
      this.$http.post(`/sys/task/ganteLog`, {
    
    taskDate: this.baseDate}).then(({
     
      data: res }) => {
    
    
          if (res.code !== 0) {
    
    
              return this.$message.error(res.msg)
          }
          this.roomData = res.data.usernameList
          this.ganttData = res.data.data
        }).catch(() => {
    
    })
    },
    getGanttInfo(data) {
    
    
      this.dialogVisible = true;
      // 根据data的长度判断是新增还是编辑
      // 新增
      if (data.length === 2) {
    
    
        this.formTitle = "新增";
        this.form = this.$options.data().form;
        this.$set(this.form, "index", data[1]);
      } else {
    
    
        this.formTitle = "修改";
        this.form = data[0];
      }
    },
    saveData() {
    
    
      if (this.formTitle === "修改") {
    
    
        this.ganttData = this.ganttData.filter((item) => {
    
    
          return item.value[0].id !== this.form.id;
        });
      } else {
    
    
        this.$set(this.form, "status", "0");
      }
      const obj = Object.assign({
    
    }, this.form);
      this.ganttData.push({
    
     value: [obj] });
      this.$refs.gantt.myEcharts();
      this.dialogVisible = false;
    },
  },
};
</script>

<style scoped>
/* .a-gantt {
  position: absolute;
  top: 0;
  height: 60px;
  width: 100%;
  box-sizing: border-box;
  text-align: center;
} */

/* .appointment {
  position: relative;
  height: 100%;
  overflow-y: hidden;
  border: 1px solid #ddd;
  color: #0f1419;
  box-sizing: border-box;
} */
.f-gantt {
    
    
  position: absolute;
  bottom: 10px;
  top: 80px;
  width: 100%;
  /*height: 600px;*/
  box-sizing: border-box;
}
</style>

データ構造に注意する
ここに画像の説明を挿入します

おすすめ

転載: blog.csdn.net/weixin_44021888/article/details/132736742
おすすめ