小小儁爺
2026-01-22 f8d4f5e58cdcade758423c7a3337fea00dc97ada
src/views/gantt/index.vue
@@ -36,6 +36,7 @@
        value-format="yyyy-MM-dd"
        type="daterange"
        :clearable="false"
        :picker-options="pickerOptions"
        range-separator="至"
        start-placeholder="开始日期"
        end-placeholder="结束日期"
@@ -75,7 +76,7 @@
</template>
<script>
import { gantt } from '@/components/dhtmlxGantt'
import { gantt } from '@/components/dhtmlxGantt' // 目前dhtmlxgantt版本8.0.x
import '@/components/dhtmlxGantt/codebase/dhtmlxgantt.css'
import { handleDateReduceOneDay, handleDatetime, handleDatetime2 } from '@/utils/global'
import { nanoid } from 'nanoid'
@@ -90,7 +91,7 @@
        { code: '360min', name: '360min' }
      ],
      scaleValue: '240min',
      ganttDateRange: ['2026-01-21', '2026-01-22'], // '2026-01-20', '2026-01-25'
      ganttDateRange: ['2026-01-22', '2026-01-25'], // '2026-01-20', '2026-01-25'
      selectedIds: [],
      // 分页相关数据
      currentPage: 1,
@@ -106,18 +107,23 @@
      priorityMethodArr: [
        { code: 'device', name: '设备优先' },
        { code: 'time', name: '时间优先' }
      ]
      ],
      pickerOptions: {
        // disabledDate(time) {
        //   return time.getTime() <= Date.now() - 24 * 60 * 60 * 1000
        // }
      }
    }
  },
  mounted() {
    // 先改变日期范围配置
    this.ganttDateRangeChange(this.ganttDateRange)
    // 初始化甘特图配置
    this.initGantt()
    // 改变日期范围配置
    this.ganttDateRangeChange(this.ganttDateRange)
    // 然后加载任务数据(会自动渲染当前页)
    this.loadTasks()
    // this.loadTasks()
  },
  methods: {
@@ -236,7 +242,6 @@
      // 自定义浮动框的显示内容   tooltip浮动框显示的End Date被追加1的问题修复(应该显示数据库的原始值)
      gantt.templates.tooltip_text = function(start, end, task) {
        // console.log(JSON.parse(JSON.stringify(task)))
        // return '<b>任务:</b> ' + task.text + '<br/><b>开始时间:</b> ' + `${gantt.date.date_to_str('%Y-%m-%d')(start)}` + '<br/><b>结束时间:</b> ' + handleDateReduceOneDay(end)
        // return '<b>任务:</b> ' + task.text + '<br/><b>开始时间:</b> ' + handleDatetime2(start) + '<br/><b>结束时间:</b> ' + handleDateReduceOneDay(end) + '<br/><b>进度:</b> ' + task.progress * 100 + '%'
        return '<b>任务:</b> ' + task.text +
@@ -258,7 +263,7 @@
          // return task.producedCount
        }
        if (task.type === 'task3') {
          return `<div  class="task3Css">`
          return `<div  class="task3Css">${task.producedCount}</div>`
        }
        return ''
      }
