yuhan 1 year ago
parent
commit
431021c6fc

+ 644 - 0
itdmWeb/src/components/module-iTDM/uGantt/index.vue

@@ -0,0 +1,644 @@
+<template>
+  <div class="app-container">
+    
+    <div class="u-gantt-container u-flex">
+      <div>
+        <el-table
+          :data="tableData" 
+          stripe border
+          :cell-class-name="tableCellClassName"
+          :header-cell-class-name="tableCellClassName"
+          @row-dblclick="rowDblclick"
+          row-key="id"
+          default-expand-all
+          :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+          @expand-change="expandChange"
+          >
+          <template v-for="(item, index) in configColumns">
+            <el-table-column
+              :prop="item.name"
+              :label="item.label"
+              :width="item.width"
+              :align="item.align"
+              :key="index"
+              show-overflow-tooltip
+            ></el-table-column>
+            <!-- :fixed="item.fixed" -->
+          </template>
+        </el-table>
+      </div>
+      <div class="u-gantt" ref="uGantt">
+        <div class="u-gantt-title u-flex" >
+          <div v-for="(item, index) in uGanttColumns" :key="index" class="item-title">{{ item.label}}</div>
+        </div>
+        <div class="u-gantt-content">
+          <div class="u-gantt-bg">
+            <div v-for="(item, tr) in ganttLists" :key="tr" class="item-tr u-flex">
+              <!--  :style="{'display': item.show}" -->
+              <div class="item-td" v-for="(item, td) in uGanttColumns" :key="td"></div>
+            </div>
+          </div>
+          <div class="u-gantt-task">
+
+              <div class="u-gantt-task-content uGanttTaskItem" ref="uGanttTaskItem" v-for="(item, index) in ganttLists" :key="index" :style="setStyle(item)">
+                <!-- <span class="resize" ref="`resize${index}}`" @mousedown="dragControllerDiv(index)"></span> -->
+                <div class="u-gantt-task-drag" ref="uGanttDrag"></div>
+                <div class="u-gantt-task-resize resize-left" ref="uGanttResizeL"></div>
+                <div class="u-gantt-task-text">{{ item.content }}</div>
+                <div class="u-gantt-task-resize resize-right" ref="uGanttResizeR"></div>
+              </div>
+            
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <!-- 自定义内容:弹窗 -->
+    <slot/>
+
+  </div>
+</template>
+
+<script>
+  export default {
+    props: {
+      configColumns: {
+        type: Array,
+        default: []
+      },
+      taskLists: {
+        type: Array,
+        default: []
+      }
+    },
+    data(){
+      return {
+        // taskLists: [
+        //   {
+        //     id: 0,
+        //     testItems: 'ceshi',
+        //     sampleName: 'ceshi',
+        //     task_start: '2023-07-03',
+        //     task_end: '2023-07-04',
+        //     statusC: '0',
+        //     content: '111'
+        //   }, {
+        //     id: 1,
+        //     testItems: '测试',
+        //     sampleName: '测试',
+        //     task_start: '',
+        //     task_end: '',
+        //     statusC: '0',
+        //   }, {
+        //     id: 2,
+        //     testItems: 'ceshi',
+        //     sampleName: 'ceshi',
+        //     task_start: '2023-07-06',
+        //     task_end: '2023-07-10',
+        //     statusC: '1',
+        //   }, {
+        //     id: 3,
+        //     testItems: '测试',
+        //     sampleName: '测试',
+        //     task_start: '',
+        //     task_end: '',
+        //     statusC: '1',
+        //   },{
+        //     id: 4,
+        //     testItems: '测试',
+        //     sampleName: '测试',
+        //     task_start: '',
+        //     task_end: '',
+        //     statusC: '1',
+        //   },
+        //   {
+        //     id: 5,
+        //     testItems: '测试',
+        //     sampleName: '测试',
+        //     task_start: '',
+        //     task_end: '',
+        //     statusC: '1',
+        //   },
+        //   {
+        //     id: 6,
+        //     testItems: '测试',
+        //     sampleName: '测试',
+        //     task_start: '',
+        //     task_end: '',
+        //     statusC: '1',
+        //   },
+        //   {
+        //     id: 7,
+        //     testItems: '测试',
+        //     sampleName: '测试',
+        //     task_start: '',
+        //     task_end: '',
+        //     statusC: '1',
+        //   },
+        //   {
+        //     id: 8,
+        //     testItems: '测试',
+        //     sampleName: '测试',
+        //     task_start: '',
+        //     task_end: '',
+        //     statusC: '1',
+        //   },
+        //   {
+        //     id: 21,
+        //     testItems: 'ceshi1',
+        //     sampleName: 'ceshi',
+        //     task_start: '2023-07-05',
+        //     task_end: '2023-07-08',
+        //     statusC: '1',
+        //     parentId: 2
+        //   }, {
+        //     id: 23,
+        //     testItems: 'ceshi3',
+        //     sampleName: 'ceshi',
+        //     task_start: '2023-07-02',
+        //     task_end: '2023-07-04',
+        //     statusC: '1',
+        //     parentId: 2
+        //   },
+        //   {
+        //     id: 22,
+        //     testItems: 'ceshi2',
+        //     sampleName: 'ceshi',
+        //     task_start: '2023-07-06',
+        //     task_end: '2023-07-10',
+        //     statusC: '1',
+        //     parentId: 2
+        //   }
+        // ],
+        // 甘特图部分时间表头
+        uGanttColumns: [],
+        // 表格使用数据
+        tableData: [],
+        // 甘特图显示的
+        ganttLists: [],
+        
+      }
+    },
+    // computed: {
+    //   // 甘特图标题日期分配
+    //   uGanttColumns() {
+    //     // 获取标准时间
+    //     var nowdays = new Date()
+    //     // 获取当年
+    //     var currentYear = new Date().getFullYear()
+    //     // 获取当月
+    //     var currentMonth = new Date().getMonth() + 1
+    //     // 获取当天
+    //     var nowDay = new Date().getDate()
+    //     // 获取当前月有多少天
+    //     var currentMonthNum = new Date(currentYear, currentMonth, 0).getDate()
+    //     console.log(nowDay, currentMonth, currentMonthNum)
+    //     // 
+    //     // let now = new Date(nowDay)
+    //     // console.log(nowdays, now)
+    //     // 当前月份所有日期集合
+    //     let currentMonthArr = []
+    //     for (let i = 1; i <= currentMonthNum; i++) {
+    //       // let day = nowdays.setDate(i);
+    //       // console.log(day)
+    //       // 年月日(yyyy-MM-dd)
+    //       let dateLabel = (currentMonth < 10 ? '0' + currentMonth : currentMonth) + "月" + (i < 10 ? '0' + i : i) + "日";
+    //       let dateName = currentYear + "-" + (currentMonth < 10 ? '0' + currentMonth : currentMonth) + "-" + (i < 10 ? '0' + i : i);
+    //       // let day = 
+    //       currentMonthArr.push({label: dateLabel, name: dateName});
+    //     }
+    //     console.log(currentMonthArr)
+    //     return currentMonthArr
+    //   },
+      
+    // },
+    created (){
+      this.changeTableTree()
+      // this.changeTaskSort()
+      this.getStartEndTime()
+    },
+    mounted () {
+      this.uGanttDrag()
+      this.uGanttResizeL()
+      this.uGanttResizeR()
+    },
+    methods: {
+      // 获取最开始和最末尾时间
+      getStartEndTime(){
+        // var setTimeData = JSON.parse(JSON.stringify(this.taskLists))
+        var setTimeData = this.taskLists.filter(res=> res.task_start)
+        setTimeData.sort(function(a, b) {
+          return b.task_start < a.task_start ? 1 : -1
+        })
+        console.log(setTimeData[0].task_start)
+        console.log(setTimeData[setTimeData.length - 1].task_end)
+        var end = this.addDate(setTimeData[setTimeData.length - 1].task_end, 2)
+        this.uGanttColumns = this.getBetweenDate(setTimeData[0].task_start, end)
+      },
+      /**
+       * 计算某个日期几天后的日期
+       * @param {*} date 相加前的时间
+       * @param {*} days 需要相加的天数
+       */
+      addDate(date, days) {
+        var date = new Date(date);
+        date.setDate(date.getDate() + days);
+        var year = date.getFullYear();
+        var month = date.getMonth() + 1;
+        var day = date.getDate();
+        var mm = "'" + month + "'";
+        var dd = "'" + day + "'";
+        if(mm.length == 3) {
+          month = "0" + month;
+        }
+        if(dd.length == 3) {
+          day = "0" + day;
+        }
+        var time = year + "-" + month + "-" + day
+        return time;
+      },
+      /** 获取两个日期之间的间隔日期
+       * @param { Date | number | string } startTime 开始时间 标准时间格式 时间戳格式 字符串格式(2008-08-08,2008-8-8,2008-08-8,2008-8-08)
+       * @param { Date | number | string } endTime 结束时间 标准时间格式 时间戳格式 字符串格式(2008-08-08,2008-8-8,2008-08-8,2008-8-08)
+       *  */
+      getBetweenDate(startTime, endTime){
+        // 校验时间格式
+        if (typeof startTime === 'string') {
+          const reg = /^\d{4}-(0?[1-9]|1[0-2])-((0?[1-9])|((1|2)[0-9])|30|31)$/g
+          if (!reg.test(startTime)) throw `开始时间:${startTime}时间格式错误`
+        }
+        if (typeof endTime === 'string') {
+          const reg = /^\d{4}-(0?[1-9]|1[0-2])-((0?[1-9])|((1|2)[0-9])|30|31)$/g
+          if (!reg.test(endTime)) throw `结束时间:${endTime}时间格式错误`
+        }
+        let start = new Date(startTime)
+        let end = new Date(endTime)
+        const resultTime = []
+        // 当 开始时间小于结束时间的时候进入循环
+        while (start <= end) {
+          let getDay = start.getDate()
+          // 月份需要加 1
+          let getMonth = start.getMonth() + 1
+          let getYear = start.getFullYear()
+          /**
+           * 拼接时间格式
+           * (getMonth >= 10 ? `${getMonth}` : `0${getMonth}`) 自动给 小于10的时间前面补0
+           */
+          let setTime =
+              `${getYear}-` +
+              (getMonth >= 10 ? `${getMonth}` : `0${getMonth}`) +
+              '-' +
+              (getDay >= 10 ? `${getDay}` : `0${getDay}`)
+          let dateLabel = (getMonth < 10 ? '0' + getMonth : getMonth) + "月" + (getDay < 10 ? '0' + getDay : getDay) + "日";
+          resultTime.push({label: dateLabel, name: setTime})
+          /**
+           * 重新设置开始时间
+           * 使用 setFullYear() 方法会自动将时间累加,返回的是时间戳格式
+           * 使用 new Date() 将时间重新设置为标准时间
+           * getMonth - 1 将月份时间重新还原
+           */
+          start = new Date(start.setFullYear(getYear, getMonth - 1, getDay + 1))
+        }
+        return resultTime
+      },
+      // 将一维数组改成多维数组
+      changeTableTree(){
+        this.tableData = this.handleTree(this.taskLists, 'id', "parentId")
+        this.changeTaskSort(this.tableData)
+      },
+      // 绘制甘特条
+      setStyle(item){
+        var startIndex = this.uGanttColumns.findIndex(res => res.name === item.task_start)
+        var endIndex = this.uGanttColumns.findIndex(res => res.name === item.task_end)
+        var trIndex = this.ganttLists.findIndex(res => res.id === item.id)
+        // console.log(trIndex, this.ganttLists)
+        var style = {
+          left: 70 * startIndex + 'px',
+          width: 70 * (endIndex - startIndex + 1) + 'px',
+          top: (34 * trIndex + 2) + 'px'
+        }
+        return style
+      },
+      // 将组好的多维数组转成一维数组--是为了左右对应
+      changeTaskSort(arr){
+        for(var i = 0; i < arr.length; i++){
+          // arr[i].show = 'flex'
+          if(Array.isArray(arr[i].children)){
+            this.ganttLists.push(arr[i]);
+            this.changeTaskSort(arr[i].children);
+          }else{
+            this.ganttLists.push(arr[i]);
+          }
+        }
+      },
+      // 位移事件
+      uGanttDrag(){
+        var _this = this
+        var uGanttDrag = this.$refs.uGanttDrag;
+        var uGanttTaskItem = this.$refs.uGanttTaskItem;
+        for (let i = 0; i < uGanttDrag.length; i++) {
+          // 鼠标按下
+          uGanttDrag[i].onmousedown = function (e) {
+            const offsetLeft = uGanttTaskItem[i].offsetLeft
+            const offsetWidth = uGanttTaskItem[i].offsetWidth
+            var startX = e.clientX;
+            var moveLen
+            // 向上取证获取当前是第几行
+            var ganttIndex = Math.trunc(uGanttTaskItem[i].offsetTop/34)
+            // 移动事件
+            document.onmousemove = function (e) {
+              var endX = e.clientX;
+              moveLen = offsetLeft + ( endX - startX )
+              // 设置当前甘特条距离左侧的距离(使得左侧移动,而宽度不变,右侧对应向右移,产生移动效果)
+              uGanttTaskItem[i].style.left = moveLen + 'px'
+              // 移动过程鼠标变成拖拽形状
+              uGanttDrag[i].style.cursor = 'move'
+              
+              // 监听位置进行滚动条滚动--尚未完成
+              var uGantt = _this.$refs.uGantt
+              const offsetRight = uGantt.offsetWidth - (uGanttTaskItem[i].offsetLeft + uGanttTaskItem[i].offsetWidth)
+              console.log(offsetRight)
+              if(offsetRight<0){
+                uGantt.scrollLeft = uGanttTaskItem[i].offsetWidth
+              }
+            }
+            document.onmouseup = function (evt) {
+              // 同样:不能停在一段的中间位置,所以计算使其整段整段的形式显示
+              uGanttTaskItem[i].style.left = Math.round(moveLen/70) * 70 + 'px';
+              // 获取最终左侧停在第几列
+              var startNum = (uGanttTaskItem[i].offsetLeft)/70
+              // 获取最终右侧停在第几列
+              var endNum = (offsetWidth / 70) + startNum
+              // 找到对应的时间强制赋值刷新
+              _this.$set(_this.ganttLists[ganttIndex], 'task_start', _this.uGanttColumns[startNum].name)
+              _this.$set(_this.ganttLists[ganttIndex], 'task_end', _this.uGanttColumns[endNum - 1].name)
+              // 鼠标变回手型
+              uGanttDrag[i].style.cursor = 'pointer'
+              // 释放
+              document.onmousemove = null;
+              document.onmouseup = null; 
+              document.releaseCapture && document.releaseCapture();
+            }
+            document.setCapture && document.setCapture();
+            return false;
+          }
+        }
+      },
+      // 改变大小
+      uGanttResizeL(){
+        var _this = this
+        var resize = this.$refs.uGanttResizeL;
+        var uGanttTaskItem = this.$refs.uGanttTaskItem;
+        for (let i = 0; i < resize.length; i++) {
+          resize[i].onmousedown = function (e) {
+            var startX = e.clientX;
+            var ganttIndex = Math.trunc(uGanttTaskItem[i].offsetTop/34)
+            const offsetLeft = uGanttTaskItem[i].offsetLeft;
+            const offsetWidth = uGanttTaskItem[i].offsetWidth
+            var moveLen
+            var ganttWidth
+            document.onmousemove = function (e) {
+              var endX = e.clientX;
+              moveLen = offsetLeft - (startX - endX);
+              ganttWidth = (startX - endX) + offsetWidth
+              if (ganttWidth < 70){
+                ganttWidth = 70
+                moveLen = offsetLeft + offsetWidth - 70
+              }
+              
+              uGanttTaskItem[i].style.left = moveLen + 'px';
+              uGanttTaskItem[i].style.width = ganttWidth + 'px';
+            }
+            document.onmouseup = function (evt) {
+              uGanttTaskItem[i].style.left = Math.round(moveLen/70) * 70 + 'px';
+              uGanttTaskItem[i].style.width = Math.round(ganttWidth/70) * 70 + 'px';
+              var num = (uGanttTaskItem[i].offsetLeft)/70
+              console.log(num)
+              // 普通赋值
+              // _this.ganttLists[0].task_end = _this.uGanttColumns[num - 1].name
+              // 强制赋值刷新
+              console.log(ganttIndex)
+              _this.$set(_this.ganttLists[ganttIndex], 'task_start', _this.uGanttColumns[num].name)
+              // 强制刷新
+              // _this.$forceUpdate()
+              document.onmousemove = null;
+              document.onmouseup = null; 
+              document.releaseCapture && document.releaseCapture();
+            }
+            document.setCapture && document.setCapture();
+            return false;
+          }
+        }
+      },
+      // 改变大小
+      uGanttResizeR(){
+        // 方法域(onmousedown等方法中有自己的this,所以在外面重新赋值this,让内部方法调用)
+        var _this = this
+        // 1.获取ref
+        var resize = this.$refs.uGanttResizeR;
+        var uGanttTaskItem = this.$refs.uGanttTaskItem;
+        // 2.循环监听获取当前点击的事件
+        // 上面设置onmousedown方法会出现第一次点击无法调用的问题,所以在mounted中写(不知道为什么有类似监听的效果)
+        // 因为ref有好几个,获取的数组,所以这里要循环
+        for (let i = 0; i < resize.length; i++) {
+          // 不可以设置var resize = resize[i] 下面统一使用resize的方式 =>这样会有问题
+          // 1.鼠标按下事件:
+          // 用[resize[i].],而不是全局document监听,这样才能监听到是哪儿一个甘特条触发了事件
+          resize[i].onmousedown = function (e) {
+            // 1.获取当前点击的甘特条是第几行的,也就是对应左侧项目组中的index
+            var ganttIndex = Math.trunc(uGanttTaskItem[i].offsetTop/34)
+            // 2.获取按下位置距离
+            var startX = e.clientX;
+            // 3.获取当前右侧拖拽区域距离父元素左侧距离(也就是右侧拖拽区域距离甘特图左边的距离:注意父子关系)
+            var offsetLeft = resize[i].offsetLeft;
+            // 转言之:上面那个就是当前甘特条的宽度--也就可以写作下面的方式
+            // var offsetLeft = uGanttTaskItem[i].offsetWidth;
+            // 4.定义拖拽参数--主要是为了onmouseup能调用
+            var moveLen
+            // 5.鼠标移动事件--注意:这里是document全局,这样就可以实现超出位置依旧可以控制拖拽
+            document.onmousemove = function (e) {
+              // 1.获取移动过程中实时位置
+              var endX = e.clientX;
+              // 2.设置当前甘特条的宽度:一开始甘特条的宽度 +(拖拽区域(鼠标点)末位置-初始位置)
+              moveLen = offsetLeft + (endX - startX);
+              // 3.判断如果小于1格,就不再减少
+              if (moveLen < 70) moveLen = 70; 
+              // 这一步好像是没啥用啊?
+              // resize[i].style.left = moveLen;
+              // 设置甘特条随move变化:即实时宽度也为moveLen即可
+              uGanttTaskItem[i].style.width = moveLen + 'px';
+            }
+            // 鼠标抬起事件
+            document.onmouseup = function (evt) {
+              // 1.因为时间一段一段的,设置少于35(70的一半)最终结果向左靠,反之向右靠
+              uGanttTaskItem[i].style.width = Math.round(moveLen/70) * 70 + 'px';
+              // 2.获取当前甘特条最后位置在第几列--用于赋值
+              var num = (uGanttTaskItem[i].offsetLeft + uGanttTaskItem[i].offsetWidth)/70
+              // 普通赋值
+              // _this.ganttLists[0].task_end = _this.uGanttColumns[num - 1].name
+              // 3.强制赋值刷新--获取列对应的时间,赋值给左侧的第ganttIndex个项目的task_end
+              _this.$set(_this.ganttLists[ganttIndex], 'task_end', _this.uGanttColumns[num - 1].name)
+              // 强制刷新
+              // _this.$forceUpdate()
+              // 4.释放鼠标事件
+              document.onmousemove = null;
+              document.onmouseup = null; 
+              // 5.从当前线程中的窗口释放鼠标捕获,并恢复通常的鼠标输入处理
+              document.releaseCapture && document.releaseCapture();
+            }
+            // 当前线程的给定窗口设置鼠标捕获
+            document.setCapture && document.setCapture();
+            return false;
+          }
+        }
+      },
+      tableCellClassName({ row, column, rowIndex, columnIndex }){
+        //把每一行的索引放进row--可以用于获取index
+        // row.index = rowIndex;
+        return 'u-table-cell'
+      },
+      // 展开隐藏事件
+      expandChange(row, isExpend){
+        console.log(row, isExpend)
+        if(isExpend){
+          // 展开
+          // this.ganttLists.map((res, index) => {
+          //   console.log(res)
+          //   if(res.parentId === row.id){
+          //     res.show = 'flex'
+          //   }
+          //   return res
+          // })
+          var index = this.ganttLists.findIndex(res=>res.id === row.id)
+          this.ganttLists.splice(index+1, 0, ...row.children)
+
+          this.$forceUpdate()
+
+        } else {
+          // 隐藏
+          // this.ganttLists.map((res, index) => {
+          //   console.log(res)
+          //   if(res.parentId === row.id){
+          //     res.show = 'none'
+          //   }
+          //   return res
+          // })
+          this.ganttLists = this.ganttLists.filter(res=>res.parentId !== row.id)
+          this.$forceUpdate()
+        }
+      },
+      // 双击事件
+      rowDblclick(row, column, event){
+        // console.log(row, column, event)
+        // 深拷贝:直接赋值会有还没点确定,甘特图部分就已经改变的bug
+        // this.currentDbEdit = JSON.parse(JSON.stringify(row))
+        this.$emit('dbclick', JSON.parse(JSON.stringify(row)))
+      },
+    }
+  }
+</script>
+
+<style lang="scss">
+.u-flex{
+  display: flex;
+}
+.u-gantt-container{
+  // width: calc(100vw - 240px);
+  .el-table{
+    user-select: none;
+    // width: auto;
+    .u-table-cell{
+      padding: 0 !important;
+      height: 34px !important;
+      line-height: 34px !important;
+      box-sizing: border-box !important;
+    }
+    .el-table--enable-row-transition .el-table__body td.el-table__cell{
+      padding: 0 !important;
+    }
+    
+  }
+  .u-gantt{
+    // width: calc(100% - 371px);
+    flex: 1;
+    border-top: 1px solid #ebebeb;
+    border-left: 1px solid #ebebeb;
+    overflow: auto;
+  }
+  .u-gantt-title{
+    .item-title{
+      width: 70px;
+      height: 34px;
+      line-height: 34px;
+      text-align: center;
+      border-right: 1px solid #ebebeb;
+      border-bottom: 1px solid #ebebeb;
+      font-size: 12px;
+      color: #787878;
+      flex-shrink: 0; // 设置宽度不够时,元素不压缩而是超出滚动
+    }
+  }
+  .u-gantt-content{
+    position: relative;
+    // 底层表格线框
+    .u-gantt-bg{
+      // position: absolute;
+      .item-tr{
+        height: 34px;
+      }
+      .item-td{
+        width: 70px;
+        height: 34px;
+        border-right: 1px solid #ebebeb;
+        border-bottom: 1px solid #ebebeb;
+        flex-shrink: 0; // 设置宽度不够时,元素不压缩而是超出滚动
+      }
+    }
+    // 项目甘特条
+    .u-gantt-task{
+      // position: absolute;
+      // top: 0;
+      // left: 0;
+      // right: 0;
+      // bottom: 0;
+      // background-color: #b72222;
+      .u-gantt-task-content{
+        position: absolute;
+        top: 36px;
+        left: 140px;
+        width: 140px;
+        height: 30px;
+        line-height: 30px;
+        background-color: #44c2e5;
+        border-radius: 2px;
+        .u-gantt-task-drag{
+          position: absolute;
+          top: 0;
+          left: 1px;
+          right: 1px;
+          bottom: 0;
+          cursor: pointer;
+        }
+        .u-gantt-task-resize{
+          position: absolute;
+          width: 8px;
+          height: 30px;
+          top: 0;
+          cursor: w-resize;
+        }
+        .resize-left{
+          left: -7px;
+        }
+        .u-gantt-task-text{
+          color: #fff;
+          text-align: center;
+          
+        }
+        .resize-right{
+          right: -7px;
+        }
+      }
+    }
+  }
+}
+</style>

