vue甘特图vxe-gantt如何实现拖拽任务条时如有已关联依赖线,同时更新依赖任务的日期的方式

vue甘特图vxe-gantt如何实现拖拽任务条时如有已关联依赖线,同时更新依赖任务的日期的方式

当任务关联前置任务或后置任务依赖线时,拖拽该任务时同步更新对应的起始日期和结束日期,可以通过 task-bar-drag-config.moveSetMethod 来自定义业务逻辑

基础代码

简单实现同步移动任务

html 复制代码
<template>
  <div>
    <vxe-gantt v-bind="ganttOptions"></vxe-gantt>
  </div>
</template>

<script setup>
import { reactive } from 'vue'
import { VxeGanttDependencyType } from 'vxe-gantt'
import XEUtils from 'xe-utils'

const ganttOptions = reactive({
  border: true,
  height: 600,
  rowConfig: {
    keyField: 'id' // 行主键
  },
  taskBarConfig: {
    showProgress: true, // 是否显示进度条
    showContent: true, // 是否在任务条显示内容
    moveable: true, // 是否允许拖拽任务移动日期
    resizable: true, // 是否允许拖拽任务调整日期
    linkCreatable: true, // 是否允许自定义创建依赖线
    barStyle: {
      round: true, // 圆角
      bgColor: '#fca60b', // 任务条的背景颜色
      completedBgColor: '#65c16f' // 已完成部分任务条的背景颜色
    }
  },
  taskLinkConfig: {
    isHover: true, // 当鼠标移到依赖线时,是否要高亮当前依赖线
    isCurrent: true, // 当鼠标点击依赖线时,是否要高亮当前依赖线
    isDblclickToRemove: true // 是否允许双击依赖线删除
  },
  taskViewConfig: {
    tableStyle: {
      width: 480 // 表格宽度
    }
  },
  taskBarMoveConfig: {
    // 自定义拖拽结束时任务日期被赋值的方法
    async moveSetMethod ({ row, startValue, endValue, offsetSize, linkInfo }) {
      const { toRows, fromRows } = linkInfo
      row.start = startValue
      row.end = endValue
      // 实现拖拽任务后,关联任务自动同步更新日期
      fromRows.forEach(row => {
        row.start = XEUtils.toDateString(XEUtils.getWhatDay(row.start, offsetSize), 'yyyy-MM-dd')
        row.end = XEUtils.toDateString(XEUtils.getWhatDay(row.end, offsetSize), 'yyyy-MM-dd')
      })
      toRows.forEach(row => {
        row.start = XEUtils.toDateString(XEUtils.getWhatDay(row.start, offsetSize), 'yyyy-MM-dd')
        row.end = XEUtils.toDateString(XEUtils.getWhatDay(row.end, offsetSize), 'yyyy-MM-dd')
      })
    }
  },
  links: [
    { from: 10001, to: 10002, type: VxeGanttDependencyType.FinishToFinish },
    { from: 10004, to: 10005, type: VxeGanttDependencyType.StartToStart },
    { from: 10005, to: 10006, type: VxeGanttDependencyType.FinishToStart },
    { from: 10013, to: 10012, type: VxeGanttDependencyType.StartToFinish }
  ],
  columns: [
    { type: 'seq', width: 70 },
    { field: 'title', title: '任务名称' },
    { field: 'start', title: '开始时间', width: 100 },
    { field: 'end', title: '结束时间', width: 100 },
    { field: 'progress', title: '进度(%)', width: 80 }
  ],
  data: [
    { id: 10001, title: '任务1', start: '2024-03-01', end: '2024-03-04', progress: 3 },
    { id: 10002, title: '任务2', start: '2024-03-03', end: '2024-03-08', progress: 10 },
    { id: 10003, title: '任务3', start: '2024-03-03', end: '2024-03-11', progress: 90 },
    { id: 10004, title: '任务4', start: '2024-03-05', end: '2024-03-11', progress: 15 },
    { id: 10005, title: '任务5', start: '2024-03-08', end: '2024-03-15', progress: 100 },
    { id: 10006, title: '任务6', start: '2024-03-10', end: '2024-03-21', progress: 5 },
    { id: 10007, title: '任务7', start: '2024-03-15', end: '2024-03-24', progress: 70 },
    { id: 10008, title: '任务8', start: '2024-03-05', end: '2024-03-15', progress: 50 },
    { id: 10009, title: '任务9', start: '2024-03-19', end: '2024-03-20', progress: 5 },
    { id: 10010, title: '任务10', start: '2024-03-12', end: '2024-03-20', progress: 10 },
    { id: 10011, title: '任务11', start: '2024-03-01', end: '2024-03-08', progress: 90 },
    { id: 10012, title: '任务12', start: '2024-03-03', end: '2024-03-06', progress: 60 },
    { id: 10013, title: '任务13', start: '2024-03-02', end: '2024-03-05', progress: 50 },
    { id: 10014, title: '任务14', start: '2024-03-04', end: '2024-03-15', progress: 0 },
    { id: 10015, title: '任务15', start: '2024-03-01', end: '2024-03-05', progress: 30 }
  ]
})
</script>

还可以实现更复杂的逻辑

html 复制代码
<template>
  <div>
    <vxe-gantt ref="ganttRef" v-bind="ganttOptions" @task-bar-drag-end="onTaskDragEnd"></vxe-gantt>
  </div>
</template>

<script setup>
import { reactive, ref } from 'vue'
import { VxeGanttDependencyType } from 'vxe-gantt'
import XEUtils from 'xe-utils'

const ganttRef = ref(null)

