2023-03-15

2023-03-14  本文已影响0人  大佬教我写程序
<template>
  <div class="gantt" v-loading="loading" ref="ganttRoot">
    <div id="wrapper" class="gantt-content" @click="hiddenBlockMenu($event)" @mouseup="ganttMainUp($event)">
      <!-- @mouseleave="ganttMainLeave($event)" -->
      <!-- @mousemove="ganttMainMove($event)" -->
      <!-- @mousedown="ganttMainDown($event)" -->
      <!-- @scroll="wrapperScroll($event)" -->
      <div class="gantt-block">
        <div></div>
        <div>资源</div>
      </div>
      <div class="gantt-calendar">
        <div class="calendar-dom">
          <div
            class="calendar-li"
            v-for="(item, index) in timeList"
            :key="index"
            :style="{ width: parseInt(setWidth * ganttRate) + 'px' }"
          >
            <div class="calendar-day" :style="{ color: item.color }">{{ item.time }}</div>
            <div class="calendar-time">
              <div class="calendar-h" v-for="(item, index) in hourList" :key="index">
                <template v-if="ganttRate > 0.192">
                  {{ item }}
                </template>
                <template v-else-if="ganttRate == 0.192">
                  {{ parseInt(item) % 4 == 0 ? item : '' }}
                </template>
              </div>
            </div>
            <div class="gantt-time"></div>
          </div>
          <div
            class="gantt-dom-range"
            v-show="ganttDomRange.width > 0"
            :style="{
              width: ganttDomRange.width + 'px',
              left: ganttDomRange.left + 'px'
            }"
          ></div>
          <div
            class="gantt-dom-move"
            v-show="ganttDomMove.width > 0"
            :style="{
              width: ganttDomMove.width + 'px',
              left: ganttDomMove.left + 'px',
              backgroundColor: ganttDomMove.color
            }"
          ></div>
        </div>
      </div>
      <div class="gantt-aside">
        <div class="aside-list">
          <div
            class="aside-li"
            v-for="(item, index) in asideList"
            :key="index"
            :processId="item.resourceId"
            @drop="ganttRowDrop($event)"
            @dragover="allowDrop($event)"
            :class="{
              mainType: item.mainType == 'MAIN',
              adjustOptional: adjustOptional.indexOf(item.resourceId) > -1
            }"
          >
            <span>{{ item.resourceCode }}</span>
          </div>
        </div>
      </div>
      <div
        class="gantt-main"
        :style="{
          width: setWidth * timeList.length * ganttRate + 100 + 'px',
          height: asideList.length * 31 + 60 + 'px'
        }"
        @dragend="mainDragEnd"
        @mousedown="maindDown($event)"
        @mousemove="maindMove($event)"
        @mouseleave="maindLeave($event)"
        @mouseup="maindUp"
      >
        <div class="nodata" v-if="asideList.length == 0">暂无数据!</div>
        <div class="gantt-col-bg">
          <div
            class="gantt-col-ul"
            :class="{ 'gantt-col-ol': ganttLi == 0 }"
            v-for="(item, index) in ganttCol"
            :key="index"
            :style="{ width: parseInt(setWidth * ganttRate) + 'px' }"
          >
            <div
              class="gantt-col-li"
              :style="{ width: (1 / ganttLi) * 100 + '%' }"
              v-for="(item, index) in ganttLi"
              :key="index"
            ></div>
          </div>
        </div>
        <div
          class="gantt-row"
          v-for="(item, index) in ganttRowData"
          :key="index"
          :processId="item.resourceId"
          @drop="ganttRowDrop($event)"
          @dragover="allowDrop($event)"
          @mouseup="ganttRowUp($event)"
          :class="{ adjustOptional: adjustOptional.indexOf(item.resourceId) > -1 }"
        >
          <template v-if="item.restData">
            <template v-for="info in item.restData.blocks">
              <div
                v-if="info.startTime != info.endTime"
                class="rest-dom"
                :key="info.index"
                :style="{
                  left: ganttDomLeft(info.startTime) + 'px',
                  width: ganttDomWidth(info.startTime, info.endTime) + 'px'
                }"
              ></div>
            </template>
          </template>
          <template v-if="item.ganttData">
            <template v-for="info in item.ganttData.blocks">
              <div
                v-if="info.startTime != info.endTime"
                class="gantt-dom"
                :id="item.ganttData.processId + '&' + info.blockId"
                :key="info.blockId"
                :blockId="info.blockId"
                :top="index * 31 + 5"
                :style="{
                  left: ganttDomLeft(info.startTime) + 'px',
                  width: ganttDomWidth(info.startTime, info.endTime) + 'px',
                  height:
                    info.properties.multipleCount == 1
                      ? 13 + 'px'
                      : 31 / info.properties.multipleCount - info.properties.multipleCount * 3 + 'px',
                  top:
                    (31 / info.properties.multipleCount - info.properties.multipleCount * 3 + 3) *
                      info.properties.multipleSort +
                    3 +
                    'px',
                  backgroundColor: info.properties.status =='PLANNED' && info.properties.lockStatus == 'LOCKED' ? '#e5994b' : info.blockColor,
                  borderColor: info.borderColor
                }"
                :class="{ 'gantt-dom-act': actblockId.includes(item.ganttData.processId + '&' + info.blockId) }"
                :title="ganttDetails(info)"
                draggable="true"
                @dragstart="ganttDragStart($event, item, info)"
                @drag="getGanttMove($event)"
                @contextmenu.stop="blocksContextmenu($event, info, item.ganttData.processId + '&' + info.blockId)"
                @click="getGanttDom($event, item.ganttData.processId + '&' + info.blockId)"
              >
                {{ info.blockName }}
                <div
                  v-for="(sub, subindex) in info.properties.subBlocks"
                  :key="subindex"
                  style="position: absolute; height: 100%; top: 0px"
                  :style="{
                    width: ganttDomWidth(sub.startTime, sub.endTime) + 'px',
                    left: ganttDomLeft(sub.startTime) - ganttDomLeft(info.startTime) + 'px',
                    backgroundColor: sub.subBlockColor
                  }"
                ></div>
                <div v-if="info.properties.alarm" class="trangle"></div>
              </div>
            </template>
          </template>
        </div>
        <div
          v-if="planStartDate < baseDate && baseDate < planStartDate + 24 * 3600 * 1000 * afterDays"
          class="base-time"
          :style="{ left: ganttDomLeft(baseDate) + 100 + 'px' }"
        ></div>
        <div v-show="isShowBlockMenu" class="block-menu">
          <div @click="blockMenu('选中工序')">选中工序</div>
          <div @click="blockMenu('强调')">强调</div>
          <div @click="blockMenu('取消强调')">取消强调</div>
          <div @click="blockMenu('冻结')">冻结</div>
          <div @click="blockMenu('解锁')">解锁</div>
          <div class="gotoNewDom">
            跳转至页面
            <div class="gotoNew" @click="blockMenu('制造订单展开')">制造订单展开</div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import {
  getScheduleperiod,
  getResource,
  getGanttInfo,
  getCodeToMain,
  getRest,
  getGanttline,
  handworkschedule
} from '@/api/planSchedule/gantt';
import { lockOperation, unlockOperation } from '@/api/planSchedule/productPeriod';
// import { restData, ganttData } from './ganttData';
import moment from 'moment'; // moment(text).format('YYYY-MM-DD HH:mm:ss')
import bus from '@/utils/bus';

