PagerGantt 二次开发指南 V1.1

更新时间:2012-03-01

上海普加软件有限公司

目录

  1. 安装部署
  2. 项目文件目录介绍
  3. 二次开发工作
    1. 加载数据
    2. 保存数据
    3. 扩展任务属性
    4. 自定义列
    5. 自定义表格:行样式、单元格样式、单元格内容
    6. 自定义条形图显示
    7. 控制单元格可编辑
    8. 自定义右键菜单
    9. 集成到第三方JS框架(jQuery、Ext等)
    10. 语言本地化
  4. 项目数据结构
    1. JSON数据结构
    2. 数据库表结构
  5. PagerGantt API参考
  6. 常见问题
  7. 历史更新
  8. 获得支持

安装部署

下载开发包

访问 http://www.plusgantt.com/download/

获得软件开发包后解压缩,并把解压缩后的项目文件,放入到Web项目。
如果是.Net版本,可以直接用Visual Studio以"打开网站"的方式打开运行。
如果是Java版本,请使用Eclipse以"导入项目"的方式导入打开。

数据库安装

在下载解压缩后的文件夹内,有一个"dbsql"目录,里面有mssql.sql、oracle.sql、mysql.sql数据库表文件。
请使用这里的表结构创建一个数据库。
比如新建一个数据库,名字为:testproject。然后把拷贝的SQL运行一下,就生成了plus_project、plus_task表。

创建数据库表完成后,请在"App_Code\Utils\DBUtil.cs"修改数据库连接配置信息以便正常运行。
Java的文件路径是"src\PluSoft\DBUtil.java"。

导入项目

运行"demo/ImportProject.aspx"文件。选择本地MS PROJECT XML文件,上传导入到数据库中。

如果导入成功,会弹出提示信息,可以选择跳转到"Gantt.html"查看刚才导入的项目数据。
如果导入失败,会弹出异常提示,定位解决错误。
(注:通常导入错误都是数据库配置信息有误;或文件选择错误。)
必须导入"Upload\软件开发-100.xml"项目文件,它是作为DEMO示例的示例项目数据。

新建项目

运行"demo/NewProject.aspx"文件。此文件使用服务端Project对象,创建一个空项目,并保存到项目中。

查看项目

运行"demo/Projects.aspx"文件,打开一个当前项目列表,可以选择“打开”项目,跳转到Gantt.html,查看项目。

2.项目文件目录介绍

.Net开发包目录

.Net开发包目录文件一一如下:

二次开发工作

以下详细介绍PagerGantt是如何从数据库加载数据,以及如何保存到数据库内的。

DBProject类

DBProject是用来处理从数据库加载和保存项目的。里面有两个重要方法:LoadProjectSaveProject

开发者往往需要改造这个类,修改项目加载和保存的实现方式,以满足开发的需要。

PagerGantt并不关心和限制开发者如何加载和保存项目数据,只需要在创建和使用PagerGantt时,提供好符合数据格式的JSON数据即可。
所以开发者可以使用任意的数据库,以及数据库操作方式,灵活性和可控性非常高。

加载数据

在DBProject的LoadProject方法中,根据项目UID,加载项目数据和任务数据,并进行数据格式转换工作,最后得到一个Hashtable对象返回。
开发者可以参考LoadProject方法的代码,使用自己熟悉的数据库操作方式,比如IBatis、Hibernate等第三方类库,查询数据后,按项目数据结构进行格式转换工作。

需要注意的是,获取任务的方法SelectTasks。
从数据库查询出任务列表后,需要进行一个for循环遍历操作,一一将任务属性转换为标准任务字段。

    foreach (Hashtable dbtask in dbtasks)
    {
        Hashtable task = new Hashtable();
        task["UID"] = dbtask["UID_"];   //唯一标识符
         task["ID"] = dbtask["ID_"];     //序号
      	......
        tasks.Add(task);
    }

另外,获得任务列表后,需要生成树形结构数据。这个可以使用TreeUtil的标准方法来实现:

//任务列表
ArrayList tasks = SelectTasks(projectUID);
//列表转树形
tasks = TreeUtil.ToTree(tasks, "children", "UID", "ParentTaskUID");
project["Tasks"] = tasks;

