在项目管理中,计划进度与实际进度的对比是衡量执行偏差的关键指标。vxe-gantt 提供了灵活的树形结构和自定义任务条能力,通过巧妙的数据拆分策略,我们可以在一棵甘特树中同时展示计划和实际两条进度条,并且支持从一级到多级的完整继承。
本文将分两个方式来实现方案:
- 一级双进度:仅对顶层任务拆分计划和实际,子任务不拆分。
- 多级双进度:所有层级(包括孙任务)都展示计划和实际,父级自动汇总子级进度
实现一级双进度
实现计划进度和实际进度双进度任务条;以此为例,不管是三层进度、四层进度都能轻松实现们,该方式只能对一级任务进行拆分,无法再拆分子级。
思路
vxe-gantt 的树形甘特图支持通过 treeConfig 将扁平数据转换为树结构。要实现"计划/实际"双进度,最直接的方法是将每个原始任务拆分为两条虚拟记录:
- 计划记录:使用计划日期字段(planStartDate / planEndDate)
- 实际记录:使用实际日期字段(actualStartDate / actualEndDate)
这两条记录作为原始任务的子级(或同级),通过自定义 type 字段标记为 Subview(子任务视图),并分别赋予不同的颜色和样式,从而实现视觉上的双条对比。
关键配置项
| 配置 | 作用 |
|---|---|
| treeConfig | 启用树形结构,自定义主键和父键字段。 |
| taskConfig | 映射日期、进度、标题等字段到数据属性。 |
| taskBarSubviewConfig | 子任务视图的样式(偏移位置、颜色等)。 |
| VxeGanttTaskType.Subview | 标记该行作为子任务视图,在父行内展开。 |
样式区分
在 taskBarConfig.barStyle 中根据 flag 返回不同颜色:
javascript
taskBarConfig: {
barStyle({ row }) {
return {
bgColor: row.flag === 1 ? '#40d9eff' : '#31d231' // 计划蓝色,实际绿色
}
}
}
代码
适用场景:只需要对比顶层任务的计划与实际,子任务不需要单独展示双进度。
数据转换逻辑
对每个原始任务,生成两条新记录:
- 计划记录:flag: 1,使用计划日期
- 实际记录:flag: 2,使用实际日期
如果原始任务有子任务(hasChild: true),则将其类型设为 Subview,以便在父行内展开显示。

