DHTMLX Gantt 甘特图计算工期少1天的问题解决及解决过程附带产生的问题解决

这几天在对之前开发的项目管理系统可视化部分当中的甘特图模块进行功能优化,过程中发现了之前未发现的Bug问题。

如下图所示,甘特图的工期计算结果少1天:

为此我排查了之前写的存储过程,对甘特图所需的duration字段值的计算追加1天:

  1 CREATE DEFINER=`root`@`localhost` PROCEDURE `pmstest`.`P_GanttAnalysis`(in ProjectId varchar(64))
  2 BEGIN
  3 
  4     DECLARE done INT default 0;
  5     DECLARE id_value varchar(50);
  6     
  7     DECLARE cur CURSOR FOR
  8         SELECT id FROM  pm_plan where status = '0' and proj_id = ProjectId;
  9 
 10     DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
 11 
 12          DROP TABLE IF exists temp_result;
 13 
 14         create temporary table temp_result
 15         (
 16             id varchar(50),
 17             text varchar(200),
 18             start_date varchar(32),
 19             end_date varchar(32),
 20             user varchar(64),
 21             username varchar(100),
 22             duration int,
 23             parent varchar(64),
 24             progress DECIMAL(8,2),
 25             open varchar(10),
 26             classification varchar(100)
 27         );
 28 
 29     INSERT INTO temp_result(id,text,start_date,end_date,user,username,duration,parent,progress,open,classification)
 30     select A.id,A.text,A.start_date,A.end_date,A.user,A.username,A.duration,A.parent,B.progress,A.open,A.classification
 31     from 
 32     (
 33         select a.id as id,a.proj_name as text,a.start_date as start_date,a.end_date as end_date
 34         ,a.proj_manager as user,b.user_name as username,DATEDIFF(a.end_date,a.start_date)+1 as duration,'' as parent,"true" as open,a.status,'项目' as classification 
 35         from pm_infor a 
 36         left join js_sys_user b 
 37         on a.proj_manager = b.user_code 
 38         where a.status = '0' and id = ProjectId
 39     ) A
 40     left join 
 41     (
 42         select m.proj_id,m.taskcount,m.taskcompletecount,
 43         CASE 
 44         WHEN m.taskcount !=0 then ROUND(m.taskcompletecount/m.taskcount,2)
 45         else 0
 46         END as progress
 47         from 
 48         (
 49         select a.proj_id,
 50         SUM(CASE WHEN a.status = '0' THEN 1 ELSE 0 END) AS taskcount,
 51         SUM(CASE WHEN (a.status='0' and (a.task_status = '2' or a.task_status = '4')) then 1 else 0 end) as taskcompletecount
 52         from pm_task a
 53         where a.proj_id = ProjectId
 54         group by a.proj_id
 55         )m
 56     )B
 57     on A.id = B.proj_id;
 58     
 59          DROP TABLE IF exists temp_plan_right;
 60 
 61 
 62         create temporary table temp_plan_right
 63         (
 64             plan_id varchar(50),
 65             taskcount int,
 66             taskcompletecount int,
 67             progress DECIMAL(8,2)
 68         );
 69 
 70     
 71 
 72     OPEN cur;
 73     read_loop: LOOP
 74         FETCH cur INTO id_value;
 75         IF done = 1 THEN
 76             LEAVE read_loop;
 77         END IF;
 78         
 79 
 80           INSERT INTO temp_plan_right(plan_id,taskcount,taskcompletecount,progress)
 81           select m.plan_id,m.taskcount,m.taskcompletecount,
 82         CASE 
 83         WHEN m.taskcount !=0 then ROUND(m.taskcompletecount/m.taskcount,2)
 84         else 0
 85         END as progress
 86     from 
 87     (
 88         select a.plan_id,
 89         SUM(CASE WHEN a.status = '0' THEN 1 ELSE 0 END) AS taskcount,
 90         SUM(CASE WHEN (a.status='0' and (a.task_status = '2' or a.task_status = '4')) then 1 else 0 end) as taskcompletecount
 91         from pm_task a
 92         where a.plan_id = id_value
 93         group by a.plan_id
 94     ) m ;
 95       
 96         
 97     END LOOP;
 98     
 99     CLOSE cur;
