前端采用jqueryGantt,github地址为:https://github.com/robicch/jQueryGantt

原以为后端只需要简单地保存甘特图任务列表和返回任务列表就行了。

但功能需求是:创建一套任务模板(拖动图片,更改任务依赖关系),然后根据设置的项目开始时间和选择的任务模板动态生成项目的任务列表。

这个生成任务的时间有几点问题。

1.甘特图的任务时间是不包括周六日的时间(周末双休),生成的项目任务的开始时间计算要排除周六日时间。

2.这个任务间依赖规则,这个依赖规则不是按照任务顺序来(任务1要在任务3执行完后才开始执行即depends=3)

  ,如下图是按照从上到下下的顺序规则来执行任务的。

在经过研究这个jqueryGant甘特图的源码后,整理出了一套处理模板任务开始和结束时间的计算规则。

参考甘特图js过程

甘特图初始化任务过程:
gantt.html
   ge = new GanttMaster();
   ge.loadProject(Data)
GanttMaster.js
  loadProject(project)
    loadTasks(project.tasks)
      加载任务就是把所有任务属性都加入master的tasks中,在此过程中会将所有任务开始和结束时间进行计算
      updateLinks更新任务链接,需要判断所有links链接是否有循环引用。在这里会对存在依赖规则的任务开始和结束时间进行计算
执行这些过程需要用到了方法。
GanttUtilities.js ->computeStart(start)//计算开始日期,如果是周六日则会跳过。
GanttUtilities.js ->computeEnd(end) //计算结束日期也要把非工作日给去除。
i18nJs.js ->isHoliday(end) //判断是否是周六日。
GanttTask.js ->computeStartBySuperiors(proposedStart) //会计算依赖规则链接后算出这个任务开始时间的最大值
GanttTask.js ->computeEndByDuration(start, this.duration) //通过开始时间计算结束时间

后端要根据任务模板生成任务规则 :

前置条件:项目开始时间、任务模板列表、
处理过程:
  1.以项目开始时间作为任务模板列表中最早开始任务的开始时间。
  2.其他没有依赖规则的任务开始和结束时间优先计算,任务开始时间和这个固定不变的工作日时间差来计算任务开始时间。
  3.最后再统一计算有依赖规则的任务的开始和结束时间。

过程1

  根据甘特图的js限制规则,根节点,即level为0的节点开始时间一定比子节点的任务开始时间早。所以只要找出任务模板中任务是根节点,任务没有依赖规则且开始时间最早的任务作为最早任务(有依赖规则的任务的开始时间是不确定的。)。

代码

TaskTemplate earlyTask = null;
Date projectStartDate = project.getStartDate();
int taskPos = ;
for (int i = ; i < taskTemplateList.size(); i++) {
TaskTemplate taskItem = taskTemplateList.get(i);
if (taskItem.getLevel().equals() && StringUtils.isBlank(taskItem.getDepends())) {
if (earlyTask == null) {
earlyTask = taskItem;
taskPos = i;
} else {
if (earlyTask.getStart().getTime() > taskItem.getStart().getTime()) {
earlyTask = taskItem;
taskPos = i;
}
}
}
}
if (earlyTask == null) {
return null;//避免程序异常
}

过程2

  遍历一次任务模板列表,将所有任务属性都复制到任务列表中(保证顺序不变,或者自己后面根据sort由小到大重排序)

  在此过程中还要做件事,复制属性和计算无依赖规则的任务的开始和结束时间。

  根据任务列表创建任务依赖规则链接 links

代码:

        List<Task> taskList = new ArrayList<>();
//复制属性和计算无依赖规则任务时间,不处理任务文件
for (int i = 0; i < taskTemplateList.size(); i++) {
TaskTemplate item = taskTemplateList.get(i);
Task taskItem = new Task();
BeanUtils.copyProperties(item, taskItem);
if (item.getMilestone().equals(ProjectConsts.TASK_MILESTONE_YES)) {
taskItem.setCanDelete("false");
}
taskItem.setId(null);
taskItem.setProjectId(project.getId());
if (StringUtils.isNotBlank(taskItem.getDepends())) {
taskList.add(taskItem);
continue;
}
//无依赖规则任务计算
//初始化开始结束时间。当前任务和最早开始任务的时间差,只包含工作日
int subDay = DateUtils.getWorkdayTimeInDate(earlyTask.getStart(), item.getStart());
Date realStartDate = DateUtils.incrementDateByWorkingDays(projectStartDate, subDay);
taskItem.setStart(realStartDate);
Date realEndDate = DateUtils.incrementDateByWorkingDays(realStartDate, taskItem.getDuration());
taskItem.setEnd(realEndDate); taskList.add(taskItem);
} //创建任务依赖规则链接,并put到任务列表中
//创建没有依赖规则的任务开始和结束时间,获取所有任务的更新链接links
List<TaskLink> links = new ArrayList<>();
for (int i = 0; i < taskList.size(); i++) {
Task taskItem = taskList.get(i);
if (StringUtils.isBlank(taskItem.getDepends())) {
continue;//跳过
}
String[] depends = taskItem.getDepends().split(",");
for (int j = 0; j < depends.length; j++) {
String[] regular = depends[j].split(":");
TaskLink taskLink = null;
if (regular.length == 2) {
//这个规则的序号从1开始
taskLink = new TaskLink(taskList.get(Integer.valueOf(regular[0])-1), taskItem, Integer.valueOf(regular[1]));
} else {
taskLink = new TaskLink(taskList.get(Integer.valueOf(regular[0])-1), taskItem, 1);
}
links.add(taskLink);
}
}