最后,需要获取项目的“部门”和“负责人”信息。这两个方法开发者可以重写实现。(示例是生成静态的数据)

//部门, 负责人获取
project["Departments"] = GetDepartments(projectUID);
project["Principals"] = GetPrincipals(projectUID);

保存数据

在DBProject有一个SaveAll方法。
其原理是:删除所有旧任务,新增所有新任务,达到更新任务的目的。

//删除任务
DeleteTasks(projectUID);

//树形转列表        
ArrayList tasks = TreeUtil.ToList((ArrayList)dataProject["Tasks"],"-1", "children", "UID", "ParentTaskUID");

//保存任务表
InsertTasks(projectUID, tasks);

扩展任务属性

对任务属性的扩展,主要处理如下几个地方:

  1. 增加plus_task表的一个字段
  2. 修改DBProject的SelectTasks方法,将新字段增加到任务对象上。
  3. 修改DBProject的InsertTask方法,将新字段在"insert"语句中增加,保存到任务表。
  4. 在Javascript内扩展一个表格列,根据不同数据类型进行扩展。具体参考:自定义表格列

plus_task表的新字段,是用来存放新字段数据的;
在加载数据时,确保任务对象上有新字段的属性值。因为任务对象是一个Hashtable,所以这一点极其简单。
在保存数据时,修改任务的"insert"语句,把新字段的值写入到数据库,保存起来。
做好这几点,其实任务的属性已经扩展了。
下面只是需要一个界面显示和操作的载体,一般用表格列来完成。
关于表格列的扩展,请参考:自定义表格列示例。

自定义表格列

开发者可以根据自己扩展的任务属性类型,来创建自己的列。

具体请参考"自定义列示例"。

自定义单元格内容

通过监听处理"drawcell"事件,可以根据任务信息,设置行、单元格样式,以及自定义单元格Html内容。

gantt.on("drawcell", function (e) {
    var task = e.record, column = e.column, field = e.field;

    //单元格样式
    if (column.name == "Name") {
        e.cellCls = "mycellcls";
    }

    //行样式
    if (task.Summary == 1) {
        e.rowCls = "myrowcls";
    }

    ////自定义单元格Html。如果是工期列, 并且工期大与5天, 显示红色
    if (field == "Name" && task.Duration > 5) {
        e.cellHtml = '<b style="color:red;">' + task.Name + '</b>';
    }
    if (field == "Name" && task.Duration <= 2) {
        e.cellHtml = '<span style="color:blue;">' + task.Name + '</span>';
    }

    if (task.Duration == 0) {
        e.rowCls = "deletetask";
    }
});

示例请参考"自定义显示"

自定义单元格可编辑

通过监听表格的"cellbeginedit"事件,可以控制每个行、每个单元格是否可编辑。

//控制单元格是否可编辑
gantt.on("cellbeginedit", function (e) {
    var task = e.record, column = e.column, field = e.field;

    if (task.Summary == 1) {
        e.cancel = true;
    }

    if (field == 'Duration') {
        e.cancel = true;
    }
});

示例请参考"控制单元格可编辑"

自定义条形图外观

开发者可以控制右侧条形图的HTML外观,达到任意的条形图效果:

//1)自定义条形图外观显示
gantt.on("drawitem", function (e) {
    var item = e.item;
    if (!item.Summary && !item.Milestone) {
        if (item.PercentComplete == 100) {
            e.itemCls = "item1";
        } else {
            e.itemCls = "item2";
        }
    }
});

//2)自定义条形图提示信息
gantt.on('itemtooltipneeded', function (e) {
    var task = e.task;
    e.tooltip = "<div>任务:" + task.Name + "</div>"
    //                +   "<div ><div style='float:left;'>进度:<b>"+task.PercentComplete + "%</b></div>"
    //                +   "<div style='float:right;'>工期:"+task.Duration + "日</div></div>"
                + "<div style='clear:both;'>开始日期:" + mini.formatDate(task.Start, 'yyyy-MM-dd') + "</div>"
                + "<div>完成日期:" + mini.formatDate(task.Finish, 'yyyy-MM-dd') + "</div>";
});

示例请参考"自定义显示条形图"

自定义右键菜单

弹出右键菜单时,根据当前选择的行,显示隐藏、启用禁用菜单项。

示例请参考"自定义右键菜单"