const ganttOptions = reactive({
  // ...(保持原有配置)
  taskBarMoveConfig: {
    // 自定义拖拽结束时任务日期被赋值的方法
    async moveSetMethod({ row, startValue, endValue, offsetSize, linkInfo }) {
      const { toRows, fromRows, toLinks, fromLinks } = linkInfo
    
      // 1. 获取变更前的日期(用于错误恢复)
      // const oldStart = row.start
      // const oldEnd = row.end

      // 2. 更新当前拖拽任务的日期
      row.start = startValue
      row.end = endValue


      // 4. 统一更新依赖任务的方法
      //   根据依赖类型计算出新的日期,而不是简单粗暴地整体偏移
      const updateDependentTasks = (tasks, currentRow, linkType, offsetDays) => {
        tasks.forEach(task => {
          const currentStart = new Date(currentRow.start)
          const currentEnd = new Date(currentRow.end)
          let newStart, newEnd

          // 根据不同的依赖类型,更新关联任务的日期
          switch (linkType) {
            case VxeGanttDependencyType.FinishToStart:
              // 前置任务结束后,后置任务才能开始
              newStart = XEUtils.toDateString(
                XEUtils.getWhatDay(currentRow.end, offsetDays),
                'yyyy-MM-dd'
              )
              newEnd = XEUtils.toDateString(
                XEUtils.getWhatDay(task.end, offsetDays),
                'yyyy-MM-dd'
              )
              break
            case VxeGanttDependencyType.StartToStart:
              // 两个任务同时开始
              newStart = XEUtils.toDateString(
                XEUtils.getWhatDay(currentRow.start, offsetDays),
                'yyyy-MM-dd'
              )
              newEnd = XEUtils.toDateString(
                XEUtils.getWhatDay(task.end, offsetDays),
                'yyyy-MM-dd'
              )
              break
            case VxeGanttDependencyType.FinishToFinish:
              // 两个任务同时完成
              newStart = XEUtils.toDateString(
                XEUtils.getWhatDay(task.start, offsetDays),
                'yyyy-MM-dd'
              )
              newEnd = XEUtils.toDateString(
                XEUtils.getWhatDay(currentRow.end, offsetDays),
                'yyyy-MM-dd'
              )
              break
            case VxeGanttDependencyType.StartToFinish:
              // 当前任务完成才能开始
              newStart = XEUtils.toDateString(
                XEUtils.getWhatDay(currentRow.start, offsetDays),
                'yyyy-MM-dd'
              )
              newEnd = XEUtils.toDateString(
                XEUtils.getWhatDay(task.end, offsetDays),
                'yyyy-MM-dd'
              )
              break
            default:
              // 默认整体偏移
              newStart = XEUtils.toDateString(
                XEUtils.getWhatDay(task.start, offsetDays),
                'yyyy-MM-dd'
              )
              newEnd = XEUtils.toDateString(
                XEUtils.getWhatDay(task.end, offsetDays),
                'yyyy-MM-dd'
              )
          }

          // 更新任务数据
          task.start = newStart || task.start
          task.end = newEnd || task.end
        })
      }

      // 6. 更新依赖任务(前置和后置)
      // 使用依赖关系信息来精确更新
      if (fromRows.length && fromLinks.length) {
         updateDependentTasks([fromRows[0]], row, fromLinks[0], offsetSize)
      }

      if (toRows.length && toLinks.length) {
        updateDependentTasks([toRows[0]], row, toLinks[0], offsetSize)
      }

    }
  },
  // ...(保持原有数据配置)
})

// 监听拖拽事件,执行其他业务逻辑(如保存到后端)
const onTaskDragEnd = ({ row, startValue, endValue }) => {
  // 可以在这里保存更新后的任务数据,或者执行其他业务逻辑
  console.log('任务拖拽完成', { row, startValue, endValue })
  
  // 可选:触发数据更新到后端
  // updateTaskToBackend(row)
}
</script>

依赖类型说明

依赖类型 原逻辑缺陷 优化后逻辑
FinishToStart 前置任务结束日期推迟,后置任务应该整体推迟?❌ 应该是后置任务的开始日期=前置任务的结束日期 仅更新后置任务的开始日期,保持持续时间不变
StartToStart 同时开始的任务,拖拽一个不应该导致另一个结束日期整体偏移 保持两个任务的结束日期相对不变,仅调整开始日期
FinishToFinish 两个任务同时结束,拖拽一个不应该影响另一个的开始日期 保持两个任务的开始日期相对不变,仅调整结束日期
StartToFinish 前置任务开始日期影响后置任务完成日期 根据依赖关系的具体约束来精确更新

gantt.vxeui.com

相关推荐
我有满天星辰6 小时前
Vue 3 响应式双雄:ref 与 reactive 完全指南
前端·javascript·vue.js
leoZ23117 小时前
Claude 驱动的全栈开发:Spring Boot + Vue 的 BS 架构实践
vue.js·spring boot·架构
荒诞英雄21 小时前
从 17MB Vendor 大包到按需加载:Vite 多入口 Vue 组件库首屏优化实践
vue.js·vite
jsonbro21 小时前
手把手带你实现发布订阅模式
前端·vue.js·设计模式
Cobyte1 天前
23.Vue Vapor 组件 attrs 的实现
前端·javascript·vue.js
斯特凡今天也很帅1 天前
xml页面可以打开,不报错,但是显示数据的地方也不显示,我是怎么解决的
xml·vue.js
柯克七七1 天前
给老项目加了 TypeScript,本来只想自己爽,结果全公司代码审查标准被我抬高了
前端·vue.js·typescript
自然 醒1 天前
前端如何实现在线预览office常见文件功能?
前端·vue.js
肉肉不吃 肉1 天前
前端调试跨域如何解决
前端·vue.js
卓怡学长1 天前
w268基于springboot + vue 物流系统
java·数据库·vue.js·spring boot·spring·intellij-idea