100     
101        INSERT INTO temp_result(id,text,start_date,end_date,user,username,duration,parent,progress,open,classification)
102        select A.id,A.text,A.start_date,A.end_date,A.user,A.username,A.duration,A.parent,B.progress,A.open,A.classification
103        FROM
104        (
105            select a.id as id,a.plan_name as text,a.plan_start_date as start_date,a.plan_end_date as end_date
106         ,a.plan_manager as user,b.user_name as username,DATEDIFF(a.plan_end_date,a.plan_start_date)+1 as duration,a.proj_id as parent,"true" as open,a.status,'计划' as classification 
107         from pm_plan a 
108         left join js_sys_user b 
109         on a.plan_manager = b.user_code 
110         where a.status = '0' and a.proj_id = ProjectId
111     ) A
112         left join temp_plan_right B 
113     on A.id = B.plan_id;
114         
115 
116     INSERT INTO temp_result(id,text,start_date,end_date,user,username,duration,parent,progress,open,classification)
117     select a.id as id,a.task_name as text,a.task_start_date  as start_date,a.task_end_date as end_date,task_manager as user,b.user_name as username,
118     DATEDIFF(a.task_end_date,a.task_start_date)+1 as duration,a.plan_id as parent, 
119     CASE WHEN (a.task_status = '2' or a.task_status = '4') then 1 else 0 end
120     as progress
121     ,"true" as open,'任务' as classification
122     FROM 
123     pm_task a left join js_sys_user b 
124     on a.task_manager = b.user_code  
125      where a.status = '0' and a.proj_id = ProjectId;
126 
127 
128 select * from temp_result;
129 
130     
131 END

运行页面后,发现【工期】duration列数据没有任何改变,还是少1天。我又对前端拿到的后端数据打了日志,发现后端确实是把加了1天的duration数据给到前端了,部分日志如下:

1 甘特图图表数据:{"data":[{"id":"1800444694382850048","text":"智能测试评估系统开发","start_date":"2024-06-03","end_date":"2024-09-30","user":"XXXX_tllq","username":"XXX","duration":"120","parent":null,"progress":"0.62","open":"true","classification":"项目"},{"id":"1800445991181955072","text":"系统管理员大屏V1.0展示开发","start_date":"2024-06-01","end_date":"2024-06-25","user":"XXXX_nbjb","username":"XX","duration":"25","parent":"1800444694382850048","progress":"0.60","open":"true","classification":"计划"},{"id":"1800448916302147584","text":"用户看板V1.0展示开发","start_date":"2024-06-26","end_date":"2024-07-31","user":"XXXXXXX_nbjb","username":"XX","duration":"36","parent":"1800444694382850048","progress":"0.00","open":"true","classification":"计划"}

那么为什么DHTMLX Gantt的甘特图页面的工期列还是没有加1呢?

我查了网络上关于DHTMLX Gantt的工期问题相关资料,发现了问题缘由:

首先虽然前端我是按照DHTMLX Gantt官方语法格式定义的列,如下:

 1  gantt.config.columns = [
 3       {
 4         name: "text", label: "工作描述", tree: true, min_width: 200, width: 220, resize: true,
 5         //20240308 保证项目名超过特定字数,后面以...进行显示
 6         template: obj => obj.text.length > 10 ? obj.text.substring(0, 10) + '...' : obj.text
 7       },
 9       {
10         name: "progress", label: "进度", align: "center", width: 50, resize: true,
11         //template: obj => `${Math.round(obj.progress * 100, 2) + '%'}` 
12         template: obj => (Math.round(obj.progress * 100)).toString() + '%'
13       },
15       { name: "start_date", label: "开始日期", align: "center", width: 75, resize: true },
16       {
17         name: "end_date", label: "结束日期", align: "center", width: 75, resize: true
18       },
19       {
20         name: "duration", label: "工期(天)", align: "center", width: 60, resize: true
21       },
22       {
23         name: "username", label: "责任人", align: "center", width: 70, resize: true
24       }
25     ];

并且在后端存储过程返回的数据也明确给定了duration的值(+1后的值),但是DHTMLX Gantt有个问题是它前端显示的duration是不依赖于后端计算的duration的,它是根据后端传过来的开始日期、结束日期进行计算,得出他的“duration”进行显示的!!这本来也没有问题,但是由于数据的开始日期、结束日期的格式是YYYY-MM-dd,没有时分秒,在这种情况下,DHTMLX Gantt的duration默认计算方式是按照结束日期YYYY-MM-dd 00:00:00 - 开始日期的YYYY-MM-dd 00:00:00。这就会导致少1天。如某项任务开始日期2024-06-11,结束日期2024-06-12,实际上正确计算出的duration应当是2天(即按照:2024-06-12 23:59:59 - 2024-06-11 00:00:00 = 2天),但是按照DHTMLX Gantt的duration默认计算方式,则变成的了duration为1天了(即按照:2024-06-12 00:00:00 - 2024-06-11 00:00:00 = 1天),这与我们想要的实际不符!

解决的其中一个办法就是对DHTMLX Gantt的结束日期多加1天,可这会导致数据库的结束日期与前端界面显示的结束日期不一致的问题,这是不合理的!

后面考虑的方案是,结束日期不修改,遵循数据库的数据;但人为修改duration值的显示。

以下是解决的过程,以及对过程中产生的新问题进行解决的过程:

 1.解决左侧工期列值少1天问题:对duration显示时人为+1

gantt.config.columns列定义中,修改duration的定义,内部追加模板修改工期的显示值:

 {
        name: "duration", label: "工期(天)", align: "center", width: 60, resize: true,
        template: function (task) {
          // 如果duration是null或undefined,返回0  
          return (task.duration || 0) + 1; // 在当前duration的基础上加1  
        }
      },

 这样确实工期列值实现了加1,可是右侧的进度条图形显示还是按照原本少一天进行显示,如下图:

2.解决右侧进度条甘特图图形显示还是按照DHTMLX Gantt原始duration值显示的问题(即还是少1天的问题)

改一下两处代码:

 1 gantt.config.columns = [  
 2     // ... 其他列定义 ...  
 3     { name: "start_date", label: "开始日期", align: "center", width: 75, resize: true },  
 4     {  
 5         name: "end_date",   
 6         label: "结束日期",   
 7         align: "center",   
 8         width: 75,   
 9         resize: true,  
10         template: function(task) {  
11             // 返回任务的原始结束日期  
12             return task.original_end_date ? gantt.date.date_to_str("%Y-%m-%d")(task.original_end_date) : "";  
13         }  
14     },  
15     { name: "duration", label: "工期(天)", align: "center", width: 60, resize: true },  
16     // ... 其他列定义 ...  
17 ];  
18 
19 // 解析任务数据前调整结束日期  
20 gantt.attachEvent("onParse", function() {  
21     gantt.eachTask(function(task) {  
22         // 保存原始结束日期  
23         task.original_end_date = task.end_date;  
24 
25         if (task.start_date && task.duration !== null && task.duration !== undefined) {  
26             // 基于目前的开始日期和持续时间加1天而更新结束日期  
27             task.end_date = gantt.date.add(task.start_date, task.duration + 1, "day");  
28         }  
29     });  
30 }); 

修改以上两处代码问题解决,问题解决。可是又发现了新问题:甘特图的浮动框显示的End Date值不对,被改成了数据库日期+1的值,而我希望保留显示数据库的原始结束日期值。

现象图如下:

 

3.解决浮动框End Date结束日期值被加1问题

在以上代码修改的基础上,追加DHTMLX Gantt提供的gantt.templates.tooltip_text方法,自定义鼠标悬停时显示的内容。

 1   //20250211 tooltip浮动框显示的End Date被追加1的问题修复(应该显示数据库的原始值)
 2     // 自定义浮动框的显示内容  
 3     gantt.templates.tooltip_text = function (start, end, task) {
 4       // 使用原始结束日期显示  
 5       var originalEndDate = task.original_end_date ? gantt.date.date_to_str("%Y-%m-%d")(task.original_end_date) : "";
 6       return `<b>工作描述:</b> ${task.text}<br/>  
 7             <b>开始日期:</b> ${gantt.date.date_to_str("%Y-%m-%d")(task.start_date)}<br/>  
 8             <b>结束日期:</b> ${originalEndDate}<br/>  
 9             <b>工期:</b> ${task.duration + 1}天<br/>
10             <b>进度:</b> ${task.progress*100}%<br/> 
11             <b>责任人:</b> ${task.username}<br/> 
12             ` ;
13     };

好了,以上所有问题解决,最终效果图如下:

posted @ 2025-02-11 17:40  上清风  阅读(395)  评论(0)    收藏  举报