集成到第三方JS框架(jQuery、Ext等)

首先,对于jQuery, YUI, Prototype.js等框架来说,它们对页面的操作基于原始Dom元素的。
所以,你可以不用做任何额外的处理,按PagerGantt正常的例子,把项目甘特图对象加入到页面元素就可以了。

其次,对于ExtJS这样封装度很高的框架,可以从Ext对象找到它的dom,然后render加入即可。使用代码如下:

//获取ext控件对象
var extControl = Ext.get(id);

//设置尺寸为100%自适应
gantt.setStyle("width:100%;height:100%");

//把project加入到ext控件对象的dom属性中
gantt.render(extControl.dom);

只需要这样设置后,PagerGantt就能在Ext的布局面板中自动调整尺寸大小,看上去跟Ext原生的控件一样了。

语言本地化

如果要显示他语言界面,只需要引用locale文件夹下资源js文件即可,例如英文资源包使用如下:

<script src="../scripts/miniui/locale/en_US.js" type="text/javascript"></script>

语言本地化(英语)示例,请查看这里

项目数据结构

1.JSON数据结构

PagerGantt项目数据包含如下信息:项目本身数据、日历、任务列表、部门列表、负责人列表等。
其中,任务会跟部门、负责人有分配关系。

本节使用JSON格式描述项目数据结构,对应到服务端数据,转换类型如下:

//普加项目管理中间件数据结构
{
	UID: 100,
	Name: 'ProjectName',
	StartDate: '2007-01-01T08:00:00',
	FinishDate: '2007-05-14T15:00:00',
	CalendarUID: 1,
	//日历
	Calendars: [
		{
			UID: 1,
			Name: 'CalendarName',
			WeekDays: [             //工作周: DayType(1~7)
				{
					DayType: 1,
					DayWorking: 1   //工作日1, 非工作日0
				}
			],
			Exceptions: [           //例外日期: DayType = 0
				{
                    			DayType: 0,     
                    			DayWorking: 0,
                    			Name: '',
                    			TimePeriod: {   //例外的日期范围
	            			        FromDate: '2007-01-01T00:00:00',
	           			            ToDate: '2007-01-02T23:59:59'
                  			  }
				}
			]
		}
	],
	//任务集合
	Tasks: [
		{
                        UID: 1,                 //必要任务UID(唯一性标识符)
			Name: '',               //必要。任务名称
			
			Start: '2010-01-01T00:00:00',//必要。DateTime。开始日期
			Finish: '2010-01-01T23:59:59',//必要。DateTime。完成日期
			
			Duration: 24,           //必要。Number。工期			
			PercentComplete: 100,   //必要。Number。进度

			ConstraintType: 1,      //限制类型:0越早越好;1越晚越好;2必须开始于;3必须完成于;
                                    //4不得早于...开始;5不得晚于...开始;6不得早于...完成;7不得晚于...完成

			ConstraintDate: null,   //DateTime。限制日期


			FixedDate:1,	        //1或0。是否固定日期(仅限于摘要任务使用)
		    
			ID: 1,                  //Number。序号
			OutlineNumber: '1.2.1', //体现树形层次和顺序
			OutlineLevel: 1,        //层次
			
			Work: 8,                //Number。工时
			Weight: 100,            //Number。权重		
						
			Milestone: 1,           //1或0。里程碑
			Summary: 1,             //1或0。摘要任务
			Critical: 1,            //1或0。关键任务
			Priority: 200,          //Number。重要级别
			Notes: '',              //任务备注
			
			PredecessorLink: [      //前置任务(0FF,1FS,2SF,3SS)
				{PredecessorUID: 2,Type: 1,LinkLag: 0},
				......
			],

                        Assignments: [      //资源分配关系
				{ResenderUID: 2, Units: 1},
				......
			],
			
			Department: '1',        //部门
			Principal: '1,2'        //负责人,


                        children: [             //下一级子任务, 体现树形结构
                                ......
                        ]
			
		}
	],
	//资源集合
	Resenders: [
		{UID: 1, Name: '市场部', Type: 1, MaxUnits: 1},
		......
	],
	//部门集合
	Departments: [
		{UID: 1, Name: '市场部'},
		......
	],
	//负责人集合
	Principals: [
		{UID: 1, Name: '张三', Department: 1},
		......
	]
}