+ 164 - 443
itdmWeb/src/views/module-iTDM/itdmGongdanMaster/uGantt.vue

@@ -1,458 +1,179 @@
 <template>
-  <div class="app-container">
-    
-    <div class="u-gantt-container u-flex">
-      <el-table
-        :data="taskLists" 
-        stripe border
-        :cell-class-name="tableCellClassName"
-        :header-cell-class-name="tableCellClassName"
-        @row-dblclick="rowDblclick">
-        <template v-for="(item, index) in configColumns">
-          <el-table-column
-            :prop="item.name"
-            :label="item.label"
-            :fixed="item.fixed"
-            :width="item.width"
-            :align="item.align"
-            :key="index"
-            show-overflow-tooltip
-          ></el-table-column>
-        </template>
-      </el-table>
-      <div class="u-gantt">
-        <div class="u-gantt-title u-flex" >
-          <div v-for="(item, index) in uGanttColumns" :key="index" class="item-title">{{ item.label}}</div>
+  <div>
+    <uGantt :configColumns="configColumns" :taskLists="taskLists" ref="uGantt" @dbclick="rowDblclick">
+      <!-- 其他需要自定义的弹窗数据 -->
+      <!-- 双击事件弹窗 -->
+      <el-dialog title="修改" :visible.sync="dialogVisible" width="40%">
+        <div>
+          <!-- 参数设定是固定格式,千万别改 -->
+          开始:<el-date-picker v-model="currentDbEdit.task_start" type="date" value-format="yyyy-MM-dd" placeholder="选择日期"></el-date-picker>
         </div>