html
<template>
<div>
<vxe-switch v-model="treeConfig.showIcon"></vxe-switch>
<vxe-gantt v-bind="ganttOptions"></vxe-gantt>
</div>
</template>
<script setup>
import { reactive } from 'vue'
import { VxeGanttTaskType } from 'vxe-gantt'
const treeConfig = reactive({
transform: true, // 自动将列表转为树结构
rowField: 'newId', // 自定义树节点关联的主键
parentField: 'newParentId', // 自定义树节点关联的父节点的字段名
showIcon: false // 是否显示展开按钮
})
const ganttOptions = reactive({
border: true,
height: 600,
treeConfig,
columnConfig: {
resizable: true
},
taskConfig: {
titleField: 'title', // 自定义标题字段名
startField: 'start', // 自定义开始日期字段名
endField: 'end', // 自定义结束期字段名
progressField: 'progress', // 自定义进度值字段名
typeField: 'type' // 自定义渲染类型字段名
},
taskBarSubviewConfig: {
showOverview: true, // 是否显示任务总览,当子任务被展开后自动显示任务总览
// 自定义子任务视图任务条的样式
barStyle({ row }) {
if (row.flag === 1) {
return {
backgroundColor: '#40d9eff'
}
}
if (row.flag === 2) {
return {
backgroundColor: '#31d231'
}
}
}
},
taskBarConfig: {
showContent: true, // 是否在任务条显示内容
moveable: true, // 是否允许拖拽任务移动日期
resizable: true, // 是否允许拖拽任务调整日期
barStyle({ row }) {
return {
round: true, // 圆角
bgColor: row.flag === 1 ? '#40d9eff' : '#31d231' // 已完成部分任务条的背景颜色
}
}
},
taskViewConfig: {
tableStyle: {
width: 200
},
viewStyle: {
border: 'inner'
}
},
columns: [
{ field: 'newTitle', title: '任务名称', minWidth: 160, treeNode: true },
{ field: 'planStartDate', title: '计划开始日期', width: 140 },
{ field: 'planEndDate', title: '实际 结束日期', width: 140 },
{ field: 'actualStartDate', title: '计划开始日期', width: 140 },
{ field: 'actualEndDate', title: '实际结束日期', width: 140 }
],
data: []
})
// 将实际和计划一分二
const handleMultiTask = (list) => {
const multiRest = []
list.forEach((item) => {
// 计划
const planRow = {
...item,
newTitle: `计划:${item.title}`,
flag: 1,
newId: `p${item.id}`,
newParentId: item.parentId ? `p${item.parentId}` : null,
start: item.planStartDate,
end: item.planEndDate,
progress: 0
}
// 实际
const actualRow = {
...item,
newTitle: `实际:${item.title}`,
flag: 2,
newId: `a${item.id}`,
newParentId: item.parentId ? `a${item.parentId}` : null,
start: item.actualStartDate,
end: item.actualEndDate,
progress: 0
}
if (item.hasChild) {
planRow.type = VxeGanttTaskType.Subview
actualRow.type = VxeGanttTaskType.Subview
}
multiRest.push(planRow, actualRow)
})
return multiRest
}
const loadList = () => {
const list = [
{ id: 10001, parentId: null, title: '任务1', planStartDate: '', planEndDate: '', actualStartDate: '', actualEndDate: '', planProgress: 90, actualProgress: 80, hasChild: true },
{ id: 10002, parentId: 10001, title: '任务2', planStartDate: '2024-02-27', planEndDate: '2024-03-03', actualStartDate: '2024-03-01', actualEndDate: '2024-03-02', planProgress: 90, actualProgress: 80 },
{ id: 10003, parentId: null, title: '任务3', planStartDate: '', planEndDate: '', actualStartDate: '', actualEndDate: '', planProgress: 90, actualProgress: 80, hasChild: true },
{ id: 10004, parentId: 10003, title: '任务4', planStartDate: '2024-03-01', planEndDate: '2024-03-02', actualStartDate: '2024-03-03', actualEndDate: '2024-03-04', planProgress: 90, actualProgress: 80 },
{ id: 10005, parentId: 10003, title: '任务5', planStartDate: '2024-03-03', planEndDate: '2024-03-05', actualStartDate: '2024-03-04', actualEndDate: '2024-03-07', planProgress: 90, actualProgress: 80 },
{ id: 10006, parentId: 10003, title: '任务6', planStartDate: '2024-03-19', planEndDate: '2024-03-22', actualStartDate: '2024-03-17', actualEndDate: '2024-03-20', planProgress: 90, actualProgress: 80 },
{ id: 10008, parentId: null, title: '任务8', planStartDate: '', planEndDate: '', actualStartDate: '', actualEndDate: '', planProgress: 90, actualProgress: 80, hasChild: true },
{ id: 10009, parentId: 10008, title: '任务9', planStartDate: '2024-03-02', planEndDate: '2024-03-03', actualStartDate: '2024-03-02', actualEndDate: '2024-03-03', planProgress: 90, actualProgress: 80 },
{ id: 10010, parentId: 10008, title: '任务10', planStartDate: '2024-03-05', planEndDate: '2024-03-07', actualStartDate: '2024-03-05', actualEndDate: '2024-03-09', planProgress: 90, actualProgress: 80 },
{ id: 10011, parentId: 10008, title: '任务11', planStartDate: '2024-03-08', planEndDate: '2024-03-11', actualStartDate: '2024-03-11', actualEndDate: '2024-03-15', planProgress: 90, actualProgress: 80 },
{ id: 10012, parentId: null, title: '任务12', planStartDate: '', planEndDate: '', actualStartDate: '', actualEndDate: '', planProgress: 90, actualProgress: 80, hasChild: true },
{ id: 10013, parentId: 10012, title: '任务13', planStartDate: '2024-03-04', planEndDate: '2024-03-05', actualStartDate: '2024-03-06', actualEndDate: '2024-03-08', planProgress: 90, actualProgress: 80 },
{ id: 10014, parentId: 10012, title: '任务14', planStartDate: '2024-03-06', planEndDate: '2024-03-07', actualStartDate: '2024-03-05', actualEndDate: '2024-03-05', planProgress: 90, actualProgress: 80 },
{ id: 10015, parentId: 10012, title: '任务15', planStartDate: '2024-03-09', planEndDate: '2024-03-12', actualStartDate: '2024-03-10', actualEndDate: '2024-03-11', planProgress: 90, actualProgress: 80 },
{ id: 10016, parentId: 10012, title: '任务16', planStartDate: '2024-03-13', planEndDate: '2024-03-15', actualStartDate: '2024-03-14', actualEndDate: '2024-03-16', planProgress: 90, actualProgress: 80 },
{ id: 10017, parentId: 10012, title: '任务17', planStartDate: '2024-03-17', planEndDate: '2024-03-21', actualStartDate: '2024-03-17', actualEndDate: '2024-03-18', planProgress: 90, actualProgress: 80 },
{ id: 10018, parentId: null, title: '任务18', planStartDate: '2024-03-11', planEndDate: '2024-03-12', actualStartDate: '2024-03-12', actualEndDate: '2024-03-15', planProgress: 90, actualProgress: 80 },
{ id: 10019, parentId: null, title: '任务19', planStartDate: '2024-03-15', planEndDate: '2024-03-17', actualStartDate: '2024-03-17', actualEndDate: '2024-03-20', planProgress: 90, actualProgress: 80 },
{ id: 10020, parentId: null, title: '任务20', planStartDate: '', planEndDate: '', actualStartDate: '', actualEndDate: '', planProgress: 90, actualProgress: 80, hasChild: true },
{ id: 10021, parentId: 10020, title: '任务21', planStartDate: '2024-03-18', planEndDate: '2024-03-21', actualStartDate: '2024-03-19', actualEndDate: '2024-03-21', planProgress: 90, actualProgress: 80 },
{ id: 10022, parentId: 10020, title: '任务22', planStartDate: '2024-03-23', planEndDate: '2024-03-25', actualStartDate: '2024-03-23', actualEndDate: '2024-03-25', planProgress: 90, actualProgress: 80 },
{ id: 10023, parentId: 10020, title: '任务23', planStartDate: '2024-03-27', planEndDate: '2024-04-02', actualStartDate: '2024-03-27', actualEndDate: '2024-03-28', planProgress: 90, actualProgress: 80 },
{ id: 10024, parentId: 10020, title: '任务24', planStartDate: '2024-04-04', planEndDate: '2024-04-06', actualStartDate: '2024-04-02', actualEndDate: '2024-04-05', planProgress: 90, actualProgress: 80 },
{ id: 10025, parentId: 10020, title: '任务25', planStartDate: '2024-04-07', planEndDate: '2024-04-11', actualStartDate: '2024-04-08', actualEndDate: '2024-04-13', planProgress: 90, actualProgress: 80 },
{ id: 10026, parentId: null, title: '任务26', planStartDate: '2024-04-05', planEndDate: '2024-04-08', actualStartDate: '2024-04-07', actualEndDate: '2024-04-10', planProgress: 90, actualProgress: 80 },
{ id: 10027, parentId: null, title: '任务27', planStartDate: '', planEndDate: '', actualStartDate: '', actualEndDate: '', planProgress: 90, actualProgress: 80, hasChild: true },
{ id: 10028, parentId: 10027, title: '任务28', planStartDate: '2024-03-10', planEndDate: '2024-03-13', actualStartDate: '2024-03-13', actualEndDate: '2024-03-14', planProgress: 90, actualProgress: 80 },
{ id: 10029, parentId: 10027, title: '任务29', planStartDate: '2024-03-14', planEndDate: '2024-03-18', actualStartDate: '2024-03-16', actualEndDate: '2024-03-18', planProgress: 90, actualProgress: 80 },
{ id: 10030, parentId: 10027, title: '任务30', planStartDate: '2024-03-19', planEndDate: '2024-03-25', actualStartDate: '2024-03-20', actualEndDate: '2024-03-26', planProgress: 90, actualProgress: 80 },
{ id: 10031, parentId: null, title: '任务31', planStartDate: '2024-03-22', planEndDate: '2024-03-24', actualStartDate: '2024-03-19', actualEndDate: '2024-03-20', planProgress: 90, actualProgress: 80 },
{ id: 10032, parentId: null, title: '任务32', planStartDate: '', planEndDate: '', actualStartDate: '', actualEndDate: '', planProgress: 90, actualProgress: 80, hasChild: true },
{ id: 10033, parentId: 10032, title: '任务33', planStartDate: '2024-03-09', planEndDate: '2024-03-14', actualStartDate: '2024-03-11', actualEndDate: '2024-03-15', planProgress: 90, actualProgress: 80 },
{ id: 10034, parentId: 10032, title: '任务34', planStartDate: '2024-03-15', planEndDate: '2024-03-21', actualStartDate: '2024-03-16', actualEndDate: '2024-03-19', planProgress: 90, actualProgress: 80 }
]
const multiRest = handleMultiTask(list)
ganttOptions.data = multiRest
}
loadList()
</script>
实现多级双进度
适用场景:需要每一层级的子任务都展示计划与实际,且父级自动汇总子级进度。
数据转换策略
与一级方案不同,这里将每个叶子任务拆分为计划和实际两条记录,而每个父级任务(hasChild: true)则作为一个独立的 Subview 组节点,其子节点包含该父级下所有叶子任务的计划和实际记录。这样,无论嵌套多少层,每一层都能独立展示双进度。
子任务视图偏移
为了让计划和实际条在视觉上不重叠,在 taskBarSubviewConfig.barStyle 中设置 top 偏移:
javascript
taskBarSubviewConfig: {
barStyle({ row }) {
if (row.flag === 1) {
return { top: '-12px', backgroundColor: '#40d9eff' }
}
if (row.flag === 2) {
return { top: '12px', backgroundColor: '#31d231' }
}
}
}
- 计划条上移 12px,实际条下移 12px,形成双条并排效果。
- 父级组节点自动汇总子级进度,并显示为"总览"条。
代码

