diff --git a/db/update16.5.sql b/db/update16.5.sql
index 73162f6d57..f3e96818db 100644
--- a/db/update16.5.sql
+++ b/db/update16.5.sql
@@ -114,168 +114,302 @@ UPDATE `zt_workflowfield` SET `control` = 'date' WHERE `module` = 'story' and `f
UPDATE `zt_workflowfield` SET `control` = 'datetime' WHERE `module` = 'story' and `field` = 'closedDate';
UPDATE `zt_workflowfield` SET `control` = 'radio' WHERE `module` = 'story' and `field` = 'deleted';
+UPDATE `zt_workflowaction` SET `position` = 'browse' WHERE `module` = 'product' and `action` = 'all' and `vision` = 'rnd';
+UPDATE `zt_workflowaction` SET `type` = 'batch', `position` = 'browse' WHERE `module` = 'product' and `action` = 'batchedit' and `vision` = 'rnd';
+UPDATE `zt_workflowaction` SET `position` = 'browse' WHERE `module` = 'product' and `action` = 'browse' and `vision` = 'rnd';
+UPDATE `zt_workflowaction` SET `show` = 'direct' WHERE `module` = 'product' and `vision` = 'rnd';
+UPDATE `zt_workflowaction` SET `type` = 'batch', `position` = 'browse' WHERE `module` = 'productplan' and `action` = 'batchedit' and `vision` = 'rnd';
+UPDATE `zt_workflowaction` SET `position` = 'browse' WHERE `module` = 'productplan' and `action` = 'browse' and `vision` = 'rnd';
+UPDATE `zt_workflowaction` SET `show` = 'direct' WHERE `module` = 'productplan' and `vision` = 'rnd';
+UPDATE `zt_workflowaction` SET `position` = 'browse' WHERE `module` = 'release' and `action` = 'browse' and `vision` = 'rnd';
+UPDATE `zt_workflowaction` SET `show` = 'direct' WHERE `module` = 'release' and `vision` = 'rnd';
+UPDATE `zt_workflowaction` SET `type` = 'batch' WHERE `module` = 'story' and `action` = 'batchcreate' and `vision` = 'rnd';
+UPDATE `zt_workflowaction` SET `type` = 'batch' WHERE `module` = 'story' and `action` = 'batchedit' and `vision` = 'rnd';
+UPDATE `zt_workflowaction` SET `position` = 'browse' WHERE `module` = 'story' and `action` = 'browse' and `vision` = 'rnd';
+UPDATE `zt_workflowaction` SET `position` = 'browse' WHERE `module` = 'story' and `action` = 'exporttemplate' and `vision` = 'rnd';
+UPDATE `zt_workflowaction` SET `position` = 'browse' WHERE `module` = 'story' and `action` = 'import' and `vision` = 'rnd';
+UPDATE `zt_workflowaction` SET `position` = 'view' WHERE `module` = 'story' and `action` = 'view' and `vision` = 'rnd';
DELETE FROM `zt_workflowfield` WHERE `module`='execution' AND `field`='stage';
DELETE FROM `zt_workflowfield` WHERE `module`='program' AND `field`='stage';
DELETE FROM `zt_workflowfield` WHERE `module`='project' AND `field`='stage';
DELETE FROM `zt_workflowfield` WHERE `module`='bug' AND `field`='feedback';
DELETE FROM `zt_workflowfield` WHERE `module`='task' AND `field`='feedback';
-INSERT INTO `zt_workflowdatasource` (`type`, `name`, `code`, `buildin`, `datasource`, `view`, `keyField`, `valueField`) VALUES('lang', '项目模型', 'projectModel', '1', 'projectModel', '', '', '');
+
+REPLACE INTO `zt_workflowdatasource` (`type`, `name`, `code`, `buildin`, `datasource`, `view`, `keyField`, `valueField`) VALUES
+('lang', '项目模型', 'projectModel', '1', 'projectModel', '', '', ''),
+('lang', '反馈类型', 'feedbackType', '1', 'feedbackType', '', '', ''),
+('lang', '反馈处理方案', 'feedbackSolution', '1', 'feedbackSolution', '', '', ''),
+('lang', '反馈关闭原因', 'feedbackclosedReason', '1', 'feedbackclosedReason', '', '', '');
+
REPLACE INTO `zt_workflowfield` (`module`, `field`, `type`, `length`, `name`, `control`, `expression`, `options`, `default`, `rules`, `placeholder`, `order`, `searchOrder`, `exportOrder`, `canExport`, `canSearch`, `isValue`, `readonly`, `buildin`, `desc`, `createdBy`, `createdDate`, `editedBy`, `editedDate`) VALUES
-('execution', 'type', 'char', '30', '迭代类型', 'select', '', '16', 'sprint', '', '', 3, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'begin', 'date', '', '计划开始', 'date', '', '', '', '', '', 14, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'end', 'date', '', '计划完成', 'date', '', '', '', '', '', 15, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'days', 'smallint', '5', '可用工作日', 'integer', '', '', '', '', '', 18, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'pri', 'enum', '', '优先级', 'select', '', '[1,2,3,4]', '1', '', '', 20, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'desc', 'text', '', '迭代描述', 'richtext', '', '', '', '', '', 21, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'openedDate', 'datetime', '', '创建日期', 'datetime', '', '', '', '', '', 27, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'closedDate', 'datetime', '', '关闭日期', 'datetime', '', '', '', '', '', 32, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'canceledDate', 'datetime', '', '取消日期', 'datetime', '', '', '', '', '', 34, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'acl', 'char', '30', '访问控制', 'select', '', '18', 'open', '', '', 41, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'whitelist', 'text', '', '白名单', 'multi-select', '', 'user', '', '', '', 42, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'deleted', 'enum', '', '已删除', 'radio', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 47, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'type', 'char', '30', '类型', 'select', '', '16', 'sprint', '', '', 2, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'begin', 'date', '', '计划开始', 'date', '', '', '', '', '', 15, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'end', 'date', '', '计划完成', 'date', '', '', '', '', '', 16, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'days', 'smallint', '5', '可用工作日', 'integer', '', '', '', '', '', 19, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'pri', 'enum', '', '优先级', 'select', '', '[1,2,3,4]', '1', '', '', 21, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'desc', 'text', '', '项目集描述', 'richtext', '', '', '', '', '', 22, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'openedDate', 'datetime', '', '创建日期', 'datetime', '', '', '', '', '', 28, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'closedDate', 'datetime', '', '关闭日期', 'datetime', '', '', '', '', '', 33, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'canceledDate', 'datetime', '', '取消日期', 'datetime', '', '', '', '', '', 35, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'whitelist', 'text', '', '白名单', 'multi-select', '', 'user', '', '', '', 43, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'deleted', 'enum', '', '已删除', 'radio', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 48, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'type', 'char', '30', '项目类型', 'select', '', '16', 'sprint', '', '', 3, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'model', 'char', '30', '项目管理方式', 'input', '', '45', '', '', '', 2, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'name', 'varchar', '90', '项目名称', 'input', '', '', '', '', '', 15, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'begin', 'date', '', '计划开始', 'date', '', '', '', '', '', 16, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'end', 'date', '', '计划完成', 'date', '', '', '', '', '', 17, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'days', 'smallint', '5', '可用工作日', 'integer', '', '', '', '', '', 20, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'pri', 'enum', '', '优先级', 'select', '', '[1,2,3,4]', '1', '', '', 22, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'desc', 'text', '', '项目描述', 'richtext', '', '', '', '', '', 23, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'openedDate', 'datetime', '', '创建日期', 'datetime', '', '', '', '', '', 29, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'closedDate', 'datetime', '', '关闭日期', 'datetime', '', '', '', '', '', 34, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'canceledDate', 'datetime', '', '取消日期', 'datetime', '', '', '', '', '', 36, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'acl', 'char', '30', '访问控制', 'select', '', '18', 'open', '', '', 43, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'whitelist', 'text', '', '项目白名单', 'multi-select', '', 'user', '', '', '', 44, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'deleted', 'enum', '', '已删除', 'radio', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 49, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('build', 'project', 'mediumint', '8', '所属项目', 'select', '', '2', '0', '', '', 4, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('build', 'date', 'date', '', '打包日期', 'date', '', '', '', '', '', 9, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('build', 'desc', 'text', '', '描述', 'richtext', '', '', '', '', '', 13, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('build', 'deleted', 'enum', '', '已删除', 'radio', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 14, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'project', 'mediumint', '8', '所属项目', 'select', '', '2', '0', '', '', 2, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'storyVersion', 'smallint', '6', '研发需求版本', 'integer', '', '', '1', '', '', 9, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'toTask', 'mediumint', '8', '转任务', 'select', '', '5', '0', '', '', 11, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'toStory', 'mediumint', '8', '转研发需求', 'select', '', '4', '0', '', '', 12, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'steps', 'mediumtext', '', '重现步骤', 'richtext', '', '', '', '', '', 22, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'activatedDate', 'datetime', '', '激活日期', 'datetime', '', '', '', '', '', 27, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'openedDate', 'datetime', '', '创建日期', 'datetime', '', '', '', '', '', 32, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'openedBuild', 'varchar', '255', '影响版本', 'multi-select', '', '10', '', '', '', 33, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'assignedDate', 'datetime', '', '指派日期', 'datetime', '', '', '', '', '', 35, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'deadline', 'date', '', '截止日期', 'date', '', '', '', '', '', 36, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'resolvedDate', 'datetime', '30', '解决日期', 'datetime', '', '', '', '', '', 40, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'closedDate', 'datetime', '', '关闭日期', 'datetime', '', '', '', '', '', 42, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'case', 'mediumint', '8', '相关用例', 'select', '', '41', '', '', '', 45, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'caseVersion', 'smallint', '6', '用例版本', 'integer', '', '', '', '', '', 46, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'lastEditedDate', 'datetime', '30', '修改日期', 'datetime', '', '', '', '', '', 58, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'deleted', 'enum', '', '已删除', 'radio', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 59, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'project', 'mediumint', '8', '所属项目', 'select', '', '2', '0', '', '', 2, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'storyVersion', 'smallint', '6', '研发需求版本', 'integer', '', '', '1', '', '', 7, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'estimate', 'float ', '', '最初预计', 'decimal', '', '', '', '', '', 13, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'consumed', 'float ', '', '总计消耗', 'decimal', '', '', '', '', '', 14, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'left', 'float ', '', '预计剩余', 'decimal', '', '', '', '', '', 15, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'deadline', 'date', '', '截止日期', 'date', '', '', '', '', '', 16, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'desc', 'text', '', '任务描述', 'richtext', '', '', '', '', '', 20, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'openedDate', 'datetime', '', '创建日期', 'datetime', '', '', '', '', '', 23, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'assignedDate', 'datetime', '30', '指派日期', 'datetime', '', '', '', '', '', 25, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'estStarted', 'date', '', '预计开始', 'date', '', '', '', '', '', 26, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'realStarted', 'date', '', '实际开始', 'date', '', '', '', '', '', 27, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'finishedDate', 'datetime', '', '实际完成', 'datetime', '', '', '', '', '', 29, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'canceledDate', 'datetime', '', '取消时间', 'datetime', '', '', '', '', '', 32, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'closedDate', 'datetime', '', '关闭时间', 'datetime', '', '', '', '', '', 34, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'lastEditedDate', 'datetime', '', '最后修改日期', 'datetime', '', '', '', '', '', 39, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'deleted', 'enum', '', '已删除', 'select', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 48, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'lifetime', 'char', '30', 'lifetime', 'input', '', '', '', '', '', 4, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'lifetime', 'char', '30', 'lifetime', 'input', '', '', '', '', '', 3, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'designVersion', 'smallint', '6', '设计版本', 'integer', '', '', '', '', '', 8, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'attribute', 'varchar', '30', 'attribute', 'input', '', '', '0', '', '', 5, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'percent', 'float', '', 'percent', 'input', '', '', '0', '', '', 6, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'milestone', 'enum', '', 'milestone', 'radio', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 7, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'output', 'text', '', 'output', 'textarea', '', '', '', '', '', 8, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'auth', 'char', '30', 'auth', 'input', '', '', '', '', '', 9, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'path', 'varchar', '255', 'path', 'input', '', '', '0', '', '', 10, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'grade', 'tinyint', '3', 'grade', 'integer', '', '', '0', '', '', 11, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'realBegan', 'date', '', '实际开始日期', 'date', '', '', '', '', '', 16, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'realEnd', 'date', '', '实际完成日期', 'date', '', '', '', '', '', 17, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'version', 'smallint', '6', 'version', 'integer', '', '', '', '', '', 22, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'parentVersion', 'smallint', '6', 'parentVersion', 'integer', '', '', '', '', '', 23, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'planDuration', 'int', '11', 'planDuration', 'integer', '', '', '', '', '', 24, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'realDuration', 'int', '11', 'realDuration', 'integer', '', '', '', '', '', 25, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'openedVersion', 'varchar', '20', 'openedVersion', 'input', '', '', '', '', '', 28, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'lastEditedBy', 'varchar', '30', 'lastEditedBy', 'select', '', 'user', '', '', '', 29, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'lastEditedDate', 'datetime', '', 'lastEditedDate', 'datetime', '', '', '', '', '', 30, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'suspendedDate', 'date', '', 'suspendedDate', 'date', '', '', '', '', '', 35, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'vision', 'varchar', '10', 'vision', 'input', '', '', 'rnd', '', '', 44, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'displayCards', 'enum', '', 'displayCards', 'radio', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 45, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('execution', 'fluidBoard', 'enum', '', 'fluidBoard', 'radio', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 46, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'output', 'text', '', 'output', 'textarea', '', '', '', '', '', 9, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'auth', 'char', '30', 'auth', 'input', '', '', '', '', '', 10, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'path', 'varchar', '255', 'path', 'input', '', '', '0', '', '', 12, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'grade', 'tinyint', '3', 'grade', 'integer', '', '', '0', '', '', 13, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'realBegan', 'date', '', 'realBegan', 'date', '', '', '', '', '', 17, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'realEnd', 'date', '', 'realEnd', 'date', '', '', '', '', '', 18, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'version', 'smallint', '6', 'version', 'integer', '', '', '', '', '', 23, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'parentVersion', 'smallint', '6', 'parentVersion', 'integer', '', '', '', '', '', 24, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'planDuration', 'int', '11', 'planDuration', 'integer', '', '', '', '', '', 25, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'realDuration', 'int', '11', 'realDuration', 'integer', '', '', '', '', '', 26, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'openedVersion', 'varchar', '20', 'openedVersion', 'input', '', '', '', '', '', 29, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'lastEditedBy', 'varchar', '30', 'lastEditedBy', 'select', '', 'user', '', '', '', 30, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'lastEditedDate', 'datetime', '', 'lastEditedDate', 'datetime', '', '', '', '', '', 31, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'suspendedDate', 'date', '', 'suspendedDate', 'date', '', '', '', '', '', 36, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'vision', 'varchar', '10', 'vision', 'input', '', '', 'rnd', '', '', 45, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'displayCards', 'enum', '', 'displayCards', 'radio', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 46, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('program', 'fluidBoard', 'enum', '', 'fluidBoard', 'radio', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 47, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'lifetime', 'char', '30', '项目周期', 'input', '', '', '', '', '', 4, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'attribute', 'varchar', '30', '阶段类型', 'input', '', '', '0', '', '', 7, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'percent', 'float', '', '工作量占比', 'input', '', '', '0', '', '', 8, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'milestone', 'enum', '', '里程碑', 'radio', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 9, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'output', 'text', '', '输出', 'textarea', '', '', '', '', '', 10, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'auth', 'char', '30', '权限控制', 'input', '', '', '', '', '', 11, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'path', 'varchar', '255', '路径', 'input', '', '', '0', '', '', 13, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'grade', 'tinyint', '3', '层级', 'integer', '', '', '0', '', '', 14, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'realBegan', 'date', '', '实际开始日期', 'date', '', '', '', '', '', 18, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'realEnd', 'date', '', '实际完成日期', 'date', '', '', '', '', '', 19, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'version', 'smallint', '6', '版本', 'integer', '', '', '', '', '', 24, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'parentVersion', 'smallint', '6', '父版本', 'integer', '', '', '', '', '', 25, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'planDuration', 'int', '11', '计划周期天数', 'integer', '', '', '', '', '', 26, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'realDuration', 'int', '11', '实际周期天数', 'integer', '', '', '', '', '', 27, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'openedVersion', 'varchar', '20', '创建版本', 'input', '', '', '', '', '', 30, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'lastEditedBy', 'varchar', '30', '最后编辑人', 'select', '', 'user', '', '', '', 31, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'lastEditedDate', 'datetime', '', '最后编辑日期', 'datetime', '', '', '', '', '', 32, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'suspendedDate', 'date', '', 'suspendedDate', 'date', '', '', '', '', '', 37, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'vision', 'varchar', '10', 'vision', 'input', '', '', 'rnd', '', '', 46, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'displayCards', 'enum', '', 'displayCards', 'radio', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 47, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('project', 'fluidBoard', 'enum', '', 'fluidBoard', 'radio', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 48, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'hardware', 'varchar', '30', '硬件', 'input', '', '', '', '', '', 20, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'feedbackBy', 'varchar', '100', '反馈者', 'input', '', '', '', '', '', 28, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'notifyEmail', 'varchar', '100', '通知邮箱', 'input', '', '', '', '', '', 29, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'result', 'mediumint', '8', '结果', 'input', '', '', '', '', '', 47, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'repo', 'mediumint', '8', '所属版本库', 'input', '', '', '', '', '', 48, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'mr', 'mediumint', '8', 'mr', 'input', '', '', '', '', '', 49, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'entry', 'text', '', 'entry', 'input', '', '', '', '', '', 50, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'lines', 'varchar', '10', '代码行', 'input', '', '', '', '', '', 51, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'v1', 'varchar', '40', '版本1', 'input', '', '', '', '', '', 52, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'v2', 'varchar', '40', '版本2', 'input', '', '', '', '', '', 53, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'repoType', 'varchar', '30', '版本库类型', 'input', '', '', '', '', '', 54, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('bug', 'issueKey', 'varchar', '50', 'issueKey', 'input', '', '', '', '', '', 55, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'version', 'smallint', '6', '版本', 'integer', '', '', '', '', '', 21, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'planDuration', 'int', '11', '计划持续天数', 'integer', '', '', '', '', '', 35, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'realDuration', 'int', '11', '实际持续天数', 'integer', '', '', '', '', '', 36, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'activatedDate', 'datetime', '', '激活日期', 'datetime', '', '', '', '', '', 40, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'repo', 'mediumint', '8', 'repo', 'input', '', '', '', '', '', 41, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'mr', 'mediumint', '8', 'mr', 'input', '', '', '', '', '', 42, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'entry', 'text', '', 'entry', 'input', '', '', '', '', '', 43, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'lines', 'varchar', '10', 'lines', 'input', '', '', '', '', '', 44, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'v1', 'varchar', '40', 'v1', 'input', '', '', '', '', '', 45, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'v2', 'varchar', '40', 'v2', 'input', '', '', '', '', '', 46, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
-('task', 'vision', 'varchar', '10', 'vision', 'input', '', '', 'rnd', '', '', 47, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00');
-UPDATE `zt_workflowfield` SET `options`=(SELECT id FROM `zt_workflowdatasource` WHERE `code`='projectModel' LIMIT 1) WHERE `module`='project' AND `field`='model';
\ No newline at end of file
+('execution', 'type', 'char', '30', '迭代类型', 'select', '', '16', 'sprint', '', '', 3, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'begin', 'date', '', '计划开始', 'date', '', '', '', '', '', 14, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'end', 'date', '', '计划完成', 'date', '', '', '', '', '', 15, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'days', 'smallint', '5', '可用工作日', 'integer', '', '', '', '', '', 18, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'pri', 'enum', '', '优先级', 'select', '', '[1,2,3,4]', '1', '', '', 20, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'desc', 'text', '', '迭代描述', 'richtext', '', '', '', '', '', 21, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'openedDate', 'datetime', '', '创建日期', 'datetime', '', '', '', '', '', 27, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'closedDate', 'datetime', '', '关闭日期', 'datetime', '', '', '', '', '', 32, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'canceledDate', 'datetime', '', '取消日期', 'datetime', '', '', '', '', '', 34, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'acl', 'char', '30', '访问控制', 'select', '', '18', 'open', '', '', 41, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'whitelist', 'text', '', '白名单', 'multi-select', '', 'user', '', '', '', 42, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'deleted', 'enum', '', '已删除', 'radio', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 47, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'type', 'char', '30', '类型', 'select', '', '16', 'sprint', '', '', 2, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'begin', 'date', '', '计划开始', 'date', '', '', '', '', '', 15, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'end', 'date', '', '计划完成', 'date', '', '', '', '', '', 16, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'days', 'smallint', '5', '可用工作日', 'integer', '', '', '', '', '', 19, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'pri', 'enum', '', '优先级', 'select', '', '[1,2,3,4]', '1', '', '', 21, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'desc', 'text', '', '项目集描述', 'richtext', '', '', '', '', '', 22, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'openedDate', 'datetime', '', '创建日期', 'datetime', '', '', '', '', '', 28, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'closedDate', 'datetime', '', '关闭日期', 'datetime', '', '', '', '', '', 33, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'canceledDate', 'datetime', '', '取消日期', 'datetime', '', '', '', '', '', 35, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'whitelist', 'text', '', '白名单', 'multi-select', '', 'user', '', '', '', 43, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'deleted', 'enum', '', '已删除', 'radio', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 48, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'type', 'char', '30', '项目类型', 'select', '', '16', 'sprint', '', '', 3, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'model', 'char', '30', '项目管理方式', 'input', '', '45', '', '', '', 2, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'name', 'varchar', '90', '项目名称', 'input', '', '', '', '', '', 15, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'begin', 'date', '', '计划开始', 'date', '', '', '', '', '', 16, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'end', 'date', '', '计划完成', 'date', '', '', '', '', '', 17, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'days', 'smallint', '5', '可用工作日', 'integer', '', '', '', '', '', 20, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'pri', 'enum', '', '优先级', 'select', '', '[1,2,3,4]', '1', '', '', 22, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'desc', 'text', '', '项目描述', 'richtext', '', '', '', '', '', 23, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'openedDate', 'datetime', '', '创建日期', 'datetime', '', '', '', '', '', 29, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'closedDate', 'datetime', '', '关闭日期', 'datetime', '', '', '', '', '', 34, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'canceledDate', 'datetime', '', '取消日期', 'datetime', '', '', '', '', '', 36, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'acl', 'char', '30', '访问控制', 'select', '', '18', 'open', '', '', 43, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'whitelist', 'text', '', '项目白名单', 'multi-select', '', 'user', '', '', '', 44, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'deleted', 'enum', '', '已删除', 'radio', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 49, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('build', 'project', 'mediumint', '8', '所属项目', 'select', '', '2', '0', '', '', 4, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('build', 'date', 'date', '', '打包日期', 'date', '', '', '', '', '', 9, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('build', 'desc', 'text', '', '描述', 'richtext', '', '', '', '', '', 13, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('build', 'deleted', 'enum', '', '已删除', 'radio', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 14, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'project', 'mediumint', '8', '所属项目', 'select', '', '2', '0', '', '', 2, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'storyVersion', 'smallint', '6', '研发需求版本', 'integer', '', '', '1', '', '', 9, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'toTask', 'mediumint', '8', '转任务', 'select', '', '5', '0', '', '', 11, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'toStory', 'mediumint', '8', '转研发需求', 'select', '', '4', '0', '', '', 12, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'steps', 'mediumtext', '', '重现步骤', 'richtext', '', '', '', '', '', 22, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'activatedDate', 'datetime', '', '激活日期', 'datetime', '', '', '', '', '', 27, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'openedDate', 'datetime', '', '创建日期', 'datetime', '', '', '', '', '', 32, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'openedBuild', 'varchar', '255', '影响版本', 'multi-select', '', '10', '', '', '', 33, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'assignedDate', 'datetime', '', '指派日期', 'datetime', '', '', '', '', '', 35, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'deadline', 'date', '', '截止日期', 'date', '', '', '', '', '', 36, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'resolvedDate', 'datetime', '30', '解决日期', 'datetime', '', '', '', '', '', 40, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'closedDate', 'datetime', '', '关闭日期', 'datetime', '', '', '', '', '', 42, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'case', 'mediumint', '8', '相关用例', 'select', '', '41', '', '', '', 45, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'caseVersion', 'smallint', '6', '用例版本', 'integer', '', '', '', '', '', 46, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'lastEditedDate', 'datetime', '30', '修改日期', 'datetime', '', '', '', '', '', 58, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'deleted', 'enum', '', '已删除', 'radio', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 59, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'project', 'mediumint', '8', '所属项目', 'select', '', '2', '0', '', '', 2, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'storyVersion', 'smallint', '6', '研发需求版本', 'integer', '', '', '1', '', '', 7, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'estimate', 'float', '', '最初预计', 'decimal', '', '', '', '', '', 13, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'consumed', 'float', '', '总计消耗', 'decimal', '', '', '', '', '', 14, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'left', 'float', '', '预计剩余', 'decimal', '', '', '', '', '', 15, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'deadline', 'date', '', '截止日期', 'date', '', '', '', '', '', 16, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'desc', 'text', '', '任务描述', 'richtext', '', '', '', '', '', 20, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'openedDate', 'datetime', '', '创建日期', 'datetime', '', '', '', '', '', 23, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'assignedDate', 'datetime', '30', '指派日期', 'datetime', '', '', '', '', '', 25, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'estStarted', 'date', '', '预计开始', 'date', '', '', '', '', '', 26, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'realStarted', 'date', '', '实际开始', 'date', '', '', '', '', '', 27, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'finishedDate', 'datetime', '', '实际完成', 'datetime', '', '', '', '', '', 29, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'canceledDate', 'datetime', '', '取消时间', 'datetime', '', '', '', '', '', 32, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'closedDate', 'datetime', '', '关闭时间', 'datetime', '', '', '', '', '', 34, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'lastEditedDate', 'datetime', '', '最后修改日期', 'datetime', '', '', '', '', '', 39, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'deleted', 'enum', '', '已删除', 'select', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 48, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'lifetime', 'char', '30', 'lifetime', 'input', '', '', '', '', '', 4, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'lifetime', 'char', '30', 'lifetime', 'input', '', '', '', '', '', 3, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'designVersion', 'smallint', '6', '设计版本', 'integer', '', '', '', '', '', 8, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'attribute', 'varchar', '30', 'attribute', 'input', '', '', '0', '', '', 5, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'percent', 'float', '', 'percent', 'input', '', '', '0', '', '', 6, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'milestone', 'enum', '', 'milestone', 'radio', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 7, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'output', 'text', '', 'output', 'textarea', '', '', '', '', '', 8, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'auth', 'char', '30', 'auth', 'input', '', '', '', '', '', 9, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'path', 'varchar', '255', 'path', 'input', '', '', '0', '', '', 10, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'grade', 'tinyint', '3', 'grade', 'integer', '', '', '0', '', '', 11, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'realBegan', 'date', '', '实际开始日期', 'date', '', '', '', '', '', 16, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'realEnd', 'date', '', '实际完成日期', 'date', '', '', '', '', '', 17, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'version', 'smallint', '6', 'version', 'integer', '', '', '', '', '', 22, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'parentVersion', 'smallint', '6', 'parentVersion', 'integer', '', '', '', '', '', 23, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'planDuration', 'int', '11', 'planDuration', 'integer', '', '', '', '', '', 24, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'realDuration', 'int', '11', 'realDuration', 'integer', '', '', '', '', '', 25, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'openedVersion', 'varchar', '20', 'openedVersion', 'input', '', '', '', '', '', 28, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'lastEditedBy', 'varchar', '30', 'lastEditedBy', 'select', '', 'user', '', '', '', 29, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'lastEditedDate', 'datetime', '', 'lastEditedDate', 'datetime', '', '', '', '', '', 30, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'suspendedDate', 'date', '', 'suspendedDate', 'date', '', '', '', '', '', 35, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'vision', 'varchar', '10', 'vision', 'input', '', '', 'rnd', '', '', 44, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'displayCards', 'enum', '', 'displayCards', 'radio', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 45, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('execution', 'fluidBoard', 'enum', '', 'fluidBoard', 'radio', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 46, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'output', 'text', '', 'output', 'textarea', '', '', '', '', '', 9, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'auth', 'char', '30', 'auth', 'input', '', '', '', '', '', 10, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'path', 'varchar', '255', 'path', 'input', '', '', '0', '', '', 12, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'grade', 'tinyint', '3', 'grade', 'integer', '', '', '0', '', '', 13, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'realBegan', 'date', '', 'realBegan', 'date', '', '', '', '', '', 17, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'realEnd', 'date', '', 'realEnd', 'date', '', '', '', '', '', 18, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'version', 'smallint', '6', 'version', 'integer', '', '', '', '', '', 23, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'parentVersion', 'smallint', '6', 'parentVersion', 'integer', '', '', '', '', '', 24, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'planDuration', 'int', '11', 'planDuration', 'integer', '', '', '', '', '', 25, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'realDuration', 'int', '11', 'realDuration', 'integer', '', '', '', '', '', 26, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'openedVersion', 'varchar', '20', 'openedVersion', 'input', '', '', '', '', '', 29, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'lastEditedBy', 'varchar', '30', 'lastEditedBy', 'select', '', 'user', '', '', '', 30, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'lastEditedDate', 'datetime', '', 'lastEditedDate', 'datetime', '', '', '', '', '', 31, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'suspendedDate', 'date', '', 'suspendedDate', 'date', '', '', '', '', '', 36, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'vision', 'varchar', '10', 'vision', 'input', '', '', 'rnd', '', '', 45, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'displayCards', 'enum', '', 'displayCards', 'radio', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 46, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('program', 'fluidBoard', 'enum', '', 'fluidBoard', 'radio', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 47, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'lifetime', 'char', '30', '项目周期', 'input', '', '', '', '', '', 4, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'attribute', 'varchar', '30', '阶段类型', 'input', '', '', '0', '', '', 7, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'percent', 'float', '', '工作量占比', 'input', '', '', '0', '', '', 8, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'milestone', 'enum', '', '里程碑', 'radio', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 9, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'output', 'text', '', '输出', 'textarea', '', '', '', '', '', 10, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'auth', 'char', '30', '权限控制', 'input', '', '', '', '', '', 11, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'path', 'varchar', '255', '路径', 'input', '', '', '0', '', '', 13, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'grade', 'tinyint', '3', '层级', 'integer', '', '', '0', '', '', 14, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'realBegan', 'date', '', '实际开始日期', 'date', '', '', '', '', '', 18, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'realEnd', 'date', '', '实际完成日期', 'date', '', '', '', '', '', 19, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'version', 'smallint', '6', '版本', 'integer', '', '', '', '', '', 24, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'parentVersion', 'smallint', '6', '父版本', 'integer', '', '', '', '', '', 25, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'planDuration', 'int', '11', '计划周期天数', 'integer', '', '', '', '', '', 26, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'realDuration', 'int', '11', '实际周期天数', 'integer', '', '', '', '', '', 27, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'openedVersion', 'varchar', '20', '创建版本', 'input', '', '', '', '', '', 30, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'lastEditedBy', 'varchar', '30', '最后编辑人', 'select', '', 'user', '', '', '', 31, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'lastEditedDate', 'datetime', '', '最后编辑日期', 'datetime', '', '', '', '', '', 32, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'suspendedDate', 'date', '', 'suspendedDate', 'date', '', '', '', '', '', 37, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'vision', 'varchar', '10', 'vision', 'input', '', '', 'rnd', '', '', 46, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'displayCards', 'enum', '', 'displayCards', 'radio', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 47, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('project', 'fluidBoard', 'enum', '', 'fluidBoard', 'radio', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 48, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'hardware', 'varchar', '30', '硬件', 'input', '', '', '', '', '', 20, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'feedbackBy', 'varchar', '100', '反馈者', 'input', '', '', '', '', '', 28, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'notifyEmail', 'varchar', '100', '通知邮箱', 'input', '', '', '', '', '', 29, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'result', 'mediumint', '8', '结果', 'input', '', '', '', '', '', 47, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'repo', 'mediumint', '8', '所属版本库', 'input', '', '', '', '', '', 48, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'mr', 'mediumint', '8', 'mr', 'input', '', '', '', '', '', 49, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'entry', 'text', '', 'entry', 'input', '', '', '', '', '', 50, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'lines', 'varchar', '10', '代码行', 'input', '', '', '', '', '', 51, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'v1', 'varchar', '40', '版本1', 'input', '', '', '', '', '', 52, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'v2', 'varchar', '40', '版本2', 'input', '', '', '', '', '', 53, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'repoType', 'varchar', '30', '版本库类型', 'input', '', '', '', '', '', 54, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('bug', 'issueKey', 'varchar', '50', 'issueKey', 'input', '', '', '', '', '', 55, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'version', 'smallint', '6', '版本', 'integer', '', '', '', '', '', 21, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'planDuration', 'int', '11', '计划持续天数', 'integer', '', '', '', '', '', 35, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'realDuration', 'int', '11', '实际持续天数', 'integer', '', '', '', '', '', 36, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'activatedDate', 'datetime', '', '激活日期', 'datetime', '', '', '', '', '', 40, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'repo', 'mediumint', '8', 'repo', 'input', '', '', '', '', '', 41, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'mr', 'mediumint', '8', 'mr', 'input', '', '', '', '', '', 42, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'entry', 'text', '', 'entry', 'input', '', '', '', '', '', 43, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'lines', 'varchar', '10', 'lines', 'input', '', '', '', '', '', 44, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'v1', 'varchar', '40', 'v1', 'input', '', '', '', '', '', 45, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'v2', 'varchar', '40', 'v2', 'input', '', '', '', '', '', 46, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('task', 'vision', 'varchar', '10', 'vision', 'input', '', '', '', '', '', 47, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('feedback', 'type', 'char', '30', '反馈类型', 'select', '', '', '', '', '', 4, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('feedback', 'notifyEmail', 'varchar', '100', '通知邮箱', 'input', '', '', '', '', '', 9, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('feedback', 'faq', 'mediumint', '8', 'FAQ', 'input', '', '', '', '', '', 11, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('feedback', 'feedbackBy', 'varchar', '100', '反馈者', 'select', '', 'user', '', '', '', 25, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('feedback', 'solution', 'char', '30', '反馈处理方案', 'select', '', '', '', '', '', 5, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('testcase', 'auto', 'varchar', '10', '自动化测试用例', 'input', '', '', '', '', '', 15, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('testcase', 'frame', 'varchar', '10', '自动化测试框架', 'input', '', '', '', '', '', 16, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('testcase', 'howRun', 'char', '30', '测试方式', 'input', '', '', '', '', '', 18, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('testcase', 'scriptedBy', 'char', '30', '脚本由谁创建', 'select', '', 'user', '', '', '', 18, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('testcase', 'scriptedDate', 'char', '30', '脚本创建日期', 'date', '', '', '', '', '', 18, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('testcase', 'scriptStatus', 'char', '30', '脚本状态', 'input', '', '', '', '', '', 18, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('testcase', 'scriptLocation', 'char', '30', '脚本地址', 'input', '', '', '', '', '', 18, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('testcase', 'frequency', 'char', '30', '使用频率', 'input', '', '', '', '', '', 28, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('testcase', 'fromCaseID', 'char', '30', '用例来源ID', 'input', '', '', '', '', '', 28, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('testcase', 'fromCaseVersion', 'char', '30', '用例来源版本', 'input', '', '', '', '', '', 5, 0, 0, '0', '0', '0', '1', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00'),
+('testcase', 'subStatus', 'varchar', '30', '子状态', 'select', '', '', '', '', '', 17, 0, 0, '0', '0', '0', '0', 1, '', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00');
+UPDATE `zt_workflowfield` SET `options`=(SELECT id FROM `zt_workflowdatasource` WHERE `code`='projectModel' LIMIT 1) WHERE `module`='project' AND `field`='model';
+UPDATE `zt_workflowfield` SET `options`=(SELECT id FROM `zt_workflowdatasource` WHERE `code`='feedbackType' LIMIT 1) WHERE `module`='feedback' AND `field`='type';
+UPDATE `zt_workflowfield` SET `options`=(SELECT id FROM `zt_workflowdatasource` WHERE `code`='feedbackSolution' LIMIT 1) WHERE `module`='feedback' AND `field`='solution';
+
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='project' AND `action`='browse';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browse', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='project' AND `action`='create';
+UPDATE `zt_workflowaction` SET `type`='batch', `position`='browse', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='project' AND `action`='batchedit';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='project' AND `action`='edit';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browse', `show`='direct', `open`='normal', `layout`='side' WHERE `module`='project' AND `action`='view';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='dropdownlist', `open`='none', `layout`='normal' WHERE `module`='project' AND `action`='delete';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='dropdownlist', `open`='modal', `layout`='normal' WHERE `module`='project' AND `action`='close';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='dropdownlist', `open`='modal', `layout`='normal' WHERE `module`='project' AND `action`='activate';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='project' AND `action`='start';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='dropdownlist', `open`='modal', `layout`='normal' WHERE `module`='project' AND `action`='suspend';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='execution' AND `action`='task';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='execution' AND `action`='create';
+UPDATE `zt_workflowaction` SET `type`='batch', `position`='browse', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='execution' AND `action`='batchedit';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='execution' AND `action`='edit';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browse', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='execution' AND `action`='view';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='none', `layout`='normal' WHERE `module`='execution' AND `action`='delete';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='view', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='execution' AND `action`='close';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='view', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='execution' AND `action`='activate';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='execution' AND `action`='start';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='view', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='execution' AND `action`='putoff';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='execution' AND `action`='suspend';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='execution' AND `action`='all';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='task' AND `action`='browse';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='task' AND `action`='create';
+UPDATE `zt_workflowaction` SET `type`='batch', `position`='browseandview', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='task' AND `action`='batchcreate';
+UPDATE `zt_workflowaction` SET `type`='batch', `position`='browse', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='task' AND `action`='batchedit';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browse', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='task' AND `action`='exporttemplate';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browse', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='task' AND `action`='import';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browse', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='task' AND `action`='showimport';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='normal', `layout`='side' WHERE `module`='task' AND `action`='edit';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browse', `show`='direct', `open`='normal', `layout`='side' WHERE `module`='task' AND `action`='view';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='view', `show`='direct', `open`='none', `layout`='normal' WHERE `module`='task' AND `action`='delete';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='task' AND `action`='close';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='view', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='task' AND `action`='activate';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='task' AND `action`='assignTo';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='view', `show`='direct', `open`='none', `layout`='normal' WHERE `module`='task' AND `action`='confirmStoryChange';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='task' AND `action`='start';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='task' AND `action`='finish';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='view', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='task' AND `action`='pause';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='task' AND `action`='restart';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='view', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='task' AND `action`='cancel';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='build' AND `action`='browse';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browse', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='build' AND `action`='create';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='build' AND `action`='edit';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browse', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='build' AND `action`='view';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='none', `layout`='normal' WHERE `module`='build' AND `action`='delete';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='bug' AND `action`='browse';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='bug' AND `action`='create';
+UPDATE `zt_workflowaction` SET `type`='batch', `position`='browse', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='bug' AND `action`='batchcreate';
+UPDATE `zt_workflowaction` SET `type`='batch', `position`='browse', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='bug' AND `action`='batchedit';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browse', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='bug' AND `action`='exporttemplate';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browse', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='bug' AND `action`='import';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browse', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='bug' AND `action`='showimport';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='normal', `layout`='side' WHERE `module`='bug' AND `action`='edit';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browse', `show`='direct', `open`='normal', `layout`='side' WHERE `module`='bug' AND `action`='view';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='view', `show`='direct', `open`='none', `layout`='normal' WHERE `module`='bug' AND `action`='delete';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='bug' AND `action`='close';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='view', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='bug' AND `action`='activate';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='bug' AND `action`='assignTo';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='bug' AND `action`='confirmBug';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='bug' AND `action`='resolve';
+UPDATE `zt_workflowaction` SET `type`='batch', `position`='browse', `show`='direct', `open`='none', `layout`='normal' WHERE `module`='bug' AND `action`='batchconfirm';
+UPDATE `zt_workflowaction` SET `type`='batch', `position`='browse', `show`='direct', `open`='none', `layout`='normal' WHERE `module`='bug' AND `action`='batchresolve';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='dropdownlist', `open`='modal', `layout`='normal' WHERE `module`='project' AND `action`='activate';
+UPDATE `zt_workflowaction` SET `type`='batch', `position`='browse', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='project' AND `action`='batchedit';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='project' AND `action`='browse';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='dropdownlist', `open`='modal', `layout`='normal' WHERE `module`='project' AND `action`='close';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browse', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='project' AND `action`='create';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='dropdownlist', `open`='none', `layout`='normal' WHERE `module`='project' AND `action`='delete';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='project' AND `action`='edit';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='project' AND `action`='start';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='dropdownlist', `open`='modal', `layout`='normal' WHERE `module`='project' AND `action`='suspend';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browse', `show`='direct', `open`='normal', `layout`='side' WHERE `module`='project' AND `action`='view';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='view', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='task' AND `action`='activate';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='task' AND `action`='assignTo';
+UPDATE `zt_workflowaction` SET `type`='batch', `position`='browseandview', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='task' AND `action`='batchcreate';
+UPDATE `zt_workflowaction` SET `type`='batch', `position`='browse', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='task' AND `action`='batchedit';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='task' AND `action`='browse';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='view', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='task' AND `action`='cancel';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='task' AND `action`='close';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='view', `show`='direct', `open`='none', `layout`='normal' WHERE `module`='task' AND `action`='confirmStoryChange';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='normal', `layout`='normal' WHERE `module`='task' AND `action`='create';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='view', `show`='direct', `open`='none', `layout`='normal' WHERE `module`='task' AND `action`='delete';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='normal', `layout`='side' WHERE `module`='task' AND `action`='edit';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browse', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='task' AND `action`='exporttemplate';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='task' AND `action`='finish';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browse', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='task' AND `action`='import';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='view', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='task' AND `action`='pause';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='task' AND `action`='restart';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browse', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='task' AND `action`='showimport';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browseandview', `show`='direct', `open`='modal', `layout`='normal' WHERE `module`='task' AND `action`='start';
+UPDATE `zt_workflowaction` SET `type`='single', `position`='browse', `show`='direct', `open`='normal', `layout`='side' WHERE `module`='task' AND `action`='view';
+UPDATE `zt_workflowaction` SET `type`='batch' WHERE `module`IN ('feedback','caselib','testsuite','testtask','testcase') AND `action` IN ('admin','browse','batchedit','batchcreate','import','showimport');
+UPDATE `zt_workflowaction` SET `position`='browse' WHERE `module`IN ('feedback','caselib','testsuite','testtask','testcase') AND `action` IN ('batchedit','batchcreate','import','showimport');
diff --git a/framework/control.class.php b/framework/control.class.php
index 326c9f9c20..c153bb29f0 100644
--- a/framework/control.class.php
+++ b/framework/control.class.php
@@ -326,10 +326,7 @@ class control extends baseControl
if(!isset($this->config->bizVersion)) return false;
$moduleName = $this->moduleName;
- if(strpos(',bug,feedback,caselib,testsuite,testtask,testcase,product,productplan,', ",{$moduleName},") !== false) return $this->$moduleName->buildOperateMenu($object, $type);
-
- $flow = $this->loadModel('workflow')->getByModule($moduleName);
- return $this->loadModel('flow')->buildOperateMenu($flow, $object, $type);
+ return $this->$moduleName->buildOperateMenu($object, $type);
}
/**
diff --git a/module/action/config.php b/module/action/config.php
index caa2de9145..b5c5f0c8c0 100755
--- a/module/action/config.php
+++ b/module/action/config.php
@@ -60,3 +60,9 @@ $config->action->majorList['execution'] = array('opened', 'edited');
$config->action->needGetProjectType = 'build,task,bug,case,testcase,caselib,testtask,testsuite,testreport,doc,issue,release,risk,design,opportunity,trainplan,gapanalysis,researchplan,researchreport,';
$config->action->needGetRelateField = ',story,productplan,release,task,build,bug,testcase,case,testtask,testreport,doc,doclib,issue,risk,opportunity,trainplan,gapanalysis,team,whitelist,researchplan,researchreport,meeting,kanbanlane,kanbancolumn,';
$config->action->noLinkModules = ',doclib,module,webhook,gitlab,sonarqube,pipeline,jenkins,kanban,kanbanspace,kanbancolumn,kanbanlane,kanbanregion,kanbancard,execution,project,traincategory,apistruct,program,product,';
+
+$config->action->preferredTypeNum = 10;
+
+$config->action->preferredType = new stdclass();
+$config->action->preferredType->new = array('user', 'story', 'task', 'bug', 'case', 'doc', 'program', 'product', 'project', 'execution');
+$config->action->preferredType->classic = array('user', 'story', 'task', 'bug', 'case', 'doc', 'product', 'execution', 'productplan', 'build');
diff --git a/module/action/control.php b/module/action/control.php
index 7a143d26ba..1057f4fc8a 100755
--- a/module/action/control.php
+++ b/module/action/control.php
@@ -14,6 +14,7 @@ class action extends control
/**
* Trash.
*
+ * @param string $browseType
* @param string $type all|hidden
* @param string $orderBy
* @param int $recTotal
@@ -22,7 +23,7 @@ class action extends control
* @access public
* @return void
*/
- public function trash($type = 'all', $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
+ public function trash($browseType = 'all', $type = 'all', $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
{
$this->loadModel('backup');
@@ -60,18 +61,37 @@ class action extends control
$pager = pager::init($recTotal, $recPerPage, $pageID);
/* Append id for secend sort. */
- $sort = common::appendOrder($orderBy);
- $trashes = $this->action->getTrashes($type, $sort, $pager);
+ $sort = common::appendOrder($orderBy);
+ $trashes = $this->action->getTrashes($browseType, $type, $sort, $pager);
+ $objectTypeList = $this->action->getTrashObjectTypes($type);
+ $objectTypeList = array_keys($objectTypeList);
+
+ $preferredType = array();
+ $moreType = array();
+ $preferredTypeConfig = $this->config->systemMode == 'new' ? $this->config->action->preferredType->new : $this->config->action->preferredType->classic;
+ foreach($objectTypeList as $objectType)
+ {
+ in_array($objectType, $preferredTypeConfig) ? $preferredType[$objectType] = $objectType : $moreType[$objectType] = $objectType;
+ }
+ if(count($preferredType) < $this->config->action->preferredTypeNum)
+ {
+ $toPreferredType = array_splice($moreType, 0, $this->config->action->preferredTypeNum - count($preferredType));
+ $preferredType = $preferredType + $toPreferredType;
+ }
/* Title and position. */
$this->view->title = $this->lang->action->trash;
$this->view->position[] = $this->lang->action->trash;
- $this->view->trashes = $trashes;
- $this->view->type = $type;
- $this->view->orderBy = $orderBy;
- $this->view->pager = $pager;
- $this->view->users = $this->loadModel('user')->getPairs('noletter');
+ $this->view->trashes = $trashes;
+ $this->view->type = $type;
+ $this->view->currentObjectType = $browseType;
+ $this->view->orderBy = $orderBy;
+ $this->view->pager = $pager;
+ $this->view->users = $this->loadModel('user')->getPairs('noletter');
+ $this->view->preferredType = $preferredType;
+ $this->view->moreType = $moreType;
+ $this->view->preferredTypeConfig = $preferredTypeConfig;
$this->display();
}
diff --git a/module/action/css/trash.css b/module/action/css/trash.css
index afbfc580cc..2f9190111c 100755
--- a/module/action/css/trash.css
+++ b/module/action/css/trash.css
@@ -1,3 +1,7 @@
.table-footer .table-actions {width: auto; visibility: visible; opacity: 1;}
.table-footer .table-actions .text {line-height: 28px;}
table tbody tr td {overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}
+
+#mainMenu .btn-toolbar .btn-group .dropdown-menu .btn-active-text:hover .text {color: #fff}
+
+.dropdown-menu .btn-active-text:hover .text:after {border-bottom: 0px;}
diff --git a/module/action/model.php b/module/action/model.php
index bbea80d598..2791f3ee01 100755
--- a/module/action/model.php
+++ b/module/action/model.php
@@ -610,17 +610,19 @@ class actionModel extends model
/**
* Get deleted objects.
*
+ * @param string $objectType
* @param string $type all|hidden
* @param string $orderBy
* @param object $pager
* @access public
* @return array
*/
- public function getTrashes($type, $orderBy, $pager)
+ public function getTrashes($objectType, $type, $orderBy, $pager)
{
- $extra = $type == 'hidden' ? self::BE_HIDDEN : self::CAN_UNDELETED;
+ $extra = $type == 'hidden' ? self::BE_HIDDEN : self::CAN_UNDELETED;
$trashes = $this->dao->select('*')->from(TABLE_ACTION)
->where('action')->eq('deleted')
+ ->beginIF($objectType != 'all')->andWhere('objectType')->eq($objectType)->fi()
->andWhere('extra')->eq($extra)
->andWhere('vision')->eq($this->config->vision)
->orderBy($orderBy)->page($pager)->fetchAll();
@@ -665,9 +667,23 @@ class actionModel extends model
$trash->objectName = isset($objectNames[$objectType][$trash->objectID]) ? $objectNames[$objectType][$trash->objectID] : '';
}
+
return $trashes;
}
+ /**
+ * Get object type list of trashes.
+ *
+ * @param string $type
+ * @access public
+ * @return array
+ */
+ public function getTrashObjectTypes($type)
+ {
+ $extra = $type == 'hidden' ? self::BE_HIDDEN : self::CAN_UNDELETED;
+ return $this->dao->select('objectType')->from(TABLE_ACTION)->where('action')->eq('deleted')->andWhere('extra')->eq($extra)->andWhere('vision')->eq($this->config->vision)->fetchAll('objectType');
+ }
+
/**
* Get histories of an action.
*
diff --git a/module/action/view/trash.html.php b/module/action/view/trash.html.php
index 2651f5754a..16edede05c 100755
--- a/module/action/view/trash.html.php
+++ b/module/action/view/trash.html.php
@@ -12,9 +12,53 @@
?>
+
- goback, '', "class='btn'");?>
- " . $lang->action->dynamic->hidden, '', "class='btn btn-danger'");?>
+ goback, '', "class='btn'");?>
+ " . $lang->action->dynamic->hidden, '', "class='btn btn-danger'");?>
@@ -31,7 +75,7 @@
- recTotal}&recPerPage={$pager->recPerPage}"; ?>
+ recTotal}&recPerPage={$pager->recPerPage}"; ?>
| action->objectType);?> |
diff --git a/module/api/model.php b/module/api/model.php
index 4296aa73d6..0cfde0ab69 100644
--- a/module/api/model.php
+++ b/module/api/model.php
@@ -764,6 +764,7 @@ class apiModel extends model
public function createDemoData($name, $baseUrl, $version = '16.0')
{
/* Replace the doc lib name to api lib name. */
+ $this->app->loadLang('doc');
$this->lang->doclib->name = $this->lang->doclib->apiLibName;
$firstAccount = $this->dao->select('account')->from(TABLE_USER)->orderBy('id_asc')->limit(1)->fetch('account');
diff --git a/module/bug/model.php b/module/bug/model.php
index 2f445064f5..9ff6b81d69 100644
--- a/module/bug/model.php
+++ b/module/bug/model.php
@@ -1679,12 +1679,7 @@ class bugModel extends model
}
}
- $allProduct = "`product` = 'all'";
- $bugQuery = $this->session->projectBugQuery;
- if(strpos($this->session->projectBugQuery, $allProduct) !== false)
- {
- $bugQuery = str_replace($allProduct, '1', $this->session->projectBugQuery);
- }
+ $bugQuery = $this->getBugQuery($this->session->projectBugQuery);
$bugs = $this->dao->select('*')->from(TABLE_BUG)
->where($bugQuery)
@@ -1746,12 +1741,7 @@ class bugModel extends model
}
}
- $allProduct = "`product` = 'all'";
- $bugQuery = $this->session->executionBugQuery;
- if(strpos($this->session->executionBugQuery, $allProduct) !== false)
- {
- $bugQuery = str_replace($allProduct, '1', $this->session->executionBugQuery);
- }
+ $bugQuery = $this->getBugQuery($this->session->executionBugQuery);
$bugs = $this->dao->select('*')->from(TABLE_BUG)
->where($bugQuery)
@@ -2703,10 +2693,41 @@ class bugModel extends model
if($this->session->bugQuery == false) $this->session->set('bugQuery', ' 1 = 1');
}
- $allProduct = "`product` = 'all'";
- $bugQuery = $this->session->bugQuery;
+ $bugQuery = $this->getBugQuery($this->session->bugQuery);
+
if(is_array($productIDList)) $productIDList = implode(',', $productIDList);
if(strpos($bugQuery, '`product` =') === false) $bugQuery .= ' AND `product` in (' . $productIDList . ')';
+
+ $allBranch = "`branch` = 'all'";
+ if($branch !== 'all' and strpos($bugQuery, '`branch` =') === false) $bugQuery .= " AND `branch` in('0','$branch')";
+ if(strpos($bugQuery, $allBranch) !== false) $bugQuery = str_replace($allBranch, '1', $bugQuery);
+
+ $bugs = $this->dao->select('*')->from(TABLE_BUG)->where($bugQuery)
+ ->beginIF(!$this->app->user->admin)->andWhere('execution')->in('0,' . $this->app->user->view->sprints)->fi()
+ ->beginIF($excludeBugs)->andWhere('id')->notIN($excludeBugs)->fi()
+
+ ->beginIF($projectID)
+ ->andWhere('project', true)->eq($projectID)
+ ->orWhere('project')->eq(0)
+ ->andWhere('openedBuild')->eq('trunk')
+ ->markRight(1)
+ ->fi()
+
+ ->andWhere('deleted')->eq(0)
+ ->orderBy($orderBy)->page($pager)->fetchAll();
+ return $bugs;
+ }
+
+ /**
+ * Get bug query.
+ *
+ * @param string $bugQuery
+ * @access public
+ * @return string
+ */
+ public function getBugQuery($bugQuery)
+ {
+ $allProduct = "`product` = 'all'";
if(strpos($bugQuery, $allProduct) !== false)
{
$products = $this->app->user->view->products;
@@ -2714,10 +2735,6 @@ class bugModel extends model
$bugQuery = $bugQuery . ' AND `product` ' . helper::dbIN($products);
}
- $allBranch = "`branch` = 'all'";
- if($branch !== 'all' and strpos($bugQuery, '`branch` =') === false) $bugQuery .= " AND `branch` in('0','$branch')";
- if(strpos($bugQuery, $allBranch) !== false) $bugQuery = str_replace($allBranch, '1', $bugQuery);
-
$allProject = "`project` = 'all'";
if(strpos($bugQuery, $allProject) !== false)
{
@@ -2745,26 +2762,12 @@ class bugModel extends model
->orWhere('t2.verify')->like("%$searchValue%")
->fetchPairs('id');
- $bugQuery = preg_replace("/`story`[ ]+(NOT[ ]*)?LIKE[ ]+'%$searchValue%'/Ui", '`story` $1 IN (' . implode($story, ',') .')', $bugQuery);
+ $bugQuery = preg_replace("/`story`[ ]+(NOT[ ]*)?LIKE[ ]+'%$searchValue%'/Ui", '`story` $1 IN (' . implode(',', $story) .')', $bugQuery);
}
}
$bugQuery .= ' AND `story` != 0';
}
-
- $bugs = $this->dao->select('*')->from(TABLE_BUG)->where($bugQuery)
- ->beginIF(!$this->app->user->admin)->andWhere('execution')->in('0,' . $this->app->user->view->sprints)->fi()
- ->beginIF($excludeBugs)->andWhere('id')->notIN($excludeBugs)->fi()
-
- ->beginIF($projectID)
- ->andWhere('project', true)->eq($projectID)
- ->orWhere('project')->eq(0)
- ->andWhere('openedBuild')->eq('trunk')
- ->markRight(1)
- ->fi()
-
- ->andWhere('deleted')->eq(0)
- ->orderBy($orderBy)->page($pager)->fetchAll();
- return $bugs;
+ return $bugQuery;
}
/**
diff --git a/module/bug/view/view.html.php b/module/bug/view/view.html.php
index f80245adc1..b7f0629533 100644
--- a/module/bug/view/view.html.php
+++ b/module/bug/view/view.html.php
@@ -96,7 +96,7 @@
deleted):?>
- buildOperateMenu($bug, 'view');?>
+ bug->buildOperateMenu($bug, 'view');?>
diff --git a/module/build/model.php b/module/build/model.php
index b72d747ec6..06a61c1dc0 100644
--- a/module/build/model.php
+++ b/module/build/model.php
@@ -505,7 +505,6 @@ class buildModel extends model
*/
public function batchUnlinkBug($buildID)
{
-
$bugList = $this->post->unlinkBugs;
if(empty($bugList)) return true;
@@ -518,4 +517,27 @@ class buildModel extends model
$this->loadModel('action');
foreach($this->post->unlinkBugs as $unlinkBugID) $this->action->create('bug', $unlinkBugID, 'unlinkedfrombuild', '', $buildID);
}
+
+ /**
+ * Build action menu.
+ *
+ * @param object $build
+ * @param string $type
+ * @access public
+ * @return string
+ */
+ public function buildOperateMenu($build, $type = 'view')
+ {
+ $canBeChanged = common::canBeChanged('build', $build);
+ if($build->deleted || !$canBeChanged) return '';
+
+ $menu = '';
+ $params = "buildID=$build->id";
+
+ $menu .= $this->buildFlowMenu('build', $build, 'view', 'direct');
+ $menu .= $this->buildMenu('build', 'edit', $params, $build, $type);
+ $menu .= $this->buildMenu('build', 'delete', $params, $build, $type, 'trash', 'hiddenwin');
+
+ return $menu;
+ }
}
diff --git a/module/build/view/view.html.php b/module/build/view/view.html.php
index 101bd6b0fb..b2dad81742 100644
--- a/module/build/view/view.html.php
+++ b/module/build/view/view.html.php
@@ -48,15 +48,7 @@ tbody tr td:first-child input {display: none;}
- deleted and $canBeChanged)
- {
- echo $this->buildOperateMenu($build, 'view');
-
- if(common::hasPriv('build', 'edit')) echo html::a($this->createLink('build', 'edit', "buildID=$build->id"), " " . $this->lang->edit, '', "class='btn btn-link' title='{$this->lang->edit}' data-app='{$app->tab}'");
- if(common::hasPriv('build', 'delete')) echo html::a($this->createLink('build', 'delete', "buildID=$build->id"), " " . $this->lang->delete, '', "class='btn btn-link' title='{$this->lang->delete}' target='hiddenwin' data-app='{$app->tab}'");
- }
- ?>
+ build->buildOperateMenu($build, 'view');?>
diff --git a/module/caselib/lang/zh-cn.php b/module/caselib/lang/zh-cn.php
index 90cc8b069e..114092a784 100644
--- a/module/caselib/lang/zh-cn.php
+++ b/module/caselib/lang/zh-cn.php
@@ -25,7 +25,8 @@ $lang->caselib->exportTemplet = '导出模板';
$lang->caselib->batchCreateCase = '批量创建用例';
$lang->caselib->import = '导入';
$lang->caselib->showImport = '显示导入数据';
-
+$lang->caselib->type = '类型';
+$lang->caselib->product = '所属' . $lang->productCommon;
$lang->caselib->browseAction = '用例库列表';
$lang->caselib->deleteAction = "删除用例库";
$lang->caselib->importAction = '导入用例';
diff --git a/module/caselib/view/browse.html.php b/module/caselib/view/browse.html.php
index 35101bfe14..980fcde929 100644
--- a/module/caselib/view/browse.html.php
+++ b/module/caselib/view/browse.html.php
@@ -157,7 +157,7 @@ js::set('flow', $config->global->flow);
processStatus('testcase', $case);?> |
" . $this->loadModel('flow')->getFieldValue($extendField, $case) . "";?>
- buildOperateMenu($case, 'browse');?>
+ caselib->buildOperateMenu($case, 'browse');?>
|
diff --git a/module/caselib/view/view.html.php b/module/caselib/view/view.html.php
index 868c67dccc..0bc7645556 100644
--- a/module/caselib/view/view.html.php
+++ b/module/caselib/view/view.html.php
@@ -39,7 +39,7 @@
";?>
- buildOperateMenu($lib, 'view');?>
+ caselib->buildOperateMenu($lib, 'view');?>
diff --git a/module/doc/control.php b/module/doc/control.php
index 362d8e7ef4..a8a29389c1 100644
--- a/module/doc/control.php
+++ b/module/doc/control.php
@@ -695,6 +695,26 @@ class doc extends control
}
}
+ /**
+ * Update order.
+ *
+ * @access public
+ * @return void
+ */
+ public function updateOrder()
+ {
+ if($_SERVER['REQUEST_METHOD'] == 'POST')
+ {
+ foreach($_POST['orders'] as $id => $order)
+ {
+ $this->dao->update(TABLE_DOC)->set('`order`')->eq($order)->where('id')->eq($id)->exec();
+ }
+
+ if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
+ return $this->send(array('result' => 'success'));
+ }
+ }
+
/**
* Ajax get modules by libID.
*
diff --git a/module/doc/css/tablecontents.css b/module/doc/css/tablecontents.css
index a864562332..9cd6f9101e 100644
--- a/module/doc/css/tablecontents.css
+++ b/module/doc/css/tablecontents.css
@@ -20,3 +20,21 @@ span.dotted-line+a {display: block;}
.tree li.has-list.open:before {content: unset;}
#modules i.icon-file-text {color: #D0D2D6; font-size: 14px;}
.tree li>a {max-width: 80%;}
+
+.sortable-sorting .module-name > a {cursor: move;}
+.sortable-sorting li >.tree-group {opacity: .5;}
+.sortable-sorting .drop-here .tree-group {background-color: #fff3e0;}
+.sortable-sorting .drop-here .tree-group > * {opacity: .1;}
+.sortable-sorting .drag-shadow .tree-group {opacity: 1!important;}
+.sortable-sorting .drag-shadow .tree-actions {visibility: hidden;}
+.is-sorting > li > .tree-group {opacity: 1; border-radius: 4px;}
+.is-sorting > li ul {display: none!important;}
+
+.tree-group {position: relative;}
+.tree-group > .module-name {white-space: nowrap; overflow: hidden; text-overflow: ellipsis; width: 100%; display: block;}
+.tree-group .tree-actions {display: none; position: absolute; right: 0; top: 0; background-color: #fff; white-space: nowrap;}
+.tree-group:hover > .module-name {width: calc(100% - 20px);}
+.tree-group:hover .tree-actions {display: block}
+.tree li.has-list.open:before {left: 6px;}
+.sortDoc>.tail-info{right: 20px;}
+.sortDoc>.tree-actions{position: absolute; right: 0px; background: #fff;}
diff --git a/module/doc/js/tablecontents.js b/module/doc/js/tablecontents.js
index a3e3e75859..d11c77d92a 100644
--- a/module/doc/js/tablecontents.js
+++ b/module/doc/js/tablecontents.js
@@ -18,4 +18,81 @@ $(function()
})
$('.menu-actions > a').blur(function() {$(this).css('background', 'none');})
+
+ /* Make modules tree sortable. */
+ $('#modules').sortable(
+ {
+ trigger: '.module-name>a.sort-module, .tree-actions>.sortModule>.icon-move, a.sortDoc, .tree-actions>.sortDoc>.icon-move',
+ dropToClass: 'sort-to',
+ stopPropagation: true,
+ nested: true,
+ selector: 'li',
+ dragCssClass: 'drop-here',
+ canMoveHere: function($ele, $target)
+ {
+ var maxTop = $('.side-col > .cell > ul').height() - $ele.height();
+ if(parseFloat($('.drag-shadow').css('top')) < 0) $('.drag-shadow').css('top', '0');
+ if(parseFloat($('.drag-shadow').css('left')) != 0) $('.drag-shadow').css('left', '0');
+ if(parseFloat($('.drag-shadow').css('top')) > maxTop) $('.drag-shadow').css('top', maxTop + 'px');
+ return true;
+ },
+ targetSelector: function($ele, $root)
+ {
+ var $ul = $ele.closest('ul');
+ setTimeout(function()
+ {
+ if($('#modules').hasClass('sortable-sorting')) $ul.addClass('is-sorting');
+ }, 100);
+
+ if($ele.hasClass('sortDoc'))
+ {
+ return $ul.children('li.sortDoc');
+ }
+ else
+ {
+ return $ul.children('li.catalog');
+ }
+ },
+ always: function()
+ {
+ $('#modules,#modules .is-sorting').removeClass('is-sorting');
+ },
+ finish: function(e)
+ {
+ if(!e.changed) return;
+
+ var orders = {};
+ var link = '';
+ var elementClass = e.list.context.className;
+ if(elementClass.indexOf('sortDoc') >= 0)
+ {
+ $('#modules').find('li.sortDoc').each(function()
+ {
+ var $li = $(this);
+
+ var item = $li.data();
+ orders['orders[' + item.id + ']'] = $li.attr('data-order') || item.order;
+ });
+
+ link = createLink('doc', 'updateOrder');
+ }
+ else
+ {
+ $('#modules').find('li.can-sort').each(function()
+ {
+ var $li = $(this);
+
+ var item = $li.data();
+ '' == 'book' ? orders['sort[' + item.id + ']'] = $li.attr('data-order') || item.order : orders['orders[' + item.id + ']'] = $li.attr('data-order') || item.order;
+ });
+
+ link = createLink('tree', 'updateOrder');
+ }
+
+ $.post(link, orders, function(data){}).error(function()
+ {
+ bootbox.alert(lang.timeout);
+ });
+ }
+ });
})
diff --git a/module/doc/lang/en.php b/module/doc/lang/en.php
index bd888eb70d..ac26a6ddbb 100644
--- a/module/doc/lang/en.php
+++ b/module/doc/lang/en.php
@@ -93,6 +93,7 @@ $lang->doc->collector = 'Collector';
$lang->doc->main = 'Main Document Library';
$lang->doc->order = 'Order';
$lang->doc->doc = 'Document';
+$lang->doc->updateOrder = 'Update Order';
$lang->doc->moduleDoc = 'By Module';
$lang->doc->searchDoc = 'Search';
diff --git a/module/doc/lang/zh-cn.php b/module/doc/lang/zh-cn.php
index ff69f8c514..1fd47b0c4d 100644
--- a/module/doc/lang/zh-cn.php
+++ b/module/doc/lang/zh-cn.php
@@ -93,6 +93,7 @@ $lang->doc->collector = '收藏者';
$lang->doc->main = '文档主库';
$lang->doc->order = '排序';
$lang->doc->doc = '文档';
+$lang->doc->updateOrder = '更新排序';
$lang->doc->moduleDoc = '按模块浏览';
$lang->doc->searchDoc = '搜索';
diff --git a/module/doc/model.php b/module/doc/model.php
index bd6c10c81c..87f9a94b0c 100644
--- a/module/doc/model.php
+++ b/module/doc/model.php
@@ -2379,6 +2379,7 @@ EOT;
$docs = $this->dao->select('*')->from(TABLE_DOC)
->where('lib')->eq($rootID)
->andWhere('deleted')->eq(0)
+ ->orderBy('`order` asc')
->fetchAll();
$moduleDocs = array();
foreach($docs as $doc)
@@ -2410,25 +2411,36 @@ EOT;
{
if(!$docID and $currentMethod != 'tablecontents') $docID = $doc->id;
- $treeMenu[0] .= 'id == $docID ? ' class="active"' : ' class="independent"') . " data-id=$doc->id>";
+ $class = common::hasPriv('doc', 'updateOrder') ? ' sortDoc' : '';
+ $treeMenu[0] .= 'id>";
if($currentMethod == 'tablecontents')
{
- $treeMenu[0] .= '' . zget($users, $doc->editedBy) . ' ' . $doc->editedDate . '';
+ $treeMenu[0] .= '' . zget($users, $doc->editedBy) . ' ' . $doc->editedDate . '';
+ if(common::hasPriv('doc', 'updateOrder'))
+ {
+ $treeMenu[0] .= "
";
+ $treeMenu[0] .= html::a('javascript:;', "", '', "title='{$this->lang->doc->updateOrder}' class='sortDoc'");
+ $treeMenu[0] .= '
';
+ }
}
if($currentMethod == 'objectlibs')
{
- $treeMenu[0] .= "
" . html::a(inlink('objectLibs', "type=$type&objectID=$objectID&libID=$rootID&docID={$doc->id}"), " " . $doc->title, '', "data-app='{$this->app->tab}' class='doc-title' title='{$doc->title}'") . '';
- if(common::hasPriv('doc', 'edit'))
+ $class = common::hasPriv('doc', 'updateOrder') ? 'sortDoc' : '';
+ $treeMenu[0] .= "
" . html::a(inlink('objectLibs', "type=$type&objectID=$objectID&libID=$rootID&docID={$doc->id}"), " " . $doc->title, '', "data-app='{$this->app->tab}' class='doc-title $class' title='{$doc->title}'") . '';
+ if(common::hasPriv('doc', 'edit') or common::hasPriv('doc', 'updateOrder'))
{
$treeMenu[0] .= "
";
- $treeMenu[0] .= html::a(helper::createLink('doc', 'edit', "docID={$doc->id}&comment=false&objectType=$type&objectID=$objectID&libID=$rootID"), "", '', "title={$this->lang->doc->edit} data-app='{$this->app->tab}'");
+ if(common::hasPriv('doc', 'edit')) $treeMenu[0] .= html::a(helper::createLink('doc', 'edit', "docID={$doc->id}&comment=false&objectType=$type&objectID=$objectID&libID=$rootID"), "", '', "title={$this->lang->doc->edit} data-app='{$this->app->tab}'");
+ if(common::hasPriv('doc', 'updateOrder')) $treeMenu[0] .= html::a('javascript:;', "", '', "title='{$this->lang->doc->updateOrder}' class='sortDoc'");
$treeMenu[0] .= '
';
}
}
else
{
- $treeMenu[0] .= html::a(inlink('objectLibs', "type=$type&objectID=$objectID&libID=$rootID&docID={$doc->id}"), "
" . $doc->title, '', "data-app='{$this->app->tab}' class='doc-title' title='{$doc->title}'");
+ $class = common::hasPriv('doc', 'updateOrder') ? 'sortDoc' : '';
+ $treeMenu[0] .= html::a(inlink('objectLibs', "type=$type&objectID=$objectID&libID=$rootID&docID={$doc->id}"), "
" . $doc->title, '', "data-app='{$this->app->tab}' class='doc-title $class' title='{$doc->title}'");
+ $treeMenu[0] .= '
';
}
$treeMenu[0] .= '';
@@ -2477,27 +2489,38 @@ EOT;
else
{
if(!$docID and $currentMethod != 'tablecontents') $docID = $doc->id;
- $treeMenu[$module->id] .= '
id == $docID ? ' class="active"' : ' class="doc"') . " data-id=$doc->id>";
+ $class = common::hasPriv('doc', 'updateOrder') ? ' sortDoc' : '';
+ $treeMenu[$module->id] .= 'id>";
if($currentMethod == 'tablecontents')
{
- $treeMenu[$module->id] .= '' . zget($users, $doc->editedBy) . ' ' . $doc->editedDate . '';
+ $treeMenu[$module->id] .= '' . zget($users, $doc->editedBy) . ' ' . $doc->editedDate . '';
+ if(common::hasPriv('doc', 'updateOrder'))
+ {
+ $treeMenu[$module->id] .= "
";
+ $treeMenu[$module->id] .= html::a('javascript:;', "", '', "title='{$this->lang->doc->updateOrder}' class='sortDoc'");
+ $treeMenu[$module->id] .= '
';
+ }
}
if($currentMethod == 'objectlibs')
{
- $treeMenu[$module->id] .= "
" . html::a(inlink('objectLibs', "type=$type&objectID=$objectID&libID=$libID&docID={$doc->id}"), " " . $doc->title, '', "data-app='{$this->app->tab}' class='doc-title' title='{$doc->title}'") . '';
- if(common::hasPriv('doc', 'edit'))
+ $class = common::hasPriv('doc', 'updateOrder') ? 'sortDoc' : '';
+ $treeMenu[$module->id] .= "
" . html::a(inlink('objectLibs', "type=$type&objectID=$objectID&libID=$libID&docID={$doc->id}"), " " . $doc->title, '', "data-app='{$this->app->tab}' class='doc-title $class' title='{$doc->title}'") . '';
+ if(common::hasPriv('doc', 'edit') or common::hasPriv('doc', 'updateOrder'))
{
$treeMenu[$module->id] .= "
";
- $treeMenu[$module->id] .= html::a(helper::createLink('doc', 'edit', "docID={$doc->id}&comment=false&objectType=$type&objectID=$objectID&libID=$libID"), "", '', "title={$this->lang->doc->edit} data-app={$this->app->tab}");
+ if(common::hasPriv('doc', 'edit')) $treeMenu[$module->id] .= html::a(helper::createLink('doc', 'edit', "docID={$doc->id}&comment=false&objectType=$type&objectID=$objectID&libID=$libID"), "", '', "title={$this->lang->doc->edit} data-app={$this->app->tab}");
+ if(common::hasPriv('doc', 'updateOrder')) $treeMenu[$module->id] .= html::a('javascript:;', "", '', "title='{$this->lang->doc->updateOrder}' class='sortDoc'");
$treeMenu[$module->id] .= '
';
}
$treeMenu[$module->id] .= '
';
}
elseif($currentMethod == 'tablecontents')
{
- $treeMenu[$module->id] .= html::a(inlink('objectLibs', "type=$type&objectID=$objectID&libID=$libID&docID={$doc->id}"), "
" . $doc->title, '', "data-app='{$this->app->tab}' class='doc-title' title='{$doc->title}'");
+ $class = common::hasPriv('doc', 'updateOrder') ? 'sortDoc' : '';
+ $treeMenu[$module->id] .= html::a(inlink('objectLibs', "type=$type&objectID=$objectID&libID=$libID&docID={$doc->id}"), "
" . $doc->title, '', "data-app='{$this->app->tab}' class='doc-title $class' title='{$doc->title}'");
+ $treeMenu[$module->id] .= '
';
}
$treeMenu[$module->id] .= '';
@@ -2511,22 +2534,25 @@ EOT;
}
else
{
- if($currentMethod == 'tablecontents')
+ $li = "
" . $module->name . '';
+ if($currentMethod == 'tablecontents' and common::hasPriv('tree', 'updateOrder'))
{
- $li = "
" . $module->name . '';
+ $li .= "
";
+ $li .= html::a('javascript:;', "", '', "title='{$this->lang->doc->updateOrder}' class='sortModule'");
+ $li .= '
';
}
else
{
- $li = "
" . $module->name . '';
- if(common::hasPriv('tree', 'edit') or common::hasPriv('tree', 'browse'))
+ if(common::hasPriv('tree', 'edit') or common::hasPriv('tree', 'browse') or common::hasPriv('tree', 'browse') or common::hasPriv('tree', 'updateOrder'))
{
$li .= "
";
- if(common::hasPriv('tree', 'edit')) $li .= html::a(helper::createLink('tree', 'edit', "module=$module->id&type=doc"), "", '', "data-toggle='modal' title={$this->lang->doc->editType}");
- if(common::hasPriv('tree', 'browse')) $li .= html::a(helper::createLink('tree', 'browse', "rootID=$libID&type=doc&module=$module->id", '', 1), "", '', "class='iframe' title={$this->lang->doc->editChildType}");
+ if(common::hasPriv('tree', 'edit')) $li .= html::a(helper::createLink('tree', 'edit', "module=$module->id&type=doc"), "", '', "data-toggle='modal' title='{$this->lang->doc->editType}'");
+ if(common::hasPriv('tree', 'browse')) $li .= html::a(helper::createLink('tree', 'browse', "rootID=$libID&type=doc&module=$module->id", '', 1), "", '', "class='iframe' title='{$this->lang->doc->editChildType}'");
+ if(common::hasPriv('tree', 'updateOrder')) $li .= html::a('javascript:;', "", '', "title='{$this->lang->doc->updateOrder}' class='sortModule'");
$li .= '
';
}
- $li .= '
';
}
+ $li .= '
';
}
if($treeMenu[$module->id])
{
diff --git a/module/doc/view/side.html.php b/module/doc/view/side.html.php
index 32cbbc41b9..701393f393 100644
--- a/module/doc/view/side.html.php
+++ b/module/doc/view/side.html.php
@@ -79,7 +79,7 @@ $sideWidth = common::checkNotCN() ? '270' : '238';
/* Make modules tree sortable */
$('#modules').sortable(
{
- trigger: '.module-name>a.sort-module',
+ trigger: '.module-name>a.sort-module, .tree-actions>.sortModule>.icon-move, .module-name>a.sortDoc, .tree-actions>.sortDoc>.icon-move',
dropToClass: 'sort-to',
stopPropagation: true,
nested: true,
@@ -100,7 +100,15 @@ $sideWidth = common::checkNotCN() ? '270' : '238';
{
if($('#modules').hasClass('sortable-sorting')) $ul.addClass('is-sorting');
}, 100);
- return $ul.children('li');
+
+ if($ele.hasClass('sortDoc'))
+ {
+ return $ul.children('li.sortDoc');
+ }
+ else
+ {
+ return $ul.children('li.catalog');
+ }
},
always: function()
{
@@ -110,16 +118,34 @@ $sideWidth = common::checkNotCN() ? '270' : '238';
{
if(!e.changed) return;
- var orders = {};
- $('#modules').find('li.can-sort').each(function()
+ var orders = {};
+ var link = '';
+ var elementClass = e.list.context.className;
+ if(elementClass.indexOf('sortDoc') >= 0)
{
- var $li = $(this);
+ $('#modules').find('li.sortDoc').each(function()
+ {
+ var $li = $(this);
- var item = $li.data();
- '' == 'book' ? orders['sort[' + item.id + ']'] = $li.attr('data-order') || item.order : orders['orders[' + item.id + ']'] = $li.attr('data-order') || item.order;
- });
+ var item = $li.data();
+ orders['orders[' + item.id + ']'] = $li.attr('data-order') || item.order;
+ });
+
+ link = createLink('doc', 'updateOrder');
+ }
+ else
+ {
+ $('#modules').find('li.can-sort').each(function()
+ {
+ var $li = $(this);
+
+ var item = $li.data();
+ '' == 'book' ? orders['sort[' + item.id + ']'] = $li.attr('data-order') || item.order : orders['orders[' + item.id + ']'] = $li.attr('data-order') || item.order;
+ });
+
+ link = '' == 'book' ? createLink('doc', 'sortBookOrder') : createLink('tree', 'updateOrder');
+ }
- var link = '' == 'book' ? createLink('doc', 'sortBookOrder') : createLink('tree', 'updateOrder');
$.post(link, orders, function(data){}).error(function()
{
bootbox.alert(lang.timeout);
diff --git a/module/execution/control.php b/module/execution/control.php
index be01e4169e..f711a2b2a1 100644
--- a/module/execution/control.php
+++ b/module/execution/control.php
@@ -1677,9 +1677,15 @@ class execution extends control
if($this->app->tab == 'project')
{
- $projectID = $this->session->project;
+ $projectID = $this->session->project;
+ $project = $this->project->getById($projectID);
+ $allProjects = $this->project->getPairsByModel($project->model, 0, 'noclosed', isset($projectID) ? $projectID : 0);
$this->project->setMenu($projectID);
- $this->view->project = $this->project->getById($projectID);
+ $this->view->project = $project;
+ }
+ else
+ {
+ $allProjects = $this->project->getPairsByModel('all', 0, 'noclosed', isset($projectID) ? $projectID : 0);
}
if(!$this->post->executionIDList) return print(js::locate($this->session->executionList, 'parent'));
@@ -1717,7 +1723,7 @@ class execution extends control
$this->view->position[] = $this->lang->execution->batchEdit;
$this->view->executionIDList = $executionIDList;
$this->view->executions = $executions;
- $this->view->allProjects = $this->project->getPairsByModel('all', 0, 'noclosed', isset($projectID) ? $projectID : 0);
+ $this->view->allProjects = $allProjects;
$this->view->pmUsers = $pmUsers;
$this->view->poUsers = $poUsers;
$this->view->qdUsers = $qdUsers;
diff --git a/module/execution/js/batchedit.js b/module/execution/js/batchedit.js
index f9fca2bb2b..6c0e349d09 100644
--- a/module/execution/js/batchedit.js
+++ b/module/execution/js/batchedit.js
@@ -1,13 +1,14 @@
-$(function()
+function changeProject(obj, executionID, projectID)
{
- $('[id^="projects"]').change(function()
+ var $td = $(obj).closest('td');
+ if($td.find('[id^="syncStories"]').length == 0)
{
- var executionID = $(this).attr('id').replace('projects', '');
- var $td = $(this).closest('td');
- if($td.find('[id^="syncStories"]').length == 0)
- {
- $td.append("
");
- }
- $("#syncStories" + executionID).val(confirm(confirmSyncStories) ? 'yes' : 'no');
- })
-});
+ $td.append("
");
+ }
+ var confirmVal = confirm(confirmSync);
+ $("#syncStories" + executionID).val(confirmVal ? 'yes' : 'no');
+ if(!confirmVal)
+ {
+ $(obj).val(projectID).trigger("chosen:updated");
+ }
+};
diff --git a/module/execution/js/edit.js b/module/execution/js/edit.js
index 0c09b6bfe8..3955629251 100644
--- a/module/execution/js/edit.js
+++ b/module/execution/js/edit.js
@@ -71,6 +71,6 @@ $(function()
{
$('#submit').after("
");
}
- $("#syncStories").val(confirm(confirmSyncStories) ? 'yes' : 'no');
+ $("#syncStories").val(confirm(confirmSync) ? 'yes' : 'no');
});
})
diff --git a/module/execution/lang/en.php b/module/execution/lang/en.php
index c9aa6aa2f0..0c7530ff03 100644
--- a/module/execution/lang/en.php
+++ b/module/execution/lang/en.php
@@ -340,7 +340,7 @@ if($config->systemMode == 'new') $lang->execution->copyTeamTitle = "Choose a
$lang->execution->confirmDelete = "Do you want to delete the {$lang->executionCommon}[%s]?";
$lang->execution->confirmUnlinkMember = "Do you want to unlink this User from {$lang->executionCommon}?";
$lang->execution->confirmUnlinkStory = "After {$lang->SRCommon} is removed, cased linked to {$lang->SRCommon} will be reomoved and tasks linked to {$lang->SRCommon} will be cancelled. Do you want to continue?";
-$lang->execution->confirmSyncStories = "After modifying the project, synchronize the execution related {$lang->SRCommon} to the new project?";
+$lang->execution->confirmSync = "After modifying the project, in order to maintain the consistency of data, the data of products, requirements, teams and whitelist associated with the implementation will be synchronized to the new project. Please know.";
$lang->execution->confirmUnlinkExecutionStory = "Do you want to unlink this Story from the execution?";
$lang->execution->notAllowedUnlinkStory = "This {$lang->SRCommon} is linked to the {$lang->executionCommon} of the execution. Remove it from the {$lang->executionCommon}, then try again.";
$lang->execution->notAllowRemoveProducts = "The story of this product is linked with the {$lang->executionCommon}. Unlink it before doing any action.";
diff --git a/module/execution/lang/zh-cn.php b/module/execution/lang/zh-cn.php
index 9248f804cb..b3cd85caf9 100644
--- a/module/execution/lang/zh-cn.php
+++ b/module/execution/lang/zh-cn.php
@@ -340,7 +340,7 @@ if($config->systemMode == 'new') $lang->execution->copyTeamTitle = "选择
$lang->execution->confirmDelete = "您确定删除{$lang->executionCommon}[%s]吗?";
$lang->execution->confirmUnlinkMember = "您确定从该{$lang->executionCommon}中移除该用户吗?";
$lang->execution->confirmUnlinkStory = "移除该{$lang->SRCommon}后,该{$lang->SRCommon}关联的用例将被移除,该{$lang->SRCommon}关联的任务将被取消,请确认。";
-$lang->execution->confirmSyncStories = "修改所属项目后,执行关联的{$lang->SRCommon}是否同步到新项目中?";
+$lang->execution->confirmSync = "修改所属项目后,为了保持数据的一致性,该执行所关联的产品、需求、团队和白名单数据将会同步到新的项目中,请知悉。";
$lang->execution->confirmUnlinkExecutionStory = "您确定从该项目中移除该{$lang->SRCommon}吗?";
$lang->execution->notAllowedUnlinkStory = "该{$lang->SRCommon}已经与项目下{$lang->executionCommon}相关联,请从{$lang->executionCommon}中移除后再操作。";
$lang->execution->notAllowRemoveProducts = "该{$lang->productCommon}中的{$lang->SRCommon}已与该{$lang->executionCommon}进行了关联,请取消关联后再操作。";
diff --git a/module/execution/model.php b/module/execution/model.php
index 507ddfe98a..e50d9ec569 100644
--- a/module/execution/model.php
+++ b/module/execution/model.php
@@ -684,6 +684,27 @@ class executionModel extends model
$projectID = isset($execution->project) ? $execution->project : $oldExecution->project;
$project = $this->project->getByID($projectID);
+ if(isset($execution->project))
+ {
+ $executionProductList = $this->loadModel('product')->getProducts($executionID);
+ $projectProductList = $this->product->getProducts($execution->project);
+ $executionProductIdList = array_keys($executionProductList);
+ $projectProductIdList = array_keys($projectProductList);
+ $diffProductIdList = array_diff($executionProductIdList, $projectProductIdList);
+ if(!empty($diffProductIdList))
+ {
+ foreach($diffProductIdList as $key => $newProductID)
+ {
+ $data = $this->dao->select('*')->from(TABLE_PROJECTPRODUCT)
+ ->where('project')->eq($executionID)
+ ->andWhere('product')->eq($newProductID)
+ ->fetch();
+ $data->project = $execution->project;
+ $this->dao->insert(TABLE_PROJECTPRODUCT)->data($data)->exec();
+ }
+ }
+ }
+
if($project and $execution->begin < $project->begin)
{
dao::$errors['begin'] = sprintf($this->lang->execution->errorLetterProject, $project->begin);
@@ -2791,15 +2812,70 @@ class executionModel extends model
public function computeBurn()
{
$today = helper::today();
- $burns = array();
-
$executions = $this->dao->select('id, code')->from(TABLE_EXECUTION)
->where('end')->ge($today)
- ->andWhere('type')->ne('ops')
+ ->andWhere('type')->in('sprint,stage')
+ ->andWhere('lifetime')->ne('ops')
->andWhere('status')->notin('done,closed,suspended')
->fetchPairs();
- if(!$executions) return $burns;
+ if(!$executions) return array();
+ /* Update historical data of burn. */
+ $table = $this->config->edition == 'open' ? TABLE_TASKESTIMATE : TABLE_EFFORT;
+ $field = $this->config->edition == 'open' ? 'task' : 'objectID';
+ $totalConsumed = $this->dao->select("t2.execution as execution, t1.$field as task, t1.date as date, sum(t1.consumed) as totalConsumed")->from($table)->alias('t1')
+ ->leftJoin(TABLE_TASK)->alias('t2')->on("t1.$field=t2.id")
+ ->where('t2.execution')->in(array_keys($executions))
+ ->beginIF($this->config->edition != 'open')->andWhere('t1.objectType')->eq('task')->fi()
+ ->andWhere('t2.deleted')->eq('0')
+ ->andWhere('t2.parent')->ge('0')
+ ->andWhere('t2.status')->ne('cancel')
+ ->andWhere('t1.date')->ne($today)
+ ->groupBy("t1.$field, t1.date")
+ ->orderBy('t1.id_desc')
+ ->fetchGroup('task', 'date');
+
+ $latestIdList = $this->dao->select('max(id) as id')->from($table)
+ ->where($field)->in(array_keys($totalConsumed))
+ ->beginIF($this->config->edition != 'open')->andWhere('objectType')->eq('task')->fi()
+ ->groupBy("$field,date")->fetchAll('id');
+ $latestLefts = $this->dao->select("$field, date, `left`")->from($table)
+ ->where('id')->in(array_keys($latestIdList))
+ ->fetchGroup($field, 'date');
+
+ $burnList = array();
+ foreach($totalConsumed as $taskID => $consumedList)
+ {
+ foreach($consumedList as $date => $consumed)
+ {
+ $executionID = $consumed->execution;
+ if(!isset($burnList[$executionID])) $burnList[$executionID] = array();
+
+ if(!isset($burnList[$executionID][$date]))
+ {
+ $burnList[$executionID][$date] = new stdclass();
+ $burnList[$executionID][$date]->consumed = 0;
+ $burnList[$executionID][$date]->left = 0;
+ }
+
+ $burnList[$executionID][$date]->consumed += $consumed->totalConsumed;
+ $burnList[$executionID][$date]->left += $latestLefts[$taskID][$date]->left;
+ }
+ }
+
+ foreach($burnList as $executionID => $burns)
+ {
+ foreach($burns as $date => $burn)
+ {
+ $burn->execution = $executionID;
+ $burn->date = $date;
+
+ $this->dao->replace(TABLE_BURN)->data($burn)->exec();
+ $burn->executionName = $executions[$burn->execution];
+ }
+ }
+
+ /* Update today's data of burn. */
$burns = $this->dao->select("execution, '$today' AS date, sum(estimate) AS `estimate`, sum(`left`) AS `left`, SUM(consumed) AS `consumed`")
->from(TABLE_TASK)
->where('execution')->in(array_keys($executions))
@@ -2852,8 +2928,10 @@ class executionModel extends model
$this->dao->replace(TABLE_BURN)->data($burn)->exec();
$burn->executionName = $executions[$burn->execution];
+ $burnList[$executionID][$today] = $burn;
}
- return $burns;
+
+ return $burnList;
}
/**
@@ -3955,4 +4033,36 @@ class executionModel extends model
}
$this->dao->update(TABLE_PROJECT)->set('path')->eq($path['path'])->set('grade')->eq($path['grade'])->where('id')->eq($execution->id)->exec();
}
+
+ /**
+ * Build execution action menu.
+ *
+ * @param object $execution
+ * @param string $type
+ * @access public
+ * @return string
+ */
+ public function buildOperateMenu($execution, $type = 'view')
+ {
+ if($execution->deleted) return '';
+
+ $menu = '';
+ $params = "executionID=$execution->id";
+
+ $menu .= "
";
+ $menu .= $this->buildMenu('execution', 'start', $params, $execution, $type, '', '', 'iframe', true);
+ $menu .= $this->buildMenu('execution', 'activate', $params, $execution, $type, '', '', 'iframe', true);
+ $menu .= $this->buildMenu('execution', 'putoff', $params, $execution, $type, '', '', 'iframe', true);
+ $menu .= $this->buildMenu('execution', 'suspend', $params, $execution, $type, '', '', 'iframe', true);
+ $menu .= $this->buildMenu('execution', 'close', $params, $execution, $type, '', '', 'iframe', true);
+
+ $menu .= "
";
+ $menu .= $this->buildFlowMenu('execution', $execution, 'view', 'direct');
+ $menu .= "
";
+
+ $menu .= $this->buildMenu('execution', 'edit', "execution=$execution->id", $execution);
+ $menu .= $this->buildMenu('execution', 'delete', "execution=$execution->id", $execution, 'button', 'trash', 'hiddenwin');
+
+ return $menu;
+ }
}
diff --git a/module/execution/view/batchedit.html.php b/module/execution/view/batchedit.html.php
index 2ad0a2b496..5520f67890 100755
--- a/module/execution/view/batchedit.html.php
+++ b/module/execution/view/batchedit.html.php
@@ -83,7 +83,7 @@
|
systemMode == 'new' and isset($project) and $project->model == 'scrum'):?>
- project, "class='form-control picker-select'");?> |
+ project, "class='form-control picker-select' onchange='changeProject(this, $executionID, {$executions[$executionID]->project})'");?> |
name, "class='form-control'");?> |
code, "class='form-control'");?> |
@@ -137,5 +137,5 @@
execution->weekend);?>
-execution->confirmSyncStories);?>
+execution->confirmSync);?>
diff --git a/module/execution/view/computeburn.html.php b/module/execution/view/computeburn.html.php
index ea9ea7d339..8cbbbff589 100644
--- a/module/execution/view/computeburn.html.php
+++ b/module/execution/view/computeburn.html.php
@@ -11,8 +11,11 @@
*/
?>
$burnList)
{
- echo $burn->execution . "\t" . $burn->executionName . "\t" . $burn->date . "\t" . $burn->left . "\n";
+ foreach($burnList as $date => $burn)
+ {
+ echo $burn->execution . "\t" . $burn->executionName . "\t" . $burn->date . "\t" . $burn->left . "\n";
+ }
}
?>
diff --git a/module/execution/view/edit.html.php b/module/execution/view/edit.html.php
index 7c664b9c0a..449d728f84 100644
--- a/module/execution/view/edit.html.php
+++ b/module/execution/view/edit.html.php
@@ -220,6 +220,6 @@
execution->notAllowRemoveProducts);?>
-execution->confirmSyncStories);?>
+execution->confirmSync);?>
systemMode);?>
diff --git a/module/execution/view/view.html.php b/module/execution/view/view.html.php
index fabcf9761c..90ec222e0e 100644
--- a/module/execution/view/view.html.php
+++ b/module/execution/view/view.html.php
@@ -146,26 +146,9 @@
- id";
- $browseLink = $this->session->executionList ? $this->session->executionList : inlink('browse', "executionID=$execution->id");
- common::printBack($browseLink);
- if(!$execution->deleted)
- {
- echo "
";
- common::printIcon('execution', 'start', "executionID=$execution->id", $execution, 'button', '', '', 'iframe', true);
- common::printIcon('execution', 'activate', "executionID=$execution->id", $execution, 'button', '', '', 'iframe', true);
- common::printIcon('execution', 'putoff', "executionID=$execution->id", $execution, 'button', '', '', 'iframe', true);
- common::printIcon('execution', 'suspend', "executionID=$execution->id", $execution, 'button', '', '', 'iframe', true);
- common::printIcon('execution', 'close', "executionID=$execution->id", $execution, 'button', '', '', 'iframe', true);
-
- echo $this->buildOperateMenu($execution, 'view');
-
- echo "
";
- common::printIcon('execution', 'edit', $params, $execution);
- common::printIcon('execution', 'delete', $params, $execution, 'button', 'trash', 'hiddenwin');
- }
- ?>
+ session->executionList ? $this->session->executionList : inlink('browse', "executionID=$execution->id");?>
+
+ execution->buildOperateMenu($execution, 'view');?>
diff --git a/module/gitlab/control.php b/module/gitlab/control.php
index dcf9627853..e3faaf7ada 100644
--- a/module/gitlab/control.php
+++ b/module/gitlab/control.php
@@ -259,7 +259,7 @@ class gitlab extends control
$user = $this->gitlab->apiGetCurrentUser($gitlab->url, $gitlab->token, true);
if(!is_object($user)) return $this->send(array('result' => 'fail', 'message' => array('url' => array(sprintf($this->lang->gitlab->hostError, $this->config->gitlab->minCompatibleVersion)))));
- if(isset($user->error)) return $this->send(array('result' => 'fail', 'message' => array('token' => array($this->lang->gitlab->tokenError))));
+ if(!isset($user->id)) return $this->send(array('result' => 'fail', 'message' => array('token' => array($this->lang->gitlab->tokenError))));
/* Verify version compatibility. */
$result = $this->gitlab->getVersion($gitlab->url, $gitlab->token);
diff --git a/module/group/lang/resource.php b/module/group/lang/resource.php
index 60aa69d0a4..9e7c18a9bd 100644
--- a/module/group/lang/resource.php
+++ b/module/group/lang/resource.php
@@ -1215,6 +1215,7 @@ $lang->resource->doc->objectLibs = 'objectLibs';
$lang->resource->doc->collect = 'collectAction';
$lang->resource->doc->tableContents = 'tableContents';
$lang->resource->doc->showFiles = 'showFiles';
+$lang->resource->doc->updateOrder = 'updateOrder';
$lang->doc->methodOrder[0] = 'index';
$lang->doc->methodOrder[5] = 'browse';
diff --git a/module/kanban/view/viewarchivedcard.html.php b/module/kanban/view/viewarchivedcard.html.php
index 09da6b4a0f..1a18aed718 100644
--- a/module/kanban/view/viewarchivedcard.html.php
+++ b/module/kanban/view/viewarchivedcard.html.php
@@ -19,6 +19,7 @@
#archivedCards .kanban-item > .info {margin-top: 5px; position: relative;}
#archivedCards .kanban-item > .info > .pri {height: 14px; border-width: 1px; font-size: 12px; line-height: 12px; min-width: 14px; padding: 0 1px;}
#archivedCards .kanban-item > .info > .time {margin-left: 10px; font-size: 12px}
+#archivedCards .kanban-item > .info.build > .time {margin-left:0px; font-size: 12px}
#archivedCards .kanban-item > .info > .user {position: absolute; right: 0; top: 0}
#archivedCards .card-actions {position: relative; padding: 15px 10px; padding-top: 0px;}
#archivedCards .card-actions > .btn {display: block;}
@@ -41,7 +42,9 @@
#archivedCards .card-item .has-color .info > .label-pri,
#archivedCards .card-item .has-color .info > .estimate,
#archivedCards .card-item .has-color .info > .label-light {color: #FFFFFF;}
+#archivedCards .info.execution .label-light, #archivedCards .info.productplan .label-light, #archivedCards .info.build .label-light, #archivedCards .info.release .label-light {background: #EFEFEF !important; color: #838A9D !important;}
#archivedCards .card-item .has-color .info > .label-pri {border-color: #FFFFFF;}
+#archivedCards .card-item .has-color .progress-box > .progress-number {color: #FFFFFF;}
#archivedCards .progress-box {width: 97%;}
#performable {padding: 25px 10px !important;}
@@ -91,51 +94,70 @@ $app->loadLang('productplan');
title) ? $card->title : $card->name;
- if(common::hasPriv($card->fromType, 'view')) echo html::a($this->createLink('productplan', 'view', "id=$card->fromID"), $name, '', "class='cardName' title='$name'");
+ if(common::hasPriv($card->fromType, 'view')) echo html::a($this->createLink($card->fromType, 'view', "id=$card->fromID"), $name, '', "class='cardName' title='$name'");
if(!common::hasPriv($card->fromType, 'view')) echo "$name
";
echo "";
- if($card->fromType != 'release' and isset($lang->{$card->fromType}->statusList[$card->objectStatus])) echo "
" . $lang->{$card->fromType}->statusList[$card->objectStatus] . '';
- if(isset($card->date) and !helper::isZeroDate($card->date)) echo "
" . date("m/d", strtotime($card->date)) . ""
+ if(isset($lang->{$card->fromType}->statusList[$card->objectStatus])) echo "
" . $lang->{$card->fromType}->statusList[$card->objectStatus] . '';
+ if(isset($card->date) and !helper::isZeroDate($card->date)) echo "
" . date("Y-m-d", strtotime($card->date)) . ""
?>
- end) and !helper::isZeroDate($card->begin)):?>
+ end) and !helper::isZeroDate($card->begin) and $card->begin != '2030-01-01' and $card->end != '2030-01-01'):?>
begin)) . $lang->kanbancard->beginAB;?>
- begin) and !helper::isZeroDate($card->end)):?>
+ begin) and !helper::isZeroDate($card->end) and $card->begin != '2030-01-01' and $card->end != '2030-01-01'):?>
end)) . $lang->kanbancard->deadlineAB;?>
- begin) and !helper::isZeroDate($card->end)):?>
+ begin) and !helper::isZeroDate($card->end) and $card->begin != '2030-01-01' and $card->end != '2030-01-01' and $card->fromType == ''):?>
begin)) . ' ~ ' . date("m/d", strtotime($card->end));?>
+ begin) and !helper::isZeroDate($card->end) and $card->begin != '2030-01-01' and $card->end != '2030-01-01' and $card->fromType != ''):?>
+
begin)) . ' ' . $lang->{$card->fromType}->to . ' ' . date("m-d", strtotime($card->end));?>
+
assignedTo);
+ if($card->begin == '2030-01-01' or $card->end == '2030-01-01') echo '
' . $lang->{$card->fromType}->future . '';
+
+ if($card->fromType == '') $assignedToList = explode(',', $card->assignedTo);
+ if($card->fromType == 'execution') $assignedToList = $card->PM;
+ if($card->fromType == 'build') $assignedToList = $card->builder;
+ if($card->fromType == 'release' or $card->fromType == 'productplan') $assignedToList = $card->createdBy;
$count = 0;
$members = '';
?>
- $account)
- {
- if(!isset($users[$account]) or !isset($usersAvatar[$account]))
- {
- unset($assignedToList[$index]);
- continue;
- }
- $members .= $users[$account] . ',';
- }
- $userCount = count($assignedToList);
- ?>
- 0):?>
-
- 2) continue;
- echo html::smallAvatar(array('avatar' => $usersAvatar[$account], 'account' => $account, 'name' => $users[$account]), 'avatar-circle');
- $count ++;
- }
- ?>
- 2) echo "...";?>
-
+
+ $account)
+ {
+ if(!isset($users[$account]) or !isset($usersAvatar[$account]))
+ {
+ unset($assignedToList[$index]);
+ continue;
+ }
+ $members .= $users[$account] . ',';
+ }
+ $userCount = count($assignedToList);
+ ?>
+ 0):?>
+
+ 2) continue;
+ echo html::smallAvatar(array('avatar' => $usersAvatar[$account], 'account' => $account, 'name' => $users[$account]), 'avatar-circle');
+ $count ++;
+ }
+ ?>
+ 2) echo "...";?>
+
+
+
+ ";
+ echo html::smallAvatar(array('avatar' => $usersAvatar[$assignedToList], 'account' => $assignedToList, 'name' => $users[$assignedToList]), 'avatar-circle');
+ echo "
";
+ }
+ ?>
performable):?>
diff --git a/module/product/config.php b/module/product/config.php
index 15b950ff39..ba557eda1f 100644
--- a/module/product/config.php
+++ b/module/product/config.php
@@ -87,6 +87,36 @@ $config->product->search['params']['closedDate'] = array('operator' => '=',
$config->product->search['params']['lastEditedDate'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date');
$config->product->search['params']['activatedDate'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date');
+$config->product->all = new stdclass();
+$config->product->all->search['module'] = 'product';
+$config->product->all->search['fields']['name'] = $lang->product->name;
+$config->product->all->search['fields']['code'] = $lang->product->code;
+$config->product->all->search['fields']['id'] = $lang->product->id;
+if($config->systemMode == 'new') $config->product->all->search['fields']['program'] = $lang->product->program;
+$config->product->all->search['fields']['line'] = $lang->product->line;
+$config->product->all->search['fields']['desc'] = $lang->product->desc;
+$config->product->all->search['fields']['PO'] = $lang->product->PO;
+$config->product->all->search['fields']['QD'] = $lang->product->QD;
+$config->product->all->search['fields']['RD'] = $lang->product->RD;
+$config->product->all->search['fields']['reviewer'] = $lang->product->reviewer;
+$config->product->all->search['fields']['type'] = $lang->product->type;
+$config->product->all->search['fields']['createdDate'] = $lang->product->createdDate;
+$config->product->all->search['fields']['createdBy'] = $lang->product->createdBy;
+
+$config->product->all->search['params']['name'] = array('operator' => 'include', 'control' => 'input', 'values' => '');
+$config->product->all->search['params']['code'] = array('operator' => 'include', 'control' => 'input', 'values' => '');
+$config->product->all->search['params']['id'] = array('operator' => '=', 'control' => 'input', 'values' => '');
+if($config->systemMode == 'new') $config->product->all->search['params']['program'] = array('operator' => '=', 'control' => 'select', 'values' => '');
+$config->product->all->search['params']['line'] = array('operator' => '=', 'control' => 'select', 'values' => '');
+$config->product->all->search['params']['desc'] = array('operator' => 'include', 'control' => 'input', 'values' => '');
+$config->product->all->search['params']['PO'] = array('operator' => '=', 'control' => 'select', 'values' => 'users');
+$config->product->all->search['params']['QD'] = array('operator' => '=', 'control' => 'select', 'values' => 'users');
+$config->product->all->search['params']['RD'] = array('operator' => '=', 'control' => 'select', 'values' => 'users');
+$config->product->all->search['params']['reviewer'] = array('operator' => 'include', 'control' => 'select', 'values' => 'users');
+$config->product->all->search['params']['type'] = array('operator' => '=', 'control' => 'select', 'values' => $lang->product->typeList);
+$config->product->all->search['params']['createdDate'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date');
+$config->product->all->search['params']['createdBy'] = array('operator' => '=', 'control' => 'select', 'values' => 'users');
+
$config->product->create = new stdclass();
$config->product->edit = new stdclass();
$config->product->create->requiredFields = 'name,code';
diff --git a/module/product/control.php b/module/product/control.php
index fc85c81ebf..401edefb9b 100644
--- a/module/product/control.php
+++ b/module/product/control.php
@@ -1197,22 +1197,30 @@ class product extends control
* @access public
* @return void
*/
- public function all($browseType = 'noclosed', $orderBy = 'order_asc')
+ public function all($browseType = 'noclosed', $orderBy = 'program_asc', $param = 0, $recTotal = 0, $recPerPage = 20, $pageID = 1)
{
/* Load module and set session. */
$this->loadModel('program');
$this->session->set('productList', $this->app->getURI(true), 'product');
+ $queryID = ($browseType == 'bySearch') ? (int)$param : 0;
+
if($this->app->viewType == 'mhtml')
{
$productID = $this->product->saveState(0, $this->products);
$this->product->setMenu($productID);
}
+ $this->app->loadClass('pager', $static = true);
+ $pager = new pager($recTotal, $recPerPage, $pageID);
+
/* Process product structure. */
- $productStats = $this->product->getStats($orderBy, '', $browseType, '', 'story');
+ $productStats = $this->product->getStats($orderBy, $pager, $browseType, '', 'story', '', $queryID);
$productStructure = $this->product->statisticProgram($productStats);
+ $actionURL = $this->createLink('product', 'all', "browseType=bySearch&orderBy=order_asc&queryID=myQueryID");
+ $this->product->buildProductSearchForm($param, $actionURL);
+
$this->view->title = $this->lang->product->common;
$this->view->position[] = $this->lang->product->common;
@@ -1221,6 +1229,7 @@ class product extends control
$this->view->productStructure = $productStructure;
$this->view->orderBy = $orderBy;
$this->view->browseType = $browseType;
+ $this->view->pager = $pager;
$this->display();
}
diff --git a/module/product/model.php b/module/product/model.php
index f8427994e5..d92ec088e7 100644
--- a/module/product/model.php
+++ b/module/product/model.php
@@ -275,6 +275,48 @@ class productModel extends model
->fetchAll('id');
}
+ /**
+ * Get list by search.
+ *
+ * @param int $queryID
+ * @access public
+ * @return array
+ */
+ public function getListBySearch($queryID = 0)
+ {
+ if($queryID)
+ {
+ $query = $this->loadModel('search')->getQuery($queryID);
+ if($query)
+ {
+ $this->session->set('productQuery', $query->sql);
+ $this->session->set('productForm', $query->form);
+ }
+ else
+ {
+ $this->session->set('productQuery', ' 1 = 1');
+ }
+ }
+ else
+ {
+ if($this->session->productQuery == false) $this->session->set('productQuery', ' 1 = 1');
+ }
+
+ $productQuery = $this->session->productQuery;
+ $productQuery = preg_replace('/`(\w+)`/', 't1.`$1`', $productQuery);
+
+ $products = $this->dao->select('t1.id as id,t1.*')->from(TABLE_PRODUCT)->alias('t1')
+ ->leftJoin(TABLE_PROGRAM)->alias('t2')->on('t1.program = t2.id')
+ ->where($productQuery)
+ ->andWhere('t1.deleted')->eq(0)
+ ->beginIF(!$this->app->user->admin)->andWhere('t1.id')->in($this->app->user->view->products)->fi()
+ ->andWhere('t1.vision')->eq($this->config->vision)->fi()
+ ->orderBy('t1.order_asc')
+ ->fetchAll('id');
+
+ return $products;
+ }
+
/**
* Get product pairs.
*
@@ -1049,6 +1091,31 @@ class productModel extends model
$this->loadModel('search')->setSearchParams($this->config->product->search);
}
+ /**
+ * Build search form for all method of product module.
+ *
+ * @param int $queryID
+ * @param string $actionURL
+ * @access public
+ * @return void
+ */
+ public function buildProductSearchForm($queryID, $actionURL)
+ {
+ $this->config->product->all->search['queryID'] = $queryID;
+ $this->config->product->all->search['actionURL'] = $actionURL;
+
+ $linePairs = $this->getLinePairs();
+ $this->config->product->all->search['params']['line']['values'] = array('' => '') + $linePairs;
+
+ if($this->config->systemMode == 'new')
+ {
+ $programPairs = $this->loadModel('program')->getTopPairs('', 'noclosed');
+ $this->config->product->all->search['params']['program']['values'] = array('' => '') + $programPairs;
+ }
+
+ $this->loadModel('search')->setSearchParams($this->config->product->all->search);
+ }
+
/**
* Get project pairs by product.
*
@@ -1569,13 +1636,13 @@ class productModel extends model
* @access public
* @return array
*/
- public function getStats($orderBy = 'order_asc', $pager = null, $status = 'noclosed', $line = 0, $storyType = 'story', $programID = 0)
+ public function getStats($orderBy = 'order_asc', $pager = null, $status = 'noclosed', $line = 0, $storyType = 'story', $programID = 0, $param = 0)
{
$this->loadModel('report');
$this->loadModel('story');
$this->loadModel('bug');
- $products = $this->getList($programID, $status, $limit = 0, $line);
+ $products = $status == 'bySearch' ? $this->getListBySearch($param) : $this->getList($programID, $status, $limit = 0, $line);
if(empty($products)) return array();
$productKeys = array_keys($products);
@@ -2043,7 +2110,7 @@ class productModel extends model
$menu .= $this->buildFlowMenu('product', $product, $type, 'direct');
$menu .= "";
- $menu .= $this->buildMenu('product', 'close', $params, $product, $type, '', '', '', '', "data-app='product'");
+ $menu .= $this->buildMenu('product', 'close', $params, $product, $type, '', '', 'iframe', true, "data-app='product'");
$menu .= "";
}
diff --git a/module/product/view/all.html.php b/module/product/view/all.html.php
index 25b5453e0b..7b29353309 100644
--- a/module/product/view/all.html.php
+++ b/module/product/view/all.html.php
@@ -17,6 +17,7 @@
{$recTotal}" : '';?>
{$label}" . $recTotalLabel, '', "class='btn btn-link' id='{$key}Tab'");?>
+ product->searchStory;?>
" . $lang->export, '', "class='btn btn-link export'", true, true)?>
@@ -26,11 +27,13 @@
+
diff --git a/module/product/view/view.html.php b/module/product/view/view.html.php
index 9dff1daa07..dd670efb83 100644
--- a/module/product/view/view.html.php
+++ b/module/product/view/view.html.php
@@ -161,7 +161,7 @@
$browseLink = $this->session->productList ? $this->session->productList : inlink('browse', "productID=$product->id");
common::printBack($browseLink);
- if(!$product->deleted) echo $this->buildOperateMenu($product, 'view');
+ if(!$product->deleted) echo $this->product->buildOperateMenu($product, 'view');
?>
diff --git a/module/productplan/view/browsebylist.html.php b/module/productplan/view/browsebylist.html.php
index db0c2e0b73..b4bbe598f4 100644
--- a/module/productplan/view/browsebylist.html.php
+++ b/module/productplan/view/browsebylist.html.php
@@ -144,7 +144,7 @@
" . $this->loadModel('flow')->getFieldValue($extendField, $plan) . "";?>
- buildOperateMenu($plan, 'browse'); ?> |
+ productplan->buildOperateMenu($plan, 'browse'); ?> |
diff --git a/module/productplan/view/view.html.php b/module/productplan/view/view.html.php
index cff6af86a6..76002e70b1 100644
--- a/module/productplan/view/view.html.php
+++ b/module/productplan/view/view.html.php
@@ -38,7 +38,7 @@
- deleted && !isonlybody()) echo $this->buildOperateMenu($plan, 'view'); ?>
+ deleted && !isonlybody()) echo $this->productplan->buildOperateMenu($plan, 'view'); ?>
diff --git a/module/program/config.php b/module/program/config.php
index d93159b907..15afcb8278 100644
--- a/module/program/config.php
+++ b/module/program/config.php
@@ -22,3 +22,31 @@ $config->program->sortFields = new stdclass();
$config->program->sortFields->id = 'id';
$config->program->sortFields->begin = 'begin';
$config->program->sortFields->end = 'end';
+
+global $lang;
+$config->program->search['module'] = 'program';
+$config->program->search['fields']['name'] = $lang->program->name;
+$config->program->search['fields']['status'] = $lang->program->status;
+$config->program->search['fields']['desc'] = $lang->program->desc;
+$config->program->search['fields']['PM'] = $lang->program->PM;
+$config->program->search['fields']['openedDate'] = $lang->program->openedDate;
+$config->program->search['fields']['begin'] = $lang->program->begin;
+$config->program->search['fields']['end'] = $lang->program->end;
+$config->program->search['fields']['openedBy'] = $lang->program->openedBy;
+$config->program->search['fields']['lastEditedDate'] = $lang->program->lastEditedDate;
+$config->program->search['fields']['realBegan'] = $lang->program->realBegin;
+$config->program->search['fields']['realEnd'] = $lang->program->realEnd;
+$config->program->search['fields']['closedDate'] = $lang->program->closedDate;
+
+$config->program->search['params']['name'] = array('operator' => 'include', 'control' => 'input', 'values' => '');
+$config->program->search['params']['status'] = array('operator' => '=', 'control' => 'select', 'values' => array('' => '') + $lang->program->statusList);
+$config->program->search['params']['desc'] = array('operator' => 'include', 'control' => 'input', 'values' => '');
+$config->program->search['params']['PM'] = array('operator' => '=', 'control' => 'select', 'values' => 'users');
+$config->program->search['params']['openedDate'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date');
+$config->program->search['params']['begin'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date');
+$config->program->search['params']['end'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date');
+$config->program->search['params']['openedBy'] = array('operator' => '=', 'control' => 'select', 'values' => 'users');
+$config->program->search['params']['lastEditedDate'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date');
+$config->program->search['params']['realBegan'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date');
+$config->program->search['params']['realEnd'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date');
+$config->program->search['params']['closedDate'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date');
diff --git a/module/program/control.php b/module/program/control.php
index 54e34c9fa2..3c8d716d36 100644
--- a/module/program/control.php
+++ b/module/program/control.php
@@ -26,13 +26,16 @@ class program extends control
* @access public
* @return void
*/
- public function browse($status = 'all', $orderBy = 'order_asc')
+ public function browse($status = 'all', $orderBy = 'order_asc', $recTotal = 0, $recPerPage = 10, $pageID = 1, $param = 0)
{
if(common::hasPriv('program', 'create')) $this->lang->pageActions = html::a($this->createLink('program', 'create'), "
" . $this->lang->program->create, '', "class='btn btn-primary create-program-btn'");
$this->session->set('programList', $this->app->getURI(true), 'program');
$this->session->set('projectList', $this->app->getURI(true), 'program');
+ $this->app->loadClass('pager', $static = true);
+ $pager = new pager($recTotal, $recPerPage, $pageID);
+
$programType = $this->cookie->programType ? $this->cookie->programType : 'bylist';
if($programType === 'bygrid')
@@ -41,7 +44,18 @@ class program extends control
}
else
{
- $programs = $this->program->getList($status, $orderBy, null, true);
+ if(strtolower($status) == 'bysearch')
+ {
+ $queryID = (int)$param;
+ $programs = $this->program->getListBySearch($orderBy, $pager, $queryID);
+ }
+ else
+ {
+ $topPrograms = $this->program->getList($status, $orderBy, $pager, 'top');
+ $programIds = array();
+ foreach($topPrograms as $programID => $program) $programIds[] = $programID;
+ $programs = $this->program->getList($status, $orderBy, null, 'child', $programIds);
+ }
}
/* Get PM id list. */
@@ -52,12 +66,19 @@ class program extends control
}
$PMList = $this->loadModel('user')->getListByAccounts($accounts, 'account');
+ /* Build the search form. */
+ $actionURL = $this->createLink('program', 'browse', "status=bySearch&orderBy={$orderBy}&recTotal={$recTotal}&recPerPage={$recPerPage}&pageID={$pageID}¶m=myQueryID");
+ $this->config->program->search['onMenuBar'] = 'yes';
+ $this->config->program->search['actionURL'] = $actionURL;
+ $this->loadModel('search')->setSearchParams($this->config->program->search);
+
$this->view->title = $this->lang->program->browse;
$this->view->position[] = $this->lang->program->browse;
$this->view->programs = $programs;
$this->view->status = $status;
$this->view->orderBy = $orderBy;
+ $this->view->pager = $pager;
$this->view->users = $this->user->getPairs('noletter');
$this->view->userIdPairs = $this->user->getPairs('noletter|showid');
$this->view->usersAvatar = $this->user->getAvatarPairs('');
diff --git a/module/program/js/browse.js b/module/program/js/browse.js
index e84d284444..dc14dca89b 100644
--- a/module/program/js/browse.js
+++ b/module/program/js/browse.js
@@ -43,6 +43,13 @@ $(function()
$('#programForm').removeClass('has-row-checked');
}
});
+
+ var myPager = $('.pager').data('zui.pager');
+ if(status != 'bySearch' && myPager)
+ {
+ myPager.lang.pageSize = pageSize;
+ myPager.set();
+ }
});
function showEditCheckbox(show)
diff --git a/module/program/lang/en.php b/module/program/lang/en.php
index 31568de285..754323b538 100644
--- a/module/program/lang/en.php
+++ b/module/program/lang/en.php
@@ -1,33 +1,36 @@
program->id = 'ID';
-$lang->program->name = 'Name';
-$lang->program->template = 'Template';
-$lang->program->category = 'Type';
-$lang->program->desc = 'Description';
-$lang->program->status = 'Status';
-$lang->program->PM = 'Manager';
-$lang->program->budget = 'Budget';
-$lang->program->budgetUnit = 'Budget Unit';
-$lang->program->begin = 'Begin';
-$lang->program->end = 'End';
-$lang->program->stage = 'Stage';
-$lang->program->type = 'Type';
-$lang->program->pri = 'Priority';
-$lang->program->parent = 'Parent';
-$lang->program->exchangeRate = 'Exchange Rate';
-$lang->program->openedBy = 'OpenedBy';
-$lang->program->openedDate = 'OpenedDate';
-$lang->program->closedBy = 'ClosedBy';
-$lang->program->closedDate = 'ClosedDate';
-$lang->program->canceledBy = 'CanceledBy';
-$lang->program->canceledDate = 'CanceledDate';
-$lang->program->team = 'Team';
-$lang->program->order = 'Rank';
-$lang->program->days = 'Days';
-$lang->program->acl = 'Access Control';
-$lang->program->whitelist = 'WhiteList';
-$lang->program->deleted = 'Deleted';
+$lang->program->id = 'ID';
+$lang->program->name = 'Name';
+$lang->program->template = 'Template';
+$lang->program->category = 'Type';
+$lang->program->desc = 'Description';
+$lang->program->status = 'Status';
+$lang->program->PM = 'Manager';
+$lang->program->budget = 'Budget';
+$lang->program->budgetUnit = 'Budget Unit';
+$lang->program->begin = 'Begin';
+$lang->program->end = 'End';
+$lang->program->realBegin = 'Actual Begin';
+$lang->program->realEnd = 'Actual End';
+$lang->program->stage = 'Stage';
+$lang->program->type = 'Type';
+$lang->program->pri = 'Priority';
+$lang->program->parent = 'Parent';
+$lang->program->exchangeRate = 'Exchange Rate';
+$lang->program->openedBy = 'OpenedBy';
+$lang->program->openedDate = 'OpenedDate';
+$lang->program->closedBy = 'ClosedBy';
+$lang->program->closedDate = 'ClosedDate';
+$lang->program->canceledBy = 'CanceledBy';
+$lang->program->canceledDate = 'CanceledDate';
+$lang->program->lastEditedDate = 'LastEditedDate';
+$lang->program->team = 'Team';
+$lang->program->order = 'Rank';
+$lang->program->days = 'Days';
+$lang->program->acl = 'Access Control';
+$lang->program->whitelist = 'WhiteList';
+$lang->program->deleted = 'Deleted';
/* Actions. */
$lang->program->common = 'Program';
@@ -71,6 +74,7 @@ $lang->program->moreProgram = 'More program';
$lang->program->stakeholderType = 'Stakeholder type';
$lang->program->parentBudget = 'Parent program surplus budget:';
$lang->program->isStakeholderKey = 'Key stakeholder';
+$lang->program->pageSize = '
{recPerPage} Top Programs per page';
$lang->program->stakeholderTypeList['inside'] = 'Inside';
$lang->program->stakeholderTypeList['outside'] = 'Outside';
diff --git a/module/program/lang/zh-cn.php b/module/program/lang/zh-cn.php
index c38753ce88..f4279b673c 100644
--- a/module/program/lang/zh-cn.php
+++ b/module/program/lang/zh-cn.php
@@ -1,33 +1,36 @@
program->id = '编号';
-$lang->program->name = '项目集名称';
-$lang->program->template = '项目集模板';
-$lang->program->category = '项目集类型';
-$lang->program->desc = '项目集描述';
-$lang->program->status = '状态';
-$lang->program->PM = '负责人';
-$lang->program->budget = '预算';
-$lang->program->budgetUnit = '预算单位';
-$lang->program->begin = '计划开始';
-$lang->program->end = '计划完成';
-$lang->program->stage = '阶段';
-$lang->program->type = '类型';
-$lang->program->pri = '优先级';
-$lang->program->parent = '父项目集';
-$lang->program->exchangeRate = '汇率';
-$lang->program->openedBy = '由谁创建';
-$lang->program->openedDate = '创建日期';
-$lang->program->closedBy = '由谁关闭';
-$lang->program->closedDate = '关闭日期';
-$lang->program->canceledBy = '由谁取消';
-$lang->program->canceledDate = '取消日期';
-$lang->program->team = '团队';
-$lang->program->order = '排序';
-$lang->program->days = '可用工作日';
-$lang->program->acl = '访问控制';
-$lang->program->whitelist = '白名单';
-$lang->program->deleted = '已删除';
+$lang->program->id = '编号';
+$lang->program->name = '项目集名称';
+$lang->program->template = '项目集模板';
+$lang->program->category = '项目集类型';
+$lang->program->desc = '项目集描述';
+$lang->program->status = '状态';
+$lang->program->PM = '负责人';
+$lang->program->budget = '预算';
+$lang->program->budgetUnit = '预算单位';
+$lang->program->begin = '计划开始';
+$lang->program->end = '计划完成';
+$lang->program->realBegin = '实际开始';
+$lang->program->realEnd = '实际完成';
+$lang->program->stage = '阶段';
+$lang->program->type = '类型';
+$lang->program->pri = '优先级';
+$lang->program->parent = '父项目集';
+$lang->program->exchangeRate = '汇率';
+$lang->program->openedBy = '由谁创建';
+$lang->program->openedDate = '创建日期';
+$lang->program->closedBy = '由谁关闭';
+$lang->program->closedDate = '关闭日期';
+$lang->program->canceledBy = '由谁取消';
+$lang->program->canceledDate = '取消日期';
+$lang->program->lastEditedDate = '最后编辑';
+$lang->program->team = '团队';
+$lang->program->order = '排序';
+$lang->program->days = '可用工作日';
+$lang->program->acl = '访问控制';
+$lang->program->whitelist = '白名单';
+$lang->program->deleted = '已删除';
/* Actions. */
$lang->program->common = '项目集';
@@ -71,6 +74,7 @@ $lang->program->moreProgram = '更多项目集';
$lang->program->stakeholderType = '干系人类型';
$lang->program->parentBudget = '所属项目集剩余预算:';
$lang->program->isStakeholderKey = '关键干系人';
+$lang->program->pageSize = '每页
{recPerPage} 项顶级项目集';
$lang->program->stakeholderTypeList['inside'] = '内部';
$lang->program->stakeholderTypeList['outside'] = '外部';
diff --git a/module/program/model.php b/module/program/model.php
index f5bd3cdb18..01c47c2219 100644
--- a/module/program/model.php
+++ b/module/program/model.php
@@ -130,11 +130,22 @@ class programModel extends model
* @param string $status
* @param string $orderBy
* @param object $pager
+ * @param string $type top|child
+ * @param mixed $idList
* @access public
* @return array
*/
- public function getList($status = 'all', $orderBy = 'id_asc', $pager = NULL)
+ public function getList($status = 'all', $orderBy = 'id_asc', $pager = NULL, $type = '', $idList = '')
{
+ $projectIdList = array();
+ if($type === 'child')
+ {
+ foreach($idList as $topID)
+ {
+ $projectIdList += $this->dao->select('id')->from(TABLE_PROGRAM)->Where('path')->like(",$topID,%")->fetchPairs('id');
+ }
+ }
+
return $this->dao->select('*')->from(TABLE_PROGRAM)
->where('deleted')->eq(0)
->andWhere('vision')->eq($this->config->vision)
@@ -146,6 +157,54 @@ class programModel extends model
->markRight(2)
->beginIF($status != 'all')->andWhere('status')->eq($status)->fi()
->beginIF(!$this->cookie->showClosed)->andWhere('status')->ne('closed')->fi()
+ ->beginIF($type === 'top')->andWhere('parent')->eq(0)->fi()
+ ->beginIF(!empty($projectIdList))->andWhere('id')->in($projectIdList)->fi()
+ ->orderBy($orderBy)
+ ->page($pager)
+ ->fetchAll('id');
+ }
+
+ /**
+ * Get program list by search.
+ *
+ * @param string $orderBy
+ * @param object $pager
+ * @param int $queryID
+ * @access public
+ * @return void
+ */
+ public function getListBySearch($orderBy = 'id_asc', $pager = NULL, $queryID = 0)
+ {
+ if($queryID)
+ {
+ $query = $this->loadModel('search')->getQuery($queryID);
+ if($query)
+ {
+ $this->session->set('programQuery', $query->sql);
+ $this->session->set('programForm', $query->form);
+ }
+ else
+ {
+ $this->session->set('programQuery', ' 1 = 1');
+ }
+ }
+ else
+ {
+ if($this->session->programQuery == false) $this->session->set('programQuery', ' 1 = 1');
+ }
+ $query = $this->session->programQuery;
+
+ return $this->dao->select('*')->from(TABLE_PROGRAM)
+ ->where('deleted')->eq(0)
+ ->andWhere('vision')->eq($this->config->vision)
+ ->andWhere('((type')->eq('program')
+ ->beginIF(!$this->app->user->admin and $this->app->rawMethod != 'browse')->andWhere('id')->in($this->app->user->view->programs)->fi()
+ ->markRight(1)
+ ->orWhere('(type')->eq('project')
+ ->beginIF(!$this->app->user->admin)->andWhere('id')->in($this->app->user->view->projects)->fi()
+ ->markRight(2)
+ ->beginIF(!$this->cookie->showClosed)->andWhere('status')->ne('closed')->fi()
+ ->beginIF($query)->andWhere($query)->fi()
->orderBy($orderBy)
->page($pager)
->fetchAll('id');
@@ -240,15 +299,15 @@ class programModel extends model
foreach($products as $product)
{
$product->plans = zget($plans, $product->id, array());
-
+
/* Convert predefined HTML entities to characters. */
!empty($product->plans) && array_map(function($planVal)
{
return $planVal->title = htmlspecialchars_decode($planVal->title, ENT_QUOTES);
- },
+ },
$product->plans);
$product->name = htmlspecialchars_decode($product->name, ENT_QUOTES);
-
+
$product->releases = zget($releases, $product->id, array());
$projects = zget($projectGroup, $product->id, array());
foreach($projects as $project)
diff --git a/module/program/view/browse.html.php b/module/program/view/browse.html.php
index 6b13491250..abbf959b56 100644
--- a/module/program/view/browse.html.php
+++ b/module/program/view/browse.html.php
@@ -15,6 +15,7 @@
edit);?>
selectAll);?>
+program->pageSize);?>
@@ -27,6 +28,7 @@
$lang->program->showClosed), '', $this->cookie->showClosed ? 'checked=checked' : '');?>
$lang->project->edit), '', $this->cookie->editProject ? 'checked=checked' : '');?>
+
user->search;?>
' . $lang->project->create, '', 'class="btn btn-secondary" data-toggle="modal" data-target="#guideDialog"');?>
@@ -35,6 +37,7 @@
+
program->noProgram;?>
@@ -43,6 +46,7 @@
+
model == 'kanban' ? 'disabled' : '';?>
- id", $program, 'list', 'edit', '', 'iframe', true);?>
- id", $program, 'list', 'group', '', "$class", '', 'data-app="project"');?>
- id", $program, 'list', 'lock', '', "$class", '', 'data-app="project"');?>
+ id", $program, 'list', 'edit', '', 'iframe', true);?>
+ id", $program, 'list', 'group', '', "$class", '', 'data-app="project"');?>
+ id", $program, 'list', 'lock', '', "$class", '', 'data-app="project"');?>
@@ -138,6 +138,7 @@
+