过程3:最后再统一计算有依赖规则的任务的开始和结束时间

这个链接的结构

  这个过程需要用到两次递归:

  递归遍历获得该task节点的所有依赖规则。即获得List<TaskLink> taskLinkList

  递归处理taskLinkList数据,知道这个列表数据为空为止

两次递归代码

    /**
* 刷新taskList中存在依赖规则的开始时间和结束时间
*
* @param taskList
* @param taskLinkList
*/
public void refreshTaskLink(List<Task> taskList, List<TaskLink> taskLinkList) {
List<TaskLink> todoList = new ArrayList<>();
if (taskLinkList.isEmpty()) {
return;
}
TaskLink taskLink = taskLinkList.get(0);
todoList.add(taskLink);
if (StringUtils.isNotBlank(taskLink.getFrom().getDepends())) {
List<TaskLink> linkTmpList = getToLinkList(taskLink.getFrom(), taskLinkList);
if (linkTmpList != null) {
todoList.addAll(linkTmpList);
}
}
List<TaskLink> onceDealWithList = new ArrayList<>();
Task preTo = null; //处理第一个节点开始到没有依赖规则为止的嵌套规则列表
for (int i = todoList.size() - 1; i >= 0; i--) {
//倒叙处理依赖规则
TaskLink link = todoList.get(i);
if (preTo == null) {
preTo = link.getTo();
}
onceDealWithList.add(link);
//是否还有下一个节点
if (i - 1 >= 0) {
if (preTo.getTaskSort().equals(todoList.get(i - 1).getTo().getTaskSort())) {
//还是相等,则跳过
continue;
} else {
//不相同,处理链接列表,设置任务开始结束时间
Task task = taskList.get(link.getTo().getTaskSort() - 1);
dealTaskByOneDealWithList(task, onceDealWithList);
//重置处理数据
onceDealWithList = new ArrayList<>();
preTo = null;
}
} else {
//不相同,处理链接列表,设置任务开始结束时间
Task task = taskList.get(link.getTo().getTaskSort() - 1);
dealTaskByOneDealWithList(task, onceDealWithList);
//重置处理数据
onceDealWithList = new ArrayList<>();
preTo = null;
}
}
taskLinkList.removeAll(todoList);
refreshTaskLink(taskList, taskLinkList); } public void dealTaskByOneDealWithList(Task task, List<TaskLink> dealLinkList) {
Date superEnd = null;
for (TaskLink taskLink1 : dealLinkList) {
if (superEnd == null) {
superEnd = DateUtils.incrementDateByWorkingDays(taskLink1.getFrom().getEnd(), taskLink1.getLag());
} else {
Date curEnd = DateUtils.incrementDateByWorkingDays(taskLink1.getFrom().getEnd(), taskLink1.getLag());
if (curEnd.getTime() > superEnd.getTime()) {
superEnd = curEnd;
}
}
}
//设置开始和结束时间,开始时间和结束时间计算不用再加1,因为当天表示如2019-11-11开始2019-11-11结束表示1天
task.setStart(superEnd);
task.setEnd(DateUtils.incrementDateByWorkingDays(task.getStart(), task.getDuration() - 1));
} /**
* 递归遍历获得该task节点的所有依赖规则。
*
* @param to
* @param taskLinkList
* @return
*/
public List<TaskLink> getToLinkList(Task to, List<TaskLink> taskLinkList) {
List<TaskLink> list = null;
for (TaskLink taskLink : taskLinkList) {
if (taskLink.getTo().getTaskSort().equals(to.getTaskSort())) {
//序号相同
if (list == null) {
list = new ArrayList<>();
}
list.add(taskLink);
if (StringUtils.isNotBlank(taskLink.getFrom().getDepends())) {
List<TaskLink> childLinkList = getToLinkList(taskLink.getFrom(), taskLinkList);
if (childLinkList != null) {
list.addAll(childLinkList);
}
}
}
}
return list;
}

逻辑代码上传到github:https://github.com/innerjob/jQueryGantt/tree/master/java

