vue甘特图vxe-gantt实现点击任务条弹出编辑表单效果

 更新时间:2026年03月27日 09:45:40   作者:zhiy3  
本文将介绍如何使用 vxe-gantt 组件实现点击任务条弹出编辑表单的功能,支持对任务的名称、时间、进度、负责人、图片附件等信息进行编辑,感兴趣的朋友跟随小编一起看看吧

基于 vxe-gantt 实现任务条点击编辑表单

在项目管理中,甘特图是展示任务进度的核心组件。本文将介绍如何使用 vxe-gantt 组件实现点击任务条弹出编辑表单的功能,支持对任务的名称、时间、进度、负责人、图片附件等信息进行编辑。

效果

点击甘特图中的任意任务条,系统会弹出模态框,展示当前任务的详细表单,编辑保存后甘特图视图自动刷新。

代码

<template>
  <div>
    <vxe-gantt ref="ganttRef" v-bind="ganttOptions" v-on="ganttEvents" />
    <vxe-modal
      v-model="editModalVisible"
      title="编辑任务"
      width="680"
      height="620"
      resize
      destroy-on-close
      show-footer
      show-confirm-button
      show-cancel-button
      :confirm-closable="false"
      @confirm="handleConfirm"
    >
      <vxe-form ref="formRef" v-bind="formOptions" />
    </vxe-modal>
  </div>
