当前位置: 首页 > news >正文

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

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

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

效果

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

Video_2026-03-27_092222-ezgif.com-video-to-gif-converter

代码

<template><div><vxe-gantt ref="ganttRef" v-bind="ganttOptions" v-on="ganttEvents" /><vxe-modalv-model="editModalVisible"title="编辑任务"width="680"height="620"resizedestroy-on-closeshow-footershow-confirm-buttonshow-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 = roweditModalVisible.value = true}
}const handleConfirm = async () => {const formInstance = formRef.valueif (!formInstance) returnconst errors = await formInstance.validate()if (errors) return  // 校验失败,阻止提交const task = currentTask.valueif (task) {// 更新任务数据Object.assign(task, {name: formOptions.data.name,startDate: formOptions.data.startDate,endDate: formOptions.data.endDate,progress: formOptions.data.progress})}editModalVisible.value = falseVxeUI.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 = roweditModalVisible.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 = falseVxeUI.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]

http://www.jsqmd.com/news/543275/

相关文章:

  • Plink实战:如何快速提取特定SNP数据(附常见错误解决)
  • 基于爱毕业AI的改写方案,五招快速解决论文30%重复率问题
  • SDXL-Turbo在虚拟现实中的应用:实时环境生成技术
  • 山东一卡通回收必读:如何选择靠谱回收平台? - 团团收购物卡回收
  • 瑞祥卡回收攻略:如何选择回收平台 - 团团收购物卡回收
  • Protobuf 在 LuatOS 中的实现与应用:高效序列化,简化嵌入式开发
  • Pixel Fashion Atelier保姆级教程:修复WebUI中文乱码与像素字体缺失问题
  • 2026年热门的高压均质机/羊汤均质机制造厂家哪家靠谱 - 行业平台推荐
  • 记一例DNS解析导致的系统卡顿问题
  • 不写代码玩AI:OpenClaw+百川2-13B-4bits可视化任务编排实战
  • 用IndexTTS-2-LLM做有声读物:快速将文字变成生动语音
  • macOS下OpenClaw安装:无缝对接nanobot轻量模型
  • 建筑模型转换革新:Web3D时代的BIM模型轻量化突破
  • 2026年移动/矿山/应急/二手/超静音/大功率发电机厂家推荐:哈尔滨铭哲机电专业供应 - 品牌推荐官
  • 利用OFA-Image-Caption自动生成Latex论文图表标题与描述
  • 围绕杭州盈创环境科技:RTO可燃气体检测仪,信用优企业、优质型号及保养攻略 - 品牌推荐大师
  • 2026年锂矿/磷矿/硫铁矿/铝土矿浮选机厂家推荐:江西省昌亿矿山机械全系供应 - 品牌推荐官
  • Blender3mfFormat完全掌握:4个技术要点解决3D打印文件格式兼容难题
  • Linux环境变量设置避坑指南:为什么你的PATH修改总是不生效?
  • PyTorch 2.8通用镜像实操手册:Git LFS管理大模型权重文件最佳实践
  • 欧洲留学机构排行2026|北京市场权威评估与核心指标解析——选择靠谱服务商全 - 企业推荐师
  • 手把手教你用Dify+Ollama,在本地电脑搭建一个完全免费的私有知识库问答机器人
  • 2026年欧洲留学机构排行|国内权威评估与核心指标解析——选择靠谱服务商 - 企业推荐师
  • 高可用、高性能的分布式系统时,网络协议是底层的“血管”。理解 TCP/IP 模型、TCP 的状态机机制以及 UDP 的适用场景
  • 爱毕业aibye等工具的智能降重方案,五步操作让30%重复论文达标
  • 寄快递便宜哪家好?2026年实用避坑指南
  • 2026年菲尼克斯端子服务商推荐:福州辰信自动化设备,菲尼克斯端板/导轨/电缆连接器服务商精选 - 品牌推荐官
  • R 循环:深度解析与高效运用
  • 当Hector SLAM建图‘跑偏’了怎么办?聊聊我们调试绝影X20导航时遇到的地图对齐问题
  • OpenClaw技能开发入门:为百川2-13B定制自动化简历筛选器