java处理jqueryGantt甘特图数据的task.depends依赖规则方法的更多相关文章

  1. java中的排序(自定义数据排序)--使用Collections的sort方法

    排序:将一组数据按相应的规则 排列 顺序 1.规则:       基本数据类型:日常的大小排序. 引用类型: 内置引用类型(String,Integer..),内部已经指定规则,直接使用即可.---- ...

  2. R-plotly|交互式甘特图(Gantt chart)-项目管理/学习计划

    本文首发于“生信补给站”微信公众号,https://mp.weixin.qq.com/s/CGz51qOjFSJ4Wx_qOMzjiw 更多关于R语言,ggplot2绘图,生信分析的内容,敬请关注小号 ...

  3. 甘特图生产排程(APS)定制开发

    高速开发完毕APS的数据可视化.订单展示.资源调度.智能排程等差点儿所有功能模块. 自己主动智能排程功能 提供专业需求分析师及开发团队,按需开发"全自己主动智能排程"这一APS的主 ...

  4. 自己做的js甘特图插件

    版权所有,禁止转载 内容都在代码中,上图上代码! 代码 <!DOCTYPE html> <html> <head> <title>ganttu.html ...

  5. 基于 ECharts 封装甘特图并实现自动滚屏

    项目中需要用到甘特图组件,之前的图表一直基于 EChart 开发,但 EChart 本身没有甘特图组件,需要自行封装 经过一番鏖战,终于完成了... 我在工程中参考 v-chart 封装了一套图表组件 ...

  6. java实现甘特图的2种方法:SwiftGantt和Jfree (转)

    http://blog.sina.com.cn/s/blog_50a7c4a601009817.html 第一种方法使用SwiftGantt实现甘特图(进度图推荐这个)   import java.a ...

  7. Java甘特图控件swing版免费下载地址

    FlexGantt 控件是现在Java 平台下最先进的甘特图解决方案,使用一个很高的抽象层次,能适用于多种不同的域,例如 ERP 系统.生产计划和日程安排.制造流程系统或项目公文管理程序等.这些使得 ...

  8. java制作甘特图

    今日来做一下甘特图.网上搜到了这个源码,但是导的jar包,并没有给我.swiftganttdemo但是名为swiftgantt制作:所以灵机一动在网上搜到了swiftangantt组件:在组件中找到了 ...

  9. Twproject Gantt开源甘特图功能扩展

    1.Twproject Gantt甘特图介绍 Twproject Gantt 是一款基于 jQuery 开发的甘特图组件,也可以创建其它图表,例如任务树(Task Trees).内置编辑.缩放和 CS ...

随机推荐

  1. 单元测试框架之unittest(六)

    一.摘要 本片博文将介绍unittest框架的一些轻便有效的特性,在我们的测试中经常可以用到 如果有一些测试方法不想执行,如果有些测试方法在某些条件下不执行 该当如何? 如果有些方法未在unittes ...

  2. watch 监控的新旧值一致问题处理

    watch 监控的新旧值一致问题处理 http://www.imooc.com/article/details/id/286654

  3. 016_STM32程序移植之_舵机

    STM32程序移植之舵机PWM测试 接线图如下: STM32引脚 舵机引脚 功能 GND GND 正极电源 具体看舵机的额定电压 PA6 PWM引脚 STM32引脚 CH340引脚 GND GND 3 ...

  4. 009_Linux驱动之_request_irq()函数

    1. request_irq()函数原型 int request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags ...

  5. kafka 介绍与使用

    在介绍为什么使用kafka之前,我们有必要来了解一下什么是kafka? 1. 什么是kafka? Kafka是由LinkedIn开发的一个分布式的消息系统,使用Scala编写,它以可水平扩展和高吞吐率 ...

  6. word黏贴图片显示不出来

    word图片转存,是指UEditor为了解决用户从word中复制了一篇图文混排的文章粘贴到编辑器之后,word文章中的图片数据无法显示在编辑器中,也无法提交到服务器上的问题而开发的一个操作简便的图片转 ...

  7. 洛谷 P3382 【模板】三分法(三分 二分)

    P3382 [模板]三分法 题目提供者HansBug 难度 普及/提高- 题目描述 如题,给出一个N次函数,保证在范围[l,r]内存在一点x,使得[l,x]上单调增,[x,r]上单调减.试求出x的值. ...

  8. Asp.Net跨平台 Jexus 5.8.1 独立版

    在Linux上运行ASP.NET网站或WebApi的传统步骤是,先安装libgdiplus,再安装mono,然后安装Jexus.在这个过程中,虽然安装Jexus是挺简便的一件事,但是安装mono就相对 ...

  9. 微服务springboot视频最新SpringBoot2.0.3版本技术视频教程【免费学习】

    超火爆的springboot微服务技术怎么学,看这里,springboot超详细的教程↓↓↓↓↓↓https://ke.qq.com/course/179440?tuin=9b386640 01.sp ...

  10. oracle中查询某个库中所有的表以及所占的表空间大小

    1. 查某一用户下的表select SEGMENT_NAME,TABLESPACE_NAME,sum(BYTES/1024/1024)||'M' from USER_extents where SEG ...