默认的日历数据如下:

[
    {  UID: 1, Name: '', 
        WeekDays: [
            { DayType: 1, DayWorking: 0 }, 
            { DayType: 2, DayWorking: 1 }, 
            { DayType: 3, DayWorking: 1 }, 
            { DayType: 4, DayWorking: 1 }, 
            { DayType: 5, DayWorking: 1 }, 
            { DayType: 6, DayWorking: 1 }, 
            { DayType: 7, DayWorking: 0}], 
        Exceptions: []
    }
]

数据库表结构

plus_project表

字段类型描述
UID_ varchar 项目唯一标识符
NAME_ varchar 项目名称
STARTDATE_ datetime 项目开始日期
FINISHDATE_ datetime 项目完成日期
LASTSAVED_ varchar 最后保存日期
CALENDARS_ varchar 日历数据(JSON字符串)
CALENDARUID_ varchar 项目日历UID

plus_task表

字段类型描述
UID_ varchar 任务唯一标识符
ID_ int 序号(是一个数字,体现任务的前后顺序)
PARENTTASKUID_ varchar 父任务UID(体现树形结构)
NAME_ varchar 任务名称
START_ datetime 开始日期
FINISH_ datetime 完成日期
DURATION_ int 工期
WORK_ int 工时
PERCENTCOMPLETE_ int 完成百分比
WEIGHT_ int 权重
CONSTRAINTTYPE_ int 任务限制类型。
CONSTRAINTDATE_ datetime 任务限制日期
MILESTONE_ int 里程碑
SUMMARY_ int 摘要任务
CRITICAL_ int 关键任务
PRIORITY_ int 重要级别
NOTES_ varchar 备注
DEPARTMENT_ varchar 所属部门。如"1"。
PRINCIPAL_ varchar 任务负责人。如"101,220,201"。
PREDECESSORLINK_ varchar 前置任务(JSON字符串)。如"[{PredecessorUID: 2,Type: 1,LinkLag: 0}, ...]"
FIXEDDATE_ int 限制日期(摘要任务专用)
PROJECTUID_ varchar 项目UID
ACTUALSTART_ datetime 实际开始日期
ACTUALSTART_ datetime 实际完成日期
ACTUALDURATION_ int 实际工期

注意:这些表是普加软件默认提供的项目和任务表。
使用者可以完全脱离我们的表结构设计,实现自定义的表。
只需要在DBProject类的LoadProject方法中,提供符合普加项目数据结构定义的数据即可。

PagerGantt API参考

属性

属性可以从对象直接读取,但是不能进行赋值操作。如果想对属性进行赋值,必须使用提供的方法。

	    var gantt = new PagerGantt();
	    var visible= project.visible;         //正确
	    project.visible= true;           //错误!!!
	    gantt.setVisible(true);            //正确
	
属性类型描述
readOnly Boolean 是否只读。
visible Boolean 是否显示。
width Number 宽度。
height Number 高度。
showTableView Boolean 是否显示任务表格。
showGanttView Boolean 是否显示条形图。
showLinkLines Boolean 是否显示箭头连线。
showCritical Boolean 是否显示关键路径
showGridLines Boolean 是否条形图表格线。
timeLines Array 时间线数组。
[
    {date: new Date(2007, 0, 3), text: "时间线"},
    {date: new Date(2007, 0, 5), text: "时间线2", 
        style: "width:2px;background:red;"}
]
multiSelect Boolean 是否允许多选任务。
allowResize Boolean 是否允许拖拽调节甘特图。

方法

方法参数类型描述
setStyle(String)
 
设置样式,比如:gantt.setStyle("width:100%;height:400px")。
setUrl(String)
 
设置项目数据加载路径。
load(params, success, fail) params:Object。参数对象。
success: Function。成功回调函数。
fail: Function。失败回调函数。
从服务端传递参数加载项目数据。
reload() 重新加载刷新甘特图。
getData()
 
返回项目JSON对象。
gotoPage(index, size)
 
跳转分页。
setSizeList(Array)
 
设置页码集合,如[10, 20, 50, 100]。
setPageSize(Number)
 
设置页码。
setPageIndex()
 
设置跳转到第几页。
getData()
 