@@ -300,11 +305,13 @@
      // 初始化完成后同步一次选中状态
      this.syncSelected()
      // this.loadTasks()
    },
    // 加载任务数据
    loadTasks() {
      // 接口获取到的数据
      // 接口获取到的数据  //这是待排数据
      const rows = [
        {
          'wo_code': null,
@@ -476,19 +483,136 @@
        }
      ]
      // 这是已排数据
      const Cont = [
        {
          'wo_code': 'MO-2023-06-0007_1',
          'eqp_code': 'JG010',
          'time_start': '2026-01-21 13:51:55',
          'time_end': '2026-01-21 18:00:00',
          'status': 'S',
          'alloc_qty': 298.00,
          'part_code': '302',
          'part_name': '8504光机',
          'uom_name': '只'
        },
        {
          'wo_code': 'MO-2023-06-0007_1',
          'eqp_code': 'JG010',
          'time_start': '2026-01-22 08:00:00',
          'time_end': '2026-01-22 11:30:00',
          'status': 'S',
          'alloc_qty': 252.00,
          'part_code': '302',
          'part_name': '8504光机',
          'uom_name': '只'
        },
        {
          'wo_code': 'MO-2023-06-0007_1',
          'eqp_code': 'JG010',
          'time_start': '2026-01-22 13:00:00',
          'time_end': '2026-01-22 18:00:00',
          'status': 'S',
          'alloc_qty': 360,
          'part_code': '302',
          'part_name': '8504光机',
          'uom_name': '只'
        },
        {
          'wo_code': 'MO-2023-06-0007_1',
          'eqp_code': 'JG010',
          'time_start': '2026-01-23 08:00:00',
          'time_end': '2026-01-23 11:30:00',
          'status': 'S',
          'alloc_qty': 252.00,
          'part_code': '302',
          'part_name': '8504光机',
          'uom_name': '只'
        },
        {
          'wo_code': 'MO-2023-06-0007_1',
          'eqp_code': 'JG010',
          'time_start': '2026-01-23 13:00:00',
          'time_end': '2026-01-23 15:00:00',
          'status': 'S',
          'alloc_qty': 144.00,
          'part_code': '302',
          'part_name': '8504光机',
          'uom_name': '只'
        }
        // {
        //   'wo_code': 'MO-2023-06-0007_1',
        //   'eqp_code': 'JG010',
        //   'time_start': '2026-01-24 08:00:00',
        //   'time_end': '2026-01-24 11:30:00',
        //   'status': 'S',
        //   'alloc_qty': 252.00,
        //   'part_code': '302',
        //   'part_name': '8504光机',
        //   'uom_name': '只'
        // },
        // {
        //   'wo_code': 'MO-2023-06-0007_1',
        //   'eqp_code': 'JG010',
        //   'time_start': '2026-01-24 13:00:00',
        //   'time_end': '2026-01-24 18:00:00',
        //   'status': 'S',
        //   'alloc_qty': 360.00,
        //   'part_code': '302',
        //   'part_name': '8504光机',
        //   'uom_name': '只'
        // },
        // {
        //   'wo_code': 'MO-2023-06-0007_1',
        //   'eqp_code': 'JG010',
        //   'time_start': '2026-01-25 08:00:00',
        //   'time_end': '2026-01-25 11:30:00',
        //   'status': 'S',
        //   'alloc_qty': 252.00,
        //   'part_code': '302',
        //   'part_name': '8504光机',
        //   'uom_name': '只'
        // },
        // {
        //   'wo_code': 'MO-2023-06-0007_1',
        //   'eqp_code': 'JG010',
        //   'time_start': '2026-01-25 13:00:00',
        //   'time_end': '2026-01-25 18:00:00',
        //   'status': 'S',
        //   'alloc_qty': 360.00,
        //   'part_code': '302',
        //   'part_name': '8504光机',
        //   'uom_name': '只'
        // }
      ]
      const newArr = []
      // 这一步的操作主要是要做产能背景的显示
      rows.forEach((item, index) => {
        // 数据接口返回的时间范围要在日期选择范围之内
        if (new Date(item.YearDate).getTime() >= new Date(this.ganttDateRange[0]).getTime() && new Date(item.YearDate).getTime() <= new Date(this.ganttDateRange[1]).getTime()) {
          // console.log(JSON.stringify(item))
          item.children.forEach((it, ind) => {
            // console.log(JSON.stringify(it))
            // 这里应该要生成一个以设备维度为基础的数组   不重不漏
            if (!newArr.map(i => i.partCode).includes(it.AdvaDevicNumber)) {
              console.log(' it.AdvaDevicNumber,', it.AdvaDevicNumber)
              newArr.push({
                id: it.AdvaDevicNumber,
                type: 'project',
                text: '我是父级',
                partName: it.AdvaDevicName,
                partCode: it.AdvaDevicNumber,
                start_date: handleDatetime2(item.YearDate + ' ' + it.OneStartDate.split('~')[0]), // 这个是无效的,只是为了预排prepareArrange方法里面不报错
                end_date: handleDatetime2(item.YearDate + ' ' + it.OneStartDate.split('~')[1]), // 这个是无效的,只是为了预排prepareArrange方法里面不报错
                // duration: this.calculateTimeRangeInMinutes(it.OneStartDate),
                checked: false,
                progress: 0.6,
                parent: 0,
                saleOrder: 'SO-2026-01001',
                open: true
              })
              console.log(it.AdvaDevicNumber + ind.toString(), 999)
              newArr.push({
                id: it.AdvaDevicNumber + ind.toString(),
                // id: it.AdvaDevicNumber,
                type: 'project',
                text: '任务名称预留',
                partName: it.AdvaDevicName,
@@ -499,7 +623,8 @@
                render: 'split', // 用于在一个工作时间段内显示不下,需要进行分割显示
                checked: false,
                progress: 0,
                parent: 0,
                parent: it.AdvaDevicNumber,
                // parent: it.AdvaDevicNumber,
                saleOrder: 'SO-2026-01001'
              })
            }
@@ -508,6 +633,7 @@
            for (let i = 0; i < 5; i++) { // 这次循环是为了显示产能
              if (it[this.fivePeriodsTimeName[i]]) {
                const duration = this.calculateTimeRangeInMinutes(it[this.fivePeriodsTimeName[i]]) // 工期 单位 分钟
                console.log(it.AdvaDevicNumber + ind.toString(), 123)
                newArr.push({
                  // id:  index.toString() + ind.toString() + i.toString(),
                  id: nanoid(),
@@ -516,11 +642,14 @@
                  partName: it.AdvaDevicName,
                  partCode: it.AdvaDevicNumber,
                  start_date: handleDatetime2(item.YearDate + ' ' + it[this.fivePeriodsTimeName[i]].split('~')[0]),
                  // start_date: new Date(handleDatetime2(item.YearDate + ' ' + it[this.fivePeriodsTimeName[i]].split('~')[0])).getTime() < new Date().getTime() ? handleDatetime2(new Date()) : handleDatetime2(item.YearDate + ' ' + it[this.fivePeriodsTimeName[i]].split('~')[0]),
                  // end_date: new Date(handleDatetime2(item.YearDate + ' ' + it[this.fivePeriodsTimeName[i]].split('~')[1])).getTime() < new Date().getTime() ? handleDatetime2(new Date()) : handleDatetime2(item.YearDate + ' ' + it[this.fivePeriodsTimeName[i]].split('~')[1]),
                  end_date: handleDatetime2(item.YearDate + ' ' + it[this.fivePeriodsTimeName[i]].split('~')[1]),
                  duration,
                  checked: false,
                  progress: 0,
                  parent: it.AdvaDevicNumber,
                  parent: it.AdvaDevicNumber + ind.toString(),
                  // parent: it.AdvaDevicNumber,
                  saleOrder: 'SO-2026-01001',
                  //  要在每一个时间段内算出能生产多少个     工期(分钟)乘以60 除以生产节拍 * 稼动率
                  producedCount: (duration * 60 / it.AdvaDevicRhythm) * (it.AdvaDevicCropMob / 100),
@@ -533,8 +662,58 @@
        }
      })
      // 这一步的操作是做已排的显示
      const scheduledDevices = [...new Set(Cont.map(i => i.eqp_code))]// 这是已排的设备编码
      Cont.forEach(item => {
        if (scheduledDevices.includes(item.eqp_code)) {
          newArr.push({
            id: nanoid(),
            type: 'task3',
            text: '任务名称预留',
            partName: item.part_name,
            partCode: item.part_code,
            start_date: item.time_start,
            end_date: item.time_end,
            // duration: this.calculateTimeRangeInMinutes(it.OneStartDate),
            duration: this.calculateTimeRangeInMinutes(item.time_start.split(' ')[1] + '~' + item.time_end.split(' ')[1]),
            checked: false,
            progress: 0,
            parent: item.eqp_code + '0',
            saleOrder: 'SO-2026-01001',
            producedCount: item.alloc_qty
          })
        }
      })
      // task 代表的是产能  task2 代表的是可以排产的值   task3 代表的是已排产的值
      // task2 的值得从 task减去task3的时间  代表可排产时间
      // 若同一父节点的值相同时,当task的开始时间和结束时间与task3相等时,代表此段不能再排产
      // 当task的开始时间等于task3的开始时间,但task的结束时间大于task3的结束时间时,这时候,可排产时间为:task3的结束时间到task的结束时间
      const task = newArr.filter(item => item.type === 'task')
      const task3 = newArr.filter(item => item.type === 'task3')
      task.forEach(item => { // 总产能
        task3.forEach(it => { // 已排数据
          if (item.parent === it.parent) { // 说明是在同一个设备下
            // 当两个时间相等时说明肯定不能排产了
            if (new Date(item.start_date).getTime() === new Date(it.start_date).getTime() && new Date(item.end_date).getTime() === new Date(it.end_date).getTime()) {
              item.schedulingPossible = false
            }
            if (new Date(item.start_date).getTime() === new Date(it.start_date).getTime() && new Date(item.end_date).getTime() > new Date(it.end_date).getTime()) {
              item.start_date2 = it.end_date
            }
            // 不知道要不要注释掉  待验证
            // if (new Date(item.start_date).getTime() < new Date().getTime() && item.producedCount !== it.producedCount) {
            //   item.start_date2 = handleDatetime2(new Date())
            // }
          }
        })
      })
      // 使用原有的示例数据作为基础
      this.allTasks = newArr
      this.allTasks = newArr.filter(i => i.schedulingPossible !== false)
      // this.allTasks = newArr
      this.totalTasks = this.allTasks.length
      this.updatePaginatedTasks()
@@ -657,7 +836,10 @@
      this.priorityMethodChange()// 清空已排值
      gantt.config.start_date = new Date(val[0] + ' 00:00')
      gantt.config.end_date = new Date(val[1] + ' 24:00')
      gantt.render()
      this.loadTasks()
      // gantt.render()
    },
    // 从甘特图中同步选中的 id 到 Vue data
    syncSelected() {
@@ -665,7 +847,6 @@
      gantt.eachTask((task) => {
        const globalTask = this.allTasks.find(t => t.id === task.id)
        if (globalTask) {
          // console.log(globalTask, 'globalTask')
          globalTask.checked = task.checked
        }
      })
@@ -713,11 +894,11 @@
        this.allTasks.sort((a, b) => a.start_date - b.start_date)
      }
      if (this.priorityMethod === 'device') {
        this.allTasks.sort((a, b) => Number(a.partCode.replace(/\D/g, '')) - Number(b.partCode.replace(/\D/g, '')))
        // this.allTasks.sort((a, b) => Number(b.partCode.replace(/\D/g, '')) - Number(a.partCode.replace(/\D/g, '')))
        // this.allTasks.sort((a, b) => a.producedCount - b.producedCount)
        this.allTasks.sort((a, b) => parseFloat(a.AdvaDevicCropMob) - parseFloat(b.AdvaDevicCropMob))
      }
      // 在这个循环里面还得考虑一个点,在已排的数据上不能再排了
      // 相当于在task 和task3中   要在task里面剔除掉task3的时间段
      const newArr = []
      // this.canArrangeNumber = 0
      let needArrangeNumber = this.needArrangeNumber
@@ -726,13 +907,19 @@
        if (item.type === 'task' &&
          new Date(item.start_date).getTime() >= new Date(this.ganttDateRange[0] + ' 00:00:00').getTime() &&
          new Date(item.end_date).getTime() >= new Date().getTime()) { // 这里的判断条件还得加个日期判断 结束时间要大于目前时间
          console.log(JSON.parse(JSON.stringify(item)))
          let ratio = 1 // 默认系数 1
          if (new Date(item.start_date).getTime() < new Date().getTime() && new Date(item.end_date).getTime() >= new Date().getTime()) {
            const d = this.calculateTimeRangeInMinutes(handleDatetime2(new Date()).split('  ')[1] + '~' + handleDatetime2(item.end_date).split('  ')[1])
          if (item.start_date2) {
            const d = this.calculateTimeRangeInMinutes(item.start_date2.split(' ')[1] + '~' + handleDatetime2(item.end_date).split(' ')[1])
            ratio = Math.round((d / item.duration) * 100) / 100
            console.log(ratio, 'ratio')
          }
          if (
            new Date(item.start_date).getTime() < new Date().getTime() &&
            new Date(item.end_date).getTime() >= new Date().getTime()
          ) {
            const d = this.calculateTimeRangeInMinutes(handleDatetime2(new Date()).split(' ')[1] + '~' + handleDatetime2(item.end_date).split(' ')[1])
            ratio = Math.round((d / item.duration) * 100) / 100
          }
          // 这个地方的count值 得变更  item.producedCount  得乘以个系数  默认系数 1
@@ -741,13 +928,10 @@
          if (count > 0 && (needArrangeNumber > 0 || Math.abs(needArrangeNumber) < item.producedCount * ratio)) { // 一定是大于零且小于整条的生产值的
            // duration   单位 分钟
            let duration = (count / (item.AdvaDevicCropMob / 100)) * item.AdvaDevicRhythm / 60
            if (count < item.producedCount && new Date().getTime() <= new Date(item.start_date)) {
              // console.log('执行1111')
              duration = duration * (count / item.producedCount)
              // item.end_date = '2026-01-24  11:00:00'
            }
            // console.log(duration, 'duration')
            const duration = (count / (item.AdvaDevicCropMob / 100)) * item.AdvaDevicRhythm / 60
            // if (count < item.producedCount && new Date().getTime() <= new Date(item.start_date).getTime()) {
            // duration = duration * (count / item.producedCount)   //好像注释掉就对了  待验证
            // }
            const obj = {
              id: nanoid(),
@@ -755,7 +939,7 @@
              text: '任务名称111',
              partName: item.partName,
              partCode: item.partCode,
              start_date: new Date(item.start_date).getTime() < new Date().getTime() ? handleDatetime2(new Date()) : handleDatetime2(item.start_date),
              start_date: new Date(item.start_date).getTime() < new Date().getTime() ? handleDatetime2(new Date()) : (item.start_date2 ? item.start_date2 : handleDatetime2(item.start_date)),
              // end_date: handleDatetime2(item.end_date),
              // end_date: item.end_date,
              duration, // 代表的是进度条
@@ -767,26 +951,20 @@
              // producedCount: count <= item.producedCount ? count : item.producedCount
            }
            this.canArrangeNumber += parseFloat(obj.producedCount)
            console.log(this.canArrangeNumber)
            if (Math.abs(this.canArrangeNumber - this.needArrangeNumber) === 1) {
              obj.producedCount = obj.producedCount + (this.needArrangeNumber - this.canArrangeNumber)
            }
            // 这个地方得加个逻辑,得根据世间日期进行push   下午研究一下
            newArr.push({ ...obj })
          }
        }
      })
      console.log(JSON.parse(JSON.stringify(newArr)), 'newArr')
      // for (let i = 0; i < this.allTasks.length; i++) {
      //
      // }
      this.allTasks = [...this.allTasks, ...newArr]
      // console.log(JSON.parse(JSON.stringify(this.allTasks)), '77')
      console.log(JSON.parse(JSON.stringify(this.allTasks)), '888')
@@ -802,7 +980,6 @@
      this.updatePaginatedTasks()
      this.renderGanttChart()
    }
  }
}