</template>
<script setup>
import { ref, reactive } from 'vue'
import { VxeUI } from 'vxe-pc-ui'
import XEUtils from 'xe-utils'
import axios from 'axios'
// ---------- 状态管理 ----------
const editModalVisible = ref(false)
const currentTask = ref(null)        // 当前正在编辑的任务
const ganttRef = ref()
const formRef = ref()
// ---------- 甘特图配置 ----------
const ganttOptions = reactive({
  border: true,
  taskConfig: {
    titleField: 'name',        // 任务名称字段
    startField: 'startDate',   // 开始时间字段
    endField: 'endDate',       // 结束时间字段
    progressField: 'progress'  // 进度字段
  },
  taskBarConfig: {
    showProgress: true,        // 显示进度百分比
    showContent: true,         // 显示任务名称
    barStyle: {
      bgColor: '#f56565',      // 未完成部分颜色
      completedBgColor: '#65c16f' // 已完成部分颜色
    }
  },
  taskViewConfig: {
    tableStyle: { width: 380 } // 左侧任务列表宽度
  },
  columns: [
    { field: 'name', title: '任务名称', minWidth: 160 },
    { field: 'startDate', title: '开始时间', width: 100 },
    { field: 'endDate', title: '结束时间', width: 100 },
    { field: 'progress', title: '进度', width: 60 },
    { field: 'responsibleBy', title: '负责人', width: 140 },
    { field: 'description', title: '备注', width: 200 },
    { field: 'createBy', title: '创建人', width: 160 },
    { field: 'imgList', title: '图片', width: 160, cellRender: imageCellRender },
    { field: 'updateBy', title: '最后更新人', width: 180 },
    { field: 'createDate', title: '创建时间', width: 140 },
    { field: 'updateDate', title: '更新时间', width: 140 }
  ],
  data: []
})
// ---------- 表格渲染器配置 ----------
const imageCellRender = reactive({
  name: 'VxeImage',
  props: { width: 36, height: 36 }
})
// ---------- 表单上传配置 ----------
const imageUploadRender = reactive({
  name: 'VxeUpload',
  props: {
    mode: 'image',
    multiple: true,
    urlMode: true,
    moreConfig: { maxCount: 2 },
    uploadMethod: async ({ file }) => {
      const formData = new FormData()
      formData.append('file', file)
      const res = await axios.post('/publicapi/api/pub/upload/single', formData)
      return res.data  // 期望返回 { url: '...' }
    }
  }
})
const fileUploadRender = reactive({
  name: 'VxeUpload',
  props: {
    multiple: true,
    moreConfig: { maxCount: 2 },
    uploadMethod: async ({ file }) => {
      const formData = new FormData()
      formData.append('file', file)
      const res = await axios.post('/publicapi/api/pub/upload/single', formData)
      return res.data  // 期望返回 { url: '...' }
    }
  }
})
// ---------- 表单配置 ----------
const formOptions = reactive({
  titleWidth: 'auto',
  titleAlign: 'right',
  titleColon: true,
  data: {
    name: '',
    startDate: '',
    endDate: '',
    progress: 0,
    responsibleBy: '',
    description: '',
    imgList: [],
    fileList: []
  },
  rules: {
    name: [{ required: true, message: '任务名称不能为空' }],
    startDate: [{ required: true, message: '开始时间不能为空' }],
    endDate: [{ required: true, message: '结束时间不能为空' }],
    progress: [{ required: true, message: '进度不能为空' }],
    responsibleBy: [{ required: true, message: '负责人不能为空' }]
  },
  items: [
    { field: 'name', title: '任务名称', span: 24, itemRender: { name: 'VxeInput' } },
    { field: 'startDate', title: '开始时间', span: 12, itemRender: { name: 'VxeDatePicker' } },
    { field: 'endDate', title: '结束时间', span: 12, itemRender: { name: 'VxeDatePicker' } },
    { field: 'progress', title: '进度', span: 12, itemRender: { name: 'VxeNumberInput', props: { type: 'integer', min: 0, max: 100 } } },
    { field: 'responsibleBy', title: '负责人', span: 12, itemRender: { name: 'VxeInput' } },
    { field: 'description', title: '备注', span: 24, itemRender: { name: 'VxeInput' } },
    { field: 'imgList', title: '图片', span: 24, itemRender: imageUploadRender },
    { field: 'fileList', title: '附件', span: 24, itemRender: fileUploadRender }
  ]
})
// ---------- 事件处理 ----------
const ganttEvents = {
  taskBarClick: ({ row }) => {
    // 将行数据解构到表单数据中
    XEUtils.destructuring(formOptions.data, row)
    currentTask.value = row
    editModalVisible.value = true
  }
}
const handleConfirm = async () => {
  const formInstance = formRef.value
  if (!formInstance) return
  const errors = await formInstance.validate()
  if (errors) return  // 校验失败,阻止提交
  const task = currentTask.value
  if (task) {
    // 更新任务数据
    Object.assign(task, {
      name: formOptions.data.name,
      startDate: formOptions.data.startDate,
      endDate: formOptions.data.endDate,
      progress: formOptions.data.progress
    })
  }
  editModalVisible.value = false
  VxeUI.modal.message({ content: '保存成功', status: 'success' })
  // 刷新甘特图视图
  if (ganttRef.value) {
    ganttRef.value.refreshTaskView()
  }
}
</script>

核心实现解析

1. 任务点击事件绑定

通过 ganttEvents 对象定义 taskBarClick 回调,当用户点击任务条时触发:

const ganttEvents = {
  taskBarClick: ({ row }) => {
    // 将点击的任务数据填充到表单
    XEUtils.destructuring(formOptions.data, row)
    currentTask.value = row
    editModalVisible.value = true
  }
}
  • row 参数包含当前任务的所有字段
  • 使用 XEUtils.destructuring 将行数据映射到表单的 data 对象,实现数据填充

2. 表单数据绑定

表单通过 vxe-formdata 属性与 formOptions.data 绑定,当用户修改表单内容时,数据实时同步:

const formOptions = reactive({
  data: {
    name: '',
    startDate: '',
    endDate: '',
    progress: 0,
    // ... 其他字段
  },
  // ...
})

3. 保存与刷新

点击模态框的“确认”按钮时,执行 handleConfirm

const handleConfirm = async () => {
  // 1. 表单校验
  const errors = await formRef.value.validate()
  if (errors) return
  // 2. 更新任务数据
  Object.assign(currentTask.value, {
    name: formOptions.data.name,
    startDate: formOptions.data.startDate,
    endDate: formOptions.data.endDate,
    progress: formOptions.data.progress
  })
  // 3. 关闭模态框并提示
  editModalVisible.value = false
  VxeUI.modal.message({ content: '保存成功', status: 'success' })
  // 4. 刷新甘特图视图
  ganttRef.value?.refreshTaskView()
}
  • 表单校验:确保必填项已填写
  • 数据更新:使用 Object.assign 将表单数据写回原任务对象
  • 视图刷新:调用 refreshTaskView() 让甘特图重新渲染