export default {
  name: 'gantt',
  data() {
    return {
      loading: false,
      setWidth: 720,
      domWidth: 0,
      timeRange: 0,
      ganttRate: 0.456,
      ganttCol: 8,
      ganttLi: 8,
      preDays: 0,
      afterDays: 7,
      planStartDate: null,
      startDate: null,
      endDate: null,
      baseDate: null,
      onlyHasTasks: false,
      onlyMain: false,
      resourceCodeForGantt: '',
      dates: [],
      hourList: ['02', '04', '06', '08', '10', '12', '14', '16', '18', '20', '22'],
      asideList: [],
      asideListCopy: [],
      timeList: [],
      restData: [],
      ganttData: [],
      ganttRowData: [],
      isShowBlockMenu: null,
      moveStartX: 0,
      moveStartY: 0,
      queryStartDate: null,
      queryEndDate: null,
      resourceIds: '',
      actblockId: '',
      adjustOptional: '',
      subProcess: {},
      ganttDomRange: {},
      ganttDomMove: {},
      isGanttDomMove: true,
      isSelect: false,
      selectBox: null,
      downX: 0,
      downY: 0,
      moveX: 0,
      moveY: 0,
      ganttTop: 0
    };
  },
  props: {
    draggleType: String,
    lineType: String,
    searchInfo: {
      type: Object,
      default: () => {
        return {};
      }
    }
  },
  mounted() {
    // this.getScheduleperiod();
    bus.$on('adjustOptional', e => {
      console.log('onbus----->', e);
      this.ganttMainEnter(e);
    });
    this.ganttTop = document.querySelector('.yhl-table-productPeriod').offsetHeight + 183
  },
  beforeDestroy() {
    bus.$off('adjustOptional');
  },
  watch: {
    draggleType() {
      if (this.draggleType === 'all') {
        this.$emit('resetAllData');
        this.blockMenu('取消强调');
      }
    },
    lineType() {
      this.blockMenu('取消强调');
    }
  },
  methods: {
    initGanttData(e) {
      this.baseDate = e.baseDate;
      // this.lockEndDate = e.lockEndDate;
      let startDate = moment(e.planStartDate).format('YYYY-MM-DD');
      this.queryStartDate = startDate;
      this.planStartDate = new Date(startDate + ' 00:00:00').getTime();
      this.queryEndDate = moment(e.planStartDate + 24 * 3600 * 1000 * this.afterDays).format('YYYY-MM-DD');
      this.getResource();
      this.unstress();
    },
    setSubProcess(e) {
      // 工序表格子数据点击,强调甘特图
      let obj = { queryDate: e.processStart };
      this.subProcess = e;
      this.queryGanttDate(obj);
    },
    getScheduleperiod() {
      getScheduleperiod()
        .then(res => {
          if (res.data.success) {
            const { baseDate, endDate, lockEndDate, planStartDate } = res.data.data;
            // this.endDate = endDate
            this.baseDate = baseDate;
            this.lockEndDate = lockEndDate;
            this.planStartDate = planStartDate;
            this.queryStartDate = moment(this.planStartDate).format('YYYY-MM-DD');
            this.queryEndDate = moment(this.planStartDate + 24 * 3600 * 1000 * this.afterDays).format('YYYY-MM-DD');
            this.getResource();
          }
        })
        .catch(err => {
          console.log(err);
        });
    },
    queryGanttDate(e) {
      this.queryStartDate = e.queryDate;
      this.onlyMain = e.onlyMain;
      this.onlyHasTasks = e.onlyHasTasks;
      this.resourceCodeForGantt = e.resourceCodeForGantt;
      let time = new Date(e.queryDate + ' 00:00:00').getTime();
      this.planStartDate = time;
      this.queryEndDate = moment(time + 24 * 3600 * 1000 * this.afterDays).format('YYYY-MM-DD');
      this.unstress();
      if (e.mainType == 'onlyMain') {
        this.getGanttRowData();
        return;
      }
      this.getResource();
    },
    getResource() {
      let info = {
        startDate: this.queryStartDate,
        endDate: this.queryEndDate,
        resourceCode: this.resourceCodeForGantt,
        hasTask: this.onlyHasTasks
      };
      this.loading = true;
      getResource(info)
        .then(res => {
          this.loading = false;
          if (res.data.success) {
            let _resourceData = res.data.data;
            this.startDate = _resourceData.startDate;
            this.endDate = this.planStartDate + this.ganttCol * 24 * 3600 * 1000;
            this.dates = _resourceData.dates;
            let categories = _resourceData.categories;
            let ids = [];
            let arr = categories.filter(e => {
              if (!ids.includes(e.resourceId)) {
                ids.push(e.resourceId);
                return e;
              }
            });
            let _arr = arr.sort((a, b) => {
              return a.indexNum - b.indexNum;
            });
            this.asideList = _arr;
            this.asideListCopy = _arr;
            // 分页延迟请求
            this.ganttData = [];
            this.restData = [];
            let len = Math.ceil(ids.length / 20);
            for (let x = 0; x < len; x++) {
              setTimeout(() => {
                this.resourceIds = ids.slice(x * 20, (x + 1) * 20).join(',');
                this.getGanttInfo();
                this.getTimeList();
              }, x * 1500);
            }
          } else {
            this.$message.warning(res.data.data ? res.data.data.msg : '获取甘特资源失败!');
          }
        })
        .catch(err => {
          this.loading = false;
          console.log(err);
        });
    },
    getGanttInfo(ids) {
      let form = new FormData();
      form.append('startDate', this.queryStartDate);
      form.append('endDate', this.queryEndDate);
      form.append('resourceIds', ids || this.resourceIds);
      getGanttInfo(form)
        .then(res => {
          if (res.data.success) {
            if (ids) {
              this.setGanttRowData(res.data.processes);
              return;
            }
            this.getRest();
            this.ganttData = this.ganttData.concat(res.data.processes);
          }
        })
        .catch(err => {
          console.log(err);
        });
    },
    getRest() {
      let form = new FormData();
      form.append('startDate', this.queryStartDate);
      form.append('endDate', this.queryEndDate);
      form.append('resourceIds', this.resourceIds);
      getRest(form)
        .then(res => {
          if (res.data.success) {
            this.restData = this.restData.concat(res.data.processes);
            this.getGanttRowData();
          }
        })
        .catch(err => {
          console.log(err);
        });
    },
    getTimeList() {
      let list = [];
      let planStartDate = this.planStartDate;
      for (let i = 0; i < this.ganttCol; i++) {
        let date = planStartDate + i * 24 * 3600 * 1000;
        let _date = new Date(date);
        let day = _date.getDay();
        let dayStr = '';
        let obj = {};
        switch (day) {
          case 0:
            dayStr = 'Sun';
            obj.color = 'red';
            break;
          case 1:
            dayStr = 'Mon';
            break;
          case 2:
            dayStr = 'Tues';
            break;
          case 3:
            dayStr = 'Wed';
            break;
          case 4:
            dayStr = 'Thur';
            break;
          case 5:
            dayStr = 'Fri';
            break;
          case 6:
            dayStr = 'Sat';
            obj.color = 'red';
            break;
        }
        if (this.ganttRate < 0.065) {
          obj.time = moment(_date).format('DD');
        } else if (this.ganttRate == '0.097') {
          obj.time = moment(_date).format('MM-DD');
        } else if (this.ganttRate == '0.192') {
          obj.time = moment(_date).format('MM-DD') + dayStr;
        } else {
          obj.time = moment(_date).format('YYYY-MM-DD') + dayStr;
        }
        list.push(obj);
      }
      this.timeList = list;
      this.domWidth = this.setWidth * list.length * this.ganttRate;
      this.timeRange = this.endDate - this.planStartDate;
      console.log(this.planStartDate, this.domWidth, this.timeRange);
    },
    getGanttRowData() {
      let arr = [];
      this.ganttRowData = [];
      this.asideList = this.asideListCopy.filter(e => {
        if (!this.onlyMain || e.mainType == 'MAIN') {
          let obj = {};
          obj.resourceId = e.resourceId;
          obj.mainType = e.mainType;
          obj.restData = this.restData.find(n => {
            return e.resourceId == n.processId;
          });
          obj.ganttData = this.ganttData.find(n => {
            return e.resourceId == n.processId;
          });
          arr.push(obj);
        }
        return !this.onlyMain || e.mainType == 'MAIN';
      });
      console.log(arr);
      this.ganttRowData = arr;

      // 子工序强调甘特
      if (this.subProcess.operationId) {
        setTimeout(() => {
          this.stress();
        }, 50);
      }
    },
    ganttDomLeft(time) {
      return ((time - this.planStartDate) / this.timeRange) * this.domWidth;
    },
    ganttDomWidth(start, end) {
      if (end - start < 1) return 0;
      return ((end - start) / this.timeRange) * this.domWidth;
    },
    ganttDragStart(e, item, info) {
      // 显示可拖拽行
      // this.removeMainMove();
      this.isSelect = false;
      this.ganttDomRange = {
        width: this.ganttDomWidth(info.properties.earliestStartTime, info.properties.latestEndTime) + 10,
        left: this.ganttDomLeft(info.properties.earliestStartTime) - 5
      };
      let ids = info.properties.optionalResources || [];
      let arr = [];
      this.asideListCopy.forEach(e => {
        if (ids.indexOf(e.resourceId) > -1 && e.mainType == item.mainType) {
          arr.push(e.resourceId);
        }
      });
      this.adjustOptional = arr.join(',');
      // 过滤工序
      let statusObj = {
        FINISHED: '已完工',
        STARTED: '已开始',
        PLAN_IDENTIFIED: '已确定计划'
      };
      let status = info.properties.status;
      if (status == 'FINISHED' || status == 'STARTED' || status == 'PLAN_IDENTIFIED') {
        this.$message.warning(statusObj[info.properties.status] + ' 的工序不可以操作!');
        return;
      }

      // 自定义拖拽样式
      let canvas = document.createElement('canvas');
      let context = canvas.getContext('2d');
      canvas.setAttribute('id', 'dragCanvas');
      context.fillStyle = '#65C16F';
      context.fillRect(0, 0, 100, 21);
      context.font = '12px calibri';
      context.fillStyle = '#fff';
      context.fillText(info.blockName, 15, 15);
      document.body.append(canvas);
      e.dataTransfer.setDragImage(canvas, 50, 15);

      let obj = {
        blockIds: [info.blockId], //待排任务[调整的]
        sourceProcessId: item.resourceId //原始process,起点
      };
      e.dataTransfer.setData('ganttObj', JSON.stringify(obj));
    },
    ganttRowDrop(e) {
      this.adjustOptional = '';
      let obj = e.dataTransfer.getData('ganttObj') || '{}';
      let processid = e.target.getAttribute('processid') || '';
      if (!processid) {
        processid = e.target.parentNode.parentNode.getAttribute('processid');
      }
      obj = JSON.parse(obj);
      (obj.adjustmentType = 'ADJUSTMENT'), //取消CANCEL,调整 ADJUSTMENT,新增ADD
        (obj.startDate = this.queryStartDate), //开始日期[没拖到任务上时传]
        (obj.endDate = this.queryEndDate), //结束日期[没拖到任务上时传]
        (obj.operType = 'PROCESS'), //操作类型:排在资源上 RESOURCE,排在process上 PROCESS
        (obj.processId = processid), //目标process,终点
        console.log('ganttRowDrop===>', obj);
      this.handworkschedule([obj]);
      document.getElementById('dragCanvas').remove();
      return;
    },
    allowDrop(ev) {
      ev.stopPropagation();
      ev.preventDefault();
    },
    getGanttMove(ev) {
      if (this.isGanttDomMove) {
        this.isGanttDomMove = false;
        let color = '#409EFF';
        let x = parseInt(ev.target.offsetLeft + ev.layerX - ev.target.offsetWidth / 2);
        let _x = parseInt(this.ganttDomRange.left + 5);
        if (x < _x || x + ev.target.offsetWidth + 5 > _x + this.ganttDomRange.width) {
          color = '#f00';
        }
        this.ganttDomMove = {
          left: x,
          color: color,
          width: ev.target.offsetWidth
        };
        setTimeout(() => {
          this.isGanttDomMove = true;
        }, 100);
      }
    },
    mainDragEnd() {
      this.ganttDomRange = {};
      this.ganttDomMove = {};
    },
    maindDown(ev) {
      if (ev.target.className !== 'gantt-row') {
        return
      }
      // 鼠标按下时才允许处理鼠标的移动事件
      this.isSelect = true;
      let selectBox = null;
      selectBox = document.createElement('div');
      // 框选div 样式
      selectBox.style.cssText =
        'position:absolute;width:0px;height:0px;border:1px dashed #0099FF;background-color:#C3D5ED;z-index:999;opacity:0.4;display:none;';
      // 添加到gantt-main下
      document.querySelector('.gantt-main').appendChild(selectBox);
      
      // 取得鼠标按下时的坐标位置
      let top = document.getElementById('wrapper').scrollTop;
      let left = document.getElementById('wrapper').scrollLeft;
      this.downX = ev.clientX - 213 + left;
      this.downY = ev.clientY - this.ganttTop + top;
      //设置你要画的矩形框的起点位置
      selectBox.style.left = this.downX + 'px';
      selectBox.style.top = this.downY + 'px';
      this.selectBox = selectBox;
      ev.stopPropagation();
      ev.preventDefault();
    },
    maindMove(ev) {
      if (this.isSelect) {
        // 取得鼠标移动时的坐标位置
        let top = document.getElementById('wrapper').scrollTop;
        let left = document.getElementById('wrapper').scrollLeft;
        this.moveX = ev.clientX - 213 + left;
        this.moveY = ev.clientY - this.ganttTop + top;
        // 显示框选元素
        let selectBox = this.selectBox;
        if (selectBox.style.display == 'none') {
          selectBox.style.display = '';
        }
        selectBox.style.left = Math.min(this.moveX, this.downX) + 'px';

        selectBox.style.top = Math.min(this.moveY, this.downY) + 'px';

        selectBox.style.width = Math.abs(this.moveX - this.downX) + 'px';

        selectBox.style.height = Math.abs(this.moveY - this.downY) + 'px';
        // A part
        if (this.moveX < this.downX && this.moveY < this.downY) {
          selectBox.style.left = this.moveX;
          selectBox.style.top = this.moveY;
        }

        // B part
        if (this.moveX > this.downX && this.moveY < this.downY) {
          selectBox.style.left = this.downX;
          selectBox.style.top = this.moveY;
        }

        // C part
        if (this.moveX < this.downX && this.moveY > this.downY) {
          selectBox.style.left = this.moveX;
          selectBox.style.top = this.downY;
        }

        // D part
        if (this.moveX > this.downX && this.moveY > this.downY) {
          selectBox.style.left = this.downX;
          selectBox.style.top = this.downY;
        }
        
        ev.stopPropagation();
        ev.preventDefault();
      }
    },
    maindUp() {
      //鼠标抬起,就不允许在处理鼠标移动事件
      this.isSelect = false;
      let selectBox = this.selectBox;
      if (!selectBox || selectBox.offsetWidth < 1 || selectBox.offsetHeight < 1) {
        return
      }
      let list = document.getElementsByClassName('gantt-dom');
      for (let i = 0; i < list.length; i++) {
        // 将移动的div的四个点和和div元素的四个点进行比较
        if (
          //判断div元素 右边框的位置大于移动div的左起始点
          selectBox.offsetLeft - 100 < list[i].offsetLeft + list[i].offsetWidth &&
          //判断div元素 下边框的位置大于移动div的上起始点
          parseInt(list[i].getAttribute('top')) + list[i].offsetHeight > selectBox.offsetTop - 60 &&
          // 判断div元素左边框的位置小于移动div的右起始点
          selectBox.offsetLeft - 100 + selectBox.offsetWidth > list[i].offsetLeft &&
          // 判断div元素上边框的位置小于移动div的下起始点
          selectBox.offsetTop - 60 + selectBox.offsetHeight > parseInt(list[i].getAttribute('top'))
        ) {
          //将已选中的样式改变
          if (list[i].className.indexOf('gantt-dom-act') == -1) {
            // list[i].className = list[i].className + ' gantt-dom-act';
            this.actblockId += '#' + list[i].getAttribute('id')
          }
          
        } else {
          //如果没有选中则清除样式
          if (list[i].className.indexOf('gantt-dom-act') != -1) {
            // list[i].className = 'gantt-dom';
            let id = list[i].getAttribute('id')
            this.actblockId = this.actblockId.replace(id, '');
          }
        }
      }
      //隐藏图层
      if (this.selectBox) {
        document.querySelector('.gantt-main').removeChild(this.selectBox);
        this.selectBox = null
      }
    },
    maindLeave() {
      //鼠标移出main div 清除框选div
      this.isSelect = false;
      //隐藏图层
      if (this.selectBox) {
        document.querySelector('.gantt-main').removeChild(this.selectBox);
        this.selectBox = null
      }
    },
    wrapperScroll(ev) {
      if (ev.target.scrollTop + ev.target.clientHeight == ev.target.scrollHeight) {
        console.log('触底了!');
        // this.resourceIdsIndex = this.resourceIdsIndex + 10;
        // let ids = this.resourceIdsCopy.slice(this.resourceIdsIndex, this.resourceIdsIndex + 10).join(',');
        // if (ids) {
        //   // this.resourceIds = ids;
        //   console.log(ids)
        // }
      }
    },
    handworkschedule(info, tableType) {
      // adjustmentType: 'ADJUSTMENT', //取消CANCEL,调整 ADJUSTMENT,新增ADD
      // blockIds: sourceProcessObj[key], //待排任务[调整的]
      // preBlockId: preBlockId, //前一个任务
      // nextBlockId: '', //下一个任务
      // sourceProcessId: key, //原始process,起点
      // startDate: this.queryStartDate, //开始日期[没拖到任务上时传]
      // endDate: this.queryEndDate, //结束日期[没拖到任务上时传]
      // operType: operType, //操作类型:排在资源上 RESOURCE,排在process上 PROCESS
      // processId: processId, //目标process,终点
      this.loading = true;
      handworkschedule(info)
        .then(res => {
          this.loading = false;
          if (res.data.success) {
            if (res.data.data.success) {
              let ids = res.data.data.resourceIds.join(',');
              this.clearGanttRowData(res.data.data.resourceIds);
              this.getGanttInfo(ids);
              if (tableType) {
                bus.$emit('handworkscheduleSuccess', true);
              }
              this.$message.success(res.data.data.msg || '操作成功!');
            } else {
              this.$message.warning(res.data.data.msg || '操作失败!');
            }
          } else {
            this.$message.warning(res.data.msg || '操作失败!');
          }
        })
        .catch(err => {
          this.loading = false;
          console.log(err);
        });
    },
    setGanttRowData(arr) {
      arr.map(n => {
        for (let i = 0; i < this.ganttRowData.length; i++) {
          if (this.ganttRowData[i].resourceId === n.processId) {
            this.ganttRowData[i].ganttData = n;
            continue;
          }
        }
      });
    },
    clearGanttRowData(arr) {
      arr.map(n => {
        for (let i = 0; i < this.ganttRowData.length; i++) {
          if (this.ganttRowData[i].resourceId === n) {
            this.ganttRowData[i].ganttData = {};
            continue;
          }
        }
      });
    },
    ganttDetails(e) {
      let p = e.properties;
      let str =
        '制造订单代码:' +
        (p.workOrderCode || '') +
        '\n物品代码:' +
        (p.workOrderCodeproductCode || '') +
        '\n物品名称:' +
        (p.productName || '') +
        '\n工艺路径代码:' +
        (p.routingStepCode || '') +
        '\n工序代码:' +
        (p.operationCode || '') +
        '\n顺序号:' +
        (p.routingStepSequenceNr || '') +
        '\n工艺代码:' +
        (p.routingStepCode || '') +
        '\n计划状态:' +
        (p.status || '') +
        '\n数量:' +
        (p.qty || '') +
        '\n齐套状态:' +
        (p.allsetStatus || '') +
        '\n最早开始时刻:' +
        (moment(p.earliestStartTime).format('MM-DD HH:mm') || '') +
        '\n最晚结束时刻:' +
        (moment(p.latestEndTime).format('MM-DD HH:mm') || '') +
        '\n开始时刻:' +
        (moment(e.startTime).format('MM-DD HH:mm') || '') +
        '\n结束时刻:' +
        (moment(e.endTime).format('MM-DD HH:mm') || '') +
        '\n冻结状态:' +
        (p.lockStatus || '') +
        (p.alarmInfo ? '\n告警信息:' + p.alarmInfo : '');
      return str;
    },
    setGanttDom(e) {
      let obj = JSON.parse(e);
      this.ganttRate = obj.value;
      this.ganttLi = parseInt(24 / Number(obj.hours));
      this.ganttCol = parseInt(obj.days) < 8 ? 8 : parseInt(obj.days) + 1;
      this.getResource();
    },
    blocksContextmenu(e, val, id) {
      e.preventDefault();
      this.isShowBlockMenu = val;
      let clientY = e.clientY;
      let clientX = e.clientX;
      // if (clientY < 100) {
      //   clientY = clientY + 80
      // }
      // if (clientX - 130 < 100) {
      //   clientX = clientX + 135
      // }
      let block = document.querySelector('.block-menu');
      block.setAttribute('domId', id)
      block.style.top = clientY + 'px';
      block.style.left = clientX + 'px';
    },
    getGanttDom(event, e) {
      if (event.ctrlKey) {
        if (this.actblockId.includes(e)) {
          this.actblockId = this.actblockId.replace(e, '');
        } else {
          this.actblockId += '#' + e;
        }
        return;
      }
      if (this.actblockId.includes(e)) {
        this.actblockId = '';
        this.unstress();
        return;
      }
      this.actblockId = e;
      this.drawLine(e.split('&')[1]);
    },
    hiddenBlockMenu() {
      this.isShowBlockMenu = null;
    },
    blockMenu(e) {
      // if (e === '连线') {
      //   this.drawLine();
      //   return;
      // }
      // if (e === '取消连线') {
      //   this.clearLine();
      //   return;
      // }
      if (e === '选中工序') {
        bus.$emit('selectProcedure', this.isShowBlockMenu.blockId);
        return;
      }
      if (e === '强调') {
        this.stress();
        return;
      }
      if (e === '取消强调') {
        this.unstress();
        return;
      }
      if (e === '冻结') {
        this.freeze();
        return;
      }
      if (e === '解锁') {
        this.unfreeze();
        return;
      }
      if (e === '制造订单展开') {
        this.$router.push({
          path: '/planSchedule/ProductionPlan/manufacturingOrder',
          query: {
            supplyOrderId: this.isShowBlockMenu.blockName
          }
        });
        return;
      }
    },
    ganttMainMove(ev) {
      // if (sessionStorage.tableData) {
      //   if (this.isGanttDomMove) {
      //     this.isGanttDomMove = false;
      //     let color = '#409EFF';
      //     console.log(ev.target.offsetWidth);
      //     let x = parseInt(ev.target.offsetLeft + ev.layerX - ev.target.offsetWidth / 2);
      //     let _x = parseInt(this.ganttDomRange.left + 5);
      //     if (x < _x || x > _x) {
      //       color = '#f00';
      //     }
      //     this.ganttDomMove = {
      //       left: x,
      //       color: color,
      //       width: ev.target.offsetWidth
      //     };
      //     setTimeout(() => {
      //       this.isGanttDomMove = true;
      //     }, 100);
      //   }
      // }
      // earliestStartCalc
      // latestEndCalc
    },
    ganttMainDown(event) {
      // 手势操作鼠标移动事件监听
      if (event.target.className === 'gantt-dom') {
        return;
      }
      let that = this;
      this.moveStartX = event.clientX;
      this.moveStartY = event.clientY;
      let wrapper = document.getElementById('wrapper');
      wrapper.addEventListener('mousemove', that.setMainMove);
    },
    setMainMove(event) {
      // 手势操作鼠标移动处理
      if (event.button != 0) {
        return;
      }
      let wrapper = document.getElementById('wrapper');
      let x = event.clientX - this.moveStartX;
      let y = event.clientY - this.moveStartY;
      wrapper.scrollLeft = wrapper.scrollLeft - x;
      wrapper.scrollTop = wrapper.scrollTop - y;
      if (this.moveStartX != event.clientX) {
        this.moveStartX = event.clientX;
      }
      if (this.moveStartY != event.clientY) {
        this.moveStartY = event.clientY;
      }
    },
    ganttRowUp(e) {
      this.adjustOptional = '';
      if (sessionStorage.tableData) {
        let table = JSON.parse(sessionStorage.tableData);
        console.log(sessionStorage.tableData);
        let ids = table.map(n => {
          return n.operationId;
        });
        let processid = e.target.getAttribute('processid') || '';
        let obj = {};
        (obj.blockIds = ids), //取消CANCEL,调整 ADJUSTMENT,新增ADD
          (obj.adjustmentType = 'ADD'),
          (obj.startDate = this.queryStartDate), //开始日期[没拖到任务上时传]
          (obj.endDate = this.queryEndDate), //结束日期[没拖到任务上时传]
          (obj.operType = 'PROCESS'), //操作类型:排在资源上 RESOURCE,排在process上 PROCESS
          (obj.processId = processid), //目标process,终点
          (obj.nextBlockId = ''), //下一个任务
          (obj.sourceProcessId = ''), //原始process,起点
          this.handworkschedule([obj], 'table');
      }
    },
    ganttMainEnter(e) {
      // 查找甘特中匹配从表格拖拽过来的数据
      if (!e) {
        this.clearTabData();
        return;
      }
      if (sessionStorage.tableData) {
        let data = JSON.parse(sessionStorage.tableData)[0];
        let end = new Date(this.queryEndDate + ' 00:00:00').getTime();
        let _end = data.latestEndCalc > end ? end : data.latestEndCalc;
        let w = this.ganttDomWidth(data.earliestStartCalc, _end) + 10;
        this.ganttDomRange = {
          width: w,
          left: this.ganttDomLeft(data.earliestStartCalc) - 5
        };
      }
      // 给符合的甘特条加上符合样式,滚动条到第一条符合的数据位置
      let ids = e.split(',');
      this.adjustOptional = e;
      let doms = document.getElementsByClassName('aside-li');
      for (let i = 0; i < doms.length; i++) {
        if (ids[0] == doms[i].getAttribute('processid')) {
          document.getElementById('wrapper').scrollTop = doms[i].offsetTop - 31;
          break;
        }
      }
    },
    ganttMainUp() {
      this.clearTabData();
      // this.removeMainMove();
    },
    ganttMainLeave() {
      // this.removeMainMove();
    },
    clearTabData() {
      this.adjustOptional = '';
      this.ganttDomRange = {};
      sessionStorage.tableData = '';
    },
    removeMainMove() {
      // 移除鼠标移动事件监听
      let that = this;
      let wrapper = document.getElementById('wrapper');
      wrapper.removeEventListener('mousemove', that.setMainMove);
    },
    stress() {
      let dom = document.getElementsByClassName('gantt-dom');
      let len = dom.length;
      for (let i = 0; i < len; i++) {
        dom[i].style.opacity = 0.3;
      }
      let block = document.querySelector('.block-menu').getAttribute('domId');
      document.getElementById(block).style.opacity = 1;
      this.drawLine();
    },
    unstress() {
      if (this.draggleType === 'afterOnly') {
        this.ganttRowData = [...this.allGanttRowData];
        this.asideList = [...this.allAsideList];
      }
      let dom = document.getElementsByClassName('gantt-dom');
      let len = dom.length;
      for (let i = 0; i < len; i++) {
        dom[i].style.opacity = 1;
      }
      this.actblockId = '';
      this.clearLine();
    },
    freeze() {
      if (!this.actblockId) {
        this.$message.warning('请选择要冻结的工序!');
        return;
      }
      let ids = this.actblockId
        .split('#')
        .map(e => {
          return e.split('&')[1];
        })
        .filter(n =>{
          return n
        })
        .join(',');
      lockOperation({
        operationIds: ids
      }).then(res => {
        if (res.data.success) {
          this.actblockId = '';
          this.getResource();
          this.$message.success(res.data.msg);
        } else {
          this.$message.error(res.data.msg);
        }
      });
    },
    unfreeze() {
      if (!this.actblockId) {
        this.$message.warning('请选择要解锁的工序!');
        return;
      }
      let ids = this.actblockId
        .split('#')
        .map(e => {
          return e.split('&')[1];
        })
        .filter(n =>{
          return n
        })
        .join(',');
      unlockOperation({
        operationIds: ids
      }).then(res => {
        if (res.data.success) {
          this.actblockId = '';
          this.getResource();
          this.$message.success(res.data.msg);
        } else {
          this.$message.error(res.data.msg);
        }
      });
    },
    drawLine(e) {
      this.clearLine();
      let id = e || this.subProcess.operationId || this.isShowBlockMenu.blockId;
      let info = {
        operationId: id
      };
      getGanttline(info)
        .then(res => {
          if (res.data.success) {
            if (res.data.lines.length == 0) {
              this.$message.warning('未查到连线信息!');
              this.unstress();
              return;
            }
            if (res.data.processes.length > 0) {
              this.setLineGantt(res.data.processes);
            }
            this.$nextTick(() => {
              let targetBlock = {};
              let index = 0;
              for (let i = 0; i < res.data.lines.length; i++) {
                if (res.data.lines[i].blockId === id) {
                  targetBlock = { ...res.data.lines[i] };
                  index = i;
                }
              }
              let lines = [targetBlock];
              if (this.lineType === 'all' || !e) {
                lines = [...res.data.lines];
              } else {
                let preBlock = res.data.lines.find(x => x.nextBlockId === targetBlock.blockId);
                let nextBlock = res.data.lines.find(x => x.blockId === targetBlock.nextBlockId);
                if(preBlock) {
                  lines.unshift(preBlock)
                }
                if(this.lineType !== 'one') {
                  const contrast = {
                    one: 1,
                    two: 2,
                    three: 3,
                    four: 4,
                    five: 5,
                    ten: 10,
                    twenty: 20
                  };
                  for (let i = 1; i <= (contrast[this.lineType]-1); i++) {
                    if(preBlock && res.data.lines.some(x => x.nextBlockId === preBlock.blockId)) {
                      lines = lines.concat(res.data.lines.find(x => x.nextBlockId === preBlock.blockId));
                      preBlock = res.data.lines.find(x => x.nextBlockId === preBlock.blockId);
                    }
                    if(nextBlock && res.data.lines.some(x => x.blockId === nextBlock.nextBlockId)) {
                      lines.push(nextBlock)
                      nextBlock = res.data.lines.find(x => x.blockId === nextBlock.nextBlockId)
                    }
                  }
                }
              }
              console.log(lines)
              lines.map(n => {
                this.setLineDom(n.processId + '&' + n.blockId, n.nextProcessId + '&' + n.nextBlockId);
              });
              if (this.subProcess.operationId) {
                this.setWrapperScroll(this.subProcess.plannedResourceId + '&' + this.subProcess.operationId);
                this.subProcess = {};
              }
            });
          }
        })
        .catch(err => {
          console.log(err);
        });
    },
    setLineGantt(arr) {
      const hideArr = [];
      arr.map(n => {
        for (let i = 0; i < this.ganttRowData.length; i++) {
          if (this.ganttRowData[i].resourceId === n.processId) {
            let ganttData = this.ganttRowData[i].ganttData;
            if (ganttData) {
              let isto = ganttData.blocks.includes(item => {
                return item.block !== n.blocks[0].blockId;
              });
              if (isto) {
                this.ganttRowData[i].ganttData.blocks.push(n.blocks[0]);
              }
            }
            break;
          }
        }
      });
      if (this.draggleType === 'afterOnly') {
        this.allGanttRowData = [...this.ganttRowData];
        this.allAsideList = [...this.asideList];
        this.ganttRowData = this.ganttRowData.filter(x => arr.some(y => y.processId === x.resourceId));
        this.asideList = this.asideList.filter(x => arr.some(y => y.processName === x.resourceName));
      }
    },
    setWrapperScroll(id) {
      let wrapper = document.getElementById('wrapper');
      let dom = document.getElementById(id);
      if (!dom) {
        return;
      }
      wrapper.scrollTop = dom.parentNode.offsetTop - 60;
      wrapper.scrollLeft = dom.offsetLeft - 30;
    },
    setLineDom(startId, endId) {
      let startObj = document.getElementById(startId);
      let endObj = document.getElementById(endId);
      if (startObj) {
        startObj.style.opacity = 1;
      }
      if (endObj) {
        endObj.style.opacity = 1;
      }
      if (!startObj || !endObj) {
        return;
      }
      //起点元素中心坐标
      let y_start = startObj.parentNode.offsetTop + 15;
      let x_start = startObj.offsetLeft + startObj.offsetWidth + 100;
      //终点元素中心坐标
      let y_end = endObj.parentNode.offsetTop + 15;
      let x_end = endObj.offsetLeft + 100;
      //用勾股定律计算出斜边长度及其夹角(即连线的旋转角度)
      let lx = x_end - x_start;
      let ly = y_end - y_start;
      //计算连线长度
      let length = Math.sqrt(lx * lx + ly * ly);
      //弧度值转换为角度值
      let c = (360 * Math.atan2(ly, lx)) / (2 * Math.PI);
      //连线中心坐标
      let midX = (x_end + x_start) / 2;
      let midY = (y_end + y_start) / 2;
      let deg = c <= -90 ? 360 + c : c; //负角转换为正角

      let node = document.createElement('div');
      node.className = 'line';
      node.style.zIndex = 2;
      node.style.position = 'absolute';
      node.style.borderTop = '1px solid #3500ff';
      node.style.top = midY + 'px';
      node.style.left = midX - length / 2 + 'px';
      node.style.width = length + 'px';
      node.style.transform = 'rotate(' + deg + 'deg)';
      document.querySelector('.gantt-main').appendChild(node);
    },
    clearLine() {
      let dom = document.getElementsByClassName('line');
      let len = dom.length;
      for (let i = 0; i < len; i++) {
        dom[0].remove();
      }
    },
    setGanttHeight(height) {
      this.$refs.ganttRoot.style.height = height;
      setTimeout(() => {
        this.ganttTop = document.querySelector('.yhl-table-productPeriod').offsetHeight + 183
      }, 500)
    }
  }
};
</script>
<style lang="scss" scoped>
.gantt {
  width: 100%;
  height: calc(40vh - 35px);
  position: relative;
  background: #fff;
  border: 1px solid #eeeeee;
  cursor: pointer;
  .gantt-content {
    position: absolute;
    top: 0px;
    right: 0px;
    bottom: 0px;
    left: 0px;
    overflow: auto;
    .gantt-block {
      position: sticky;
      top: 0;
      left: 0;
      float: left;
      width: 100px;
      height: 60px;
      border-right: 1px solid #eeeeee;
      border-bottom: 1px solid #eeeeee;
      z-index: 9;
      background-color: #fff;
      div {
        text-align: center;
        line-height: 30px;
        height: 30px;
        font-weight: bold;
        border-bottom: 1px solid #eeeeee;
      }
    }
    .gantt-aside {
      position: sticky;
      top: 0;
      left: 0;
      float: left;
      width: 100px;
      min-height: 100%;
      overflow: hidden;
      border-right: 1px solid #eeeeee;
      z-index: 8;
      background-color: #fff;
      .aside-list {
        width: 100%;
        .aside-li {
          height: 31px;
          position: relative;
          border-bottom: 1px solid #eeeeee;
          span {
            display: inline-block;
            height: 25px;
            line-height: 25px;
            text-align: left;
            font-size: 12px;
            transform: scale(0.9);
            margin-left: 5px;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
          }
        }
        .mainType::before {
          content: '*';
          color: red;
          position: absolute;
          top: 5px;
          left: 0;
          font-weight: bold;
        }
        .adjustOptional::after {
          content: '';
          position: absolute;
          right: 0;
          height: 100%;
          width: 6px;
          background: #3500ff;
        }
      }
    }
    .gantt-calendar {
      position: sticky;
      top: 0;
      float: left;
      width: calc(100% - 100px);
      height: 60px;
      z-index: 8;
      .calendar-dom {
        display: flex;
        font-size: 12px;
        height: 50px;
        position: relative;
        .calendar-li {
          width: 720px;
          flex-grow: 0;
          flex-shrink: 0;
          display: inline-block;
          border-right: 1px solid #eeeeee;
          background-color: #fff;
          .calendar-day {
            text-align: center;
            height: 30px;
            line-height: 30px;
            border-bottom: 1px solid #eeeeee;
          }
          .calendar-time {
            display: flex;
            height: 20px;
            line-height: 20px;
            padding: 0 4%;
            border-bottom: 1px solid #eeeeee;
            .calendar-h {
              width: 9.1%;
              text-align: center;
            }
          }
          .gantt-time {
            width: calc(100% + 1px);
            height: 10px;
            background-color: #fff;
            border-bottom: 1px solid #eeeeee;
          }
        }
        .gantt-dom-range {
          width: 200px;
          height: 10px;
          position: absolute;
          bottom: -10px;
        }
        .gantt-dom-range::before {
          content: '';
          position: absolute;
          top: 0;
          left: 0;
          border-style: solid;
          border-color: transparent;
          border-width: 5px 0 5px 5px;
          border-left-color: #f00;
        }
        .gantt-dom-range::after {
          content: '';
          position: absolute;
          top: 0;
          right: 0;
          border-style: solid;
          border-color: transparent;
          border-width: 5px 5px 5px 0;
          border-right-color: #f00;
        }
        .gantt-dom-move {
          width: 200px;
          height: 10px;
          background-color: #409eff;
          position: absolute;
          bottom: -10px;
        }
      }
    }
    .gantt-main {
      padding-top: 60px;
      padding-left: 100px;
      position: absolute;
      overflow: hidden;
      .gantt-row {
        position: relative;
        width: 100%;
        height: 31px;
        border-bottom: 1px solid #eeeeee;
        z-index: 1;
        user-select: none;
        content-visibility: auto;
        overflow: hidden;
        .gantt-dom {
          position: absolute;
          top: 15%;
          left: 400px;
          width: 30px;
          height: 70%;
          background: #f2f2f2;
          box-shadow: 0 0 3px #666;
          // display: flex;
          // justify-content: space-between;
          color: #fff;
          line-height: 18px;
          font-size: 12px;
          content-visibility: auto;
          z-index: 2;
          text-align: center;
          line-height: 21px;
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
          .trangle {
            width: 0;
            height: 0;
            border-top: 10px solid #db1111;
            border-right: 10px solid transparent;
            position: absolute;
            top: -2px;
            left: -2px;
          }
        }
        .gantt-dom:hover {
          box-shadow: 0 0 3px 3px #aaaaaa;
          z-index: 99;
        }
        .gantt-dom-act {
          outline: 2px dashed #3500ff;
        }
        // .gantt-dom-choice {
        //   border: 2px solid #06f;
        // }
      }
      .adjustOptional {
        box-shadow: rgb(221, 221, 221) 0px 0px 8px inset;
        animation: animate 1s linear infinite;
      }
      @keyframes animate {
        0% {
          box-shadow: inset 0 0 10px rgba(91, 0, 255, 0.5);
        }
        50% {
          box-shadow: inset 0 0 10px rgba(91, 0, 255, 1);
        }
        100% {
          box-shadow: inset 0 0 10px rgba(91, 0, 255, 0.5);
        }
      }
      .gantt-row:hover {
        box-shadow: #eeeeee 0 0 8px inset;
      }
      .rest-dom {
        position: absolute;
        height: 100%;
        background: rgba(0, 0, 0, 0.25);
        z-index: 1;
        content-visibility: auto;
      }
      .block-menu {
        position: fixed;
        top: 11vw;
        left: 50vw;
        width: 90px;
        background-color: #ffffff;
        box-shadow: 0 0 5px #000;
        z-index: 8;
        div {
          padding: 4px 0 4px 5px;
          font-size: 12px;
          text-align: left;
          color: #333;
          border-bottom: 1px solid #eeeeee;
        }
        div:hover {
          background-color: #dddddd;
        }
        .gotoNewDom:hover {
          .gotoNew {
            display: block;
          }
        }
        .gotoNew {
          width: 110px;
          display: none;
          position: absolute;
          right: -110px;
          bottom: 0;
          border: 1px solid #aaaaaa;
          background-color: #ffffff;
        }
      }
      .gantt-col-bg {
        position: absolute;
        width: calc(100% - 100px);
        height: calc(100% - 60px);
        display: flex;
        .gantt-col-ul {
          width: 600px;
          height: 100%;
          display: flex;
          flex-grow: 0;
          flex-shrink: 0;
          content-visibility: auto;
          .gantt-col-li {
            width: 9.1;
            height: 100%;
            border-right: 1px solid #eeeeee;
          }
        }
        .gantt-col-ol:nth-child(2n) {
          border-right: 1px solid #eeeeee;
        }
      }
      .base-time {
        position: absolute;
        top: 60px;
        border-left: 2px solid rgba(255, 0, 0, 0.5);
        height: calc(100% - 60px);
        z-index: 6;
      }
      .nodata {
        width: 200px;
        text-align: center;
        position: absolute;
        top: 160px;
        left: 39vw;
        font-size: 16px;
        color: #999;
      }
    }
  }
  /* 定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸 */
  ::-webkit-scrollbar {
    width: 10px;
    height: 10px;
  }
  /* 定义滚动条轨道 内阴影+圆角 */
  ::-webkit-scrollbar-track {
    background-color: #fff;
  }
  /* 定义滑块 内阴影+圆角 */
  ::-webkit-scrollbar-thumb {
    border-radius: 6px;
    background-color: #ddd;
  }
}
</style>
<style>
#dragCanvas {
  position: absolute;
  left: -100%;
}
</style>
上一篇 下一篇

猜你喜欢

热点阅读