html
<template>
<div>
<vxe-switch v-model="treeConfig.showIcon"></vxe-switch>
<vxe-gantt v-bind="ganttOptions"></vxe-gantt>
</div>
</template>
<script setup>
import { reactive } from 'vue'
import { VxeGanttTaskType } from 'vxe-gantt'
const treeConfig = reactive({
transform: true, // 自动将列表转为树结构
rowField: 'newId', // 自定义树节点关联的主键
parentField: 'newParentId', // 自定义树节点关联的父节点的字段名
showIcon: true // 是否显示展开按钮
})
const ganttOptions = reactive({
border: true,
height: 600,
columnConfig: {
resizable: true
},
treeConfig,
taskConfig: {
titleField: 'newTitle', // 自定义标题字段名
startField: 'start', // 自定义开始日期字段名
endField: 'end', // 自定义结束期字段名
progressField: 'progress', // 自定义进度值字段名
typeField: 'type' // 自定义渲染类型字段名
},
taskBarSubviewConfig: {
showOverview: true, // 是否显示任务总览,当子任务被展开后自动显示任务总览
// 自定义子任务视图任务条的样式
barStyle({ row }) {
if (row.flag === 1) {
return {
top: '-12px', // 偏移位置,计划于实际不重叠
backgroundColor: '#40d9eff'
}
}
if (row.flag === 2) {
return {
top: '12px', // 偏移位置,计划于实际不重叠
backgroundColor: '#31d231'
}
}
}
},
taskBarConfig: {
showContent: true, // 是否在任务条显示内容
moveable: true, // 是否允许拖拽任务移动日期
resizable: true, // 是否允许拖拽任务调整日期
barStyle({ row }) {
return {
round: true, // 圆角
bgColor: row.flag === 1 ? '#40d9eff' : '#31d231' // 已完成部分任务条的背景颜色
}
}
},
taskViewConfig: {
tableStyle: {
width: 200
},
viewStyle: {
border: 'inner'
}
},
columns: [
{ field: 'newTitle', title: '任务名称', minWidth: 160, treeNode: true },
{ field: 'planStartDate', title: '计划开始日期', width: 140 },
{ field: 'planEndDate', title: '实际 结束日期', width: 140 },
{ field: 'actualStartDate', title: '计划开始日期', width: 140 },
{ field: 'actualEndDate', title: '实际结束日期', width: 140 }
],
data: []
})
// 将实际和计划一分二
const handleMultiTask = (list) => {
const multiRest = []
list.forEach((item) => {
if (item.hasChild) {
const groupRow = {
...item,
newTitle: `${item.title}`,
flag: 3,
newId: `g${item.id}`,
newParentId: item.parentId ? `g${item.parentId}` : null,
start: '',
end: '',
progress: 0,
type: VxeGanttTaskType.Subview
}
multiRest.push(groupRow)
} else {
// 计划
const planRow = {
...item,
newTitle: `计划:${item.title}`,
flag: 1,
newId: `p${item.id}`,
newParentId: item.parentId ? `g${item.parentId}` : null,
start: item.planStartDate,
end: item.planEndDate,
progress: 0
}
// 实际
const actualRow = {
...item,
newTitle: `实际:${item.title}`,
flag: 2,
newId: `a${item.id}`,
newParentId: item.parentId ? `g${item.parentId}` : null,
start: item.actualStartDate,
end: item.actualEndDate,
progress: 0
}
multiRest.push(planRow, actualRow)
}
})
return multiRest
}
const loadList = () => {
const list = [
{ id: 10001, parentId: null, title: '任务1', planStartDate: '', planEndDate: '', actualStartDate: '', actualEndDate: '', planProgress: 90, actualProgress: 80, hasChild: true },
{ id: 10002, parentId: 10001, title: '任务2', planStartDate: '2024-02-27', planEndDate: '2024-03-03', actualStartDate: '2024-03-01', actualEndDate: '2024-03-02', planProgress: 90, actualProgress: 80 },
{ id: 10003, parentId: null, title: '任务3', planStartDate: '', planEndDate: '', actualStartDate: '', actualEndDate: '', planProgress: 90, actualProgress: 80, hasChild: true },
{ id: 10004, parentId: 10003, title: '任务4', planStartDate: '2024-03-01', planEndDate: '2024-03-02', actualStartDate: '2024-03-03', actualEndDate: '2024-03-04', planProgress: 90, actualProgress: 80 },
{ id: 10005, parentId: 10003, title: '任务5', planStartDate: '2024-03-03', planEndDate: '2024-03-05', actualStartDate: '2024-03-04', actualEndDate: '2024-03-07', planProgress: 90, actualProgress: 80, hasChild: true },
{ id: 10006, parentId: 10003, title: '任务6', planStartDate: '2024-03-19', planEndDate: '2024-03-22', actualStartDate: '2024-03-17', actualEndDate: '2024-03-20', planProgress: 90, actualProgress: 80 },
{ id: 10007, parentId: 10005, title: '任务7', planStartDate: '2024-03-17', planEndDate: '2024-03-20', actualStartDate: '2024-03-19', actualEndDate: '2024-03-22', planProgress: 90, actualProgress: 80 },
{ id: 10008, parentId: null, title: '任务8', planStartDate: '', planEndDate: '', actualStartDate: '', actualEndDate: '', planProgress: 90, actualProgress: 80, hasChild: true },
{ id: 10009, parentId: 10008, title: '任务9', planStartDate: '2024-03-02', planEndDate: '2024-03-03', actualStartDate: '2024-03-02', actualEndDate: '2024-03-03', planProgress: 90, actualProgress: 80 },
{ id: 10010, parentId: 10008, title: '任务10', planStartDate: '2024-03-05', planEndDate: '2024-03-07', actualStartDate: '2024-03-05', actualEndDate: '2024-03-09', planProgress: 90, actualProgress: 80 },
{ id: 10011, parentId: 10008, title: '任务11', planStartDate: '2024-03-08', planEndDate: '2024-03-11', actualStartDate: '2024-03-11', actualEndDate: '2024-03-15', planProgress: 90, actualProgress: 80 },
{ id: 10012, parentId: null, title: '任务12', planStartDate: '', planEndDate: '', actualStartDate: '', actualEndDate: '', planProgress: 90, actualProgress: 80, hasChild: true },
{ id: 10013, parentId: 10012, title: '任务13', planStartDate: '2024-03-04', planEndDate: '2024-03-05', actualStartDate: '2024-03-06', actualEndDate: '2024-03-08', planProgress: 90, actualProgress: 80 },
{ id: 10014, parentId: 10012, title: '任务14', planStartDate: '2024-03-06', planEndDate: '2024-03-07', actualStartDate: '2024-03-03', actualEndDate: '2024-03-05', planProgress: 90, actualProgress: 80 },
{ id: 10015, parentId: 10012, title: '任务15', planStartDate: '2024-03-09', planEndDate: '2024-03-12', actualStartDate: '2024-03-10', actualEndDate: '2024-03-11', planProgress: 90, actualProgress: 80, hasChild: true },
{ id: 10016, parentId: 10012, title: '任务16', planStartDate: '2024-03-13', planEndDate: '2024-03-15', actualStartDate: '2024-03-17', actualEndDate: '2024-03-18', planProgress: 90, actualProgress: 80, hasChild: true },
{ id: 10017, parentId: 10012, title: '任务17', planStartDate: '2024-03-17', planEndDate: '2024-03-21', actualStartDate: '2024-03-18', actualEndDate: '2024-03-19', planProgress: 90, actualProgress: 80 },
{ id: 10018, parentId: null, title: '任务18', planStartDate: '2024-03-11', planEndDate: '2024-03-12', actualStartDate: '2024-03-12', actualEndDate: '2024-03-15', planProgress: 90, actualProgress: 80 },
{ id: 10019, parentId: null, title: '任务19', planStartDate: '2024-03-15', planEndDate: '2024-03-17', actualStartDate: '2024-03-17', actualEndDate: '2024-03-20', planProgress: 90, actualProgress: 80 },
{ id: 10020, parentId: null, title: '任务20', planStartDate: '', planEndDate: '', actualStartDate: '', actualEndDate: '', planProgress: 90, actualProgress: 80, hasChild: true },
{ id: 10021, parentId: 10020, title: '任务21', planStartDate: '2024-03-18', planEndDate: '2024-03-21', actualStartDate: '2024-03-19', actualEndDate: '2024-03-21', planProgress: 90, actualProgress: 80 },
{ id: 10022, parentId: 10020, title: '任务22', planStartDate: '2024-03-23', planEndDate: '2024-03-25', actualStartDate: '2024-03-23', actualEndDate: '2024-03-25', planProgress: 90, actualProgress: 80 },
{ id: 10023, parentId: 10020, title: '任务23', planStartDate: '2024-03-27', planEndDate: '2024-04-02', actualStartDate: '2024-03-27', actualEndDate: '2024-03-28', planProgress: 90, actualProgress: 80 },
{ id: 10024, parentId: 10020, title: '任务24', planStartDate: '2024-04-04', planEndDate: '2024-04-06', actualStartDate: '2024-04-02', actualEndDate: '2024-04-05', planProgress: 90, actualProgress: 80 },
{ id: 10025, parentId: 10020, title: '任务25', planStartDate: '2024-04-07', planEndDate: '2024-04-11', actualStartDate: '2024-04-08', actualEndDate: '2024-04-13', planProgress: 90, actualProgress: 80 },
{ id: 10026, parentId: null, title: '任务26', planStartDate: '2024-04-05', planEndDate: '2024-04-08', actualStartDate: '2024-04-07', actualEndDate: '2024-04-10', planProgress: 90, actualProgress: 80 },
{ id: 10027, parentId: null, title: '任务27', planStartDate: '', planEndDate: '', actualStartDate: '', actualEndDate: '', planProgress: 90, actualProgress: 80, hasChild: true },
{ id: 10028, parentId: 10027, title: '任务28', planStartDate: '2024-03-10', planEndDate: '2024-03-13', actualStartDate: '2024-03-13', actualEndDate: '2024-03-14', planProgress: 90, actualProgress: 80 },
{ id: 10029, parentId: 10027, title: '任务29', planStartDate: '2024-03-14', planEndDate: '2024-03-18', actualStartDate: '2024-03-16', actualEndDate: '2024-03-18', planProgress: 90, actualProgress: 80 },
{ id: 10030, parentId: 10027, title: '任务30', planStartDate: '2024-03-19', planEndDate: '2024-03-25', actualStartDate: '2024-03-20', actualEndDate: '2024-03-26', planProgress: 90, actualProgress: 80 },
{ id: 10031, parentId: null, title: '任务31', planStartDate: '2024-03-22', planEndDate: '2024-03-24', actualStartDate: '2024-03-19', actualEndDate: '2024-03-20', planProgress: 90, actualProgress: 80 },
{ id: 10032, parentId: null, title: '任务32', planStartDate: '', planEndDate: '', actualStartDate: '', actualEndDate: '', planProgress: 90, actualProgress: 80, hasChild: true },
{ id: 10033, parentId: 10032, title: '任务33', planStartDate: '2024-03-09', planEndDate: '2024-03-14', actualStartDate: '2024-03-11', actualEndDate: '2024-03-15', planProgress: 90, actualProgress: 80 },
{ id: 10034, parentId: 10032, title: '任务34', planStartDate: '2024-03-15', planEndDate: '2024-03-21', actualStartDate: '2024-03-16', actualEndDate: '2024-03-19', planProgress: 90, actualProgress: 80 },
{ id: 10035, parentId: 10015, title: '任务35', planStartDate: '2024-03-16', planEndDate: '2024-03-18', actualStartDate: '2024-03-17', actualEndDate: '2024-03-19', planProgress: 90, actualProgress: 80 },
{ id: 10036, parentId: 10015, title: '任务36', planStartDate: '2024-03-12', planEndDate: '2024-03-14', actualStartDate: '2024-03-13', actualEndDate: '2024-03-15', planProgress: 90, actualProgress: 80 },
{ id: 10037, parentId: 10016, title: '任务37', planStartDate: '2024-03-19', planEndDate: '2024-03-22', actualStartDate: '2024-03-21', actualEndDate: '2024-03-23', planProgress: 90, actualProgress: 80 },
{ id: 10038, parentId: 10016, title: '任务38', planStartDate: '2024-03-23', planEndDate: '2024-03-25', actualStartDate: '2024-03-24', actualEndDate: '2024-03-27', planProgress: 90, actualProgress: 80 }
]
const multiRest = handleMultiTask(list)
ganttOptions.data = multiRest
}
loadList()
</script>
两种实现方式对比
| 特性 | 一级双进度 | 多级双进度 |
|---|---|---|
| 拆分粒度 | 仅顶层任务 | 所有层级(包括叶子) |
| 父级汇总 | 不汇总子级进度 | 自动汇总子级双进度 |
| 子任务条偏移 | 无(仅单条) | 计划/实际偏移显示 |
| 适用场景 | 只需关注顶层对比 | 需要精细到每层级的对比 |
| 数据复杂度 | 较低 | 较高(需要递归处理) |
注意事项
- 主键唯一性
拆分后的记录必须使用全新主键(如 p10001、a10001),否则树结构会冲突。 - 父级关联
计划和实际记录的 parentId 需要映射到对应的组节点 ID(如 g10001),而非原始父 ID。 - 日期字段
确保计划日期和实际日期字段存在(示例中为 planStartDate 等),并在 start 和 end 中正确引用。 - 进度值
示例中将进度固定为 0,实际使用时可从原始数据中读取 planProgress / actualProgress 并赋值给 progress 字段。 - 样式微调
偏移量 top: '-12px' 和 top: '12px' 可根据行高调整,以保证双条不重叠且视觉平衡。 - 开启树形展开
使用 treeConfig.showIcon: true 让用户可展开/折叠节点,查看子任务详情。
vxe-gantt 实现该功能的核心在于数据拆分和父级分组,配合 VxeGanttTaskType.Subview 和样式偏移,即可获得清晰、直观的双进度甘特图。