4. 文件上传支持

通过 VxeUpload 组件实现图片和附件的上传功能:

const imageUploadRender = reactive({
  name: 'VxeUpload',
  props: {
    mode: 'image',
    multiple: true,
    urlMode: true,
    moreConfig: { maxCount: 2 },
    uploadMethod: async ({ file }) => {
      const formData = new FormData()
      formData.append('file', file)
      const res = await axios.post('/api/upload', formData)
      return res.data  // 返回 { url: '...' }
    }
  }
})
  • urlMode 启用后,组件直接管理 URL 列表,无需手动处理文件对象
  • uploadMethod 定义上传逻辑,返回上传后的文件 URL

[https://gantt.vxeui.com]

到此这篇关于vue甘特图vxe-gantt实现点击任务条弹出编辑表单效果的文章就介绍到这了,更多相关vue甘特图vxe-gantt内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • vue的diff算法知识点总结

    vue的diff算法知识点总结

    本篇文章给大家分享了关于vue的diff算法的相关知识点总结,有兴趣的朋友参考学习下。
    2018-03-03
  • Vue3中如何使用SCSS编写样式

    Vue3中如何使用SCSS编写样式

    在Vue模板中启用这些表现力库插件的最简单方法是在初始化项目时安装它们,或使用 npm install(或 yarn add)安装包,这篇文章主要介绍了Vue3中如何使用SCSS编写样式,需要的朋友可以参考下
    2023-12-12
  • 详解element-ui设置下拉选择切换必填和非必填

    详解element-ui设置下拉选择切换必填和非必填

    这篇文章主要介绍了详解element-ui设置下拉选择切换必填和非必填,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-06-06
  • Vue实现boradcast和dispatch的示例

    Vue实现boradcast和dispatch的示例

    这篇文章主要介绍了Vue实现boradcast和dispatch的示例,帮助大家更好的理解和使用vue,感兴趣的朋友可以了解下
    2020-11-11
  • vue打包之后的dist文件如何运行

    vue打包之后的dist文件如何运行

    我们知道使用webpack打包vue项目后会生成一个dist文件夹,dist文件夹下有html文件和其他css、js以及图片等,那么打包后的文件该如何正确运行呢?这篇文章主要给大家介绍了关于vue打包之后的dist文件如何运行的相关资料,需要的朋友可以参考下
    2023-05-05
  • Vue报错Component name"Home"should always be multi问题

    Vue报错Component name"Home"should always be mult

    这篇文章主要介绍了Vue报错Component name"Home"should always be multi问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • Vue 子组件与数据传递问题及注意事项

    Vue 子组件与数据传递问题及注意事项

    这篇文章主要介绍了Vue子组件与数据传递问题及需要注意事项,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-07-07
  • laravel5.3 vue 实现收藏夹功能实例详解

    laravel5.3 vue 实现收藏夹功能实例详解

    这篇文章主要介绍了laravel5.3 vue 实现收藏夹功能,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2018-01-01
  • Vue3项目页面实现echarts图表渐变色的动态配置的实现步骤

    Vue3项目页面实现echarts图表渐变色的动态配置的实现步骤

    在开发可配置业务平台时,需要实现让用户对项目内echarts图表的动态配置,让用户脱离代码也能实现简单的图表样式配置,颜色作为图表样式的重要组成部分,其配置方式是项目要解决的重点问题,所以本文介绍了Vue3项目页面实现echarts图表渐变色的动态配置
    2024-10-10
  • 从源码角度来回答keep-alive组件的缓存原理

    从源码角度来回答keep-alive组件的缓存原理

    这篇文章主要介绍了从源码角度来回答keep-alive组件的缓存原理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01

最新评论