-        <div class="u-gantt-content">
-          <div class="u-gantt-bg">
-            <div v-for="(item, tr) in taskLists" :key="tr" class="item-tr u-flex">
-              <div class="item-td" v-for="(item, td) in uGanttColumns" :key="td"></div>
-            </div>
-          </div>
-          <div class="u-gantt-task">
-
-              <div class="u-gantt-task-content uGanttTaskItem" ref="uGanttTaskItem" v-for="(item, index) in taskLists" :key="index" :style="setStyle(item)">
-                <!-- <span class="resize" ref="`resize${index}}`" @mousedown="dragControllerDiv(index)"></span> -->
-                <div class="u-gantt-task-drag" ref="uGanttDrag"></div>
-                <div class="u-gantt-task-resize resize-left" ref="uGanttResizeL"></div>
-                <div class="u-gantt-task-text">{{ item.content }}</div>
-                <div class="u-gantt-task-resize resize-right" ref="uGanttResizeR"></div>
-              </div>
-            
-          </div>
+        <div>
+          结束:<el-date-picker v-model="currentDbEdit.task_end" type="date" value-format="yyyy-MM-dd" placeholder="选择日期"></el-date-picker>
         </div>
-      </div>
-    </div>
-
-    <!-- 双击事件弹窗 -->
-    <el-dialog title="修改" :visible.sync="dialogVisible" width="40%">
-      <div>
-        开始:<el-date-picker v-model="currentDbEdit.task_start" type="date" value-format="yyyy-MM-dd" placeholder="选择日期"></el-date-picker>
-      </div>
-      <div>
-        结束:<el-date-picker v-model="currentDbEdit.task_end" type="date" value-format="yyyy-MM-dd" placeholder="选择日期"></el-date-picker>
-      </div>
-      <!-- 其他需要自定义的弹窗数据 -->
-      <slot/>
-      <span slot="footer" class="dialog-footer">
-        <el-button @click="cancel">取 消</el-button>
-        <el-button type="primary" @click="submit">确 定</el-button>
-      </span>
-    </el-dialog>
-
-
-
+        <!-- 其他需要自定义的弹窗数据 -->
+        <slot/>
+        <span slot="footer" class="dialog-footer">
+          <el-button @click="cancel">取 消</el-button>
+          <el-button type="primary" @click="submit">确 定</el-button>
+        </span>
+      </el-dialog>
+    </uGantt>
   </div>
 </template>
 
 <script>
