vue2.X 中使用 echarts5.4.0实现项目进度甘特图

vue2.X 中使用 echarts5.4.0实现项目进度甘特图

效果图:
vue2.X 中使用 echarts5.4.0实现项目进度甘特图_第1张图片
左侧都是名称上面时间,当中的内容是日志内容

  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 +
                  // "
" +
// (params.data.value[i].status === "1" ? '已完成' : '进行中') + "
"
+ params.data.value[i].stime + " - " + params.data.value[i].etime ); // 作用:鼠标悬浮在内容,出现弹窗显示内容详情,这里限制了宽,以防止宽度过长 var tooltipHtml = '
'+content+'
'
; 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. log页面
<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>

注意数据结构
vue2.X 中使用 echarts5.4.0实现项目进度甘特图_第2张图片

你可能感兴趣的:(Vue,甘特图,echarts,甘特图,vue,echarts)