返回项目JSON对象。
setColumns( Array ) 设置表格列集合。
setTreeColumn( String ) 设置树形节点列。
getColumn( String ) 根据列名,获取列对象。
hideColumn( String ) 隐藏列。
showColumn( String ) 显示列。
getTask(taskUID) 根据任务UID,获取任务。
getSelected()
 
获取选中的任务。
getSelecteds()
 
获取选中的任务集合。
isSelected(task)
 
判断是否选中任务。
select(task)
 
选中任务。
deselect(task) 取消选中任务。
selectAll()
 
选中所有任务。
deselectAll() 取消选中所有任务。
setMultiSelect( Boolean )
 
设置是否多选任务。
collapseAll ( )
 
折叠所有任务。
expandAll ( )
 
展开所有任务。
collapseLevel( Number )
 
折叠某层级任务。
expandLevel( Number )
 
展开某层级任务。
collapse(task)
 
折叠任务。
expand(task)
 
展开任务。
setShowTableView( Boolean )
 
设置表格是否显示。
setShowGanttView( Boolean )
 
设置条形图是否显示。
setTableViewExpanded( Boolean )
 
设置表格折叠。
setGanttViewExpanded( Boolean )
 
设置条形图折叠。
setTableViewWidth( Number )
 
设置表格宽度。
setGanttViewWidth( Number )
 
设置条形图宽度。
setShowLinkLines( Boolean )
 
设置是否显示箭头连线。
setShowCritical( Boolean )
 
设置是否显示关键路径
setShowGridLines( Boolean )
 
设置是否显示条形图背景表格线。
setTimeLines( Array )
 
设置项目时间线。
setTopTimeScale( String ) String:时间刻度。
"year/halfyear/quarter/month/week/day/hour"
设置顶层时间刻度。
setBottomTimeScale( String )
同上 
设置底层时间刻度。(底层必须比顶层要小)
zoomIn( ) 放大时间刻度
zoomOut( ) 缩小时间刻度
scrollIntoView(task)
 
定位显示任务。
beginEdit(task)
 
启动行编辑。
cancelEdit()
 
取消所有行编辑。
cancelEditRow(task)
 
取消指定行编辑。
isEditing()
 
判断甘特图是否处于编辑状态。
getEditData()
 
获取所有编辑中的行数据集合。

事件

通过如下方式监听事件:

	    functon onTaskDblClick(e){
	        var project = e.sender;
            var task = e.task;
	        //e是事件对象, 具体请看每个事件的"参数类型"
	    }
	    project.on('taskdblclick', onTaskDblClick);
	
事件名称事件对象描述
drawcell
{
    sender: Object, //甘特图对象
    record: Object, //任务对象
    column: Object, //列对象
    field: String,  //属性名
    value: Object,  //单元格值
    rowCls: String, //行样式
    cellCls: String, //单元格样式
    cellHtml: Stirng//单元格内容HTML
}
	            
绘制单元格时发生。
drawitem
{
    sender: Object, //甘特图对象
    item: Object,   //条形图,任务对象
    itemBox: Object, //条形图的坐标尺寸
    itemCls: Stirng, //条形图样式
    itemHtml: Stirng//单元格内容HTML
}
	            
绘制条形图时发生。
taskclick
{
    sender: Object, //甘特图对象
    task: Object    //任务对象
}    
	            
单击任务时发生。
taskdblclick
{
    sender: Object, //甘特图对象
    task: Object    //任务对象
}    
	            
双击任务时发生。
cellbeginedit
{
    sender: Object,     //甘特图对象    
    record: Object,       //任务对象
    column: Object, //列对象
    field: String,  //属性名
    value: Object,  //单元格值
    cancel: Boolean     //是否取消操作
}
	            
单元格开始编辑时发生

常见问题

  1. 安装部署项目时,如果报"PagerGantt未定义",请检查"scripts/boot.js",将"PATH"变量修改成当前WEB项目名称。
  2. 任务的唯一标识符,是UID,而不是ID。ID只是一个序号,UID可以是数字,也可以是字符串。
  3. 任务只能分配给一个部门,但是可以分配给多个负责人。
  4. 如果要给项目或任务增加属性,直接在Hashtable/HashMap上增加即可。
  5. 增加的任务属性仅仅反映到数据上,如果要在界面显示,请扩展表格列。