-  export default {
-    data(){
-      return {
-        configColumns: [
-          { name: "testItems", label: "检测项目", width: 80, fixed: true, resize: true, align: "center",resize: true, tree: true },
-          { name: "sampleName", label: "样品名称", width: 90, fixed: true, resize: true, align: "center" },
-          { name: "task_start", label: "开始时间", width: 100, fixed: true, resize: true, align: "center" },
-          { name: "task_end", label: "结束时间", width: 100, fixed: true, resize: true, align: "center" },
-        ],
-        taskLists: [{
-            id: 0,
-            testItems: 'ceshi',
-            sampleName: 'ceshi',
-            task_start: '2023-07-03',
-            task_end: '2023-07-04',
-            statusC: '0',
-            content: '111'
-          }, {
-            id: 1,
-            testItems: '测试',
-            sampleName: '测试',
-            task_start: '',
-            task_end: '',
-            statusC: '0',
-          }, {
-            id: 2,
-            testItems: 'ceshi',
-            sampleName: 'ceshi',
-            task_start: '2023-07-06',
-            task_end: '2023-07-10',
-            statusC: '1',
-          }, {
-            id: 3,
-            testItems: '测试',
-            sampleName: '测试',
-            task_start: '',
-            task_end: '',
-            statusC: '1',
-          },{
-            id: 4,
-            testItems: '测试',
-            sampleName: '测试',
-            task_start: '',
-            task_end: '',
-            statusC: '1',
-          },
-          {
-            id: 5,
-            testItems: '测试',
-            sampleName: '测试',
-            task_start: '',
-            task_end: '',
-            statusC: '1',
-          },
-          {
-            id: 6,
-            testItems: '测试',
-            sampleName: '测试',
-            task_start: '',
-            task_end: '',
-            statusC: '1',
-          },
-          {
-            id: 7,
-            testItems: '测试',
-            sampleName: '测试',
-            task_start: '',
-            task_end: '',
-            statusC: '1',
-          },
-          {
-            id: 8,
-            testItems: '测试',
-            sampleName: '测试',
-            task_start: '',
-            task_end: '',
-            statusC: '1',
-          },],
-
-        // 当前双击的数据
-        currentDbEdit: {},
-        dialogVisible: false,
-      }
-    },
-    computed: {
-      // 甘特图标题日期分配
-      uGanttColumns() {
-        // 获取标准时间
-        var nowdays = new Date()
-        // 获取当年
-        var currentYear = new Date().getFullYear()
-        // 获取当月
-        var currentMonth = new Date().getMonth() + 1
-        // 获取当天
-        var nowDay = new Date().getDate()
-        // 获取当前月有多少天
-        var currentMonthNum = new Date(currentYear, currentMonth, 0).getDate()
-        console.log(nowDay, currentMonth, currentMonthNum)
-        // 
-        // let now = new Date(nowDay)
-        // console.log(nowdays, now)
-        // 当前月份所有日期集合
-        let currentMonthArr = []
-        for (let i = 1; i <= currentMonthNum; i++) {
-          // let day = nowdays.setDate(i);
-          // console.log(day)
-          // 年月日(yyyy-MM-dd)
-          let dateLabel = (currentMonth < 10 ? '0' + currentMonth : currentMonth) + "月" + (i < 10 ? '0' + i : i) + "日";
-          let dateName = currentYear + "-" + (currentMonth < 10 ? '0' + currentMonth : currentMonth) + "-" + (i < 10 ? '0' + i : i);
-          // let day = 
-          currentMonthArr.push({label: dateLabel, name: dateName});
+import uGantt from './components/uGantt.vue'
+export default {
+  name: '',
+  components: { uGantt },
+  data () {
+    return {
+      // width:每列宽度--现在逻辑全部默认显示左边table,右边滚动
+      // fixed:现在没有,如果需要一部分固定,一部分滚动,则需要重新设置一下组件
+      // resize:暂时没用
+      // align:每列文字显示
+      // tree:暂时没用
+      // 注意:task_start(开始日期)和task_end(结束日期)和add(添加按钮)是固定死的参数名,不能更改
+      configColumns: [
+        { name: "testItems", label: "检测项目", width: 100, fixed: true, resize: true, align: "center", tree: true },
+        { name: "sampleName", label: "样品名称", width: 90, fixed: true, resize: true, align: "center" },
+        { name: "task_start", label: "开始时间", width: 100, fixed: true, resize: true, align: "center" },
+        { name: "task_end", label: "结束时间", width: 100, fixed: true, resize: true, align: "center" },
+        // { name: "statusC", label: "状态", width: 60, fixed: true, resize: true, align: "center" },
+        // { name: "add", label:"", width: 30 }
+      ],
+      // 注意:task_start(开始日期)和task_end(结束日期)和add(添加按钮)是固定死的参数名,不能更改
+      // id、content: 也是固定死的,如果需要可以改组件
+      taskLists: [{
+          id: 0,
+          testItems: 'ceshi',
+          sampleName: 'ceshi',
+          task_start: '2023-07-03',
+          task_end: '2023-07-04',
+          statusC: '0',
+          content: '111'
+        }, {
+          id: 1,
+          testItems: '测试',
+          sampleName: '测试',
+          task_start: '',
+          task_end: '',
+          statusC: '0',
+        }, {
+          id: 2,
+          testItems: 'ceshi',
+          sampleName: 'ceshi',
+          task_start: '2023-07-06',
+          task_end: '2023-07-10',
+          statusC: '1',
+        }, {
+          id: 3,
+          testItems: '测试',
+          sampleName: '测试',
+          task_start: '',
+          task_end: '',
+          statusC: '1',
+        },{
+          id: 4,
+          testItems: '测试',
+          sampleName: '测试',
+          task_start: '',
+          task_end: '',
+          statusC: '1',
+        },
+        {
+          id: 5,
+          testItems: '测试',
+          sampleName: '测试',
+          task_start: '',
+          task_end: '',
+          statusC: '1',
+        },
+        {
+          id: 6,
+          testItems: '测试',
+          sampleName: '测试',
+          task_start: '',
+          task_end: '',
+          statusC: '1',
+        },
+        {
+          id: 7,
+          testItems: '测试',
+          sampleName: '测试',
+          task_start: '',
+          task_end: '',
+          statusC: '1',
+        },
+        {
+          id: 8,
+          testItems: '测试',
+          sampleName: '测试',
+          task_start: '',
+          task_end: '',
+          statusC: '1',
+        },
+        {
+          id: 21,
+          testItems: 'ceshi1',
+          sampleName: 'ceshi',
+          task_start: '2023-07-05',
+          task_end: '2023-07-08',
+          statusC: '1',
+          parentId: 2
+        }, {
+          id: 23,
+          testItems: 'ceshi3',
+          sampleName: 'ceshi',
+          task_start: '2023-07-02',
+          task_end: '2023-07-04',
+          statusC: '1',
+          parentId: 2
+        },
+        {
+          id: 22,
+          testItems: 'ceshi2',
+          sampleName: 'ceshi',
+          task_start: '2023-07-06',
+          task_end: '2023-07-10',
+          statusC: '1',
+          parentId: 2
         }
-        console.log(currentMonthArr)
-        return currentMonthArr
-      },
-      
+      ],
+      // 弹窗
+      dialogVisible: false,
+      // 弹窗内容
+      currentDbEdit: {},
+      // 数组中的第几个
+      currentIndex: null
+    }
+  },
+  created () {
+  },
+  mounted () {
+  },
+  methods: {
+    // 双击事件
+    rowDblclick(current){
+      console.log(current)
+      this.currentIndex = this.taskLists.findIndex(res=>res.id === current.id)
+      this.currentDbEdit = this.taskLists[this.currentIndex]
+      this.dialogVisible = true
     },
-    mounted () {
-      this.uGanttDrag()
-      this.uGanttResizeL()
-      this.uGanttResizeR()
+    cancel(){
+      this.currentDbEdit = {}
+      this.dialogVisible = false
     },
-    methods: {
-      setStyle(item){
-        var startIndex = this.uGanttColumns.findIndex(res => res.name === item.task_start)
-        var endIndex = this.uGanttColumns.findIndex(res => res.name === item.task_end)
-        var trIndex = this.taskLists.findIndex(res => res.id === item.id)
-        // console.log(trIndex, this.taskLists)
-        var style = {
-          left: 70 * startIndex + 'px',
-          width: 70 * (endIndex - startIndex + 1) + 'px',
-          top: (34 * trIndex + 2) + 'px'
-        }
-        return style
-      },
-      // 位移事件
-      uGanttDrag(){
-        var _this = this
-        var uGanttDrag = this.$refs.uGanttDrag;
-        var uGanttTaskItem = this.$refs.uGanttTaskItem;
-        for (let i = 0; i < uGanttDrag.length; i++) {
-          uGanttDrag[i].onmousedown = function (e) {
-            const offsetLeft = uGanttTaskItem[i].offsetLeft
-            const offsetWidth = uGanttTaskItem[i].offsetWidth
-            var startX = e.clientX;
-            var moveLen
-            var ganttIndex = Math.trunc(uGanttTaskItem[i].offsetTop/34)
-            document.onmousemove = function (e) {
-              var endX = e.clientX;
-              moveLen = offsetLeft + ( endX - startX )
-              uGanttTaskItem[i].style.left = moveLen + 'px'
-              uGanttDrag[i].style.cursor = 'move'
-              
-            }
-            document.onmouseup = function (evt) {
-              uGanttTaskItem[i].style.left = Math.round(moveLen/70) * 70 + 'px';
-              var startNum = (uGanttTaskItem[i].offsetLeft)/70
-              var endNum = (offsetWidth / 70) + startNum
-              // // 普通赋值
-              // // _this.taskLists[0].task_end = _this.uGanttColumns[num - 1].name
-              // // 强制赋值刷新
-              console.log(ganttIndex)
-              _this.$set(_this.taskLists[ganttIndex], 'task_start', _this.uGanttColumns[startNum].name)
-              _this.$set(_this.taskLists[ganttIndex], 'task_end', _this.uGanttColumns[endNum - 1].name)
-              uGanttDrag[i].style.cursor = 'pointer'
-              // // 强制刷新
-              // // _this.$forceUpdate()
-              document.onmousemove = null;
-              document.onmouseup = null; 
-              document.releaseCapture && document.releaseCapture();
-            }
-            document.setCapture && document.setCapture();
-            return false;
-          }
-        }
-      },
-      // 改变大小
-      uGanttResizeL(){
-        var _this = this
-        var resize = this.$refs.uGanttResizeL;
-        var uGanttTaskItem = this.$refs.uGanttTaskItem;
-        for (let i = 0; i < resize.length; i++) {
-          resize[i].onmousedown = function (e) {
-            var startX = e.clientX;
-            var ganttIndex = Math.trunc(uGanttTaskItem[i].offsetTop/34)
-            const offsetLeft = uGanttTaskItem[i].offsetLeft;
-            const offsetWidth = uGanttTaskItem[i].offsetWidth
-            var moveLen
-            var ganttWidth
-            document.onmousemove = function (e) {
-              var endX = e.clientX;
-              moveLen = offsetLeft - (startX - endX);
-              ganttWidth = (startX - endX) + offsetWidth
-              if (ganttWidth < 70){
-                ganttWidth = 70
-                moveLen = offsetLeft + offsetWidth - 70
-              }
-              
-              uGanttTaskItem[i].style.left = moveLen + 'px';
-              uGanttTaskItem[i].style.width = ganttWidth + 'px';
-            }
-            document.onmouseup = function (evt) {
-              uGanttTaskItem[i].style.left = Math.round(moveLen/70) * 70 + 'px';
-              uGanttTaskItem[i].style.width = Math.round(ganttWidth/70) * 70 + 'px';
-              var num = (uGanttTaskItem[i].offsetLeft)/70
-              console.log(num)
-              // 普通赋值
-              // _this.taskLists[0].task_end = _this.uGanttColumns[num - 1].name
-              // 强制赋值刷新
-              console.log(ganttIndex)
-              _this.$set(_this.taskLists[ganttIndex], 'task_start', _this.uGanttColumns[num].name)
-              // 强制刷新
-              // _this.$forceUpdate()
-              document.onmousemove = null;
-              document.onmouseup = null; 
-              document.releaseCapture && document.releaseCapture();
-            }
-            document.setCapture && document.setCapture();
-            return false;
-          }
-        }
-      },
-      // 改变大小
-      uGanttResizeR(){
-        var _this = this
-        var resize = this.$refs.uGanttResizeR;
-        var uGanttTaskItem = this.$refs.uGanttTaskItem;
-        // var ganttIndex = this.taskLists.findIndex(res=>res.id === 0)
-        for (let i = 0; i < resize.length; i++) {
-          resize[i].onmousedown = function (e) {
-            var ganttIndex = Math.trunc(uGanttTaskItem[i].offsetTop/34)
-            var startX = e.clientX;
-            resize[i].left = resize[i].offsetLeft;
-            var moveLen
-            document.onmousemove = function (e) {
-              var endX = e.clientX;
-              moveLen = resize[i].left + (endX - startX);
-              if (moveLen < 70) moveLen = 70; 
-    
-              resize[i].style.left = moveLen;
-              
-              uGanttTaskItem[i].style.width = moveLen + 'px';
-            }
-            document.onmouseup = function (evt) {
-              uGanttTaskItem[i].style.width = Math.round(moveLen/70) * 70 + 'px';
-              var num = (uGanttTaskItem[i].offsetLeft + uGanttTaskItem[i].offsetWidth)/70
-              // 普通赋值
-              // _this.taskLists[0].task_end = _this.uGanttColumns[num - 1].name
-              // 强制赋值刷新
-              _this.$set(_this.taskLists[ganttIndex], 'task_end', _this.uGanttColumns[num - 1].name)
-              // 强制刷新
-              // _this.$forceUpdate()
-              document.onmousemove = null;
-              document.onmouseup = null; 
-              document.releaseCapture && document.releaseCapture();
-            }
-            document.setCapture && document.setCapture();
-            return false;
-          }
-        }
-      },
-      tableCellClassName({ row, column, rowIndex, columnIndex }){
-        //把每一行的索引放进row--可以用于获取index
-        // row.index = rowIndex;
-        return 'u-table-cell'
-      },
-      // 双击事件
-      rowDblclick(row, column, event){
-        console.log(row, column, event)
-        // 深拷贝:直接赋值会有还没点确定,甘特图部分就已经改变的bug
-        this.currentDbEdit = JSON.parse(JSON.stringify(row))
-        this.dialogVisible = true
-      },
-      cancel(){
-        this.currentDbEdit = {}
-        this.dialogVisible = false
-      },
-      submit(){
-        var taskIndex = this.taskLists.findIndex(res=>res.id === this.currentDbEdit.id)
-        this.taskLists[taskIndex].task_start = this.currentDbEdit.task_start
-        this.taskLists[taskIndex].task_end = this.currentDbEdit.task_end
-        this.dialogVisible = false
-        this.currentDbEdit = {}
-      }
+    submit(){
+      this.taskLists[this.currentIndex].task_start = this.currentDbEdit.task_start
+      this.taskLists[this.currentIndex].task_end = this.currentDbEdit.task_end
+      this.dialogVisible = false
+      this.currentDbEdit = {}
     }
   }
+}
 </script>
 
-<style lang="scss">
-.u-flex{
-  display: flex;
-}
-.u-gantt-container{
-  // width: calc(100vw - 240px);
-  .el-table{
-    .u-table-cell{
-      padding: 0 !important;
-      height: 34px !important;
-      line-height: 34px !important;
-      box-sizing: border-box !important;
-    }
-    .el-table--enable-row-transition .el-table__body td.el-table__cell{
-      padding: 0 !important;
-    }
-    
-  }
-  .u-gantt{
-    width: calc(100% - 371px);
-    border-top: 1px solid #ebebeb;
-    border-left: 1px solid #ebebeb;
-    overflow: auto;
-  }
-  .u-gantt-title{
-    .item-title{
-      width: 70px;
-      height: 34px;
-      line-height: 34px;
-      text-align: center;
-      border-right: 1px solid #ebebeb;
-      border-bottom: 1px solid #ebebeb;
-      font-size: 12px;
-      color: #787878;
-      flex-shrink: 0; // 设置宽度不够时,元素不压缩而是超出滚动
-    }
-  }
-  .u-gantt-content{
-    position: relative;
-    // 底层表格线框
-    .u-gantt-bg{
-      // position: absolute;
-      .item-tr{
-        height: 34px;
-      }
-      .item-td{
-        width: 70px;
-        height: 34px;
-        border-right: 1px solid #ebebeb;
-        border-bottom: 1px solid #ebebeb;
-        flex-shrink: 0; // 设置宽度不够时,元素不压缩而是超出滚动
-      }
-    }
-    // 项目甘特条
-    .u-gantt-task{
-      // position: absolute;
-      // top: 0;
-      // left: 0;
-      // right: 0;
-      // bottom: 0;
-      // background-color: #b72222;
-      .u-gantt-task-content{
-        position: absolute;
-        top: 36px;
-        left: 140px;
-        width: 140px;
-        height: 30px;
-        line-height: 30px;
-        background-color: #44c2e5;
-        border-radius: 2px;
-        .u-gantt-task-drag{
-          position: absolute;
-          top: 0;
-          left: 1px;
-          right: 1px;
-          bottom: 0;
-          cursor: pointer;
-        }
-        .u-gantt-task-resize{
-          position: absolute;
-          width: 8px;
-          height: 30px;
-          top: 0;
-          cursor: w-resize;
-        }
-        .resize-left{
-          left: -7px;
-        }
-        .u-gantt-task-text{
-          color: #fff;
-          text-align: center;
-          
-        }
-        .resize-right{
-          right: -7px;
-        }
-      }
-    }
-  }
-}
+<style lang="scss" scoped>
 </style>